freeslot("MT_SAMSPAWNITEM", "MT_SAMSPAWNITEMSONIC")
--===========================FUNCTIONS PAGE==============================
--This Lua section houses functions I can refer back to for the sake of organization (and general laziness)
--=======================================================================
local SAM = MetroidVanguard

--Checks for either Samus skin.
rawset(_G, "YouAreSamus", function(s) if not (s and s.valid) return false end --
	if s.skin == "samus" or s.skin == "basesamus"
		return true --
	end return false --
end)

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

--Try several times to spawn this thing! SHOTSCALE is optional.
local function SAM_Missile(s,EX,EY,EZ,TYPE, SHOTSCALE)
	SHOTSCALE = (SHOTSCALE) or s.scale
	local SPEEDINFO = (mobjinfo[TYPE]) and mobjinfo[TYPE].speed or 0 --Projectile speed.
	local ghs
	for i = 1,6 --Keep trying to spawn the shot until we've got success!
		ghs = P_SpawnMobj(s.x+EX, s.y+EY, s.z+EZ, TYPE)
		if ghs and ghs.valid 
			return ghs --Yes, we did it!
		elseif (i >= 5)
			EX,EY,EZ = 0,0,s.height/4 --LAST try!
		else
			EX,EY = FixedDiv(FixedMul($,4),5), FixedDiv(FixedMul($,4),5)
			EZ = FixedDiv(FixedMul($,20),21)
		end
	end
end

local function SAM_BulletSpeed(s,p,ghs) --Scale speed with certain types of bullet!
	if ghs and ghs.valid
		local SAMUSSPEED = p.speed+abs(s.momz/2)
		if (SAMUSSPEED > 45<<16)
			SAMUSSPEED = min(88, FixedInt($)-5)
			ghs.momx = FixedDiv(FixedMul($,SAMUSSPEED), 40)
			ghs.momy = FixedDiv(FixedMul($,SAMUSSPEED), 40)
			ghs.momz = FixedDiv(FixedMul($,SAMUSSPEED), 40)
		end				
	end	
end

--ghs is the bullet adjusted. s, p, and ghs are mandatory.
local function SAM_Bullet(s,p,ghs,SHOTSCALE,SPEEDINFO,skip, FIREANG)
	ghs.blendmode = AST_ADD
	ghs.target = s
	ghs.scale = (SHOTSCALE) or ghs.scale
	if skip != true and ghs and ghs.valid
		if SPEEDINFO == nil SPEEDINFO = (mobjinfo[TYPE]) and mobjinfo[TYPE].speed or 0 end
		
		local AIMMOMZ = FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), sin(p.aiming))
		local ADD = s.height/6
		if (ghs.type == MT_SPSHOT) or (ghs.type == MT_SPCHARGESHOT)
			SHOTSCALE = ghs.scale
			AIMMOMZ = FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), sin(p.aiming))
			ADD = 0
		elseif (s.eflags & MFE_VERTICALFLIP) --Settle some offsets...  
			ghs.flags2 = MF2_OBJECTFLIP 
			AIMMOMZ = ($*20)/19
			ADD = s.height*5/7
		end
		ghs.z = $+AIMMOMZ+ADD --Shift!
		
		if ghs and ghs.valid --Now the momentum values.
			if FIREANG == nil FIREANG = s.angle end	
			ghs.momz = $+AIMMOMZ
			P_Thrust(ghs, FIREANG, FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), cos(p.aiming)))
		end 	
	end
end

--TYPE is projectile to spawn. Var3 is Gattling Vortex. Var2 is identifier for special shot patterns like Wave Beam and Spazer.
rawset(_G, "SamusBeamFire", function(s, TYPE, var2, var3)
	local p = s.player
	local crosshaired,XYSPEED,ZSPEED
	local FIREANG = s.angle
	local ADJUSTSHOT = ANG2 --Adjusts projectile angle later.
	local SPEEDINFO = (mobjinfo[TYPE]) and mobjinfo[TYPE].speed or 0 --Projectile speed.
	local SHOTSCALE = s.scale
	local ZFLIP = P_MobjFlip(s)
	
	if s.sam_automob and s.sam_automob.valid
		local t = s.sam_automob
		
		FIREANG = R_PointToAngle2(s.x, s.y, t.x, t.y)
		p.drawangle,s.angle = FIREANG,FIREANG
		
		local ZOFFSET = t.superbrak and t.height*6/11 or t.height/5
		if not t.player 
			if (t.momx or t.momy)
				FIREANG = R_PointToAngle2(s.x, s.y, t.x+(t.momx*4/3), t.y+(t.momy*4/3))	
			end
			if t.z < s.z
				ZOFFSET = $*2/3
			elseif (t.z > s.z+s.height*4)
				ZOFFSET = $*7/6
			end
		end
		p.aiming = R_PointToAngle2(0, 0, R_PointToDist2(s.x, s.y, t.x, t.y), (t.z+ZOFFSET)-s.z)	
		s.SAM_didlockon = 2 --To prevent projectile sliding for 2 frames
		
	else --When NOT locked on, manual aim applies, naturally.
		s.sam_automob = nil
		if (twodlevel or (s.flags2 & MF2_TWOD)) --2D aiming feature. Hold up or down to shoot diagonally.
			if (abs(p.cmd.forwardmove) > 8)
				p.aiming = (p.cmd.forwardmove > 0) and 6000<<16 or -6000<<16
				s.diagshoot = true
			end
		elseif (p.powers[pw_carry] == CR_MINECART) --Aiming in minecarts is glitched, so just disable vertical aiming.
			p.aiming = 0
		elseif (p.pflags & PF_ANALOGMODE) and not p.sammorphed --Analog mode autoaim.
			local t = P_LookForEnemies(p)
			for i = 1,2
				if i == 2 t = P_LookForEnemies(p, true, true) end
				if t and t.valid
					if (t.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR)) and (t.flags & MF_SHOOTABLE) and (t.type != MT_BIGMINE)
					or t.frozenbox
					or (t.type == MT_EGGSHIELD) 
					or (t.type == MT_MINUS)
						if t.health
						and (FixedHypot(FixedHypot(s.x-t.x, s.y-t.y), s.z-t.z) < 2000<<16)
						and P_CheckSight(s, t)
							s.automob = t 
							FIREANG = R_PointToAngle2(s.x, s.y, t.x, t.y)
							p.drawangle = FIREANG break --
						end
					end
				end
			end
		elseif not netgame
			if (CV_FindVar("crosshair").value == 1) and (abs(p.aiming) < 6000<<16)
				p.aiming = $+80<<16
				crosshaired = true
			end
		end
	end

	p.sams_firecd = 2
	p.sam_shinesparkstop = 0
	p.sams_supermissileready = 0
	p.sams_beamanim = 15 --The animation.
	if (TYPE != MT_SPCHARGESHOT)
		P_SpawnPlayerMissile(s, MT_SAMMONBREAKER) --Little invisible explosion that destroys monitors at point blank range.
	end

	if (TYPE == MT_PLCHARGESHOT) or (TYPE == MT_SPCHARGESHOT) or (TYPE == MT_SAMSUPERMISSILE) or (TYPE == MT_HBSHOT)
	or (TYPE == MT_ICCHARGESHOT) or (TYPE == MT_PBCHARGESHOT) or (TYPE == MT_ICCHARGECOMBO) or (TYPE == MT_SPCHARGECOMBO)
		local RECOIL = (s.eflags & MFE_UNDERWATER) and 2 or 1 --1 is the strongest lift. (Hyperbeam, BeamCombos, and Ice Charge Shot)
		if (TYPE == MT_SPCHARGESHOT) or (TYPE == MT_SAMSUPERMISSILE) --How much to divide the recoil?
			RECOIL = 2
		elseif (TYPE == MT_PLCHARGESHOT) --PLASMAbeam chargeshot
			RECOIL = $+5
		elseif (TYPE == MT_PBCHARGESHOT) --POWERbeam chargeshot
			RECOIL = 11 --Tiny bit of lift.
		end	
		local TADJUST = -2<<16 --How much the shot will push you back.
		if (abs(p.aiming) < 9000<<16)
			TADJUST = (abs(p.aiming) < 5000<<16) and -11<<16 or -8<<16
		end
		P_Thrust(s, FIREANG, TADJUST/RECOIL)
		if p.aiming!=0
			local JUMPBOOST = FixedMul(FixedMul(-4<<16/RECOIL, SHOTSCALE*5/4), sin(p.aiming))
			if (p.aiming>0) JUMPBOOST = $*2/3 end --Don't thrust down as much.
			s.momz = $+JUMPBOOST
		end
	end
	

	if not var2 --No special identifier? If not the Gattling Vortex, then it must be a basic shot!
		local SHOT
		if var3	--It's the Gattling Vortex! The number determines the exact shot properties!
		
			ADJUSTSHOT = ANG2 --Adjusts projectile angle later.		
			local ANGSHIFT = ANG2*4 --Adjusts angle of spawning position		
			local EZ = (s.height/3*ZFLIP) --Z spawn position
			local MOMX,MOMY,ZADD = s.momx,s.momy,0 --Whether to add momx,momy, or any Z offsets.
			
			if var3 == 4 // Middle shot
				ADJUSTSHOT = 0
			elseif var3 == 8 // Rightshot
				MOMX,MOMY = 0,0
				ZADD = 2<<16*ZFLIP
				ANGSHIFT = ANG2*32
				ADJUSTSHOT = -ANG2*2
			elseif var3 == 12 // Up-rightshot
				EZ = (s.height*10/11)*ZFLIP
				ZADD = 2<<16*ZFLIP
				ANGSHIFT = ANG2*20
				ADJUSTSHOT = -ANG2
			elseif var3 == 16 // Upshot
				EZ = (s.height*10/8)*ZFLIP
				ZADD = 5<<16*ZFLIP
				ANGSHIFT = ANG2*4
				ADJUSTSHOT = 0
			elseif var3 == 20 // Leftupshot
				MOMX,MOMY = 0,0
				EZ = (s.height*10/11)*ZFLIP
				ZADD = 2<<16*ZFLIP
				ANGSHIFT = ANG2*8
				ADJUSTSHOT = ANG2
			elseif var3 == 24 // Leftshot
				MOMX,MOMY = 0,0
				ANGSHIFT = ANG2*24
				ADJUSTSHOT = ANG2*2
			end
			local SPAWNDIST = P_RandomRange(0,2) and s.radius*4 or 96<<16 --Amount of distance to spawn away from Samus.
			
			local EX = MOMX+FixedMul(SPAWNDIST, cos(FIREANG-ANGSHIFT)) --Extra X.
			local EY = MOMY+FixedMul(SPAWNDIST, sin(FIREANG-ANGSHIFT)) --Extra Y
			EZ = $+ZADD
			
			local vCOLOR = P_RandomRange(1, 3) --Translate to one of these colors.
			vCOLOR = (vCOLOR==1) and SKINCOLOR_RED or (vCOLOR==2) and SKINCOLOR_CRIMSON or SKINCOLOR_ORANGE	
			
			ZSPEED = FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), sin(p.aiming)) --Z and XY thrust values						
			XYSPEED = FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), cos(p.aiming))
			
			SHOT = SAM_Missile(s,EX,EY,EZ,TYPE, FIREANG,SHOTSCALE)
			if SHOT and SHOT.valid --Yes, we got 'em!
				p.sams_shot = SHOT
				SHOT.momz = $ + ZSPEED
				P_Thrust(SHOT, FIREANG-ADJUSTSHOT, XYSPEED or 0)
				SHOT.angle = R_PointToAngle2(SHOT.x, SHOT.y, SHOT.x+SHOT.momx, SHOT.y+SHOT.momy)
				SHOT.color = vCOLOR
				SHOT.gattlingvortex = true
				SHOT.gattlingvortex1 = (var3==4) and true or nil --Main shot?			
			end
		
		--Okay, not special shots or Gattling Vortex! Use the regular behaviour then!
		
		elseif s.automob and s.automob.valid and s.automob.health --Auto-aim fire!
		
			p.sams_shot = P_SpawnMissile(s, s.automob, TYPE)
			
		else --No autoaim! Here's the basic shot function.
			
			local EX = s.momx + FixedMul(s.radius*4, cos(FIREANG-(ANG2*4)))
			local EY = s.momy + FixedMul(s.radius*4, sin(FIREANG-(ANG2*4)))
			local EZ = (s.eflags & MFE_VERTICALFLIP) and s.height or s.height/3
			
			SHOT = SAM_Missile(s,EX,EY,EZ,TYPE, FIREANG,SHOTSCALE)
			if SHOT and SHOT.valid --Yes, we got 'em!
				p.sams_shot = SHOT
				ZSPEED = FixedMul(FixedMul(SPEEDINFO, SHOT.scale), sin(p.aiming)) --Z and XY thrust values
				XYSPEED = FixedMul(FixedMul(SPEEDINFO, SHOT.scale), cos(p.aiming))
				SHOT.momz = $ + ZSPEED
				P_Thrust(SHOT, FIREANG, XYSPEED)
				SHOT.angle = R_PointToAngle2(SHOT.x, SHOT.y, SHOT.x+SHOT.momx, SHOT.y+SHOT.momy)	
			end
		end
		
		--Manipulate every basic shot to use these properties.
		if SHOT and SHOT.valid			
			p.sams_shot,p.plshot = SHOT,SHOT
			SAM_Bullet(s,p,SHOT,SHOTSCALE,SPEEDINFO, true, FIREANG)
			if ZSPEED
				if not (s.eflags & MFE_VERTICALFLIP)
					SHOT.z = $+ZSPEED
				else
					SHOT.flags2 = MF2_OBJECTFLIP
					SHOT.z = $+ZSPEED-((TYPE==MT_WVCHARGESHOT) and s.height*5/4 or s.height*5/7)
				end
			end	
			if SHOT and SHOT.valid --Didn't die horribly from that Z shift?
				if (TYPE == MT_SAMMISSILE)
					SHOT.flags2 = $|MF2_SCATTER
				elseif (TYPE == MT_PBSHOT) or (TYPE == MT_PBCHARGESHOT) --Apply Short Beam traits to these.
					if (leveltime < 3150) and (gametyperules & GTR_RINGSLINGER) 
					and G_GametypeHasSpectators() and not p.sam_powerbeamcombo
						SHOT.ShortBeam = (TYPE == MT_PBSHOT) and 14 or 21
					end					
				elseif (TYPE == MT_HBSHOT) or (TYPE == MT_ICSHOT)
					SAM_BulletSpeed(s,p,SHOT)
				elseif (SHOT.type == MT_SAMSUPERMISSILE)	
					SHOT.flags2 = $|MF2_RAILRING|MF2_SUPERFIRE
					if p.sams_beamcombocharge
						SHOT.shinyshot = true --Makes the powerbeam combo shiny.
					end
				elseif (TYPE == MT_ICCHARGECOMBO)
					SHOT.flags2 = $|MF2_RAILRING|MF2_SUPERFIRE
					SHOT.scale = $*20
					SHOT.spriteyoffset = $-FRACUNIT*6
					local SHOT = SAM_Missile(s,0,0,s.height/2*ZFLIP,MT_ICCHARGESHOT, FIREANG, SHOTSCALE)
					if SHOT and SHOT.valid --Add Icecharge Shot blasts everywhere for the combo!
						p.plshot,p.sams_shoty = SHOT,SHOT
						SHOT.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE
						SHOT.combograce = 14
						SHOT.target = s
						SHOT.scale = SHOTSCALE
						SHOT.romio = p.sams_shot
						if (s.eflags & MFE_VERTICALFLIP)
							SHOT.z = s.z+(2*s.height/3)-FixedMul(SHOT.info.height, SHOTSCALE)
							SHOT.flags2 = MF2_OBJECTFLIP						
						elseif (SHOT.z+SHOT.height+50<<16 < s.ceilingz)
							SHOT.z = $+50<<16
						end
					end 					
				end
			end
		end
		
	elseif var2 == 1 --Spazer Beam! (Uncharged! Charged version's behaviour starts in its MobjThinker!)
	
	    if ((s.flags2 & MF2_TWOD) or twodlevel) --2D shooting. Vertically stacked beams.
					
			p.sams_shot = P_SpawnMobj(
			s.x+FixedMul(s.radius*4, cos(FIREANG-(ANG2*16))), 
			s.y+FixedMul(s.radius*4, sin(FIREANG-(ANG2*16))), 
			s.z+((s.height/3)+s.height/6*(ZFLIP)), TYPE)
			if p.sams_shot and p.sams_shot.valid
				p.plshot = p.sams_shot				
				p.sams_shot.angle = FIREANG
				p.sams_shot.wave4 = true
				SAM_Bullet(s,p,p.sams_shot,SHOTSCALE,SPEEDINFO, nil, FIREANG)
			end
			
			p.sams_shot2 = P_SpawnMobj(
			s.x+FixedMul(s.radius*4, cos(FIREANG-ANG2*4)), 
			s.y+FixedMul(s.radius*4, sin(FIREANG-ANG2*4)), 
			s.z+((s.height/3-s.height/6)*ZFLIP), TYPE)
			
			if p.sams_shot2 and p.sams_shot2.valid
				local ghs = p.sams_shot2
				p.plshot2 = ghs
				ghs.wave2 = true
				ghs.angle = FIREANG
				P_SpawnGhostMobj(ghs)
				SAM_Bullet(s,p,ghs,SHOTSCALE,SPEEDINFO, true, FIREANG) --Skip height adjustment on this one.
				if ghs and ghs.valid
					if (s.eflags & MFE_VERTICALFLIP)
						p.sams_shot2.momz = ($+FixedMul(FixedMul(SPEEDINFO, p.sams_shot2.scale), sin(p.aiming)))*20/19
					else
						p.sams_shot2.z = $+(FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), sin(p.aiming)))-s.height/6
						p.sams_shot2.momz = $+FixedMul(FixedMul(SPEEDINFO, p.sams_shot2.scale), sin(p.aiming))
					end
					P_Thrust(p.sams_shot2, FIREANG, FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), cos(p.aiming)))
					if p.sams_shot2 and (s.eflags & MFE_VERTICALFLIP)
						p.sams_shot2.flags2 = MF2_OBJECTFLIP
						p.sams_shot2.z = $+(FixedMul(FixedMul(SPEEDINFO, SHOTSCALE), sin(p.aiming)))+s.height*5/7
					end
				end
			end
			p.sams_shot3 = P_SpawnMobj(s.x+FixedMul(s.radius*4, cos(FIREANG+(ANG2*8))), s.y+FixedMul(s.radius*4, sin(FIREANG+(ANG2*8))), s.z+((s.height/3)+s.height/2*(ZFLIP)), TYPE)
			if p.sams_shot3 and p.sams_shot3.valid
				local ghs = p.sams_shot3
				p.plshot3 = ghs
				ghs.wave2,ghs.wave5 = true,true
				ghs.angle = FIREANG				
				SAM_Bullet(s,p,ghs,SHOTSCALE,SPEEDINFO, true, FIREANG) --Skip height adjustment on this one.
				if ghs and ghs.valid				
					if (s.eflags & MFE_VERTICALFLIP)
						ghs.momz = ($+FixedMul(FixedMul(ghs.info.speed, ghs.scale), sin(p.aiming)))*20/19
					else
						ghs.z = $+(FixedMul(FixedMul(ghs.info.speed, SHOTSCALE), sin(p.aiming)))+s.height/2
						ghs.momz = $+FixedMul(FixedMul(ghs.info.speed, ghs.scale), sin(p.aiming))
					end
					P_Thrust(ghs, FIREANG, FixedMul(FixedMul(ghs.info.speed, SHOTSCALE), cos(p.aiming)))
					if ghs and (s.eflags & MFE_VERTICALFLIP)
						ghs.flags2 = MF2_OBJECTFLIP
						ghs.z = $+(FixedMul(FixedMul(ghs.info.speed, SHOTSCALE), sin(p.aiming)))+s.height*5/7
					end
				end
			end

	    else --3D shooting. Horizontal Spazer Beams are more useful here!	
			local EX = FixedMul(s.radius*4, cos(FIREANG-ANG2*16))
			local EY = FixedMul(s.radius*4, sin(FIREANG-ANG2*16))
			local EZ = s.height/3 * ZFLIP
			local SHOT = SAM_Missile(s,EX,EY,EZ,TYPE, SHOTSCALE)
			if SHOT and SHOT.valid --Yes, we got 'em!		
				p.sams_shot,p.plshot = SHOT,SHOT
				SHOT.angle = FIREANG
				SHOT.wave4 = true
				SAM_Bullet(s,p,SHOT,SHOTSCALE,SPEEDINFO, nil, FIREANG)
			end
			
			EX = FixedMul(s.radius*4, cos(FIREANG-ANG2*4))
			EY = FixedMul(s.radius*4, sin(FIREANG-ANG2*4))
			local SHOT2 = SAM_Missile(s,EX,EY,EZ,TYPE, SHOTSCALE)			
			if SHOT2 and SHOT2.valid
				p.sams_shot2,p.plshot2 = SHOT2,SHOT2
				SHOT2.wave2 = true
				SHOT2.angle = FIREANG+ANG2
				SAM_Bullet(s,p,SHOT2,SHOTSCALE,SPEEDINFO, nil, FIREANG)
			end
			
			EX = FixedMul(s.radius*4, cos(FIREANG+ANG2*8)) --It's a + this time!
			EY = FixedMul(s.radius*4, sin(FIREANG+ANG2*8))
			local SHOT3 = SAM_Missile(s,EX,EY,EZ,TYPE, SHOTSCALE)				
			if SHOT3 and SHOT3.valid
				p.sams_shot3,p.plshot3 = SHOT3,SHOT3
				SHOT3.wave2,SHOT3.wave5 = true,true --Wave2 indicates if you're a "side" projectile. Wave 5 indicates you're the "right" side projectile.
				SHOT3.angle = FIREANG+ANG2+ANG2
				SAM_Bullet(s,p,SHOT3,SHOTSCALE,SPEEDINFO, nil, FIREANG)
			end		
	    end	
		local SHOT1,SHOT2,SHOT3 = p.sams_shot,p.sams_shot2,p.sams_shot3
		for i = 1,3 --Make each projectile track each other!
			local TRACK = (i==1) and p.sams_shot or (i==2) and p.sams_shot2 or p.sams_shot3 
			if TRACK and TRACK.valid
				TRACK.lilbro1,TRACK.lilbro2,TRACK.lilbro3 = SHOT1,SHOT2,SHOT3
			end
		end

	elseif var2 --WAVE BEAM (2) or PLASMA SHOT/SPAZER CHARGE BEAM!(3)
	
		local SHOT,SHOT2
		local EX = FixedMul(s.radius*4, cos(FIREANG-ANG2*4))
		local EY = FixedMul(s.radius*4, sin(FIREANG-ANG2*4))
		local EZ = (TYPE == MT_WVSHOT) and s.height/4*ZFLIP or s.height/3*ZFLIP
		if s.automob and s.automob.valid and s.automob.health
			SHOT = P_SpawnMissile(s, s.automob, TYPE)
		else
			SHOT = SAM_Missile(s,EX,EY,EZ,TYPE, FIREANG,SHOTSCALE)
		end	

		if SHOT and SHOT.valid	
			p.sams_shot,p.plshot = SHOT,SHOT
			SHOT.angle = FIREANG+ANG2			
			SAM_Bullet(s,p, SHOT, SHOTSCALE, SPEEDINFO, nil, FIREANG)
			
			if var2 == 2 -- MT_WVSHOT			
				if s.automob and s.automob.valid and s.automob.health
					SHOT2 = P_SpawnMissile(s, s.automob, TYPE)
				else
					SHOT2 = SAM_Missile(s,EX,EY,EZ,TYPE, FIREANG,SHOTSCALE)
				end
				if SHOT2 and SHOT2.valid
					p.sams_shot2, p.plshot2 = SHOT2,SHOT2
					SHOT2.wave2 = true
					SHOT2.angle = FIREANG+ANG2
					SAM_Bullet(s,p, SHOT2, SHOTSCALE, SPEEDINFO, nil, FIREANG)
				end
				if p.sams_shot and p.sams_shot2
					p.sams_shot.lilbro2 = p.sams_shot2
					p.sams_shot2.lilbro1 = p.sams_shot
				end
			elseif (TYPE == MT_SPCHARGESHOT) --and var2 == 3
				SHOT.flags2 = $|MF2_SCATTER
				SHOT.wave2 = true
			end
		end
	end
	if crosshaired and not netgame --Adjust Samus' aim to compensate if using the "cross" crosshair.
		p.aiming = $-80<<16
	end
	p.sams_notyet = 0
	s.sams_beamcombocharge = 0
	s.sam_beamroll = 0 --Set your beam straight in first person when firing.
	s.sam_forcebeamroll = 0
	if s.diagshoot --Diagional shots in 2D shouldn't adjust your aiming.
		p.aiming = 0
		s.diagshoot = nil
	end
	
	if p.sams_shot and p.sams_shot.valid --Failsafe to stop wallclips.
		if not P_TryMove(p.sams_shot, p.sams_shot.x, p.sams_shot.y, true)
			P_MoveOrigin(p.sams_shot, s.x, s.y, s.z+(s.height/2))
			p.sams_shot.wallclipped = true
		end
	end
	s.automob = nil
end)

function A_SAMUSMOBHP(m, p)
	if m and m.valid
		if (m.type == MT_METROID)
			m.samusHP = nil --Go directly to damage system
		end
		if SAMUSDIFFICULTY != 0
			if m.thebabyspawn or m.type == MT_HANGSTER
				m.samusHP = 3
				m.samusHPmax = 3
			elseif (m.type == MT_CYBRAKDEMON) or (m.type == MT_POPHAT)
				m.samusHP = 12
				m.samusHPmax = 12
			elseif ((m.type == MT_FACESTABBER) or (m.type == MT_UNIDUS) or (m.type == MT_DRAGONBOMBER) or (m.type == MT_METROIDPART)
			or (m.type == MT_YELLOWSHELL) or (m.type == MT_SPRINGSHELL) or (m.type == MT_SNAILER))
			or (m.flags & MF_BOSS) and not (m.type == MT_METALSONIC_BATTLE)
				m.samusHP = 9 m.samusHPmax = 9
			elseif (m.type == MT_BLUECRAWLA or m.type == MT_GFZFISH or m.type == MT_GOLDBUZZ or m.type == MT_PTERABYTE)
				m.samusHP = 6 m.samusHPmax = 6
			else
				m.samusHP = 7 m.samusHPmax = 7
			end
		else
			if (m.type == MT_CYBRAKDEMON) or (m.type == MT_POPHAT) or (m.type == MT_METROIDPART)
				m.samusHP = 9 m.samusHPmax = 9
			elseif m.thebabyspawn or m.type == MT_HANGSTER --It's like stealing candy from a baby, which is fine by me
				m.samusHP = 2 m.samusHPmax = 2
			elseif ((m.type == MT_FACESTABBER) or (m.type == MT_UNIDUS) or (m.type == MT_YELLOWSHELL) or (m.type == MT_SPRINGSHELL) or (m.type == MT_SNAILER))
			or ((m.flags & MF_BOSS) and not (m.type == MT_METALSONIC_BATTLE))
				m.samusHP = 6 m.samusHPmax = 6
			elseif (m.type == MT_BLUECRAWLA or m.type == MT_GFZFISH or m.type == MT_GOLDBUZZ)
				m.samusHP = 3 m.samusHPmax = 3
			else
				m.samusHP = 4 m.samusHPmax = 4
			end
		end
		//Set beam weaknesses and resistances. Highly recommended to give only 1 of each to an enemy, but exceptions can exist.
		if (m.type == MT_BLUECRAWLA or m.type == MT_GFZFISH or m.type == MT_POPUPTURRET or m.type == MT_DETON or m.type == MT_JETTBOMBER
		or m.type == MT_GSNAPPER or m.type == MT_DRAGONBOMBER or m.type == MT_HIVEELEMENTAL or m.type == MT_SHLEEP or m.type == MT_SPINBOBERT)
			m.spazweak = true
		end
		if (m.type == MT_GOLDBUZZ or m.type == MT_REDBUZZ or m.type == MT_BUGGLE or m.type == MT_REDCRAWLA or m.type == MT_VULTURE 
		or m.type == MT_JETJAW or m.type == MT_CRAWLACOMMANDER or m.type == MT_PYREFLY or m.type == MT_CANARIVORE or m.type == MT_BUMBLEBORE
		or m.type == MT_HANGSTER)
			m.waveweak = true
		end
		if (m.type == MT_FACESTABBER or m.type == MT_POINTY or m.type == MT_UNIDUS or m.type == MT_ROBOHOOD or m.type == MT_MINUS
		or m.type == MT_GSNAPPER or m.type == MT_SKIM or m.type == MT_CRUSHSTACEAN or m.type == MT_BANPYURA or m.type == MT_CACOLANTERN)
			m.iceweak = true
		end
		if (m.type == MT_YELLOWSHELL or m.type == MT_SPRINGSHELL or m.type == MT_SNAILER or m.type == MT_EGGGUARD
		or m.type == MT_JETTGUNNER or m.type == MT_POPHAT or m.type == MT_PENGUINATOR or m.type == MT_GOOMBA or m.type == MT_BLUEGOOMBA)
			m.plasmaweak = true
		end
			
		if (m.type == MT_JETJAW or m.type == MT_CRAWLACOMMANDER or m.type == MT_POINTY or m.type == MT_VULTURE or m.type == MT_SKIM
		or m.type == MT_GOLDBUZZ or m.type == MT_REDBUZZ or m.type == MT_CANARIVORE or m.type == MT_HANGSTER or m.type == MT_METROID or m.type == MT_SUPERMETROID)
			m.spazresist = true
		end
		if (m.type == MT_JETTBOMBER or m.type == MT_JETTGUNNER or m.type == MT_GSNAPPER or m.type == MT_SNAILER or m.type == MT_EGGGUARD 
		or m.type == MT_POINTY or m.type == MT_PTERABYTE or m.type == MT_SPINBOBERT)
			m.waveresist = true
		end
		if (m.type == MT_POPUPTURRET or m.type == MT_SPRINGSHELL or m.type == MT_YELLOWSHELL or m.type == MT_GSNAPPER or m.type == MT_CRAWLACOMMANDER
		or m.type == MT_DRAGONBOMBER or m.type == MT_PYREFLY or m.type == MT_HIVEELEMENTAL or m.type == MT_POPHAT or m.type == MT_PENGUINATOR or m.type == MT_SUPERMETROID)
		m.iceresist = true
		end
		if (m.type == MT_FACESTABBER or m.type == MT_UNIDUS or m.type == MT_MINUS or m.type == MT_BUGGLE or m.type == MT_JETJAW
		or m.type == MT_ROBOHOOD or m.type == MT_CRUSHSTACEAN or m.type == MT_BANPYURA or m.type == MT_CACOLANTERN)
			m.plasmaresist = true
		end
		if (m.type == MT_FACESTABBER or m.type == MT_UNIDUS or m.type == MT_CYBRAKDEMON or m.type == MT_EGGSHIELD
		or m.type == MT_HIVEELEMENTAL or m.type == MT_SPINBOBERT or m.type == MT_METROID or m.type == MT_SUPERMETROID)
			m.missileresist = true
		end
	end
end	

--Second dialogue function, used for item popups and mission announcements!
rawset(_G, "SamusMission", function(s, text1, text2, text3, style, nextbox, instant) --Text, style, and nextbox is all we need for this
	if not (s.valid and s.player) -- Everything breaks if there's no valid player or mobj.
	and not (s.player.sam_saveselect) and not modeattacking
		return false --
	end
	if not s.samusmission
		--Carbon Copy from SamusDialogue
		s.samusmission = {
		active = false,
		noscale = nil,
		dontrender = 0,
		text1 = 0,
		text2 = 0,
		text3 = 0,
		maxchars1 = 0,
		maxchars2 = 0,
		maxchars3 = 0,
		currentchars1 = 0,
		currentchars2 = 0,
		currentchars3 = 0,
	/*	textwait = nil,
		animtimer = nil,
		textboxscale = nil,
		textboxtrns = nil,
		textboxstyle = nil,
		animendtimer = nil,
		nextbox = nil,*/
		delay = 10}
	elseif s.samusmission and s.samusmission.active
		return false --
	end
	--Use r instead of t here
	local r = s.samusmission
	r.active = true
	r.text1 = text1
	r.maxchars1 = (string.len(r.text1))	
	r.textboxstyle = style
	r.nextbox = nextbox
	r.delay = 10
	
	if not text2
		r.text2 = 0
		r.maxchars2 = 0		
	else
		r.text2 = text2
		r.maxchars2 = (string.len(r.text2))
	end	
	
	if not text3
		r.text3 = 0
		r.maxchars3 = 0
	else
		r.text3 = text3
		r.maxchars3 = (string.len(r.text3))
	end		
	
	if instant --Instantly display all text?
		r.currentchars1,r.currentchars2,r.currentchars3 = r.maxchars1,r.maxchars2,r.maxchars3
		r.animendtimer = 160
	else
		r.animendtimer = 120
		r.currentchars1,r.currentchars2,r.currentchars3 = 0,0,0
	end
	
	if not r.noscale --Don't do the fade-in again.
		r.animtimer = 18
		r.textboxscale = 356
		r.textboxtrns = FF_TRANS90
	end
	if s.sam_acz4msg
		r.delay = 30
		r.animendtimer = 325
	end
end)

--Sets up Samus' dialogue thinker! I'm going to try and tutorialize this since my code is a bit hard to read otherwise

--s: The player mobj. Player.mo will do.
--Text1: First line of dialogue. MUST be present. Does not auto-correct in length, so make sure your text is not too long. 
--Text2: Second line of dialogue. Use nil if you don't want anything beyond the first line.
--Icon: "SAMDEF" is the default Samus face.
--Style: Set this to 1 to make the computer talk. The icon will be ignored. Otherwise set this to 2.
--Nextbox: Used for the hardcoded dialogue. Always set this to 0 and set player.mo.samusdialogue.customnextbox instead!
--DialogueWait: How many tics to wait before the dialogue actually starts?
--AlignType1: Set this to "small" if you want the first line to have small text. Otherwise set this to nil.
--AlignType2: Set this to "small" if you want the second line to have small text. Otherwise set this to nil.
--Text3: An optional third line of text. Make sure AlignType 1 and 2 are set to "small" as well if you're using this. Set to nil if you don't want to use it.

rawset(_G, "SamusDialogue", function(s, text1, text2, icon, style, nextbox, dialoguewait, aligntype1, aligntype2, text3) --Sets up Samus' dialogue thinker!
	if not (s.valid and s.player) -- Everything breaks if there's no valid player or mobj.
		return false --
	end
	if not s.samusdialogue
	--Is this not setup yet? Well, set it up, boys!	Table trick stolen from Motdspork, who stole it from Bloops!
		local samusdialogue = {
		active = false,
		noscale = nil,
		dontrender = 0,
		text1 = text1,
		maxchars1 = 0,
		text2 = 0,
		maxchars2 = 0,
		text3 = 0,
		currentchars3 = 0,
		maxchars3 = 0,
		samuscolor = 0,
		currentchars1 = 0,
		currentchars2 = 0,
		align1 = "left",
		align2 = "left",		
	/*	textwait = nil,
		animtimer = nil,
		endoffset = nil,
		textboxscale = nil,
		textboxtrns = nil,
		textboxpic = nil,
		textboxpic2 = nil, --Nil until confirmed otherwise!
		textboxstyle = nil,
		animendtimer = nil,
		nextbox = nil,
		textboxpic = nil,
		lastpic = nil, */
		tbscolor = SKINCOLOR_SUPERORANGE1,
		tbsd = 1,
		transitflash = V_90TRANS,
		samuscolor2 = 5,
		textboxpic2 = nil,
		customnextboxready = false,
		customnextbox = 0}
		s.samusdialogue = samusdialogue
	elseif s.samusdialogue and s.samusdialogue.active
		return false --
	end
	local p = s.player
	local t = s.samusdialogue
	
	t.active = true
	t.text1 = text1
	t.maxchars1 = (string.len(t.text1))
	t.customnextboxready = false
	
	t.align1 = aligntype1 or "left"
	t.align2 = aligntype2 or "left"
	
	if not text2
		t.text2 = 0
		t.maxchars2 = 0		
	else
		t.text2 = text2
		t.maxchars2 = (string.len(t.text2))
	end
	
	if not text3
		t.text3 = 0
		t.maxchars3 = 0		
	else
		t.text3 = text3
		t.maxchars3 = (string.len(t.text3))
	end		
	
	if p.sam_screwattacking and p.prescrewcolor --Don't use the screw attack colors!
		t.samuscolor = p.prescrewcolor
	else
		t.samuscolor = s.color
	end
	
	t.currentchars1,t.currentchars2,t.currentchars3 = 0,0,0
	
	if dialoguewait --Wait a bit?
		t.dontrender = dialoguewait
	else
		S_StartSound(s, sfx_samtm1) --Play sound immediately.
		t.dontrender = 0
	end
	
	if not t.noscale or t.lastpic == nil --Don't do the animation again.
		t.animtimer = 18
		t.textboxscale = 356
		t.textboxtrns = FF_TRANS90
	end
	
	t.tbscolor = SKINCOLOR_SUPERRED1
	t.tbsd = 1		
	t.endoffset = 0
	t.textboxpic = icon
	t.textboxpic2 = nil --Nil until confirmed otherwise!
	t.textboxstyle = style
	
	if not nextbox and not t.customnextbox --Last textbox stays a little longer!
		t.animendtimer = 100
		if not text2
			t.animendtimer = 75
		end
	else
		t.animendtimer = 75
		if not text2
			t.animendtimer = 25 --25!
		end
	end
	
	t.nextbox = nextbox
	
	local p = s.player
	
	if p.sam_gravitysuit --Change to Varia/Gravity Suit versions if necessary.
		local OVERLAY = (p.samvisorcolor and p.sam_gravitysuit==2) and p.samvisorcolor or nil
		if icon == "SAMDEF"
			t.textboxpic = "SAMDEFVA"
			if OVERLAY
				t.samuscolor2 = OVERLAY
				t.textboxpic2 = "SAMDEFVL" --Add the overlay for the Gravity Lights!
			end	
		elseif icon == "SAMSAD"
			t.textboxpic = "SAMSADVA"
			if OVERLAY
				t.samuscolor2 = OVERLAY
				t.textboxpic2 = "SAMSADVL" --Add the overlay for the Gravity Lights!
			end
		elseif icon == "SAMPRE"
			t.textboxpic = "SAMPREVA"
			if OVERLAY
				t.samuscolor2 = OVERLAY
				t.textboxpic2 = "SAMPREVL" --Add the overlay for the Gravity Lights!
			end
		end
	end
	if t.noscale
		t.noscale = nil
		--If the lastpic is the same as the previous pic and we're not doing an animation, don't do anything!
		if (t.lastpic != nil) and (t.lastpic != icon) and t.textboxstyle != 1 --No flash if computer style
			t.transitflash = V_90TRANS
		end
	end
	if style==1
		t.textboxcolor = SKINCOLOR_CRIMSON
		t.lastpic = nil
	else
		t.textboxcolor = SKINCOLOR_SKY
		t.lastpic = t.textboxpic
	end
end)

rawset(_G, "SamResetBeam", function(p)
	p.sam_powerbeamequip = true
	p.sam_spazerbeamequip = false
	p.sam_wavebeamequip = false
	p.sam_icebeamequip = false
	p.sam_plasmabeamequip = false
	p.sam_hyperbeamequip = false
end)

--Sets up Metroid Skins for rings, boxes, and saveposts. s can be nil, it doesn't matter.
rawset(_G, "SetMetroidVisuals", function(FORCE)
	if METROIDSKINS == true or (SAM.HUNTERS(s))
		for m in mobjs.iterate(mobjs)
			if not m.valid or m.flags == nil or (m.metroidvisual == true) continue end --

			if (m.type == MT_RING) or (m.type == MT_COIN) --Change Rings into energy orbs.
				if m.health
					m.state = S_METRING1
					m.metroidvisual = true
					m.color,m.colorized = SKINCOLOR_WHITE, true
				end			
			elseif (m.flags & MF_MONITOR) --Change monitors into Chozo Orbs.
				if not (m.type == MT_1UP_BOX)
				and not ((m.type >= MT_PITY_GOLDBOX) and (m.type <= MT_THUNDERCOIN_GOLDBOX))
				and not (m.type == MT_EGGMAN_GOLDBOX)
					m.state = S_METBOX1
					m.metroidvisual = true
					if m.type == MT_FORCE_BOX
						m.color =SKINCOLOR_BLUE
					elseif m.type == MT_ARMAGEDDON_BOX
						m.color =SKINCOLOR_RED
					elseif m.type == MT_ELEMENTAL_BOX
						m.color =SKINCOLOR_EMERALD
					elseif m.type == MT_FLAMEAURA_GOLDBOX 
						m.color =SKINCOLOR_FLAME
					elseif m.type == MT_BUBBLEWRAP_GOLDBOX 
						m.color =SKINCOLOR_AQUA
					elseif m.type == MT_THUNDERCOIN_GOLDBOX 
						m.color =SKINCOLOR_BRONZE							
					elseif m.type == MT_ATTRACT_BOX 
						m.color =29
					elseif m.type == MT_WHIRLWIND_BOX
						m.color =SKINCOLOR_SKY
					elseif m.type == MT_PITY_BOX
						m.color =SKINCOLOR_MOSS
					elseif m.type == MT_INVULN_BOX
						m.color =SKINCOLOR_WHITE
					elseif m.type == MT_MIXUP_BOX
							--
					elseif ((m.type == MT_EGGMAN_BOX) or (m.type == MT_EGGMAN_GOLDBOX))
						m.color =SKINCOLOR_BLACK
					elseif m.type == MT_SNEAKERS_BOX
						m.color =SKINCOLOR_MAGENTA
					else
						m.color =SKINCOLOR_ORANGE
					end	
				end
			elseif (m.type == MT_STARPOST) --Change the starpost into this thing.
				m.samspawnitem = P_SpawnMobj(m.x, m.y, m.z, MT_SMONTRACKER)
				m.samspawnitem.target = m
				m.samspawnitem.starposttracker = true
				m.metroidvisual = true
				if m.valid and m.health
					m.sprite = SPR_MPR1
					m.frame,m.color = O,SKINCOLOR_RED
				end
			end
		end
	end
end)

rawset(_G, "SAM_RemoveLDgrp", function(s)
	if s.sam_pwgrp and s.sam_pwgrp.valid
		s.sam_pwgrp.state = S_NULL
	end
	if s.sam_pwgrpS and s.sam_pwgrpS.valid	
		s.sam_pwgrpS.state = S_NULL
	end
end)

--Much needed shortcut
rawset(_G, "CancelScrewAttack", function(s,p)
	local check = false
	if p.sam_screwattacking
		p.aiming = 0
		p.sam_screwattacking = 0
		p.sams_screwattackcd = 35
		check = true
		if p.mo and not p.mo.sam_ldclmb
			p.mo.sam_ldclmb = 5
		end
	end
	if s and s.valid 
		s.sam_screwattackspbs = nil
		if s.spriteyscale == 74555 or s.spritexscale == 50010
			s.spritexscale,s.spriteyscale = FRACUNIT,FRACUNIT
		end		
		if s.sam_screwattackfling
			S_StopSoundByID(s, sfx_satkrl)
			s.friction = 59392
			s.sam_screwattackfling = nil
			if SAM_FirstPerson(p, true)
			--	SamCam(p, opposite of camera.chase, nothing)
			--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
				SAM_CMD(p, "nil", "true", "false", "15")
			--	SamCam(p, false, false)
			end
			if P_IsObjectOnGround(s) and p.panim == PA_ROLL
				s.state = S_PLAY_FALL
			end
			p.sams_screwattackcd = 1	
			check = true
		end
		if p.prescrewcolor
			s.color = p.prescrewcolor
			s.colorized = false
			check = true
		end
	end
	return check --
end)

rawset(_G, "SetSamusColor", function(s, p) 
	if not s 
	or not YouAreSamus(s)
	or not p
	or (p.sam_screwattacking and p.prescrewcolor)
		return false --Cancel in these cases
	end
	
	if not s.color --Always have SOME color assigned!
		s.color = SKINCOLOR_GREEN
	end
	if not p.skincolor
		p.skincolor = SKINCOLOR_GREEN
	end
	
	if G_GametypeHasTeams() --Assign team colors 
		if p.ctfteam == 2
			s.color = SKINCOLOR_BLUE
			p.skincolor = SKINCOLOR_BLUE
		elseif p.ctfteam == 1
			s.color = SKINCOLOR_RED
			p.skincolor = SKINCOLOR_RED		
		end
		return true
	else --Asign Suit Colors if you have them!
		if not p.sam_gravitysuit
			if p.customsuitc1
				if s.color != p.customsuitc1
				s.color = p.customsuitc1
				end
				if not (p.customsuitc1 >= SKINCOLOR_SUPERSILVER1)
				or ((p.customsuitc1 >= SKINCOLOR_POWERSUIT) and (p.customsuitc1 <= SKINCOLOR_PLASMABURNED))
				p.skincolor = p.customsuitc1
				return true
				end
			end
		elseif (p.sam_gravitysuit == 1)
			if p.customsuitc2
				if s.color != p.customsuitc2
				s.color = p.customsuitc2
				end
				if not (p.customsuitc2 >= SKINCOLOR_SUPERSILVER1)
				or ((p.customsuitc2 >= SKINCOLOR_POWERSUIT) and (p.customsuitc2 <= SKINCOLOR_PLASMABURNED))
				p.skincolor = p.customsuitc2
				return true
				end
			end				
		elseif (p.sam_gravitysuit >= 2)
			if p.customsuitc3
				if s.color != p.customsuitc3
				s.color = p.customsuitc3
				end
				if not (p.customsuitc3 >= SKINCOLOR_SUPERSILVER1)
				or ((p.customsuitc3 >= SKINCOLOR_POWERSUIT) and (p.customsuitc3 <= SKINCOLOR_PLASMABURNED))
				p.skincolor = p.customsuitc3
				return true
				end
			end			
		end
	end
end)

--Sets up Samus' tutorial thinker! Adds things to a list, then executes.
rawset(_G, "SamusTutorial", function(s, item, stopit) 
	--Probably annoying, but that's why we have an "off" option.
	if s.player.nosamustutorials or s.player.samustutorialsdone
		return false --
	end
	if not s.player.samustutorial
		local samustutorial = {
		active = false,
		noscale = nil,
		dontrender = 0,
		textflags = 0,
		animtimer = 0,
		goodbyedialogue = 0,
		textboxscale = 356,
		textboxtrns = V_90TRANS,
		textboxtrns2 = V_90TRANS,
		textboxflash = V_90TRANS,
		animendtimer = nil,
		beams = false,
		beamscomplete = false,
		missiles = false,
		missilescomplete = false,
		supermissiles = false,
		supermissilescomplete = false,
		beamcombo = false,
		beamcombocomplete = false,
		gravitysuit1 = false,
		gravitysuit1complete = false,
		gravitysuit2 = false,
		gravitysuit2complete = false,
		scanvisor = false,
		scanvisorcomplete = false,
		hyperbeam = false,
		hyperbeamcomplete = false,
		screwattack = false,
		screwattackcomplete = false,
		bombs = false,
		bombscomplete = false,
		pw = false,
		pwcomplete = false,
		spiderball = false,
		spiderballcomplete = false,
		lockon = false,
		lockoncomplete = false,
		chargebeam = false,
		chargebeamcomplete = false,
		monitorhunt = false,
		monitorhuntcomplete = false
		}	
	s.player.samustutorial = samustutorial	
	end	
	local t = s.player.samustutorial
	local gotathing	= false
	
	--Add which to the list?
	if item == "lockon"
		if stopit
			if t.lockon
				t.lockon = false
				t.lockoncomplete = true
				EndSamusTutorial(t,s)
			else
				return --
			end
		else
			if not t.lockon and not t.lockoncomplete
			t.lockon = true gotathing = true
			end
		end		
	elseif item == "beams"
		if stopit
			if t.beams
				t.beams = false
				t.beamscomplete = true
				EndSamusTutorial(t,s)
			else
			return
			end
		else
			if not t.beams and not t.beamscomplete
			t.beams = true gotathing = true
			end
		end
	elseif item == "monitorhunt"
		if stopit
			if t.monitorhunt
				t.monitorhunt = false
				t.monitorhuntcomplete = true
				EndSamusTutorial(t,s)
			else
			return
			end
		else
			if not t.monitorhunt and not t.monitorhuntcomplete
			t.monitorhunt = true gotathing = true
			end
		end					
	elseif item == "chargebeam"
		if stopit
			if t.chargebeam
				t.chargebeam = false
				t.chargebeamcomplete = true
				EndSamusTutorial(t,s)
			else
			return
			end
		else
			if not t.chargebeam and not t.chargebeamcomplete
			t.chargebeam = true gotathing = true
			end
		end			
	elseif item == "missiles"
		if stopit
			if t.missiles
				if not t.beams
				t.missiles = false
				t.missilescomplete = true
				EndSamusTutorial(t, s)
				end
			return
			end
		elseif not t.missiles and not t.missilescomplete
			t.missiles = true gotathing = true
		end
	elseif item == "supermissiles"
		if stopit
			if t.supermissiles
				if not (t.beams or t.missiles)
				t.supermissiles = false
				t.supermissilescomplete = true
				EndSamusTutorial(t, s)
				end
			return
			end
		elseif not t.supermissiles and not t.supermissilescomplete
			t.supermissiles = true gotathing = true
		end
	elseif item == "beamcombo"
		if stopit
			if t.beamcombo
				if not (t.missiles or t.beams or t.supermissiles)
				t.beamcombo = false
				t.beamcombocomplete = true
				EndSamusTutorial(t,s)
				end
				return
			end
		elseif not t.beamcombo and not t.beamcombocomplete
			t.beamcombo = true gotathing = true
		end
	elseif item == "variasuit" --Secretly Speedbooster and Swap Weapons because I changed my mind.
		if stopit
			if t.gravitysuit1
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo)
				t.gravitysuit1 = false
				t.gravitysuit1complete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.gravitysuit1 and not t.gravitysuit1complete
			t.gravitysuit1 = true gotathing = true
		end
	elseif item == "gravitysuit"
		if stopit
			if t.gravitysuit2 
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1)
				t.gravitysuit2 = false
				t.gravitysuit2complete = true	
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.gravitysuit2 and not t.gravitysuit2complete
			t.gravitysuit2 = true gotathing = true
		end
	elseif item == "scanvisor"
		if stopit
			if t.scanvisor 
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1 or t.gravitysuit2)
				t.scanvisor = false
				t.scanvisorcomplete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.scanvisor and not t.scanvisorcomplete
			t.scanvisor = true gotathing = true
		end
	elseif item == "screwattack"
		if stopit
			if t.screwattack 
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1 or t.gravitysuit2 or t.scanvisor)
				t.screwattack = false
				t.screwattackcomplete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.screwattack and not t.screwattackcomplete
			t.screwattack = true gotathing = true
		end
	elseif item == "bombs"
		if stopit
			if t.bombs
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1 or t.gravitysuit2 or t.scanvisor or t.screwattack)			
				t.bombs = false
				t.bombscomplete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.bombs and not t.bombscomplete
			t.bombs = true gotathing = true
		end
	elseif item == "pw"
		if stopit
			if t.pw 
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1 or t.gravitysuit2 or t.scanvisor
				or t.screwattack or t.bombs)
				t.pw = false
				t.pwcomplete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.pwcomplete and not t.pw
			t.pw = true gotathing = true
		end
	elseif item == "spiderball"
		if stopit
			if t.spiderball
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1 or t.gravitysuit2 or t.scanvisor
				or t.screwattack or t.bombs or t.pw)
				t.spiderball = false
				t.spiderballcomplete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.spiderball and not t.spiderballcomplete
			t.spiderball = true gotathing = true
		end
	elseif item == "hyperbeam"
		if stopit
			if t.hyperbeam
				if not (t.missiles or t.beams or t.supermissiles or t.beamcombo or t.gravitysuit1 or t.gravitysuit2 or t.scanvisor
				or t.screwattack or t.bombs or t.pw or t.spiderball)
			
				--There was probably a more efficient way to go about this, but unfortunately I won't hear about it until AFTER the project's out.	
		
				t.hyperbeam = false
				t.hyperbeamcomplete = true
				EndSamusTutorial(t,s)
				end
			return
			end
		elseif not t.hyperbeamcomplete and not t.hyperbeam
			t.hyperbeam = true gotathing = true
		end
	end	
		
	if stopit
		return --
	end
	if gotathing and not (t.textboxscale >= FRACUNIT)
		t.textboxtrns2 = V_90TRANS
		
		if t.goodbyedialogue
			t.goodbyedialogue = 0
			t.textboxscale = 356
			t.textboxtrns = V_90TRANS		
		end
		if t.noscale --Don't do the animation again.
			t.animtimer = 18
			t.textboxflash = V_90TRANS --Overlay a flash.
			t.noscale = nil
		else
			t.textboxscale = 356
			t.textboxtrns = V_90TRANS
		end
		t.active = true
	end
end)

rawset(_G, "SpaceJumpGFX", function(s, color, tscale, frame) 
	local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_SAMCHARGEGFX)
	ghs.state = S_SAMCHARGEGFX4
	ghs.sprite = SPR_MPR9
	ghs.frame = frame
	ghs.tics = 12
	ghs.scale = s.scale/tscale
	ghs.destscale = $*5
	ghs.color = color
	ghs.ret2spring = true
	ghs.target = s
end)


--Opening Monitor behaviour "SAM_ITEM", "SAMITEM"
function A_SAMITEM(s, m, sonicstyle)
	if not s.valid or not (m and m.valid) return end --
	local t = s.target
	if (gametype == GT_COMPETITION)
		if (m.flags & MF_MONITOR) and m.health and t
			local p = (s.player) and s.player or t.player
			if p and p.numboxes != nil
				p.numboxes = $+1
			end
		end
	end
	if m.holdon
		m.samgotme = 0
		m.holdon = nil
		m.samgotmehost = false
		if not m.health
			m.health = 1
		end return --
	end
	
	if (m.type == MT_EGGMAN_BOX) or (m.type == MT_EGGMAN_GOLDBOX)
	or (m.flags & MF_MONITOR) and ((mobjinfo[m.type].doomednum == 4064) or (mobjinfo[m.type].doomednum == 429))
		if t and t.player --Welp, that one's on you.
			P_DamageMobj(m, s, t)
			if m and m.valid and (m.flags & MF_SHOOTABLE) --Still here? KillMobj it is, then.
				P_KillMobj(m, s, t)
			end
			if not ((s.type == MT_WVCHARGESHOT) and s.bufferguard)
			and not (s.type == MT_PLSHOT) 
			and not (s.type == MT_PLCHARGESHOT)
				P_ExplodeMissile(s)
			end
		end
	elseif ((m.type == MT_RING_REDBOX) or (m.type == MT_RING_BLUEBOX)) and t.player.ctfteam and G_GametypeHasTeams()	
		if t and t.player and m.health
			if t.player.ctfteam == 1 and (m.type == MT_RING_REDBOX)
			or t.player.ctfteam == 2 and (m.type == MT_RING_BLUEBOX)
				m.samspawnitem = P_SpawnMobj(m.x, m.y, m.z, MT_SAMSPAWNITEM) 
				m.samspawnitem.chozobox = m
				m.flags = $|MF_NOCLIP & ~(MF_SHOOTABLE|MF_SOLID)
				m.samspawnitem.flags2 = m.flags2
				m.samspawnitem.eflags = m.eflags 
				m.flags2 = $|MF2_DONTDRAW
				if not ((s.type == MT_WVCHARGESHOT) and s.bufferguard)
				and not (s.type == MT_PLSHOT) and not (s.type == MT_PLCHARGESHOT)
					P_ExplodeMissile(s)
				end
			end
		end
	elseif t and m.health
		local p = (s.player) and s.player or t.player
		local SAMUSNUM = (p.samusnum) or 0
		
/*	   if m.health and s.target and s.target.player
	   and ( G_GametypeHasSpectators() or not
	   (m.samgotme != nil and not (players[0] and s.target.player == players[0]) and (s.target.player.samusnum and (m.samgotme & (s.target.player.samusnum)) or m.samgotme == s.target.player.samusnum) )
	   and not (players[0] and s.target.player == players[0] and m.samgotmehost) and not (mobjinfo[m.type].doomednum == 429) )
		m.samspawnitem = P_SpawnMobj(m.x, m.y, m.z, MT_SAMSPAWNITEM)
		m.samspawnitem.chozobox = m
		SamusTutorial(s.target, "monitorhunt", true)
			if s.target and s.target.player
				if (gametype == GT_COOP) and (s.target.player.samusnum != nil) and s.target.player.samusnumdecided 
				and (s.target.player.coopboxrespawn and (s.target.player.coopboxrespawn > 1))
					if m.samgotme == nil
					m.samgotme = 0
					end
					if players[0] and s.target.player == players[0]
					m.samgotmehost = true
					end
				m.samgotme = $|s.target.player.samusnum
				end
			m.samspawnitem.tracer = s.target
			end
			if s.player
				m.samspawnitem.tracer = s
			end		
		m.samspawnitem.eflags = m.eflags
		m.samspawnitem.flags2 = m.flags2
			if ((m.type >= MT_PITY_GOLDBOX) and (m.type <= MT_THUNDERCOIN_GOLDBOX)) and not (m.type == MT_GRAVITY_GOLDBOX) 
			m.samspawnitem.goldlaststate = m.state
			m.state = S_THOK
			m.tics = -1
			end
		m.flags = $1|MF_NOCLIP & ~MF_SHOOTABLE & ~MF_SOLID
		m.flags2 = $1|MF2_DONTDRAW
		
		
			--Open Box effect
			local brng = P_RandomRange(1,360)
			S_StartSound(m, sfx_cdfm50)
			
			for d = 1,3
				local debris = P_SpawnMobjFromMobj(m, d,d,d, MT_THOK)
					debris.sprite = SPR_MXP4
					debris.tics = 10
					debris.color = m.color
					
					if METROIDSKINS == true or (SAM.HUNTERS(s))			
						debris.frame = T
					else
						debris.frame = U
					end
					
					debris.rollangle = brng+((ANG1*69)*d)+ANGLE_45
					debris.flags = MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING
					debris.flags2 = $ & ~MF2_DONTDRAW
					P_InstaThrust(debris, brng+((ANG1*110)*d), 8*m.scale+(2*d<<16))
					P_SetObjectMomZ(debris, (4<<16)+(2*d<<16))
					
					if s.momx
						debris.momx = $+(s.momx/20)
					end
					if s.momy
						debris.momy = $+(s.momy/20)
					end
			end
			
			if not ((s.type == MT_WVCHARGESHOT) and s.bufferguard)
			and not (s.type == MT_PLSHOT) and not (s.type == MT_PLCHARGESHOT)
			P_ExplodeMissile(s)
			end */

		
		local OPENSESAME = true
		if not G_GametypeHasSpectators() and (p and p.valid) and mobjinfo[m.type].doomednum != 429
			if m.gotplayers == nil
				m.gotplayers = {}
			else
				for i,z in pairs(m.gotplayers)
					if (p == z)
						OPENSESAME = false break -- --You already got that, you greedy shit.
					end
				end
			end
		end
		if p and mobjinfo[m.type].doomednum != 429 and OPENSESAME
			m.samspawnitem = P_SpawnMobj(m.x, m.y, m.z, MT_SAMSPAWNITEM)
			m.samspawnitem.chozobox = m
			SamusTutorial(t, "monitorhunt", true)
			if (gametype == GT_COOP) and (p.coopboxrespawn and (p.coopboxrespawn > 1))
				if m.gotplayers != nil
					table.insert(m.gotplayers, p)
				end
			end
			m.samspawnitem.tracer = (s.player) and s or t
			m.samspawnitem.eflags = m.eflags
			m.samspawnitem.flags2 = m.flags2
			if ((m.type >= MT_PITY_GOLDBOX) and (m.type <= MT_THUNDERCOIN_GOLDBOX)) and not (m.type == MT_GRAVITY_GOLDBOX) 
				m.samspawnitem.goldlaststate = m.state
				m.state = S_THOK
				m.tics = -1
			end
			m.flags = $|MF_NOCLIP & ~(MF_SHOOTABLE|MF_SOLID)
			m.flags2 = $|MF2_DONTDRAW
		
			--Open Box effect
			local brng = P_RandomRange(1,360)
			S_StartSound(m, sfx_cdfm50)
			local MVISUALS = (SAM.HUNTERS(s) or (METROIDSKINS == true))
			for d = 1,3
				local debris = P_SpawnMobjFromMobj(m, d,d,d, MT_THOK)
				debris.sprite = SPR_MXP4
				debris.tics = 10
				debris.color = m.color				
				debris.frame = (MVISUALS) and T or U
				debris.rollangle = brng+((ANG1*69)*d)+ANGLE_45
				debris.flags = MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING
				debris.flags2 = $ & ~MF2_DONTDRAW
				P_InstaThrust(debris, brng+((ANG1*110)*d), 8*m.scale+(2*d<<16))
				P_SetObjectMomZ(debris, (4<<16)+(2*d<<16))
				
				debris.momx = $+(s.momx/20)
				debris.momy = $+(s.momy/20)
			end
			if not ((s.type == MT_WVCHARGESHOT) and s.bufferguard)
			and not (s.type == MT_PLSHOT) and not (s.type == MT_PLCHARGESHOT)
				P_ExplodeMissile(s)
			end 
		else
			if not (m.gotmonalready and m.gotmonalready.valid)
				S_StartSound(m, sfx_bedeen)
				m.ghs = P_SpawnGhostMobj(m)
				m.ghs.destscale = m.scale*10 
				m.ghs.tics = 30
				m.gotmonalready = P_SpawnMobj(m.x, m.y,m.z, MT_FAKESAMUSTHOK)
				m.gotmonalready.scale = m.scale*5/6
				m.gotmonalready.eflags = m.eflags
				m.gotmonalready.state = S_ZAPS1
				m.gotmonalready.fuse = 18
			else
				m.gotmonalready.fuse  = 18
			end	
	   end
	end
end


local function P_SafeRandom(a,b)
	local FRAC = 1
	if a>=FRACUNIT
		if a >= FRACUNIT*4
			a = $>>16 
			FRAC = FRACUNIT
		else
			a = min(65354, $/2)
		end
	end
	if b>=FRACUNIT
		if b >= FRACUNIT*4
			b = $>>16 
			FRAC = FRACUNIT
		else
			b = min(65354, $/2)
		end 
	end	return (P_RandomRange(a,b))*FRAC --
end


--Spawns anything you want as a randomized particle.
--Be warned, this function wants practically everything valid
--A_SAMPARTICLE(s, MT_ICCHARGESHOT, 10, 50, -4, 40, s.color, P_RandomRange(8, 16)<<16, "ice", s.target)
function A_SAMPARTICLE(s, TYPE, XYOFFSET, XYMOM, minMOMZ, maxMOMZ, COLOR, SCALE, SPECIAL, customTARGET)
	local ZRNG = s.height>>16
	if (ZRNG < 5) ZRNG = P_SafeRandom(0, $) end
	local XRNG,YRNG = 0,0
	if XYOFFSET != -XYOFFSET --Gonna try to not have as many P_RandomRange calls since that's hard on netgames.
		XRNG = P_SafeRandom(-XYOFFSET, XYOFFSET)
		YRNG = (XRNG%2==0) and XRNG*-1 or (XRNG%3==0) and XRNG/-2 or P_SafeRandom(XYOFFSET, -XYOFFSET)
	end
	local ghs  = P_SpawnMobj(s.x + XRNG<<16,s.y + YRNG<<16, s.z + ZRNG<<16, TYPE)
	ghs.color = COLOR
	ghs.renderflags = $|RF_FULLBRIGHT
	ghs.blendmode = AST_ADD
	if XYMOM
		ghs.momx = P_SafeRandom(-XYMOM, XYMOM)<<16
		ghs.momy = P_SafeRandom(XYMOM, -XYMOM)<<16
	end
	if minMOMZ != maxMOMZ
		ghs.momz = P_SafeRandom(minMOMZ, maxMOMZ)<<16
	else
		ghs.momz = minMOMZ or 0
	end
	ghs.scale = (SCALE) or s.scale
	
	if (s.type == MT_WVCHARGESHOT)
		ghs.target = customTARGET or (s.target and s.target.player) and s.target or s
		ghs.charged, ghs.wavenope = true, true
	elseif SPECIAL --Not...actually Spazer.
		if SPECIAL == "ice" --For the Ice Beam Combo.
			ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE
			ghs.combograce = 14
			ghs.icesummon = s
		elseif s.type == MT_PLSHOT --For the Gattling Vortex.
			ghs.morning = 60 --Timer for the flames.
		else
			ghs.spazersummon = true
		end
		if not ghs.target
			ghs.target = (customTARGET) or s
		end
	else
		ghs.target = (customTARGET) or s --Force a custom target if there's one.
	end
	return ghs --
end

rawset(_G, "ExplodePush", function(p, m, var3) --Normally explosions don't use this system...
	if m.samusHP and (m.samusHP > 6) --But I want to slightly nerf missiles, powerbeam chargeshots and bombs
		if not (m.type == MT_METROIDPART) and not (m.type == MT_PZBOSS)
			for d = 1,5 --to encourage players to use more varied weaponry. 
				if P_RandomRange(0,1) 
					m.moseyflash = P_SpawnMobj(m.x, m.y, m.z+m.height/2, MT_SONIC3KBOSSEXPLODE)
					S_StartSound(m, sfx_cybdth)
				else
					S_StartSound(m, sfx_dmpain)
					m.moseyflash = P_SpawnMobj(m.x, m.y, m.z+m.height/2, MT_SMOKE)
				end
				m.moseyflash.scale = m.scale
				m.moseyflash.eflags = m.eflags
				m.moseyflash.destscale = m.scale*3
				m.moseyflash.momx = (P_RandomRange(-8, 8)*m.scale)
				m.moseyflash.momy = (P_RandomRange(-8, 8)*m.scale)
				P_SetObjectMomZ(m.moseyflash, (P_RandomRange(1, 3)<<16))
			end
			m.moseyflash = P_SpawnMobj(m.x, m.y, m.z, MT_SMONTRACKER)
			m.moseyflash.target = m
			m.moseyflash.flashingt = 18
		elseif m.omega and m.omega.valid
			m.omega.painfyellow = 9
		else
			m.painfyellow = 14
		end
		if (m.type == MT_METROIDPART and (m.samusHP > 5) and p.type == MT_SAMMISSILE)
			m.samusHP = 5
		else
			m.samusHP = $-6
		end
		if not NoPushList(m)
			P_Thrust(m, R_PointToAngle2(m.x, m.y, p.x, p.y), -13<<16)
		end
		if not m.target and (m.flags & MF_ENEMY)
			if p.target and p.target.valid and p.target.health and not (m.type == MT_GFZFISH)
				m.angle =  R_PointToAngle2(m.x, m.y, p.target.x, p.target.y)
			end
		end
	else
		P_DamageMobj(m, p, var3, 1)
	end
end)
rawset(_G, "GiveSamusEnergy", function(p, amount, flash) 
	p.sam_energy = $+amount --Any overflowing energy goes to the hyperbeam
	if flash
		p.sam_energyflash = flash --How long your bar flashes. Generally 1 or 2 tics.
	end
end)

--An object will keep track of every monitor and what to spawn!
addHook("MobjThinker", function(s) if not s.valid return end --
	if s.SAM_matchmonitors == nil
		SAM.ApplyMonitorSettings(s) --applies s.SAM_metroidvisuals, s.SAM_matchmonitors, s.SAM_nosuperpowert, and more.
	end
	if s.ammospawner --We're just an ammo spawner! (special gamemode setting)
		s.tics = $+1
		if not (s.currentammo and s.currentammo.valid)
			if s.currentammotimer == nil
				s.currentammotimer = 750
			end
			if s.currentammotimer
				s.currentammotimer = $-1
			else
				local ZOFFSET = 16<<16*P_MobjFlip(s)
				if (s.ammospawner < 12)
					s.currentammo = P_SpawnMobj(s.x, s.y, s.z+ZOFFSET, MT_NRGA)
				elseif (s.ammospawner < 34)
					s.currentammo = P_SpawnMobj(s.x, s.y, s.z+ZOFFSET, MT_NRGB)
				elseif (s.ammospawner < 48)
					s.currentammo = P_SpawnMobj(s.x, s.y, s.z+ZOFFSET, MT_MPKU)
				elseif (s.ammospawner < 78)
					s.currentammo = P_SpawnMobj(s.x, s.y, s.z+ZOFFSET, MT_BMPKU)
				elseif (s.ammospawner <= 95)
					s.currentammo = P_SpawnMobj(s.x, s.y, s.z+ZOFFSET,(s.SAM_nosuperpowert) and MT_MPKU or MT_SPKU)
				elseif (s.ammospawner > 95)
					s.currentammo = P_SpawnMobj(s.x, s.y, s.z+ZOFFSET,(s.SAM_nosuperpowert) and MT_BMPKU or MT_PBOM)
				end
				if s.currentammo and s.currentammo.valid
					s.currentammo.dontsuckme = true
				end
				s.currentammotimer = 750
			end
		end
		return --
	elseif not (s.chozobox and s.chozobox.valid)
		s.state = S_NULL return --
	end
	
	local m = s.chozobox
	local samRNG = P_RandomRange(1, 100)
	local ITEM --The thing we'll spawn.
	if (s.state == S_SAMSPAWNITEM1) --Single tic state where we spawn a powerup!
		local t = s.tracer local p = (t) and t.player or nil
		if p == nil and t and t.valid --Somehow this function screwed up. See if we can salvage it!
		and t.target and t.target.valid and t.target.player and YouAreSamus(t)
			p = t.target.player
			t = t.target
		end
		--Stupid obtuse setups so I don't have to check valid all the damn time.
		local ITEMRATE = (p) and p.sams_itemcompletion or 0
		local MISSILES = (p) and p.sammissilesmax or 0
		local SUPERS = (p) and p.samsupermissilesmax or 0
		local PWBOMBS = (p) and p.sampwmax or 0
		local ETANKS = (p) and p.sam_energytanksmax or 0
		local ENERGY = (p) and p.sam_energy or 0
		local FLOAT = m.height*P_MobjFlip(m)
		
		if (m.type == MT_SNEAKERS_BOX)
			if (samRNG < 7)
				if p 
					if not p.sam_bombs
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
					elseif MISSILES<10
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					elseif not p.sam_spiderball
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPDRBL)
					elseif not p.sam_power_grip
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PWGRP)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				end
			elseif (samRNG < 8)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
			elseif (samRNG < 26)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBL)
			elseif (samRNG < 64)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, (p and p.samspbs) and MT_BSBL or MT_SPBS)
			elseif (samRNG < 95)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, (p and p.sambsbl) and MT_SPBS or MT_BSBL)
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
			end

		elseif (m.type == MT_INVULN_BOX) --The most rare stuff comes from this one!
					
			if (samRNG < 28)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, (MISSILES<20) and MT_MTNK or (not SUPERS) and MT_STNK or MT_PTNK)
			elseif (samRNG < 50)
				if G_GametypeHasSpectators()
					ITEM = P_SpawnMobj(m.x, m.y, m.z, (samRNG==48 and not PWBOMBS) and MT_PTNK or MT_ENGTNK)
				else
					if p
						if not p.sam_bombs
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
						elseif not p.sam_spiderball
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPDRBL)
						elseif ITEMRATE>77 and not PWBOMBS
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
						elseif (ENERGY >= 85+ETANKS*50)
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
						else
							ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
						end
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
					end
				end
			elseif (samRNG < 60)
				if p
					if not SUPERS
						ITEM = P_SpawnMobj(m.x, m.y, m.z, (not MISSILES) and MT_MTNK or MT_STNK)
					elseif not p.sam_highjump
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBL)
					elseif MISSILES>145 and PWBOMBS<5
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2),  MT_PBOM)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_PBOM)
				end								
			elseif (samRNG < 69)
				if p and not p.sam_chargebeam
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SATK)
				end
			elseif (samRNG < 75)
				if p
					if not p.sam_chargebeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif p.sam_gravitysuit != 2
						ITEM = P_SpawnMobj(m.x, m.y, m.z, (not p.sam_gravitysuit) and MT_VRST or MT_GVST)
					elseif not p.sam_power_grip
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PWGRP)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_GVST)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_GVST)
				end
			elseif (samRNG < 96)
				if p and MISSILES == 0 and (gametype == GT_COOP)
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK) --More generous in 
				end
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBL)
			end

		elseif (m.type == MT_ARMAGEDDON_BOX)
			if (samRNG < 9)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, (p and p.sam_chargebeam) and MT_SATK or MT_CHBM)
			elseif (samRNG < 18)
				if p and not p.sam_bombs
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, (MISSILES > 115 and not p.sam_screwattack) and MT_SATK or MT_MTNK)
				end
			elseif samRNG == 18
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
			elseif (samRNG < 54)
				if p
					if not p.sam_bombs
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
					elseif not (MISSILES > 10)
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					elseif not p.sam_chargebeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif (gametype == GT_COOP) and not p.sam_spazerbeam 
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
					elseif (ITEMRATE > 88) and not p.sam_plasmabeam
					or p.sam_plasmabeam and not p.sam_plasmabeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PLBM)
					elseif (samRNG < 40) and (SUPERS > 9) and (MISSILES < 120)
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
				end
			elseif (samRNG < 94)
				if p and (samRNG < 84)
					if not p.sam_chargebeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif (gametype == GT_COOP) and not p.sam_spazerbeam 
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PLBM)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PLBM)
				end
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
			end

		elseif (m.type == MT_WHIRLWIND_BOX) or (m.type == MT_FLAMEAURA_BOX)
			if (samRNG < 11)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
			elseif (samRNG < 14)
				if p
					if not p.sam_spiderball
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPDRBL)
					elseif not (p.sammissilesmax and (p.sammissilesmax > 15))
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)						
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
				end
			elseif (samRNG < 28)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
			elseif (samRNG < 83)
				if p or not p.sam_icebeam
					if not p.sam_spacejump
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
					elseif not p.sam_icebeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ICBM)
					elseif not p.sam_power_grip
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PWGRP)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ICBM)
				end
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBL)
			end

		elseif (m.type == MT_PITY_BOX)
			if (samRNG < 10)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ICBM)
			elseif (samRNG < 20)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
			elseif (samRNG < 41)
				if G_GametypeHasSpectators()
					if p
						if not p.sam_bombs
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
						elseif p.sam_hyperbeam
							ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
						elseif not p.sam_power_grip
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PWGRP)							
						else
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
						end
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
				end
			elseif (samRNG < 53)
				if p
					if not p.sam_powerbeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PLBM)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PLBM)
				end
			elseif (samRNG < 70)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_WVBM)
			elseif (samRNG < 87)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
			elseif (samRNG < 91)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPDRBL)
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
			end

		elseif (m.type == MT_FORCE_BOX)
			if (samRNG < 3)
				if (p and not p.sam_gravitysuit)
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_VRST)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_GVST)
				end
			elseif (samRNG < 25)
				if p and not (MISSILES<10)
					if not p.sam_powerbeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif MISSILES>49 and not p.sam_gravitysuit
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_VRST)
					elseif not p.sam_power_grip
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PWGRP)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				end
			elseif (samRNG < 34)
				if p
					if not p.sam_powerbeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif SUPERS and MISSILES<5 --You should have more missiles than this by now!
					or SUPERS>5 and MISSILES<30
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
				end
			elseif (samRNG < 47)
				if G_GametypeHasSpectators()
					if p
						if not p.sambsbl
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_BSBL)
						else
							local MME = string.lower( (p and p.name) or "i")
							if players[0] and players[0].name == "Golden Shine" and string.find(MME, "rn")
								ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
							elseif p.sam_hyperbeam
								ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGB)								
							else
								ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
							end
						end
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
					end
				elseif not (p and p.sambsbl)
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_BSBL)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
				end
			else
				if G_GametypeHasSpectators()
					if p
						if not p.sam_bombs
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
						elseif MISSILES<15 or SUPERS
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
						else
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
						end
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					end
				else
					if not p or not p.sam_chargebeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif not p.sam_bombs
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_VRST)
					end
				end
			end

		elseif (m.type == MT_ATTRACT_BOX) or (m.type == MT_THUNDERCOIN_BOX)
	
			if (samRNG < 25)
				if p
					if not p.sam_bombs
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
					elseif p.sam_wavebeam and not p.sam_wavebeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_WVBM)
					elseif not p.sam_powerbeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
					elseif MISSILES>145 and SUPERS<6
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				end
			elseif (samRNG < 28)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
			elseif (samRNG < 50)
				if G_GametypeHasSpectators()
					if p and p.sam_hyperbeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
					end
				elseif not p or (ENERGY > 80) and not p.samspbs
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBS)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
				end
			else
				if p
					if MISSILES<15
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					elseif not p.sam_wavebeamcombo and (samRNG > 61)
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_WVBM)
					elseif not p.sam_spiderball and (samRNG < 62)
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPDRBL)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_WVBM)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, (samRNG < 62) and MT_SPDRBL or MT_WVBM)
				end
			end

		elseif (m.type == MT_ELEMENTAL_BOX) or (m.type == MT_BUBBLEWRAP_BOX)
			if (samRNG < 12)
				if not p or p.sam_gravitysuit == 1
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_GVST)
				else
					if not p.sam_gravitysuit
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_VRST)
					elseif not multiplayer
						ITEM = P_SpawnMobj(m.x, m.y, m.z, (samRNG < 4) and MT_PTNK or MT_MTNK)
					end
				end
			elseif (samRNG < 38)
				if p
					if p.sam_spazerbeam and not p.sam_spazerbeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
					elseif MISSILES>145 and SUPERS<10
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				end
			elseif (samRNG < 55)
				if G_GametypeHasSpectators()
					if p and p.sam_hyperbeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGB)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
					end
				else
					if SUPERS>7 and (p and not p.sam_screwattack)
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SATK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					end
				end
			elseif (samRNG < 59)
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
			else
				if p
					if p.sam_spazerbeam and MISSILES<25
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					elseif not p.sam_spazerbeamcombo
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
				end
			end

		elseif (m.type == MT_MIXUP_BOX) --The Mixup Box acts like a Joker, giving you an amazing powerup!
		
			if p
				if p.nosuperpowert and (gametype != GT_COOP)
					p.sammissilesmax = MISSILES+5
					p.sammissiles = p.sammissiles and $+5 or 5
					CONS_Printf(p, "You got a mere missile tank! It's a good day to go on strike!")
				else
					p.sammissilesmax = MISSILES+5
					p.sammissiles = p.sammissiles and $+5 or 5
					p.samsupermissilesmax = SUPERS+2
					p.samsupermissiles = p.samsupermissiles and $+2 or 2
					p.sampwmax = p.sampwmax and $+1 or 1
					p.sampw = p.sampw and $+1 or 1
					CONS_Printf(p, "You got one of each ammo tank! It's a good day to be a Bounty Hunter.")
				end
				P_SamFP(p, PAL_MIXUP, 10)
				p.samitemgettimer = 86
				p.samitemcolor = SKINCOLOR_PINK
				p.samitemgetname = "Super Ammo Tank"
				p.samitemscale = 105000
				S_StartSound(t, sfx_spwup)
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK) --Uhh...fallback?
			end

		elseif (m.type == MT_1UP_BOX) -- 1 up boxes are somewhat special!
		
			if p and ETANKS 
				if ITEMRATE>96 and ETANKS<12 and mapheaderinfo[gamemap].lvlttl == "Black Core"
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK) --The final energy tank, guaranteed at the last moment!	
				elseif (ETANKS >= 12) --You got all E tanks! Grant major missing powerups through 1-up monitors to help completion!
					if (samRNG > 83) and (ITEMRATE>90) and (SUPERS<10)
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					elseif (samRNG > 82) and ITEMRATE>89 and PWBOMBS<5
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
					elseif (samRNG > 76) and ITEMRATE>94 and not p.sam_screwattack
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SATK)
					elseif (samRNG > 74) and ITEMRATE>93 and p.sam_gravitysuit != 2
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_GVST)
					elseif (samRNG > 60) and ITEMRATE>90 --Missing any beam combos? Let's get them!
					and (p.sam_powerbeamcombo != true or p.sam_spazerbeamcombo != true or p.sam_wavebeamcombo != true
					or p.sam_icebeamcombo != true or p.sam_plasmabeamcombo != true)
						if not p.sam_powerbeamcombo
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
						elseif not p.sam_spazerbeamcombo
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
						elseif not p.sam_wavebeamcombo
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_WVBM)
						elseif not p.sam_icebeamcombo
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ICBM)
						else
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PLBM)
						end
					else --Energy tank system!
						ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), (samRNG<60 and ENERGY>ETANKS*22) and MT_PBOM or MT_NRGD)
					end
				elseif ETANKS<7 and (samRNG > ETANKS*10)
				or ETANKS>6 and (samRNG > ETANKS*8)
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, (samRNG<25) and MT_NRGA or (samRNG<58) and MT_NRGB or MT_NRGD)
				end
				local DOBONUS = false
				if not (gametyperules & GTR_RINGSLINGER) or not (p)
					DOBONUS = true
				else
					for z in players.iterate
						if z and (p.score < z.score)
							DOBONUS = true break --
						end
					end
				end
				if DOBONUS == true
					local BONUS = P_RandomRange(0,6) --Chance to spawn a little buffet of items from 1-up monitors!
					if (BONUS > 1)
						local ANG = t and t.angle or ANG1
						local ITYPE = (ENERGY<ETANKS*14) and MT_NRGB or (p and p.sam_hyperbeam) and MT_MPKU or MT_NRGA
						local STYPE = (SUPERS and not (p and p.samsupermissiles==SUPERS)) and MT_SPKU or MT_MPKU
						local PTYPE = (PWBOMBS and not (p and p.sampw==PWBOMBS)) and MT_PBOM or MT_MPKU
						local ADDANG  = (360/BONUS)*ANG1
						for i = 1,BONUS
							local ghs = P_SpawnMobj(m.x, m.y, m.z+FLOAT, (i==4) and STYPE or (i==6) and PTYPE or ITYPE)
							for i = 1,4
								if not (ghs and ghs.valid) break end --
								local ths = P_SpawnGhostMobj(ghs)
								if ths and ths.valid
									ths.spritexscale,ths.spriteyscale = FRACUNIT*2,FRACUNIT*2
									ths.fuse,ghs.tics = 33,33
									ths.destscale = 1
									ths.scalespeed = ths.scale/(ghs.fuse+5)
								end
								P_TryMove(ghs, 
								ghs.x+FixedMul(36<<16, cos(ANG)),
								ghs.y+FixedMul(36<<16, sin(ANG)), true) 
								ANG = $+ADDANG
							end
						end
					end
				end
			else --The first one is entirely guaranteed.
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)		
			end
			if m --Hacky code to remove the monitor's associated monitor life icon.
				for nya in mobjs.iterate(mobj)
					if (nya.target==m) and (nya.type == MT_OVERLAY)
						if (FixedHypot(m.x-nya.x, m.y-nya.y) < 32355)
							nya.flags2 = $|MF2_DONTDRAW
							m.lifeiconvanished = nya break --
						end
					end
				end
			end
			
		--All other regular boxes	
		elseif not (m.type == MT_EGGMAN_BOX)
		and not (m.type == MT_EGGMAN_GOLDBOX)
		and not (m.type == MT_GRAVITY_GOLDBOX) 
		and not (m.type == MT_GRAVITY_BOX) 
		
			if (samRNG < 5)
				if samRNG==1 and SUPERS>9 and PWBOMBS<5 and (gametype == GT_COOP) 
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
				elseif (samRNG < 3) and (p and p.sam_bombs)
					ITEM = P_SpawnMobj(m.x, m.y, m.z, (not p.samspbs) and MT_SPBS or MT_SPDRBL)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
				end
			elseif (samRNG < 34)
				if p
					if not p.sam_bombs
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)
					elseif p.sam_hyperbeam
						ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGB)
					elseif MISSILES<15 and G_GametypeHasSpectators()
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
					else
						if MISSILES>45 and not SUPERS
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
						elseif p.buffbottomtier
							if (samRNG < 30) and not p.sam_autotank --Stop making me take pity and PAY attention!
								ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_AUTOTANK)
							elseif not (p.sam_ammodigitizer and (p.sam_ammodigitizer >= 2))
								ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_AMMODIGITIZER)
							else
								P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_MTNK) --If I ever hear about the funny stacked missile tanks 
								ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK) --...then that person reporting the "bug" screwed up hard.
							end
						else
							local MME = string.lower( (p and p.name) or "i")				
							if (samRNG<10) and string.find(MME, "rn") and players[0] and players[0].name == "Golden Shine"
								ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_PBOM)
							elseif (samRNG < 28) and not p.buffbottomtier
								ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_MPKU)
							else
								ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_BMPKU)
							end
						end
					end
				elseif (samRNG < 28)
					ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), (samRNG<28) and MT_MPKU or MT_BMPKU)
				end
			elseif (samRNG < 37)
				if G_GametypeHasSpectators()
					if p
						if p.sam_hyperbeam
							ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGB)
						elseif not p.sam_gravitysuit
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_VRST)
						elseif p.buffbottomtier and p.sam_gravitysuit==1
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_GVST)
						else
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
						end
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_ENGTNK)
					end
				elseif p and not p.sam_gravitysuit
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_VRST)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGA)
				end
			elseif (samRNG < 63)
				if not MISSILES
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				elseif (samRNG < 49) and p and p.buffbottomtier
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_ENGTNK)
				elseif (samRNG < 43) or G_GametypeHasSpectators()
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGD)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+FLOAT, (samRNG < 56) and MT_NRGB or MT_NRGA)
				end
			elseif (samRNG < 81)
				if SUPERS and p.buffbottomtier and not PWBOMBS
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
				else
					if G_GametypeHasSpectators() and p and (ITEMRATE < 20)
						if not p.sam_bombs
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MHBM)							
						elseif not SUPERS and (MISSILES < 15)
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
						elseif not p.sam_wavebeam
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_WVBM)
						elseif not SUPERS
							ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)						
						end
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_SPKU)
					end
				end
			elseif (samRNG < 85)
				if PWBOMBS 
					if not SUPERS or p.buffbottomtier
						ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
					else
						ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), MT_SPKU)
					end
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z+(FLOAT/2), (samRNG<89 and SUPERS>4) and MT_PTNK or MT_PBOM)
				end
			elseif (samRNG < 99)
				if SUPERS<6 and p and p.buffbottomtier
					P_SpawnMobj(m.x, m.y, m.z, (not PWBOMBS) and MT_PTNK or MT_STNK)
				else
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_MTNK)
				end
			elseif SUPERS and p --You got the lucky 99/100! Fill in what the player's missing!
				if not p.sam_chargebeam
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_CHBM)
				elseif not p.sam_spacejump
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SJMP)
				elseif not p.sam_spazerbeam
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_SPBM)
				elseif not p.samspbs
					P_SpawnMobj(m.x, m.y, m.z, MT_SPBS)
				elseif SUPERS>8 and not PWBOMBS
					ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_PTNK)
				elseif not p.sam_icebeam and (MISSILES > 60) and p.sam_highjump
					P_SpawnMobj(m.x, m.y, m.z, MT_ICBM)
				else--if not p.sam_highjump
					P_SpawnMobj(m.x, m.y, m.z, MT_SPBL)
				end
			else
				ITEM = P_SpawnMobj(m.x, m.y, m.z, MT_STNK)
			end
		end
		if ITEM and ITEM.valid --So did we get one?
			m.samspawneditem = ITEM
			local ths = P_SpawnMobjFromMobj(m,0,0,0,MT_EXPLODE)
			ths.spritexscale,ths.spriteyscale,ths.dispoffset = $*4/3,$*4/3,-9
			ths.renderflags = RF_SEMIBRIGHT|RF_NOCOLORMAPS
			ths.flags = $|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING
			ths.state = S_XPLD3
			ths.destscale = 99<<16
			ths.frame = ($ & ~FF_TRANSMASK)|FF_TRANS50
			
			ths = P_SpawnMobjFromMobj(ITEM,0,0,0,MT_SAMUSTHOK)
			ths.sprite = ITEM.sprite
			ths.frame = (ITEM.frame & ~FF_TRANSMASK)|FF_TRANS40
			ths.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ths.fuse,ths.tics = 16,16
			ths.spriteyoffset = $-5<<16
			ths.color,ths.colorized = ITEM.color,ITEM.colorized
			ths.destscale,ths.scalespeed,ths.dispoffset = 99<<16,9001,-1
		end
 	end
	if s.state == S_SAMSPAWNITEM2 //Flip the item if it's supposed to be flipped.
		if not s.poyo
			if not s.SAM_respawnboxer  --Normally, respawn time is based on amount of players available.
			or (s.SAM_respawnboxer > 1150)
				s.SAM_respawnboxer = 1050
				for z in players.iterate
					if z and z.valid
						s.SAM_respawnboxer = (d > 20) and $-P_RandomRange(10,30) or $-P_RandomRange(40,70)
					end
				end
				s.SAM_respawnboxer = max($,140)
				
			--	respawntime = max($, 140) --Never go below 4 seconds.
				s.tics = s.SAM_respawnboxer --Our final respawntime.
			end
			if s.SAM_respawnboxer --Custom spawn time?
				s.tics = max(35, min(1050, s.SAM_respawnboxer*35))
			else
				s.tics = 999 --Failsafe
			end
			s.poyo = true --Done!
		end
		if ITEM and m and m.valid
			m.samspawneditem = ITEM
			if m.samspawneditem and m.samspawneditem.valid and not s.monitorflippedyet
				if ((m.flags2 & MF2_OBJECTFLIP) or (m.eflags & MFE_VERTICALFLIP))
					m.samspawneditem.flags2 = $|MF2_OBJECTFLIP
					m.samspawneditem.eflags = $|MFE_VERTICALFLIP
				end
				s.monitorflippedyet = true
			end
		end
		--According to server preferences, respawn items after a timer or if the spawned item is picked up!
		if gametype == GT_COOP 
			if s.SAM_coopboxrespawn == nil or s.SAM_coopboxrespawn == 2 
				if not (m.samspawneditem and m.samspawneditem.valid) and (s.tics > 20) 
					s.tics = 20
				end
			elseif s and s.valid --In single player/coop, remove this tracker then!
				s.state = S_NULL return --
			end
		end
	end
	
	if (s.state == S_SAMSPAWNITEM3) and m and m.valid
	 	if G_GametypeHasSpectators() 	
			if not s.SAM_matchmonitors
				local TYPE = SAM.MonitorRandomize(m, RETURNTYPE)
				if TYPE
					m.respawnedbx = P_SpawnMobj(m.x, m.y, m.z, TYPE)
					if m and m.respawnedbx and ((m.eflags & MFE_VERTICALFLIP) or (m.flags2 & MF2_OBJECTFLIP))
						m.respawnedbx.flags2 = m.flags2 & ~MF2_DONTDRAW
					end
					if METROIDSKINS == true and m.respawnedbx and m.respawnedbx.valid and m.respawnedbx.flags != nil
						SAM.MonitorToSphere(m.respawnedbx)
					end
					if m and m.valid and m.samspawneditem and m.samspawneditem.valid
						m.samspawneditem.state = S_NULL
					end
					if m and m.valid
						P_RemoveMobj(m)
					end
				end
			end
		
	 	else --if not GameTypeHasSpectators
			if not (gametype == GT_COMPETITION) and (netgame or splitscreen)
				if m.lifeiconvanished
					if m.lifeiconvanished.valid
						if (m.lifeiconvanished.flags2)
							m.lifeiconvanished.flags2 = $ & ~MF2_DONTDRAW
						end
					else
						m.lifeiconvanished = nil
					end
				end
				m.state = (m.metroidvisual) and S_METBOX1 or m.info.spawnstate
				if not m.health
					m.health = 1
				end
				m.flags = $|MF_SHOOTABLE|MF_SOLID|MF_MONITOR & ~(MF_NOCLIP|MF_NOCLIPTHING|MF_NOTHINK|MF_NOCLIPHEIGHT)
				m.flags2 = $ & ~MF2_DONTDRAW
				if m.goldlaststate != nil
					m.state = m.goldlaststate
				end
				if m and m.valid and m.samspawneditem and m.samspawneditem.valid
					m.samspawneditem.state = S_NULL
				end
			end
	 	end
	end
end, MT_SAMSPAWNITEM)

--Sonic Version, though not actually active for monitor bopping right now.
addHook("MobjThinker", function(s) if not s.valid return end
	if not (s.ogmonitor and s.ogmonitor.valid)
		s.state = S_NULL return --
	end
	if s.missilepanel
		if s.ogmonitor and s.ogmonitor.valid
			s.ogmonitor.angle = $+(ANG2*2)
		else
			s.state = S_NULL
		end
		return --
	elseif s.holdontime
		s.holdontime = $-1
		if not s.holdontime 
			if s.ogmonitor and s.ogmonitor.valid
				s.ogmonitor.holdon = nil
				s.state = S_NULL
			end
		end
		return --
	end
	if s.waittics == nil
		if gametype == GT_COOP
			s.waittics = 105
		else
			local PLAYERS = 0
			for z in players.iterate
				if z.valid and z.mo and z.mo.valid and z.mo.health
					PLAYERS = $+1
				end
			end
			s.waittics = max(3, 1000-PLAYERS*27)
		end	
	end
	s.waittics = max($-1,0)
	
	if not s.waittics
		if gametype == GT_COOP
			s.ogmonitor.health = 1
			s.ogmonitor.state = s.ogstate
			s.ogmonitor.flags = s.ogflags
			s.ogmonitor.flags2 = s.ogflags2
			s.state = S_NULL return --
		else
			local TYPE = MT_RING_BOX --Default is Ring Box!
			local NUM = P_RandomRange(1, 120) -- Box respawn type.
			if (NUM >= 118) --Special case 1.
				TYPE = ((NUM < 119) and (leveltime > 10)) and MT_MIXUP_BOX or MT_RECYCLER_BOX
			elseif (NUM > 60)
				if (NUM < 64) --Special case 2
					m.respawnedbx = P_SpawnMobj(m.x, m.y, m.z, MT_PITY_BOX)
					if m.respawnedbx and m.respawnedbx.valid m.respawnedbx.triedspawn = true end
					return --
				elseif (NUM < 73)
					TYPE = MT_FORCE_BOX
				elseif (NUM < 81)
					TYPE = MT_WHIRLWIND_BOX
				elseif (NUM < 88)
					TYPE = MT_ELEMENTAL_BOX
				elseif (NUM < 94)
					TYPE = MT_ATTRACT_BOX
				elseif (NUM < 100)
					TYPE = MT_ARMAGEDDON_BOX
				elseif (NUM < 102)
					TYPE = MT_INVULN_BOX
				else --if (NUM < 118)
					TYPE = MT_SNEAKERS_BOX	
				end
			end
			m.respawnedbx = P_SpawnMobj(m.x, m.y, m.z, TYPE)
		end
	end
end, MT_SAMSPAWNITEMSONIC)
/*
function A_SAMUSEXPLOSIONS(actor, var1, var2, var3, var4, color, nii)
	if not (actor and actor.valid)
		return
	end
	if nii and nii == "brakdust"
	 for sa = 0,16 
		local smmk = P_SpawnMobj(actor.x, actor.y, actor.z+25<<16, var2)
		smmk.scale = actor.scale
		smmk.target = actor
		smmk.color = SKINCOLOR_SKY
		smmk.brakandco = true
		smmk.blendmode = AST_ADD
		smmk.eflags = actor.eflags
		smmk.flags2 = actor.flags2
		smmk.momx = ( (var1*(actor.scale>>16))*cos((sa*ANGLE_45+(ANG2*4))) + (actor.momx/2) )
		smmk.momy = ( (var1*(actor.scale>>16))*sin((sa*ANGLE_45+(ANG2*4))) + (actor.momy/2) )
	 end

	else
	 for sa = 0,08
		local smmk = P_SpawnMobj(actor.x, actor.y, actor.z+FixedMul(FRACUNIT, (P_MobjFlip(actor)*actor.scale)), var2)
		if smmk and smmk.valid and not nii
		smmk.flags = $1|MF_NOCLIPHEIGHT
		smmk.scale = actor.scale
		smmk.target = actor
		end
		smmk.eflags = actor.eflags
		smmk.blendmode = AST_ADD
		smmk.flags2 = actor.flags2
		smmk.samussmmk = true
		smmk.momx = ( (var1*(actor.scale>>16))*cos((sa*ANGLE_45)) + (actor.momx/2) )
		smmk.momy = ( (var1*(actor.scale>>16))*sin((sa*ANGLE_45)) + (actor.momy/2) )
		if var4
		P_SetObjectMomZ(smmk, var4, true)
		end
		if var3
		P_MoveOrigin(smmk, smmk.x, smmk.y, smmk.z+FixedMul(var3, (P_MobjFlip(actor)*actor.scale)))
		end
		if color
			if (color == true)
			smmk.pworsm = true
			else
			smmk.color = color
				if actor.type == MT_SAMMISSILE
				smmk.colorized = true
				smmk.blendmode = AST_ADD
				smmk.flags2 = $|MF2_SHADOW
				end
			end
		end
	 end
	 if var2 == MT_SAMSHATTERFOF
	 P_SpawnMobj(actor.x, actor.y, actor.z+90<<16, var2)
	 P_SpawnMobj(actor.x, actor.y, actor.z-90<<16, var2)
	 end
	end
	if actor and actor.valid and (actor.darkhyper or actor.type == MT_PZBOSS) and smmk and smmk.valid --Extra addon for Dark Samus
		smmk.color = SKINCOLOR_COBALT
		smmk.colorized = true
	end
end */

function A_SAMUSEXPLOSIONS(s, var1, TYPE, ZSET, ZTHRUST, COLOR, nii)
	if not (s and s.valid) return end --	
	local DARKPZ = (s.darkhyper or (s.type == MT_PZBOSS)) and true or false 
	if DARKPZ and COLOR != true
		COLOR = SKINCOLOR_COBALT
	end
	local ghs
	if nii == "brakdust"
		for i = 0,16 
			ghs = P_SpawnMobjFromMobj(s, 0, 0, 25<<16, TYPE)
			if not (ghs and ghs.valid) continue end --
			ghs.target = s
			if not DARKPZ
				ghs.color = SKINCOLOR_SKY
			else
				ghs.color = SKINCOLOR_COBALT
				ghs.colorized = true
			end
			ghs.flags = $|MF_NOBLOCKMAP|MF_NOCLIPTHING
			ghs.brakandco = true
			ghs.blendmode = AST_ADD
			ghs.flags2 = s.flags2
			if var1
				ghs.momx = var1*(s.scale>>16)*cos(i*ANGLE_45) + s.momx/2
				ghs.momy = var1*(s.scale>>16)*sin(i*ANGLE_45) + s.momy/2
			end
		end
	else
		local ZFLIP = 1 if s and s.valid ZFLIP = P_MobjFlip(s) end
		for i = 0,08
			ghs = P_SpawnMobjFromMobj(s,0,0,s.scale*ZFLIP, TYPE)
			if not (ghs and ghs.valid) continue end --
			if not nii
				ghs.flags = $|MF_NOCLIPHEIGHT
				ghs.scale = s.scale
				ghs.target = s
			else
				ghs.scale = FRACUNIT
			end
			ghs.flags = $|MF_NOBLOCKMAP|MF_NOCLIPTHING
			ghs.blendmode = AST_ADD
			ghs.flags2 = s.flags2
			ghs.samussmmk = true
			if var1
				ghs.momx = var1*(s.scale>>16)*cos(i*ANGLE_45) + s.momx/2
				ghs.momy = var1*(s.scale>>16)*sin(i*ANGLE_45) + s.momy/2
			end
			if ZSET
				P_MoveOrigin(ghs, ghs.x, ghs.y, ghs.z+FixedMul(ZSET, ZFLIP*s.scale))
			end			
			if ZTHRUST
				P_SetObjectMomZ(ghs, ZTHRUST, true)
			end
			if COLOR
				if (COLOR == true)
					ghs.pworsm = true
				else
					ghs.color = COLOR
					if s.type == MT_SAMMISSILE
						ghs.colorized = true
						ghs.flags2 = $|MF2_SHADOW
					end
				end
			end
		end
		if TYPE == MT_SAMSHATTERFOF
			for i = -1,1,2
				local ghs = P_SpawnMobj(s.x, s.y, s.z+ ((90*i)<<16), TYPE)
				if ghs and ghs.valid
					ghs.momx,ghs.momy = 1,1
				end
			end
		end
	end
end

--Lazy shortcuts
local function XYCheck(s,m) 
	return FixedHypot(m.x-s.x, m.y-s.y) --
end
local function ZCheck(s,m,var2) 
	if (s.z > m.z+var2) or (s.z < m.z-var2)
		return true --
	end return false --
end

local BMtype = {
[MT_MINUS] = true,
[MT_SPIKE] = true,
[MT_WALLSPIKE] = true,
[MT_ICBLOCK] = "nohealth",
[MT_EGGSHIELD] = "nohealth"
}

//var1 = width range, var2 = height range, var3 = source
--Example from MT_SAMMISSILE
--A_Samuskillstuff(s, 268<<16, 145<<16, s.target, true)
function A_Samuskillstuff(s, XYRANGE, ZRANGE, SOURCE, var4, var5, var6)

	local p = s --Warning, p is simply "mo" instead of player this time. Because I was an idiot.
	local DIST,ZDIST = 0,0
	local t = s.target --(SOURCE is usually the target, but not always)
	local ZFLIP = 1 if s and s.valid ZFLIP = P_MobjFlip(s) end
	local type = s.type
	
searchBlockmap("objects", function(ref, m)
	if not m.valid return end
	if m.samreflecttime and (type != MT_HBSHOT) return end --Reminder that SearchBlockmap uses return, not "continue"!
	
	if (m.flags & (MF_ENEMY|MF_BOSS)) and (m.flags & MF_SHOOTABLE) 
	and m.health and not (m.flags2 & MF2_FRET) and (m.info.mass!=2006)
	
	or m.player and m.health
	or (BMtype[m.type]) and (m.health or BMtype[m.type]=="nohealth")
	
		DIST = XYCheck(s,m)
		if (XYRANGE >= DIST)
		and not (ZCheck(s,m, ZRANGE))
			if m.player 
				local MP = m.player
				if (type == MT_SAMPOWERBOMB)
					if (m == s.target) and not s.gravitysuitjustgot
						if MP.sammorphed
						and (DIST <= 123<<16)
						and not (m.z < s.z-78<<16) and not (m.z > s.z+78<<16)
							P_SetObjectMomZ(m, 1350000)
							m.bombjump = 28
							m.bombjumpangle = (R_PointToAngle2(s.x, s.y, m.x, m.y))
							m.bombjumpdist = (DIST > 4<<16) and DIST or 0
							m.powerbombjump = 3
		
							if m.spiderballing --Samus Returns-style PowerBomb fling!
								m.spiderballing = 0
								SamSpiderCharge(p, m, 103)
								m.spiderbanim = 7
								m.angle = $+ANGLE_180
								m.smmachballpw = 8
								S_StartSound(m, sfx_brakrx)
								S_StartSound(m, sfx_bkpoof)
								P_InstaThrust(m, m.angle, 59<<16)
		
								m.morphedmachspeed = 45<<16
								m.morphedmachactive = true
								m.smmachball = 0
								m.smmachballwait = 0
								m.initialmockbspeed = 45<<16
								MP.pflags = $ & ~(PF_JUMPED|PF_STARTJUMP)
								m.bombjump = 0
								m.momz = $/2
								P_NukeEnemies(m, m, 0)
							end
							return --
						end
					end
				elseif (type == MT_SAMMORPHBOMB) or (type == MT_SAMMBOP)
					if MP.sammorphed and s.target == m --Only on yourself!
						if not (m.z < s.z-18<<16) 
						and not (m.z > s.z+18<<16)
						and (DIST <= 64<<16)
							P_SetObjectMomZ(m, (m.eflags & MFE_UNDERWATER) and 950000 or 1350000)
							m.bombjump = 28
							m.bombjumpangle = R_PointToAngle2(s.x, s.y, m.x, m.y)
							m.bombjumpdist = (DIST <= 4<<16) and 0 or DIST
							return --
						end
					elseif s.sambeamreflected
						ExplodePush(p, m, SOURCE) return --
					end
				end
			elseif m.type == MT_ICBLOCK
				if not (type == MT_ICSHOT)
					m.icethisfool = true
				end return --
			elseif m.type == MT_EGGSHIELD or m.type == MT_MINUS
				if m.type == MT_EGGSHIELD
					if not (type == MT_SAMSUPERMISSILE) and not (type == MT_SAMMISSILE)
						if m.target and (m.target.type == MT_EGGGUARD) and (m.target.health)
							local guard = m.target
							if guard and guard.valid
								guard.flags = MF_ENEMY|MF_SHOOTABLE
								guard.state = S_EGGGUARD_RUN1
								P_DamageMobj(guard, p, s.target)
							end
							if m and m.valid
								m.state = S_NULL
							end								
						end
					end
					if m and m.valid and (type == MT_SAMMISSILE)
						P_KillMobj(m, p, SOURCE) --Super missiles won't instakill guards on succesful block. 
					end
				else
					P_KillMobj(m, p, SOURCE) 
				end
			elseif m.type == MT_SPIKE or m.type == MT_WALLSPIKE
				if (type == MT_SAMPOWERBOMB) or (type == MT_SAMSUPERMISSILE) or (type == MT_HBSHOT)
					if m.health
						P_KillMobj(m, p, s)
					end
				end
				return --
			end
			
			if not (s and m and m.valid) return end --
			
			if var4
				if not (m.z < s.z-(150<<16*(ZFLIP)) ) 
				and not (m.type == MT_PLAYER)
				and not ((type == MT_SPCHARGECOMBO) or (type == MT_SPAZERSHOCK))
					if (type == MT_SAMMISSILE and not m.missileresist)
					or (type == MT_PBCHARGESHOT)
						ExplodePush(p, m, SOURCE)
					else
						P_DamageMobj(m, p, SOURCE, 1) 
					end
				end
			end
			
			if not (s and m and m.valid) return end --
			
			if var5 == "combowave"
			and not (s.target and (m == s.target)) 
			and ( ((G_GametypeHasSpectators() or s.sambeamreflected) and m.player) or (m.flags & (MF_ENEMY|MF_BOSS)) )
				s.meleeblast = P_SpawnMobj(m.x, m.y, m.z, MT_SPAZERSHOCK)
				s.meleeblast.rocket = m
				s.meleeblast.mojo = true
				m.spazershocked = true
				m.spcombod = true
				s.meleeblast.angle = s.angle
				if s.target
					s.meleeblast.target = s.target
				end
				S_StartSound(m, sfx_smexp)
				S_StartSound(m, sfx_smexp)
			elseif var5
			and ( not m.player
			or ((type == MT_HBSHOT) and (G_GametypeHasSpectators()
			or s.sambeamreflected) and ((type == MT_SAMPOWERBOMB)
			or not (s.target and s.target == m)))
			) 
				if (type == MT_HBSHOT)
					if not (s.lasthyper == m)
						s.meleeblast = P_SpawnMobj(m.x, m.y, m.z, MT_SPAZERSHOCK)
						s.meleeblast.rocket = m
						m.spazershocked = true
						s.meleeblast.angle = s.angle
						m.specialexpangle = (R_PointToAngle2(m.x, m.y, s.x, s.y))
						if s.target
							s.meleeblast.target = s.target
							s.meleeblast.hypered = 400
						end
						S_StartSound(m, sfx_smexp)
						P_ExplodeMissile(p)
					end
				elseif (type == MT_SAMPOWERBOMB)
					if m.type == MT_PZBOSS
						P_DamageMobj(m, p, SOURCE, (not s.phase) and 2 or 1)
					else
						P_DamageMobj(m, p, SOURCE, (m.superbrak or not s.phase) and 3 or 1)
					end
				elseif (type == MT_SAMSUPERMISSILE)
					if m.type == MT_PZBOSS
						if not m.invincible and (m.samusHP > 7)
							m.samusHP = 1
							m.painfyellow = 25
							m.invincible = 25
						else
							P_DamageMobj(m, p, SOURCE, 1)
						end
					else
						P_DamageMobj(m, p, SOURCE, 2)
					end
				else
					P_DamageMobj(m, p, SOURCE, 1)
				end					
			elseif var6 and m and m.valid
				if not ((type == MT_ICSHOT) or (type == MT_ICCHARGESHOT))
					if not m.player or s.sambeamreflected
						if (type == MT_SAMMORPHBOMB or (type == MT_SAMMBOP))
							ExplodePush(p, m, SOURCE)
						else
							P_DamageMobj(m, p, SOURCE)
						end
					end	
				else
					if not m.player and m.health
						if (m.type == MT_METROIDPART) and m.hitbox
							P_DamageMobj(m, p, SOURCE, 1)
						elseif (type == MT_ICCHARGESHOT)
							if not m.frozenbox and (m.health < 3) and not (m.type == MT_PYREFLY)
							and (m.flags & MF_SHOOTABLE)
								if (m.type == MT_METROID) 
								or (m.type == MT_METROIDLARVA) 
								or (m.type == MT_SUPERMETROID) --Metroids use custom behaviour
									P_DamageMobj(m, p, SOURCE, 1)
								else
									m.health = 1
									m.frozenmobj = P_SpawnMobj(m.x, m.y, m.z, MT_FREEZETRACKER)
									m.frozenmobj.chozobox = m
									m.frozenmobj.samusshooter = SOURCE
								end
							elseif (m.health > 2)
								P_DamageMobj(m, p, SOURCE, 1)
							end
						elseif ((type == MT_ICSHOT) and m.iceresist)
							s.sam_resisthud = 18
						elseif not ((type == MT_ICSHOT) and m.iceresist)
							if m.iceweak
								s.sam_crithud = 18
								A_SAMUSEXPLOSIONS(m, 7, MT_SMOKE, false, 1000, SKINCOLOR_BLACK)
								A_SAMUSEXPLOSIONS(m, 7, MT_MPR8, false, 90000, SKINCOLOR_SKY, "nii")
								A_SAMUSEXPLOSIONS(m, 4, MT_MPR8, false, 8000, SKINCOLOR_WHITE, "nii")
							end
							if not m.frozenbox and (m.health == 1)
							and (m.flags & MF_SHOOTABLE)
								if (m.type == MT_METROID) or (m.type == MT_METROIDLARVA) or (m.type == MT_SUPERMETROID) --Metroids use custom behaviour
									P_DamageMobj(m, p, SOURCE, 1)
								else
									m.frozenmobj = P_SpawnMobj(m.x, m.y, m.z, MT_FREEZETRACKER)
									m.frozenmobj.chozobox = m
									m.frozenmobj.samusshooter = SOURCE
								end
							elseif (m.health > 1)
								P_DamageMobj(m, p, SOURCE)
							end
						end
					end
				end
			end
			
			if not (s and m and m.valid) return end --
			
			if not m.player and (m.health <= 1) and not (m.flags2 & MF2_FRET)
			and not m.frozenmobj and not (s and (type == MT_ICSHOT))
				if not (type == MT_HBSHOT)
				and not (type == MT_SAMMORPHBOMB or (type == MT_SAMMBOP) or (type == MT_SAMMISSILE) or (type == MT_PBCHARGESHOT))
					P_DamageMobj(m, p, SOURCE, 1)
				end
			elseif (type == MT_SAMSUPERMISSILE) and m.player
				P_SamFP(m.player, PAL_MIXUP, 2)
				m.sam_flashfade = 12
				m.sam_flashfadecolor = SKINCOLOR_RED
			end

			if m.player and (G_GametypeHasSpectators() or s.sambeamreflected and not (s.target and s.target.player))
				if not (s.target and s.target == m)
					P_DamageMobj(m, p, SOURCE)
				end
			end
		end	
	elseif (m.flags & MF_MONITOR)
		if m.health and (m.flags & MF_SHOOTABLE)
		and not (s and s.player)
			DIST = XYCheck(s,m)
			if not (DIST < XYRANGE/3)
			and not (ZCheck(s,m,ZRANGE/2))
				if (type == MT_SAMPOWERBOMB) and (m.type == MT_EGGMAN_BOX or m.type == MT_EGGMAN_GOLDBOX) 
					--Don't open those with Power Bombs.
				else
					A_SAMITEM(p, m)
				end
			end
		end return --
	elseif m.type == MT_SALOONDOOR
	or m.type == MT_SALOONDOORCENTER
	or m.type == MT_EGGSHIELD	
		if (type == MT_SAMSUPERMISSILE) or (type == MT_SAMPOWERBOMB) or (type == MT_HBSHOT)
			DIST = XYCheck(s,m)
			if not (DIST < XYRANGE)
			and not (ZCheck(s,m,ZRANGE))	 
				if ((m.type == MT_SALOONDOOR) or (m.type == MT_SALOONDOORCENTER))
				and not (m.flags & MF_NOCLIP)
					S_StartSound(m, sfx_smexp)
					m.hh = P_SpawnMobj(m.x, m.y, m.z, MT_BOSSEXPLODE)
					m.hh.scale = $*6
					m.flags = $|MF_NOCLIP
					if (m.type == MT_SALOONDOOR)
						P_KillMobj(m, p, p)
					end
				end
			end
		end
		return --
	elseif m.type == MT_TURRET or m.type == MT_SPIKE or m.type == MT_WALLSPIKE  
		if (type == MT_SAMPOWERBOMB) or (type == MT_HBSHOT) or (type == MT_SAMSUPERMISSILE)
			if m.health or m.type == MT_TURRET
				DIST = XYCheck(s,m)
				if not (DIST < XYRANGE)
				and not (ZCheck(s,m,ZRANGE))		
					P_KillMobj(m, p, SOURCE)
				end
			end
		end
		return --
	elseif m.type == MT_TNTBARREL or m.type == MT_PROXIMITYTNT or m.type == MT_BIGMINE
		DIST = XYCheck(s,m)
		if not (DIST < XYRANGE)
		and not (ZCheck(s,m,ZRANGE))
		and m.health
			if (m.type == MT_PROXIMITYTNT)
				if not m.onetimexp
					m.onetimexp = true
					m.state = S_PROXIMITY_TNT_TRIGGER23
					m.tics = 1
				end
			else
				P_KillMobj(m, p, SOURCE)
			end
		end
	elseif (m.type == MT_METROIDPART) --Omegas are better affected by direct attacks!
		if (type == MT_SAMPOWERBOMB) or (type == MT_SAMMISSILE)
			return  --
		end	
	end 
end, s, s.x-(XYRANGE+160<<16), s.x+(XYRANGE+160<<16), s.y-(XYRANGE+160<<16), s.y+(XYRANGE+160<<16) )
		  
end

rawset(_G, "samwallcheck", function(s,p)
	if p.sam_iamahuntersbot and not p.hunterwalljump
	or p.sam_walljumpsound
	or s.sam_ldclmb and (s.sam_ldclmb > 22)
		return false --
	end
	local wm
	local dm = (s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling) and 1 or 3
	if (twodlevel or (s.flags2 & MF2_TWOD)) 
		if (p.cmd.sidemove > 0)
			if (s.angle == 0)
				wm = P_SPMAngle(s, MT_SAMWALLJUMP, ANGLE_180)
				p.sams_jumpcd = 3
				return true --
			end
		elseif (p.cmd.sidemove < 0)
			if (s.angle == ANGLE_180)
				wm = P_SPMAngle(s, MT_SAMWALLJUMP, 0)
				p.sams_jumpcd = 3
				return true --
			end
		end
	else --3D it is
	
		local sidemove = abs(p.cmd.sidemove) --Calculate side input first.					
		if p.sam_screwattacking --This one's free.
		and not (p.pflags & PF_ANALOGMODE)
			if not (p.cmd.sidemove or p.cmd.forwardmove)
			or ((p.cmd.forwardmove > 40) and (sidemove < 15))
				local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
				p.sams_jumpcd = 3	
				return true
			elseif (p.cmd.forwardmove > 40) --Omni-directional walljump
			or ((sidemove >= 15) and not ((p.cmd.forwardmove < 15) and (p.cmd.forwardmove > -15)))
			or (sidemove > 40)
				local turnang = R_PointToAngle2(0, 0, -(p.cmd.forwardmove<<16), -(p.cmd.sidemove<<16))						
				local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle-turnang)
				if ghs and ghs.valid
					if (sidemove > 15) --Sideways walljump!
					or ((s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling) and not ((p.cmd.forwardmove > 40) and (sidemove < 15)))
						ghs.scale = s.scale*5/dm
					end
					ghs.sideangle = s.angle-turnang
				end
				p.sams_jumpcd = 300
				return true
			end
		end
		if (p.pflags & PF_ANALOGMODE)
		
			if not (p.cmd.sidemove or p.cmd.forwardmove) --Old style analog walljump
			local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
				if ghs and ghs.valid
					if (sidemove > 15) --Sideways walljump!
					and not (s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling)
					ghs.scale = s.scale*5/dm
					end
				end
				p.sams_jumpcd = 3
				return true
			else --Newly adjusted easycake walljump controls, courtesy of SArun4
				local trueturn = (s.angle-((p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))))
				local walljumpauthorized = false
				
				if trueturn == 0
					walljumpauthorized = true
				else
					local newturn = abs(trueturn/ANG1)
					if (newturn < 35)
						walljumpauthorized = true
					end
				end
				if walljumpauthorized
					local momang = R_PointToDist2(s.x, s.y, s.x+s.momx, s.y+s.momy)
					local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
					if ghs and ghs.valid
						if (sidemove > 15)
						and not (s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling)
					--	or (s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling)
						ghs.scale = s.scale*5/dm
						end
					end
					p.sams_jumpcd = 3
					return true
				end
			end 
			
		elseif (p.cmd.forwardmove < 0) --Regular walljump
		and (sidemove < 15)
			local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
			if ghs and ghs.valid
				if s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling
					ghs.scale = s.scale*3
					ghs.momx,ghs.momy = $*3,$*3
				end
			end
			p.sams_jumpcd = 3
			return true --
		elseif (p.cmd.forwardmove > 40) --Omni-directional walljump
		or ((sidemove >= 15) and not ((p.cmd.forwardmove < 15) and (p.cmd.forwardmove > -15)))
		or (sidemove > 40)
			local turnang = R_PointToAngle2(0, 0, -(p.cmd.forwardmove<<16), -(p.cmd.sidemove<<16))						
			local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle-turnang)
			if ghs and ghs.valid
				if (sidemove >= 15)
				or (s.sam_afterboost or p.sam_screwattacking or s.sam_screwattackfling)
					if not ((p.sam_screwattacking or s.sam_screwattackfling)
					and (p.cmd.forwardmove > 40) and (sidemove < 15))
						ghs.scale = s.scale*5/dm
					end
				end
				ghs.sideangle = s.angle-turnang
			end
			p.sams_jumpcd = 3
			return true --
		end
	end
end)

--Walljump has hit, let's go!

function A_SAMWALLJUMP(s, var1, var2)
	if not (s.target and s.target.valid) or not s.health
		return
	end
	local t = s.target local p = t.player --Warning, player is not necessarily always valid!
	if (t.type == MT_SAMUSSHIP) and not s.done and not t.wallnopejump
		t.yougottaland = true
		s.flags = $|MF_NOCLIPHEIGHT
		s.health = 0
		s.done = true
		if s.valid s.state = S_NULL end
	end	
	if not (p and p.valid and t.health)
		return --
	end
	if t and t.wallnopejump
		s.state = S_NULL return --
	end
	
	if p.sammorphed
		if t.spiderballing
			if t.spiderfirstcheck
				t.spiderballgo = 3
			end
			t.spiderballstillgood = 2
			t.spiderfirstcheck = nil
			if s.valid s.state = S_NULL end	
		else
			t.spiderballgo = (t.spiderfirstcheck) and 4 or 2
			t.spiderfirstcheck = nil
			t.spiderballstillgood = 2
			if s.valid s.state = S_NULL end
		end	
	else
	
		P_SpawnMobjFromMobj(s, 0,0,0, MT_SMOKE)	
		t.player.pflags = $ & ~ PF_STARTJUMP
		S_StopSoundByID(t, sfx_sjmp)
		
		local SPBS = (p.samspbschargefull or t.sam_screwattackspbs or t.sam_afterboost) and true or false
		local jumpangle = t.angle
		local diminish = 1
		if s.sideangle != nil	
			jumpangle = s.sideangle
		end
		
		--Sideways anims and diminishers
		if p.cmd.sidemove != 0
			if (p.cmd.sidemove < 0)
				if t.sam_sidejump
					t.sam_sidejump = (t.sam_sidejump >= 0) and -1 or $-1
				else
					t.sam_sidejump = -1
				end
			else --if p.cmd.sidemove > 0
				if t.sam_sidejump
					t.sam_sidejump = (t.sam_sidejump <= 0) and 1 or $+1
				else
					t.sam_sidejump = 1
				end
			end
		else
			t.sam_sidejump = 0
		end		
		if t.sam_sidejump and not abs(t.sam_sidejump) == 1
			diminish = min(18, abs(t.sam_sidejump))*20000
			t.sam_sidejumpcd = 6
		end
		
		--Aaaaand the actual walljump begins.	
	
		if (t.eflags & MFE_UNDERWATER)
			if not (twodlevel or (t.flags2 & MF2_TWOD))
 				P_InstaThrust(t, jumpangle, FixedMul(-8<<16, t.scale))
				if s.sideangle != nil
					P_SetObjectMomZ(t, 3<<16-(diminish/2))
					if SPBS and (p.cmd.forwardmove > 15) --Assuming only gravity suit boys can get here...
						P_Thrust(t, jumpangle, FixedMul(-13<<16, t.scale))
						P_Thrust(t, t.angle, FixedMul(16<<16, t.scale))
					end						
					
				else --Standard underwater walljump
				
					t.sam_sidejump = 0
					t.angle = $+ANGLE_180
					if (t.player.pflags & PF_ANALOGMODE)
						t.player.drawangle = $+ANGLE_180
					end
					if SPBS
						P_SetObjectMomZ(t, 210000-diminish)
						P_Thrust(t, t.angle, FixedMul(22<<16, t.scale))
					else						
						P_SetObjectMomZ(t, 4<<16-diminish)	
					end
				end
				t.lastsamusangle = t.angle	
				t.player.powers[pw_nocontrol] = 2
			else
				t.sam_sidejump = 0
				P_SetObjectMomZ(t,  350000)
 				P_Thrust(t, t.angle, FixedMul(FRACUNIT/2, t.scale))
			end
		else	
			if not (twodlevel or (t.flags2 & MF2_TWOD))
				if SPBS and s.sideangle != nil and not (abs(p.cmd.sidemove) > 11) --Preventing weird bug.
					p.sams_jumpcd = 10
					if s and s.valid s.state = S_NULL end
					return false --
				end
				P_InstaThrust(t, jumpangle, FixedMul(-15<<16, t.scale))
				
				if s.sideangle != nil
					if SPBS
						if (abs(p.cmd.forwardmove) > 15) --And something fun for the advanced players!
							P_Thrust(t, jumpangle, FixedMul(-14<<16, t.scale))
							P_Thrust(t, t.angle, FixedMul(18<<16, t.scale))
							P_SetObjectMomZ(t, 395000-diminish)
						end
					else
						P_SetObjectMomZ(t, 460000-diminish)
					end
				else --Backwards standard walljump
					t.sam_sidejump = 0
					t.angle = $+ANGLE_180
					if (p.pflags & PF_ANALOGMODE)
						p.drawangle = $+ANGLE_180
					end
					
					if SPBS
						P_SetObjectMomZ(t, 430000)
						P_Thrust(t, t.angle, FixedMul(25<<16, t.scale))
					else
						P_SetObjectMomZ(t, 550000)
					end
				end	
					
				t.lastsamusangle = t.angle	
				p.powers[pw_nocontrol] = max($,2)
				
			else
				t.sam_sidejump = 0
 				P_Thrust(t, t.angle, FixedMul(FRACUNIT/2, t.scale))
				P_SetObjectMomZ(t, 700000)
			end
		end
		
		if p.sam_spacejumped and p.sam_spacejumpedboost and (p.sam_spacejumpedboost > 3)
			p.sam_spacejumpedboost = 0
			p.sam_spacejumped = false
		end
		
		--Silently restore speedbooster
		if t.sam_afterboost and not p.samspbschargefull
			p.samspbschargefull = true
			p.samspbscharge = 140
		end
		
		--Walljump "circle" effect
		local ghs = P_SpawnMobjFromMobj(t, 0, 0, 12*t.scale, MT_THOK)
		ghs.sprite = SPR_MPR9
		ghs.frame = A|FF_PAPERSPRITE
		ghs.angle = R_PointToAngle2(t.x, t.y, t.x+t.momx, t.y+t.momy)+ANGLE_90
		ghs.scale = $/50
		ghs.colorized = true	
		ghs.tics = 9 ghs.fuse = 8
		ghs.color = t.color
		ghs.scalespeed = $*2
		ghs.destscale = $*99

		p.noprimerun = 23
		p.sam_walljumpsound = 5
		p.sam_walljumping = 13
		p.sam_framejump = 0
		p.samybeam = 0
		p.sam_j1ready = 0
		t.state = S_PLAY_ROLL
		t.sam_beamroll = 0
		
		--Sideways anims and diminishers
		if abs(p.cmd.sidemove)
			t.sam_forcebeamroll = 10
			t.sam_forcebeamnum = (p.cmd.sidemove < 0) and -13 or 13
		end

		--Are we screwattacking? Then do something especially special!
		
		if p.sam_screwattacking or t.sam_screwattackfling
			local didfling
			local didboost
			if t.sam_screwattackfling
				didfling = true
				if t.sam_screwattackfling and t.sam_screwattackfling.speedboosted
					didboost = true
					t.sam_afterboost = 7
				end
			else
				if not twodlevel
				and not (s.flags2 & MF2_TWOD)
				and not p.threedimensionalexplosion	
					if SAM_displayplayer(p)
						if ((CV_FindVar("chasecam").value == 0) or camera.chase == false)
							if p.sam_firstperson
							--	SamCam(p, opposite of camera.chase, nothing)
							--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
								SAM_CMD(p, "lol", "lol", "true", "lol")
							end
					//	else
					//		SAM_CMD(p, "nil", "lol", "true", "lol")
						end
					--	SamCam(p, true, 1)
					end
				end
			end
			ghs.color = SKINCOLOR_SUPERGOLD5
			p.sam_walljumpsound = 0
			t.sam_sidejump = 0
			S_StartSound(t, sfx_satklh)
			
			--Make a tiny table just for this move!
			t.sam_screwattackfling = {
			timer = -15,
			angle = ghs.angle-ANGLE_90,
			speed = 44,
			walljumpavailable = true,
			speedboosted = false,
			chainsaw = false,
			momz = t.momz
			}
			
			local yu = t.sam_screwattackfling --And now the table is Yuji Uekawa, because of course.			
			if t.sam_screwattackspbs or didboost
				S_StartSound(t, (didboost) and sfx_satkf or sfx_sprna)
				yu.speed = 63
				t.sam_screwattackspbs = false
				yu.speedboosted = true
			end
			
			p.powers[pw_nocontrol] = max($,5)
			
			--Screw Attack walljump physics.
			if didfling
				if s.sideangle != nil
					t.momx = (yu.speedboosted) and $*4/3 or $*3/2
					t.momy = (yu.speedboosted) and $*4/3 or $*3/2
				else
					if not (s.eflags & MFE_UNDERWATER)
						P_SetObjectMomZ(t, 11<<16)
					end
					P_Thrust(t, yu.angle, 6<<16)
				end
			elseif not (s.eflags & MFE_UNDERWATER)
				P_SetObjectMomZ(t, 9<<16)
			end
			--Screw Attack walljump particles.
			local ghs
			for d = -6,6,1
				ghs = P_SpawnMobjFromMobj(t,0,0,t.height/5, MT_THOK)
				P_InstaThrust(ghs, (t.angle)+((ANG1*7)*d), p.speed+(10<<16))
				P_SetObjectMomZ(ghs, (5*t.scale)+t.momz)
				ghs.sprite = SPR_MPR6
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOBLOCKMAP & ~MF_NOGRAVITY
				ghs.color = SKINCOLOR_SUPERGOLD5+2-(d*3)
				ghs.colorized = true
				ghs.tics = 25
				ghs.fuse = 15
				ghs.frame = P_RandomRange(0,4)| ( max(FF_TRANS20, abs(d)*FF_TRANS10) )
				ghs.blendmode = AST_ADD
				ghs.destscale = $*99	
			end			
		end
	end
end

function A_SAMBEAMSWITCH(p)
	if p.sams_shotcd and (p.sams_shotcd > 3) --Can't swap beams when you're on cooldown!
		if p.sam_powerbeamequip
			if not p.sam_powerbeammeltdown return end
		elseif p.sam_spazerbeamequip
			if not p.sam_spazerbeammeltdown return end
		elseif p.sam_icebeamequip
			if not p.sam_icebeammeltdown return end 
		elseif p.sam_wavebeamequip
			if not p.sam_wavebeammeltdown return end
		elseif p.sam_plasmabeamequip
			if not p.sam_plasmabeammeltdown return end
		end
	end
	local s = p.mo
	if s and not p.sam_beamswitch and not p.sams_weappress
		p.sams_shotcd = 0
		if p.sam_wantstoswitch
			if p.sam_wantstoswitch == 1
				if not p.sam_powerbeamequip
					SamResetBeam(p)
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_wantstoswitch == 2
				if p.sam_spazerbeam and not p.sam_spazerbeamequip
					p.sam_powerbeamequip = false
					p.sam_spazerbeamequip = true
					p.sam_wavebeamequip = false
					p.sam_icebeamequip = false
					p.sam_plasmabeamequip = false
					p.sam_hyperbeamequip = false
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_wantstoswitch == 3
				if p.sam_wavebeam and not p.sam_wavebeamequip
					p.sam_powerbeamequip = false
					p.sam_spazerbeamequip = false
					p.sam_wavebeamequip = true
					p.sam_icebeamequip = false
					p.sam_plasmabeamequip = false
					p.sam_hyperbeamequip = false
					p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_wantstoswitch == 4
				if p.sam_icebeam and not p.sam_icebeamequip
					p.sam_powerbeamequip = false
					p.sam_spazerbeamequip = false
					p.sam_wavebeamequip = false
					p.sam_icebeamequip = true
					p.sam_plasmabeamequip = false
					p.sam_hyperbeamequip = false
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_wantstoswitch == 5
				if p.sam_plasmabeam and not p.sam_plasmabeamequip
					p.sam_powerbeamequip = false
					p.sam_spazerbeamequip = false
					p.sam_wavebeamequip = false
					p.sam_icebeamequip = false
					p.sam_plasmabeamequip = true
					p.sam_hyperbeamequip = false
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_wantstoswitch == 6
				if p.sam_hyperbeam and not p.sam_hyperbeamequip
					p.sam_powerbeamequip = false
					p.sam_spazerbeamequip = false
					p.sam_wavebeamequip = false
					p.sam_icebeamequip = false
					p.sam_plasmabeamequip = false
					p.sam_hyperbeamequip = true
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end
			end
			SamusTutorial(s, "gravitysuit", true)
			p.sam_wantstoswitch = 0
		
		elseif (p.cmd.buttons & BT_WEAPONNEXT) and not p.sam_scrollswap
		or (p.cmd.buttons & BT_WEAPONPREV) and p.sam_scrollswap

			if p.sam_powerbeamequip
				if p.sam_spazerbeam and not p.sam_spazerbeammeltdown
					p.sam_spazerbeamequip = true
					p.sam_beamswitch = 11
					p.sam_powerbeamequip = false
				elseif p.sam_wavebeam and not p.sam_wavebeammeltdown
					p.sam_wavebeamequip = true
					p.sam_beamswitch = 11
					p.sam_powerbeamequip = false
				elseif p.sam_icebeam and not p.sam_icebeammeltdown
					p.sam_icebeamequip = true
					p.sam_beamswitch = 11
					p.sam_powerbeamequip = false
				elseif p.sam_plasmabeam and not p.sam_plasmabeammeltdown
					p.sam_plasmabeamequip = true
					p.sam_beamswitch = 11
					p.sam_powerbeamequip = false
				elseif p.sam_hyperbeam
					p.sam_hyperbeamequip = true
					p.sam_beamswitch = 11
					p.sam_powerbeamequip = false
				elseif s
					S_StartSound(s, sfx_sdenid)
				end

			elseif p.sam_spazerbeamequip
			
				if p.sam_wavebeam and not p.sam_wavebeammeltdown
					p.sam_wavebeamequip = true
					p.sam_beamswitch = 11
					p.sam_spazerbeamequip = false
				elseif p.sam_icebeam and not p.sam_icebeammeltdown
					p.sam_icebeamequip = true
					p.sam_beamswitch = 11
					p.sam_spazerbeamequip = false
				elseif p.sam_plasmabeam and not p.sam_plasmabeammeltdown
					p.sam_plasmabeamequip = true
					p.sam_beamswitch = 11
					p.sam_spazerbeamequip = false
				elseif p.sam_hyperbeam
					p.sam_hyperbeamequip = true
					p.sam_beamswitch = 11
					p.sam_spazerbeamequip = false
				elseif not p.sam_powerbeamequip
					SamResetBeam(p)
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end

			elseif p.sam_wavebeamequip
				if p.sam_icebeam and not p.sam_icebeammeltdown
					p.sam_icebeamequip = true
					p.sam_beamswitch = 11
					p.sam_wavebeamequip = false
				elseif p.sam_plasmabeam and not p.sam_plasmabeammeltdown
					p.sam_plasmabeamequip = true
					p.sam_beamswitch = 11
					p.sam_wavebeamequip = false
				elseif p.sam_hyperbeam
					p.sam_hyperbeamequip = true
					p.sam_beamswitch = 11
					p.sam_wavebeamequip = false
				elseif not p.sam_powerbeamequip
					SamResetBeam(p)
					p.sam_beamswitch = 11
				elseif s
					S_StartSound(s, sfx_sdenid)
				end

			elseif p.sam_icebeamequip
				if p.sam_plasmabeam and not p.sam_plasmabeammeltdown
				p.sam_plasmabeamequip = true
				p.sam_beamswitch = 11
				p.sam_icebeamequip = false
				elseif p.sam_hyperbeam
				p.sam_hyperbeamequip = true
				p.sam_beamswitch = 11
				p.sam_icebeamequip = false
				elseif not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_plasmabeamequip
				if p.sam_hyperbeam
				p.sam_hyperbeamequip = true
				p.sam_beamswitch = 11
				p.sam_plasmabeamequip = false
				elseif not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_hyperbeamequip
				if not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			end
			if s
			SamusTutorial(s, "gravitysuit", true)
			end
		elseif (p.cmd.buttons & BT_WEAPONPREV) and not p.sam_scrollswap
		or (p.cmd.buttons & BT_WEAPONNEXT) and p.sam_scrollswap


			if p.sam_hyperbeamequip
				if p.sam_plasmabeam and not p.sam_plasmabeammeltdown
				p.sam_plasmabeamequip = true
				p.sam_beamswitch = 11
				p.sam_hyperbeamequip = false
				elseif p.sam_icebeam and not p.sam_icebeammeltdown
				p.sam_icebeamequip = true
				p.sam_beamswitch = 11
				p.sam_hyperbeamequip = false
				elseif p.sam_wavebeam and not p.sam_wavebeammeltdown
				p.sam_wavebeamequip = true
				p.sam_beamswitch = 11
				p.sam_hyperbeamequip = false
				elseif p.sam_spazerbeam and not p.sam_spazerbeammeltdown
				p.sam_spazerbeamequip = true
				p.sam_beamswitch = 11
				p.sam_hyperbeamequip = false
				elseif not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_plasmabeamequip
				if p.sam_icebeam and not p.sam_icebeammeltdown
				p.sam_icebeamequip = true
				p.sam_beamswitch = 11
				p.sam_plasmabeamequip = false
				elseif p.sam_wavebeam and not p.sam_wavebeammeltdown
				p.sam_wavebeamequip = true
				p.sam_beamswitch = 11
				p.sam_plasmabeamequip = false
				elseif p.sam_spazerbeam and not p.sam_spazerbeammeltdown
				p.sam_spazerbeamequip = true
				p.sam_beamswitch = 11
				p.sam_plasmabeamequip = false
				elseif not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_icebeamequip
				if p.sam_wavebeam and not p.sam_wavebeammeltdown
				p.sam_wavebeamequip = true
				p.sam_beamswitch = 11
				p.sam_icebeamequip = false
				elseif p.sam_spazerbeam and not p.sam_spazerbeammeltdown
				p.sam_spazerbeamequip = true
				p.sam_beamswitch = 11
				p.sam_icebeamequip = false
				elseif not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_wavebeamequip
				if p.sam_spazerbeam and not p.sam_spazerbeammeltdown
				p.sam_spazerbeamequip = true
				p.sam_beamswitch = 11
				p.sam_wavebeamequip = false
				elseif not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_spazerbeamequip
				if not p.sam_powerbeamequip
				SamResetBeam(p)
				p.sam_beamswitch = 11
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			elseif p.sam_powerbeamequip
				if p.sam_hyperbeam
				p.sam_hyperbeamequip = true
				p.sam_beamswitch = 11
				p.sam_powerbeamequip = false
				elseif p.sam_plasmabeam and not p.sam_plasmabeammeltdown
				p.sam_plasmabeamequip = true
				p.sam_beamswitch = 11
				p.sam_powerbeamequip = false
				elseif p.sam_icebeam and not p.sam_icebeammeltdown
				p.sam_icebeamequip = true
				p.sam_beamswitch = 11
				p.sam_powerbeamequip = false
				elseif p.sam_wavebeam and not p.sam_wavebeammeltdown
				p.sam_wavebeamequip = true
				p.sam_beamswitch = 11
				p.sam_powerbeamequip = false
				elseif p.sam_spazerbeam and not p.sam_spazerbeammeltdown
				p.sam_spazerbeamequip = true
				p.sam_beamswitch = 11
				p.sam_powerbeamequip = false
				elseif s
				S_StartSound(s, sfx_sdenid)
				end
			end
			
			if s
			SamusTutorial(s, "gravitysuit", true)
			end
		end
	end
	p.sams_supermissileready = 0
	p.sams_shotcd = 12
	p.sams_weappress = true
end

/*
rawset(_G, "SamusShotImpact", function(s)
	if s.sam_correctdist != nil and s.sam_correctangle != nil
	local ogx = s.x
	local ogy = s.y
	local ogz = s.z
		P_MoveOrigin(s,
		s.x+FixedMul(s.sam_correctdist, cos(s.sam_correctangle)),
		s.y+FixedMul(s.sam_correctdist, sin(s.sam_correctangle)),
		s.z)

		s.sam_correctdist = nil
		s.sam_correctangle = nil
		
		return true
	else
		return false
	end
end) */

--Spawn a glowing mofo.
rawset(_G, "SamusBulletHole", function(s, scale, color, burn, noground)
	if not (s or s.valid)
		return false --There's no object! This can happen since we're checking this post object-death.
	end	
	local onground
	local onwall
	--Did we hit a floor?
	if P_IsObjectOnGround(s) --HA! Piece of cake, too easy!
		onground = true
	end
	
	--Then did we hit a wall?
	if not onground
		if s.sam_hitline and s.sam_hitline.valid --This one won't be as easy.
			local x,y = P_ClosestPointOnLine(s.x, s.y, s.sam_hitline)
			onwall = R_PointToAngle2(s.x, s.y, x, y)
		else
			local dist = FRACUNIT*150
			local lastdist
			searchBlockmap("lines", function(s, linedef)	
				local x,y = P_ClosestPointOnLine(s.x, s.y, linedef)
				if lastdist == nil
				or (R_PointToDist2(s.x, s.y, x, y) < lastdist)
					onwall = R_PointToAngle2(s.x, s.y, x, y)
					lastdist = R_PointToDist2(s.x, s.y, x, y)
				end
			end, s, s.x-dist, s.x+dist, s.y-dist, s.y+dist)
		end
	end
	
	--We found neither? Last chance generosity check!
	if onwall == nil
		if (s.z-s.height <= s.floorz)
			onground = true
		else
			return --
		end
	end
	
	--Okay, spawn the graphic depending on circumstance!
	if onground or (onwall != nil)
	
		local ghs = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_THOK)
		ghs.scale = scale/4
		ghs.fuse = 10
		ghs.tics = 12
		ghs.blendmode = AST_ADD
		ghs.sprite = SPR_OILF
		
		if onground
			ghs.frame = A|FF_FULLBRIGHT|FF_TRANS70|FF_FLOORSPRITE
			ghs.renderflags = $|RF_NOCOLORMAPS|RF_SHADOWDRAW|RF_FLOORSPRITE|RF_SLOPESPLAT|RF_OBJECTSLOPESPLAT|RF_FULLBRIGHT
		else --Much more complex on walls...
			ghs.angle = onwall+ANGLE_90
			ghs.frame = A|FF_FULLBRIGHT|FF_TRANS60|FF_PAPERSPRITE
			ghs.renderflags = $|RF_NOCOLORMAPS|RF_PAPERSPRITE|RF_FULLBRIGHT			
			ghs.flags = $|MF_SOLID|MF_NOCLIPTHING & ~MF_NOCLIP & ~MF_NOCLIPHEIGHT
			ghs.radius = 1 ghs.height = 1
			for d = 1,99
				if not (P_TryMove(ghs, ghs.x+FixedMul(25356,cos(onwall)), ghs.y+FixedMul(25356,sin(onwall)), true))
				d = 100
				end
			end
			ghs.flags = $|MF_NOCLIP|MF_NOCLIPHEIGHT & ~MF_SOLID
			ghs.destscale = $*99
			if (ghs.z-150<<16 > s.z) --failsafe
			or (ghs.z+150<<16 < s.z)
			P_MoveOrigin(ghs, s.x, s.y, s.z)
			end
		end	

		if color
			ghs.color = color 
			ghs.colorized = true
		end
		
		if burn --Leave behind a burn?
			local ghs2 = P_SpawnMobj(ghs.x, ghs.y, ghs.z, MT_THOK)
			ghs2.scale = scale
			ghs2.blendmode = AST_ADD
			ghs2.sprite = SPR_MPR5
			ghs2.angle = ghs.angle
				if onground
					ghs2.frame = F|FF_FULLBRIGHT|FF_TRANS40|FF_FLOORSPRITE
					ghs2.renderflags = $|RF_FLOORSPRITE|RF_SLOPESPLAT|RF_OBJECTSLOPESPLAT
				else
					ghs2.angle = ghs.angle
					ghs2.frame = F|FF_FULLBRIGHT|FF_TRANS30|FF_PAPERSPRITE
					ghs2.renderflags = $|RF_PAPERSPRITE
					if (ghs2.z-150<<16 > s.z) --failsafe
					or (ghs2.z+150<<16 < s.z)
					P_MoveOrigin(ghs2, s.x, s.y, s.z)
					end		
				end	
			ghs2.frame = F|FF_TRANS30|FF_PAPERSPRITE
			ghs2.fuse = 100
			ghs2.tics = 105	
		end
	end
	return ghs --
end)

--Spawn a prism from an object!
rawset(_G, "SpawnSamusPrism", function(s, target, superprism)
	local ghs = P_SpawnMobj(s.x, s.y, s.z+(s.height/2), MT_NRGH)
	ghs.blendmode = AST_ADD
	ghs.fuse = 260
	ghs.donttouch = 11
	ghs.target = target
	ghs.colorized = true
	ghs.ghosttime = 10
	P_InstaThrust(ghs, P_RandomRange(1,359)*ANG1, 45<<16)
	P_SetObjectMomZ(ghs, P_RandomRange(12,26)<<16)
	if superprism --Big boi.
		ghs.color = SKINCOLOR_EMERALD
		ghs.destscale = 2<<16
		ghs.superprism = true
	else
		ghs.color = SKINCOLOR_ROSY
		ghs.scalespeed = $*3
	end
end)

--Effect for players in particular.

rawset(_G, "WaveOverloadEffect", function(s)						
	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
		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, 65354))					
		ghs.color = P_RandomRange(SKINCOLOR_SUPERPURPLE1, SKINCOLOR_SUPERPURPLE5)
	else
		t.angle = $+ANG10
		ghs.color = SKINCOLOR_GRAVITYSUIT
	end
end)

--Lazy shortcut function.

rawset(_G, "SamShinySplat", function(s, color, fuse)
	local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
	ghs.sprite = SPR_OILF
	ghs.frame = A|FF_TRANS60|FF_FULLBRIGHT
	ghs.flags = $|MF_NOGRAVITY & ~MF_NOCLIPHEIGHT
	ghs.colorized = true
	ghs.color = color
	ghs.blendmode = AST_ADD
	ghs.destscale = $*99
	ghs.flags2 = $|MF2_SPLAT
	ghs.renderflags = $|RF_SLOPESPLAT|RF_OBJECTSLOPESPLAT
	ghs.fuse = fuse ghs.tics = fuse+12
	return ghs
end)

--The Death Ball hurts, man.
SAM.DeathBallImpact = function(s, i)
	if s != i and s.player
		P_InstaThrust(i, R_PointToAngle(i.x, i.y, s.x, s.y), -20<<16)
		P_SetObjectMomZ(i, 6<<16, true)
	end
	local ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_TNTDUST)
	if ghs and ghs.valid
		ghs.flags = $|MF_NOCLIPTHING|MF_NOBLOCKMAP
		ghs.scale = s.scale*2
		ghs.destscale = 99<<16
		ghs.scalespeed = ghs.scale/7
		ghs.fuse = 99
	end
	local ZFLIP = 1 if s and s.valid ZFLIP = P_MobjFlip(s) end
	local ANG = s.angle+ANGLE_45
	
	for d = 1,8 --Even I couldn't stand the old code for this one...
		if s != i and s.player
			ghs = P_SpawnMobj(
			s.x+FixedMul(-180<<16, cos(ANG)), 
			s.y+FixedMul(-180<<16, sin(ANG)), 
			s.z+ (20<<16*ZFLIP) , MT_SAMMORPHBOMB)
			if ghs and ghs.valid
				if (ghs.floorz > s.floorz+140<<16) --Oh, geez, don't clip up there.
					ghs.state = S_NULL
				else	
					ghs.flags = $|MF_GRENADEBOUNCE|MF_BOUNCE & ~MF_NOGRAVITY
					ghs.target = i
					ghs.flags2 = $|MF2_DONTDRAW
					S_StopSound(ghs)
				end
			end
		end
		ghs = P_SpawnMobj(
		s.x+FixedMul(-130<<16, cos(ANG)),
		s.y+FixedMul(-130<<16, sin(ANG)), 
		s.z+FixedMul(20<<16, ZFLIP*s.scale), MT_MINIFIRE)
		if ghs and ghs.valid
			if (ghs.floorz > s.floorz+140<<16)
				ghs.state = S_NULL --
			else		
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.blendmode = AST_ADD
				ghs.flags = $ & ~MF_NOGRAVITY
				ghs.target = i
				ghs.morning = 140
				S_StopSound(ghs)
				ghs.destscale = SAM.scaled(ghs, (ghs.scalespeed*10)/P_RandomRange(10,17))
			end
		end
		
		ghs = P_SpawnMobj(s.x+FixedMul(-150<<16, cos(ANG)), s.y+FixedMul(-150<<16, sin(ANG)), s.z+FixedMul(20<<16, ZFLIP*s.scale), MT_THOK)
		ghs.sprite = SPR_MPR9
		ghs.flags = $|MF_NOCLIPTHING|MF_NOBLOCKMAP
		ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
		ghs.frame = (Z+1)|FF_TRANS20
		ghs.blendmode = AST_ADD
		ghs.scale = 160000
		ghs.destscale = 99<<16
		ghs.scalespeed = $*3
		P_SetObjectMomZ(ghs, 3<<16)	
		ANG = $+ANGLE_45
	end
		
	ghs = SamShinySplat(i, SKINCOLOR_SUPERGOLD5, 16)
	ghs.frame = A|FF_TRANS60|FF_FULLBRIGHT
	ghs.scalespeed = $*2
	
	for d = 1,29
		ghs = P_SpawnMobj(
		s.x+FixedMul((100+(d*7)<<16),cos(s.angle)),
		s.y+FixedMul((100+(d*7)<<16),sin(s.angle)),
		s.z, MT_THOK)
		ghs.flags = $|MF_NOBLOCKMAP|MF_NOCLIPTHING
		ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
		ghs.eflags = s.eflags
		ghs.sprite = SPR_MPR9
		P_SetObjectMomZ(ghs, (30-d)<<16)
		if d % 2 == 0
			ghs.frame = V|FF_TRANS40
			P_SetObjectMomZ(ghs, 5<<16)
			ghs.scale = $*2
			ghs.color = SKINCOLOR_RED
		else
			ghs.frame = W|FF_TRANS10
			ghs.scale = $*3
			ghs.color = SKINCOLOR_SUPERGOLD3
		end
		ghs.blendmode = AST_ADD
		ghs.destscale = 99<<16
		ghs.fuse,ghs.tics = 8+d,99
	end	
end

--The Wave Charge Shot has a status effect!
rawset(_G, "InflictWaveOverLoad", function(s, time, inflictor)
local p = s.player
	S_StartSound(s, sfx_dmpain)
	s.sam_systemreboot = time
//	P_SamFP(p, PAL_NUKE, 3)
	s.sam_flashfade = 20
	s.sam_flashfadecolor = SKINCOLOR_PURPLE	
	SamusMission(s, "  SYSTEM MALFUNCTION!", nil, nil, 3, 0, false)
	
	if s.samusmission
		s.samusmission.textwait = 0	
		s.samusmission.animtimer = 0
	end
	
	--Counterattack with an instant shinespark?
	if p.sam_shinespark and inflictor and inflictor.valid
		local ZFLIP = 1 if s and s.valid ZFLIP = P_MobjFlip(s) end
		if P_IsObjectOnGround(s)
			s.z = $+((50<<16)*ZFLIP)
		end
		if inflictor.player
			P_SamFP(inflictor.player, PAL_NUKE, 3)
			S_StartSound(nil, sfx_spbsc, inflictor.player)
		end
		p.sams_morphcd = 35
		p.sams_jumpcd = 10
		p.sams_firecd = 0
		p.sams_shotcd = 22
		p.sams_mshotcd = 22
		p.samspbschargefull = false
		p.sam_spacejumped = true
		p.samspbscharge = 0
		p.bsblboost = 0
		p.bsblboostattack = 0
		p.sambsblchargefull = false
		p.sams_supermissileready = 0
		p.sam_shinespark = 0
		S_StartSound(s, sfx_spbsc)
		for d = 1,3
			local ghs = P_SpawnMobj(s.x, s.y, s.z+((s.height*3/5)*ZFLIP), MT_PBEXPAND)
			ghs.scale = s.scale*2
			ghs.scalespeed = $*9
			ghs.destscale = s.scale*25
			ghs.colorized = true
			ghs.color = SKINCOLOR_PURPLE-1+d
		end	
		p.sam_shinesparkdirect = R_PointToAngle2(s.x, s.y, inflictor.x, inflictor.y)
		s.angle = p.sam_shinesparkdirect
		p.sam_shinesparkdirectx = (p.sammorphed) and s.scale*140 or s.scale*66
		p.sam_shinesparkdirectz = 0 
		s.momz = FRACUNIT
		p.sam_shinesparkfly = 17
		
	else --Regular behaviour
	
		s.sam_waveoverload = time-4
	end
end)

 --Disintegrate our foes. M is the dust-spawner, style is type.
 --explodepush makes it push-based without disintegration, playerpush makes Samus do it.
rawset(_G, "Dustintegrate", function(m, style, i, explodepush, playerpush)
	if not m.valid
	or m.player and (m.crystalflashanim or m.player.hypermysticsonic)
		return --
	end
	
	local s,ghs = P_SpawnMobj(m.x, m.y, m.z, MT_DUSTTRACKER)
	if m.player
		m.sprite2 = SPR2_DEAD
		m.frame = A|FF_FULLBRIGHT
		S_StopSound(m)
	end
	s.target = m
	m.flags2 = $|MF2_DONTDRAW
	
	if style
		if style == 3
			s.hyperdust = true
		elseif style == 2
			s.plasmadust = true
			m.plasmadust = true
		else
			s.metroiddust = true
			m.metroiddust = true
		end
	end
	
	if not explodepush
		for d = 1,2
			ghs = P_SpawnGhostMobj(m)
			ghs.scale = m.scale
			if d == 1
				ghs.color = SKINCOLOR_CRIMSON
			else
				ghs.color = SKINCOLOR_YELLOW
			end
			ghs.colorized = true
			ghs.tics = 13
			ghs.fuse = 13
			ghs.scalespeed = $*3*d
			ghs.destscale = $*20
		end
	end
	
	s.formershell = P_SpawnGhostMobj(m)	
	s.formershell.scale = m.scale
	s.formershell.tics = 91
	s.formershell.fuse = 91
	s.formershell.renderflags = $|RF_FULLBRIGHT
	
	if not explodepush
		s.formershell.colorized = true
		s.formershell.scalespeed = $/6
		if s.metroiddust
			s.formershell.scalespeed = $/3
		end		
		s.formershell.destscale = $*5
	end
	if explodepush --Pay attention, you NEED an inflictor for this one.
		s.dtexplodepush = 1
		s.formershell.flags = $ & ~MF_NOGRAVITY & ~MF_NOCLIPHEIGHT & ~MF_NOCLIP
		P_SetObjectMomZ(s.formershell, explodepush)
		P_Thrust(s.formershell, R_PointToAngle2(s.formershell.x, s.formershell.y, i.x, i.y), explodepush*-2)
		s.formershell.rollangle = $+(P_RandomRange(-45,45)*ANG1)
		
		if playerpush --Override explodepush settings....
			s.dtplayerpush = true
			S_StartSound(i, sfx_dmpain)
			if i.player.sam_screwattacking
				P_SetObjectMomZ(s.formershell, 11<<16, false)
			else
				P_SetObjectMomZ(s.formershell, explodepush/4, false)
			end
			P_InstaThrust(s.formershell, i.angle, i.player.speed+20<<16)
		end
		
	elseif (s.formershell.z > s.floorz+50<<16) and not i
		s.formershell.flags = $ & ~MF_NOGRAVITY & ~MF_NOCLIPHEIGHT
		s.formershell.rollangle = $+(P_RandomRange(-45,45)*ANG1)
		P_SetObjectMomZ(s.formershell, 4<<16, true)
		P_Thrust(s.formershell, s.formershell.angle, -5<<16)
	end
	
	if not explodepush
		s.ghs2 = P_SpawnMobj(m.x, m.y, m.z, MT_THOK) --Make the sound!
		s.ghs2.flags2 = $|MF2_DONTDRAW
		s.ghs2.tics = 130
		if style == 1 --Metroid Husk
			S_StartSound(s.ghs2, sfx_s3k81) S_StartSound(s.ghs2, sfx_s1c4) S_StartSound(s.ghs2, sfx_s1b8)
		elseif not i or not style --Knockback.
			S_StartSound(s.ghs2, sfx_s233)
			S_StartSound(s.ghs2, sfx_s233)
			S_StartSound(s.ghs2, sfx_s3k43) 
		elseif i and i.valid --Turn into ashes.
			s.superdisintegrate = true
			S_StartSound(s.ghs2, sfx_pldisi)
			s.formershell.rollangle = $+(ANG1*P_RandomRange(-95,95))
			s.formershell.flags = $ & ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY)
			s.formershell.renderflags = $|RF_FULLBRIGHT
			s.formershell.momx,s.formershell.momy,s.formershell.momz = i.momx/4,i.momy/4,i.momz/4
		end
	end

	s.dthealth = m.health --there's a good chance our friend will disappear soon....		
	s.dtradius = m.radius --So copy some values from our target
	s.dtangle = m.angle		
	s.dtsprite = m.sprite
	s.dtframe = m.frame
	s.dtheight = m.height
	s.dtscale = m.scale
	s.renderflags = $|RF_FULLBRIGHT
	s.dtxloc,s.dtyloc,s.dtzloc = s.formershell.x,s.formershell.y,s.formershell.z
	s.dtcolor = m.color
	
	if s.selectedframe
		if s.selectedsprite
			s.formershell.sprite = s.selectedsprite
		else 
			s.formershell.sprite = m.sprite
		end
		s.formershell.frame = s.selectedframe
	else
		s.formershell.frame = $ & ~FF_TRANSMASK
		s.selectedframe = s.formershell.frame
	end
end)

--Destroy all of Samus' powerups.
rawset(_G, "CollectSamusTax", function(p, keepachievements) 
	if G_GametypeHasSpectators()
		p.sammissilesmax = 5
	else
		if (p.sam_energy < 99)
			p.sam_energy = 99
		end
		p.sammissilesmax = 0
	end
	if not keepachievements
		p.sam_achievement1 = 0
		p.sam_achievement2 = 0
		p.sam_achievement3 = 0
	end
	p.crystalflashchance = 0
	p.samsupermissilesmax = 0
	p.sampwmax = 0
	p.sam_spiderball = false
	p.sam_power_grip = false
	p.samspbs = false
	p.sambsbl = false
	p.sam_bombs = false
	p.sam_highjump = false
	p.sam_spacejump = false
	p.sam_chargebeam = false
	p.sam_spazerbeam = false
	p.sam_wavebeam = false
	p.sam_icebeam = false
	p.sam_plasmabeam = false
	p.sam_hyperbeam = false
	p.sam_powerbeamcombo = false
	p.sam_spazerbeamcombo = false
	p.sam_wavebeamcombo = false
	p.sam_icebeamcombo = false
	p.sam_plasmabeamcombo = false
	p.sam_screwattack = false
	p.sam_fullypoweredsuit = false
	SamResetBeam(p)
	p.sams_itemcompletion = 0
	p.sam_energytanksmax = 0
	p.sam_gravitysuitjustgot = 0
	p.sam_autotank = nil
	p.sam_ammodigitizer = 1
	p.sam_gravitysuit = 0
	
	if p.mo
		SetSamusColor(p.mo, p) 
	end
end)

--Whatever causes the visor-glaring explosion makes Samus' face reflect in the glass
rawset(_G, "SamFaceReflect", function(s, radius)
	if not (s and s.valid) or not radius
		return --
	end
	for z in players.iterate --Look for nearby Samus players.
		if z.mo and YouAreSamus(z.mo) and not z.sammorphed
			if (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < radius)
				z.mo.sam_reflectfacebig = false
				z.mo.sam_reflectface = 16
				if (radius > 190<<16) and (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < (radius/2))
					z.mo.sam_reflectfacebig = true
					if (radius > 774<<16)
						z.mo.sam_reflectface = 32
					end
				end
			end
		end
	end
end)

--Set charge only if morphed Samus.
rawset(_G, "SamSpiderCharge", function(p, s, num)
	if p.sammorphed and YouAreSamus(s)
		s.spiderbcharge = num
	end
end)

--Calculate if we should continue depending on player's energy, keeping difficulty and defense in mind.
rawset(_G, "SAM_Damage", function(p, zero, hyper, fusion, IGNOREDEFENSE)
	local DIFFICULTY = 0
	if (gametype == GT_COOP)
		DIFFICULTY = (SAMUSDIFFICULTY) or 0
	end
	--Factor in difficulty, if applicable!
	fusion = (fusion) or zero
	hyper = (hyper) or zero
	local NUM = (DIFFICULTY==2) and fusion or (DIFFICULTY!=0) and hyper or zero --As in Zero Mission difficulty. Not 0.

	--Now optionally factor in defense. The base number assumes you're wearing the Varia Suit.
	--The Gravity Suit reduces the number by about 30%, while having no suit powerups boosts damage taken by 15% instead.
	if not (IGNOREDEFENSE)
		NUM = ($*8)/p.gravityrd
	end
	if ((p.sam_energy-NUM) <= 0) --We would die from this. Return false
		return false
	else --We'd live. Deal damage
		return NUM
	end
end)

--Only switches INTO Morph Ball, not out.
rawset(_G, "SamMorphSwitch", function(p, s)
	--Turn off scan visor 
	if s.sam_scanning
		s.sam_scanning = 0
		s.samusjustscanned = false
		p.scannedmons = nil
		p.scannedplays = nil
		S_StopSoundByID(s, sfx_sscan1)
	end
	--Reset a bunch of stuff	
	if s.sam_geton and s.sam_geton > 50
		s.sam_geton = 0
	end
	p.sams_beamcombocharge = 0
	p.bsblboost = 0
	p.bsblboostattack = 0
	p.sambsblchargefull = false
	p.sam_spacejumpedboost = 0
	p.thrustfactor = skins[s.skin].thrustfactor
	p.accelstart = skins[s.skin].accelstart
	p.sams_notyet = 3
	p.sams_usecd = 9
	p.sams_notyet = 3
	p.sams_firecd = 0
	p.sams_c1cd = 0
	p.sams_c2cd = 0
	p.sams_normfcd = 0
	p.sams_supermissileready = 0
	p.sams_powerbombready = 0
	
	--Morph into a ball.	
	s.state = S_PLAY_ROLL
	p.viewrollangle = 0
	s.sammorphedghs = 5		
	p.sammorphed = true
	
	local SNAPZ = nil
	if (s.eflags & MFE_VERTICALFLIP)
		if P_IsObjectOnGround(s) or (abs((s.z+s.momz)-s.ceilingz) < 24*s.scale)
			SNAPZ = s.ceilingz
		end		
	end
	--Ghost effect comes after.
	local ghs = P_SpawnGhostMobj(s)
	ghs.scale = s.scale
	ghs.renderflags = $|RF_SEMIBRIGHT
	ghs.dispoffset = 99
	ghs.momx,ghs.momy = -s.momx/9,-s.momy/9
	ghs.destscale = 1
	
	s.scale = 42001
	if SNAPZ!=nil
		s.z = SNAPZ
		ghs.z = SNAPZ
	end	
	if p.sam_spiderball
		if s.spiderbcharge == nil
		or (s.spiderbcharge < 80)
			s.spiderbcharge = 80
		end
	end
	
	if not twodlevel
	and not (s.flags2 & MF2_TWOD)
	and not p.threedimensionalexplosion		
		if SAM_displayplayer(p)
			if ( (CV_FindVar("chasecam").value == 0) or camera.chase == false )
			and p.sam_firstperson
			--	SamCam(p, opposite of camera.chase, nothing)
			--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
				SAM_CMD(p, "nil", "lol", "true", "lol")			
			end
		--	SamCam(p, true, 1)
		end
	end
end)

--Samus' morph ball trail styled like Prime. 
rawset(_G, "SamMorphTrail", function(p, s, TCOLOR)
	local renderer = 1	
	local density = 12*s.scale --Software is less powerful and can't handle as many sprites.
	if SAM_displayplayer(p) --Since OpenGL is more accurate, it benefits more from a higher density as well.
		renderer = CV_FindVar("renderer").value --2 is openGL.
		if renderer == 2
			density = 6*s.scale
		end
	end
	if p and p.sammorphed --Default morph scale is 42001, so increase density!
		density = ($*10)/6
	end
	local DIST = FixedDiv(FixedMul((R_PointToDist2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), (s.z-s.prevz2)) / density), FRACUNIT), s.scale)
	DIST = max(1, min($,176))
	local Xdist,Ydist,Zdist = (s.momx/DIST),(s.momy/DIST), (s.z-s.prevz2) or 1			
	Zdist = $/DIST
	
	local FRAME = (renderer == 2) and B|FF_TRANS90 or B|FF_TRANS70
	local FUSE = min(7, max(1, p.speed/(5<<16)) )	--Minimum of 5 tics, max of 35.
	local SCALE = (s.scale > 90001) and s.scale*4/3 or 42001
	local FLAGS2 = 0
	if p.bsblboostattack
		if (FUSE == 1 or FUSE > 5)
			FUSE = 7
		end
		TCOLOR = SKINCOLOR_SUPERGOLD5
		if (p.bsblboostattack<4)
			FLAGS2 = MF2_DONTDRAW
		end
	else
		if (FUSE > 5) and p.samvisorcolor and p.sam_gravitysuit==2
			TCOLOR = p.samvisorcolor
		end
	end
	if s.morphtrailwait
	or (SAM_displayplayer(p)) and not (CV_FindVar("chasecam").value) --If for whatever reason you're in first person morphballing
		FLAGS2 = MF2_DONTDRAW
	end
	local MOMX,MOMY = s.momx*2/3,s.momy*2/3
	local MOMZ = (s.prevz2!= nil) and (s.z-s.prevz2) or s.momz
	local LINE
	for i = DIST,1,-1 --Keep counting down by -1 until we reach 0
		LINE = P_SpawnMobjFromMobj(s, (Xdist*i)-(MOMX*((i%2) and 1 or 2)), (Ydist*i)-(MOMY*((i%2) and 1 or 2)), (Zdist*i)-MOMZ, MT_THOK)
		LINE.sprite = SPR_BBTR
		LINE.frame = FRAME
		LINE.scale = SCALE
		LINE.angle = R_PointToAngle2(LINE.x, LINE.y, s.x, s.y)+ANGLE_90
		LINE.tics,LINE.fuse = FUSE,FUSE
		LINE.blendmode = AST_ADD
		LINE.color = TCOLOR
		LINE.colorized = true
		LINE.renderflags = $|RF_FULLBRIGHT|RF_PAPERSPRITE
		LINE.flags2 = $|FLAGS2
	end
end)