--New functions that use the MetroidVanguard table.
local SAM = MetroidVanguard
local HOST = SAM.HOST

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

--First part of spawning!
SAM.StartSpawn1 = function(p,s)
	if (gamemap == 807) or (gamemap == 806) --DSZ4+ACZ4 respectively.
		if mapheaderinfo[gamemap].lvlttl == "Arid Canyon"
		or mapheaderinfo[gamemap].lvlttl == "Deep Sea"
		/*	local renderer,shaders = 1,1
			if p == consoleplayer and SAM_displayplayer(p) --This part doesn't need to sync.
				renderer = CV_FindVar("renderer").value
				shaders = CV_FindVar("gr_shaders").value
				if renderer == 2 and not shaders
					SAM_COM_BufInsertText(p, "gr_shaders on")
					CONS_Printf(p, "\x80"+"OpenGL shaders turned\x83 ON.\x80 Use\x82 'gr_shaders'\x80 console command to switch if desired.")
				end
			end */	
			if (gametype == GT_COOP) --Refresh ammo on these maps
				local MINMISSILES = (gamemap == 807) and 90 or 50
				local MINSUPERS = (gamemap == 807) and 10 or 8
				if p.sammissiles != nil and (p.sammissiles < MINMISSILES)
					p.sammissiles = MINMISSILES
				end
				if p.samsupermissiles != nil and (p.samsupermissiles < MINSUPERS)
					p.samsupermissiles = MINSUPERS
				end
				if not p.sampw
					p.sampw = 1
				end
			end
			if (gamemap == 807)
				if p.SAM_warps == nil or p.SAM_warps.warp != "ACZ4"
					p.SAM_warps = {warp = "ACZ4"}
				end
				if p.sam_hidegore
					if consoleplayer and p and p == consoleplayer
						for m in mobjs.iterate(mobjs)
							if (m.type == MT_DARKPZREMAINS)
								m.flags2 = MF2_DONTDRAW
							end
						end
					end
				else
					s.sam_acz4msg = true
				end
			else --806 then, DSZ4!
				if p.SAM_warps == nil or p.SAM_warps.warp != "DSZ4"
					p.SAM_warps = {warp = "DSZ4"}
				end
			end
		end
	else
		p.SAM_warps = nil
		if gamemap == 100 and (p.disablevote != nil or p.ui) --For Subarashii
			for m in mobjs.iterate(mobj)
				if m and m.valid and (m.flags & MF_SHOOTABLE) and (m.flags & MF_SOLID) and not m.player
					m.flags = $|MF_NOCLIP & ~(MF_SHOOTABLE|MF_MONITOR)
				end
			end
		end
	end
	if not multiplayer and not netgame --Reloads your old stuff in single player.
		ActivateHyperMode(p, 7, s, true)
	//	if not p.sam_changedmap
	//	p.sam_dontupdateenergy = true
	//	ProfileSamusSave(s, p, p.sam_saveselected, false, true, false)
	//	SetSamusColor(s, p)
	//	end
		p.sam_changedmap = false	
	end
	p.automobf = nil
	if p.buffbottomtier --Never spawn as bottom tier
		p.buffbottomtier = false
	end
	p.camerascale = FRACUNIT
	if (s.sam_difficultymsgtype != 3) and (gametype == GT_COOP)
		if SAMUSDIFFICULTY
			if SAMUSDIFFICULTY == 2
				s.sam_difficultytrns = FF_TRANS90
				s.sam_difficultymsg = 110
				s.sam_difficultymsgtype = 2
			else
				s.sam_difficultytrns = FF_TRANS90
				s.sam_difficultymsg = 110
				s.sam_difficultymsgtype = 1
			end
		end
	end
	p.viewrollangle = 0
	
	if p.superbrakdeath --Brak, PZboss, or Metroid Boss hints
		if (gamemap == 28) -- SuperBrak Hints
			if p.superbrakdeath == 1
				p.samhudmessage1 = "It's time for your acquired items to shine!"
				p.samhudmessage2 = "Blast Brak down with Beam Combos and ammo tanks!"
			elseif p.superbrakdeath == 2
				p.samhudmessage1 = "You'll need to use the speedboosters to stay ahead."
				p.samhudmessage2 = "(Type 'autospeedbooster 1' in the console to automate this.)"
			elseif p.superbrakdeath == 3
				p.samhudmessage1 = "The Spazer and Ice Beam are ineffective on crystals!"
				p.samhudmessage2 = "Your missiles get reflected. Use them for beam combos."
			elseif p.superbrakdeath == 4
				p.samhudmessage1 = "When out of usable ammo, use the charged spazer beam for"
				p.samhudmessage2 = "easy hits. Be on the lookout for any extra ammo Brak drops."
			elseif p.superbrakdeath == 5
				p.samhudmessage1 = "Super Missiles do 2x damage, and Power Bombs 3x!"
				p.samhudmessage2 = "Aim Supers at the floor for their explosive radius!"
			else
				p.samhudmessage1 = "Surely there's a way to take the Hyperbeam back...."
				p.samhudmessage2 = nil
			end
			
			p.samhudmessagetime = 230
			p.samhudmessageflags = FF_TRANS90 
			
		elseif (gamemap == 806) --Omega Metroid hints
		
			if p.superbrakdeath == 1
				p.samhudmessage1 = "The Omega Metroid's stomach is the only vulnerable"
				p.samhudmessage2 = "spot! Concentrate and aim carefully."
			elseif p.superbrakdeath == 2
				p.samhudmessage1 = "Your shots can get cut down by it's Sonic Slash."
				p.samhudmessage2 = "Time your shots when it cannot use that!"
			elseif p.superbrakdeath == 3
				p.samhudmessage1 = "Missiles are extremely effective here. If"
				p.samhudmessage2 = "you run out entirely, try spazer charge shots!"
			elseif p.superbrakdeath == 4
				p.samhudmessage1 = "The Sonic Slash's spread makes blind sprinting"
				p.samhudmessage2 = "dangerous. Slip through the cracks in bursts."
			elseif p.superbrakdeath == 5
				p.samhudmessage1 = "If you get hit by the Sonic Slash, it will always"
				p.samhudmessage2 = "follow up with a ram. Get out of the way!"
			else
				p.samhudmessage1 = "The Blizzard Burst and Gattling Vortex are"
				p.samhudmessage2 = "easier combos for taking the Omega down!"
			end
			
			p.samhudmessagetime = 230
			p.samhudmessageflags = FF_TRANS90 
			
		elseif (gamemap == 807) --Dark Samus hints
			if p.superbrakdeath == 1
				p.samhudmessage1 = "The Phazon Dive mimmicks your Screw Attack."
				p.samhudmessage2 = "Answer it with the real deal!"
			elseif p.superbrakdeath == 2
				p.samhudmessage1 = "When Dark Samus teleports, she'll always"
				p.samhudmessage2 = "appear behind you. Strafe and turn around!"
			elseif p.superbrakdeath == 3
				p.samhudmessage1 = "Use the Morph Ball to slip under the Wave"
				p.samhudmessage2 = "Homing Blasts and Phazon Vortex attacks."
			elseif p.superbrakdeath == 4
				p.samhudmessage1 = "Save your Power Bombs or Blizzard Burst for"
				p.samhudmessage2 = "the clone phase to instantly get rid of them!"
			elseif p.superbrakdeath == 5
				p.samhudmessage1 = "Charge the Spazer Beam to catch Dark Samus,"
				p.samhudmessage2 = "and don't get pressured into bad spots!"
			else
				p.samhudmessage1 = "Dark Samus' Hyper Beam has slow tracking, but"
				p.samhudmessage2 = "will devastate you. Keep moving!"
			end

			p.samhudmessagetime = 230
			p.samhudmessageflags = FF_TRANS90 	
		else
			p.superbrakdeath = nil
		end
	end
	if p.samshieldhp == nil or p.samshieldhp and (p.samshieldhp < 3)
		if p.samshieldhp == nil
				p.samshieldhp = 3
		end
		if not p.powers[pw_shield] and not (p.samshieldhp and p.samshieldhp == 3)
			p.samshieldhp = 3
		else
			if not p.samshieldhptype
				p.samshieldhptype = p.powers[pw_shield]
				p.samshieldhp = 3
			elseif (p.powers[pw_shield] != p.samshieldhptype)
				p.samshieldhptype = p.powers[pw_shield]
				p.samshieldhp = 3
			end
		end
	end
	if netgame and leveltime < 2
		p.samnetcon = 0
	end
	
	s.samemwarning = 0
	
	if not p.firstsamusmap and (gametype == GT_COOP) --Our starting map when we're loading into a new save file.
		p.firstsamusmap = gamemap
	end
	if p.samescape and ( (((YouAreSamus(s)) == false) and not multiplayer) or not (gamemap == 25) )
		p.samescape = 0
		p.samescapehud = 0 
	elseif p.samescapehud and ( (((YouAreSamus(s)) == false) and not multiplayer) or not (gamemap == 25) )
		p.samescapehud = 0
	end
	if p.sam_restricthyper --If the restricted Hyper Beam setting is on, the Hyper Beam can't be used if a boss is around.
		if not (p.sam_restricthyper.valid and p.sam_restricthyper.health)
			p.sam_restricthyper = nil
		end
	end
end

local WEATHERC = nil

--When a map initiall boots, do...
SAM.StartMap = function(p,s, WEATHERC)

	WEATHERC = nil
	
	if (gametype == GT_COOP)
	or (gamemap == 532) or (gamemap == 539)
		if not (netgame) and (gametype == GT_COOP)
			if p.samuschosefile == nil or p.sam_saveselect
				if YouAreSamus(s) 
					return --
				end
			end
		end
		local TITLE = mapheaderinfo[gamemap].lvlttl
	  	if TITLE == "Greenflower"
			if SAMUSCAMPAIGN == true
				if (gamemap == 01)  --Weather change GFZ1 + dialogue
					for m in mobjs.iterate(mobj)
						if m.valid
							if (m.type == MT_GFZFLOWER1) and (m.x == 1920<<16) and (m.y == 7744<<16)
							and not m.DidSwitch
								WEATHERC = 1
								m.DidSwitch = true break --
							end
						end
					end
					if WEATHERC != nil 
						local DODIALOGUE = false
						for z in players.iterate
							if YouAreSamus(z.mo)
								if netgame
								or (not netgame and z.samuschosefile)	
									DODIALOGUE = true break --
								end
							end
						end
						if DODIALOGUE != false
							for z in players.iterate
								if z.mo and YouAreSamus(z.mo)  --Go to Deep Zone 4 next!
									SamusDialogue(z.mo, 
									"The gunship has taken heavy damage. Idle", 
									"thrusters online. Self-repair engaged.", 
									"SAMDEF", 1, 1, 50)
								end
							end
						end
					end
				elseif (gamemap == 02)  --Weather change GFZ2+dialogue
					for m in mobjs.iterate(mobj)
						if m.valid and (m.type == MT_GFZFLOWER1) and (m.x == -4032<<16) and (m.y == -512<<16)
						and not m.DidSwitch
							WEATHERC = 1
							m.DidSwitch = true break --
						end
					end
					if WEATHERC != nil
						for z in players.iterate
							if z.mo and YouAreSamus(z.mo)
								SamusDialogue(z.mo, "The world's overrun by rampaging robots. ", "What purpose are they meant to serve?", "SAMDEF", 2, 5, 42)
							end
						end
					end
				elseif (gamemap == 03) --Weather change GFZ3
					for m in mobjs.iterate(mobj)
						if m.valid and (m.type == MT_GFZFLOWER1) and (m.x == 3840<<16) and (m.y == 2752<<16)
						and not m.DidSwitch
							WEATHERC = 1
							m.DidSwitch = true break --
						end
					end
				end
			end
		elseif TITLE == "Techno Hill"
			if SAMUSCAMPAIGN == true
				if (gamemap == 04) --dialogue THZ1
					for z in players.iterate
						if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							SamusDialogue(z.mo, "All this machinery appears to be in service to that scientist. But why wildly", "wreak havoc across the planet? What could such untargeted aggression", "SAMPRE", 2, 6, 42, "small", "small", "possibly achieve? It's uncharacteristic for intelligent life...")
						end
					end
				elseif (gamemap == 05) --dialogue THZ2
					for z in players.iterate
						if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							SamusDialogue(s, "Target signal found in current area. ", "Signal waning, lifeforms left recently.", "SAMDEF", 1, 7, 90, nil, nil)					
						end
					end
				end
			end
		elseif TITLE == "Deep Sea"
			if (gamemap == 07) --dialogue DSZ1
				if SAMUSCAMPAIGN == true
					for z in players.iterate
						if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							SamusDialogue(z.mo, "Target appears present in current zone.", "Continuing scan of surrounding area...", "SAMDEF", 1, 0, 42)
						end
					end	
				end
			elseif (gamemap == 08) --Dialogue and Zone Change DSZ2
				for z in players.iterate
					z.mo.dsz2msgprep = true
					if SAMUSCAMPAIGN == true
						G_SetCustomExitVars(806) --Go to Deep Zone 4 next!
						if YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							SamusDialogue(z.mo, "Scanning...\x85warning! Caution advised. ", "\x82 Approaching multiple Metroid life signals. Maximum firepower recommended.", "SAMDEF", 1, 2, 90, nil, "small")
						end	
					end
				end	
			elseif (gamemap == 806) --The Deep Sea Zone 4 enemies turned to husks by Metroids.
				for m in mobjs.iterate(mobj)
					if m and m.valid
					 	if (m.type == MT_EGGSHIELD) or (m.type == MT_CRUSHCLAW)
							m.state = S_NULL
						elseif (m.type == MT_BLUECRAWLA)
						or (m.type == MT_FACESTABBERSTATUE) 
						or (m.type == MT_GFZFISH) 
						or (m.type >= MT_SKIM) and (m.type <= MT_DRAGONTAIL)
							m.colorized = true
							m.health = 1
							m.color = SKINCOLOR_BEIGE
							m.flags = MF_SHOOTABLE|MF_SOLID|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
							m.tics = -1
							m.metroidstatue = true
						end
					end
				end						
			end
		elseif TITLE == "Castle Eggman"
			if SAMUSCAMPAIGN == true
				if (gamemap == 10) --Samus' self-reflection on fighting an Omega Metroid for the first time "canonically"
					for z in players.iterate
						if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							SamusDialogue(z.mo, "Was that truly a Metroid? How did", "they propagate that kind of mutation?", "SAMDEF", 2, 9, 42)
						end
					end					
				elseif (gamemap == 11)
				
					--[SAMUS DIALOGUE EXAMPLE PART 1] Example of how to start a custom dialogue chain.
					--Uncomment this, then CTRL+F: "DIALOGUE EXAMPLE PART 2" and uncomment that for this to appear in-game(Castle Eggman act 2)
					
				/*	SamusDialogue(s, "I am sick of these motherfucking ", "guards in this motherfucking castle.", "SAMSAD", 2, nil, nil)
					s.samusdialogue.customnextbox = 3 */
				end
			end
		elseif TITLE == "Arid Canyon"
			if (gamemap == 13) --Nighttime ACZ1 events.
				if SAMUSCAMPAIGN == true
					for m in mobjs.iterate(mobj)
						if m.valid and (m.type == MT_REDSPRING) and (m.x == 288<<16) and (m.y == -12064<<16) and not m.DidSwitch
							m.DidSwitch = true
							WEATHERC = 1 break --
						end
					end
					if WEATHERC != nil
						for z in players.iterate
							if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
								if not z.samspbs and not z.sam_spiderball 
								and not z.sam_screwattack and not z.sam_spacejump
									SamusDialogue(z.mo, "Closing in on target signal.", "Signal moving at 20 miles per hour.", "SAMDEF", 1, 13, 42)
								else
									SamusDialogue(z.mo, "Closing in on target signal.", "Signal moving at 20 miles per hour.", "SAMDEF", 1, 14, 42)
								end
							end
						end	
					end
				end
			elseif (gamemap == 14) --Hide dead Fang gore in ACZ4?
				if SAMUSCAMPAIGN == true
					for m in mobjs.iterate(mobj)
						if m.valid and (m.type == MT_REDHORIZ) and (m.x == 7584<<16) and (m.y == -8944<<16) and not m.DidSwitch
							m.DidSwitch = true
							WEATHERC = 1 break --
						end
					end
					if WEATHERC != nil
						for z in players.iterate --Go to Arid Canyon 4 next!
							G_SetCustomExitVars(807)
							if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
								if p.sams_itemcompletion != nil and (p.sams_itemcompletion < 4) 
									SamusDialogue(z.mo, "Target signal has stopped moving.", "\x85Warning! Metroid scan confirms mutation.", "SAMDEF", 1, 10, 62)
								elseif p.sams_itemcompletion != nil and (p.sams_itemcompletion > 85)
									SamusDialogue(z.mo, "Signal has entered nearby mines.", "\x85Warning! Metroid scan confirms mutation.", "SAMDEF", 1, 15, 62)
								else
									SamusDialogue(z.mo, "Signal has entered nearby mines.", "\x85Warning! Metroid scan confirms mutation.", "SAMDEF", 1, 11, 62)
								end
							end
						end
					end
				end
			elseif (gamemap == 807) --Hide dead Fang gore in ACZ4, a reference to the corpse in front of Kraid's Lair?
				for m in mobjs.iterate(mobjs)
					if m.valid and (m.type == MT_DARKPZREMAINS)
						for z in players.iterate
							if displayplayer and (z==displayplayer)
								if z.sam_hidegore
									m.flags2 = MF2_DONTDRAW
								end
							end
						end
						break --There's only one, sooo...break! (Topple!)
					end
				end
			end
			if WEATHERC != nil
				for z in players.iterate
					if z
						z.samweather = WEATHERC
					end
				end
			end
		elseif TITLE == "Red Volcano"
			if (gamemap == 16)
				if SAMUSCAMPAIGN == true
					if not s.sam_rvzmsg
						local HASVISOR = true
						for z in players.iterate
							if z and not z.sam_scanvisor 
								HASVISOR = false break --Someone doesn't have it!
							end
						end	
						if HASVISOR == false
							for m in mobjs.iterate(mobjs) --First check, if one already exists.
								if (m.type == MT_SCANVISOR)
									HASVISOR = true break --One already exists, don't spawn!
								end
							end
							if HASVISOR == false
								P_SpawnMobj(4384<<16, 17888<<16, 544<<16, MT_SCANVISOR) --Spawn the Scan Visor on these coordinates.
								for z in players.iterate
									if z.mo 
										z.mo.sam_rvzmsg = true 
									end
								end
							end
						end
					end
					for z in players.iterate
						if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							SamusDialogue(z.mo, "Ship auto-repairs are 96% complete.", "Sending mission status report to HQ.", "SAMDEF", 1, 17, 42)
						end
					end					
				end
			end
		elseif TITLE == "Egg Rock"
			if (gamemap == 22)
				if SAMUSCAMPAIGN == true
					for z in players.iterate
						if z.mo and YouAreSamus(z.mo) and not leveltime and not z.starpostnum
							if z.sam_hyperbeam
								SamusDialogue(z.mo, "I won't be stopped now.", nil, "SAMDEF", 2, 22, 44)
							elseif p.sams_itemcompletion != nil and (p.sams_itemcompletion < 4)
								SamusDialogue(z.mo, "Sabotaging the core could work, but", " it'll take a miracle to escape alive...", "SAMSAD", 2, 0, 44)
							else
								SamusDialogue(z.mo, "To truly destroy the station, I'll", "need extreme firepower. Is this enough?", "SAMSAD", 2, 0, 44)
							end
						end
					end
				end
			elseif (gamemap == 23)
				s.discomsgprep = true
				for z in players.iterate
					if z.mo
						z.mo.discomsgprep = true
						if SAMUSCAMPAIGN == true and YouAreSamus(z.mo) and not leveltime and not z.starpostnum					
							if z.sam_fullypoweredsuit
								SamusDialogue(z.mo, "This is far too easy... surely they", "must be aware what they're up against?", "SAMDEF", 2, 0, 44)
							elseif p.sams_itemcompletion != nil and (p.sams_itemcompletion < 4)
								SamusDialogue(z.mo, "This is utter insanity. I've gone in", "way over my head here. ...yet...", "SAMSAD", 2, 23, 44)
							else
								SamusDialogue(z.mo, "Nearing the core. Last opportunity", "for powering up is here.", "SAMPRE", 2, 0, 44)
							end
						end
					end
				end						
			end					
		elseif TITLE == "Black Core"	
			local DOESCAPE = false
			if (gamemap == 25)
				if SAMUSCAMPAIGN == false
					WEATHERC = 2
					for z in players.iterate
						if z
							z.samescapehud,z.samescapeseconds,z.samescapemseconds = nil,nil,nil
						end
					end
				else
					WEATHERC = 1
					local ghs = P_SpawnMobj(3000<<16, 2433<<16, 300<<16, MT_SAMSUPERMISSILE)
					if ghs and ghs.valid
						P_ExplodeMissile(ghs)
					end
					ghs = P_SpawnMobj(3142<<16, 2433<<16, 320<<16, MT_SAMSUPERMISSILE)
					if ghs and ghs.valid
						P_ExplodeMissile(ghs)
					end
					ghs = P_SpawnMobj(-9440<<16, -1600<<16, 0, MT_SPRINGSHELL)
					if ghs and ghs.valid
						ghs.angle = ANGLE_270
					end
					if ghs and ghs.valid
						ghs = P_SpawnMobj(-9973<<16, -7040<<16, 600<<16, MT_SNAILER)
						ghs.eflags = $|MFE_VERTICALFLIP
						ghs.flags = $|MF_NOCLIP
						ghs.flags2 = $|MF2_DONTDRAW
					end
				end
			elseif (gamemap == 26)
				for z in players.iterate
					if z.mo
						z.mo.bcz4prep = true
					end
				end
			end
		else
			if (gamemap == 532) and TITLE == "Jade Valley" --Transform this into something Metroid-y.
				if SAMUSCAMPAIGN == true or (SAM.HUNTERS(s))
					for m in mobjs.iterate(mobj)
						if m.valid and (m.type == MT_RING) and ((m.x >= -4192<<16) and (m.y == -768<<16) and (m.z >= 928<<16))
						and not m.DidIt
							m.DidIt = true
							WEATHERC = 1 break --
						end
					end
				end
			end 
		end
	end
	if WEATHERC != nil
		for z in players.iterate
			if z 
				z.samweather = WEATHERC --This is mainly only still used for the Metal Sonic race at this point.
			end
		end
		if WEATHERC == 1
			if not (HOST and HOST.valid)
				HOST = (SAM.PickHost(0))
			end	
			if gamemap == 13 --Nighttime ACZ1
				for sector in sectors.iterate
					sector.lightlevel = ($-(sector.lightlevel/4))
				end
				P_SetupLevelSky(6, true)
			elseif gamemap == 14 --Sunrise ACZ2
				for sector in sectors.iterate
					if (sector.lightlevel > 192)
						sector.lightlevel = ($-(sector.lightlevel/9))
					else
						sector.lightlevel = ($-(sector.lightlevel/10))
					end
				end
				P_SetupLevelSky(15, true)
			elseif gamemap == 25 --Escape Sequence Black Core
				for ns in players.iterate
					ns.spawnsship = false
					ns.samescapehud = 3281
				end
	
				for sector in sectors.iterate
					if sector.lightlevel and (sector.lightlevel > 31) 
					and not (sector.floorheight <= -1919<<16)
						sector.lightlevel = ($-(sector.lightlevel/9))
					end
					if (sector.floorheight == 448<<16) and (sector.ceilingheight == 448<<16)
						sector.tag = 0
						sector.floorheight = 256<<16
						sector.ceilingheight = 640<<16
					end
				end
				if HOST
					HOST.samescape = 3281
				end
				P_SwitchWeather(PRECIP_STORM_NORAIN)
				
			elseif gamemap == 532	
				local TITLE = mapheaderinfo[gamemap].lvlttl
				if TITLE == "Jade Valley" --Metroid-styled Jade Valley, just for fun.
					local REPLACE
					for m in mobjs.iterate(all) --Nice, you can really do "all"!
						if not (m and m.valid) continue end --
						if m.type == MT_GFZFLOWER1
							REPLACE = MT_BLUECRYSTAL
						elseif m.type == MT_GFZFLOWER2
							REPLACE = MT_STALAGMITE8
						elseif m.type == MT_GFZFLOWER3 // or m.type == MT_BSZTULIP_PURPLE
							REPLACE = MT_CEZBUSH1
						elseif m.type == MT_BERRYBUSH
							REPLACE = MT_BSZBUSH_CYAN
						elseif m.type == MT_BUSH
							REPLACE = MT_BSZBUSH_RED
						else 
							continue --
						end
						P_SpawnMobj(m.x, m.y, m.z, REPLACE)
						P_RemoveMobj(m) --Is there any advantage to this over setting the state to S_NULL??
					end
					for SEC in sectors.iterate
						if SEC.lightlevel != nil 
							SEC.lightlevel = $-($/3) --Darken most of the stage!
							if (SEC.lightlevel < 140) --Yet brighten up the darkest spots!
								SEC.lightlevel = 224
							end
						end
						if SEC.tag --Special lightlevels for these tagged sectors!
							if SEC.tag == 5 --Special lightlevels for these tagged sectors!
								SEC.lightlevel = 224
							elseif SEC.tag == 4 or SEC.tag == 3 or SEC.tag == 1
								SEC.lightlevel = 255
							end
						end
						if SEC.ceilingpic --Change around some textures for a whole new feel!
							if SEC.ceilingpic == "FWATER1"
								SEC.floorpic = "LWATER1"
								SEC.ceilingpic = "LWATER1"
							elseif SEC.ceilingpic == "GFZFLR01"
								SEC.ceilingpic = "RCZFLR3"
							elseif SEC.ceilingpic == "GFZFLR02"
								SEC.ceilingpic = "JNGGRS02"
							elseif SEC.ceilingpic == "GFZFLR10"
								SEC.ceilingpic = "JNGGRS10"
							end
						end
						if SEC.floorpic
							if SEC.floorpic == "GFZFLR01"
								SEC.floorpic = "RCZFLR3"
							elseif SEC.floorpic == "GFZFLR02"
								SEC.floorpic = "JNGGRS02"
							elseif SEC.floorpic == "GFZFLR10"
								SEC.floorpic = "JNGGRS10"
							end
						end
					end
					for side in sides.iterate //Texture check
						if side.toptexture
							if side.toptexture == "#40A0FFJ" --Change the water colormaps.
								side.toptexture = "#00E0C0"
								side.bottomtexture = "#00FFFF"
							elseif (side.toptexture >= R_TextureNumForName("GFZROCK")) and (side.toptexture <= R_TextureNumForName("GFZCHEK2")) --1481, 1483, 1486
								side.toptexture = R_TextureNumForName("SHALE1") --Wha?! Was this function ALWAYS here? --GFZROCK 
							end
						end
						if side.midtexture
							local MID = side.midtexture			
							if MID == R_TextureNumForName("FWBY_04")
							or MID >= R_TextureNumForName("OFALL1") and MID <= R_TextureNumForName("GOOPW16")  --3532
								side.midtexture = R_TextureNumForName("LFALL1")
							elseif (MID == R_TextureNumForName("GFZROCK"))
								side.midtexture = R_TextureNumForName("RCZFLR5") --120
							elseif (MID > R_TextureNumForName("GFZROCK")) and (MID <= R_TextureNumForName("GFZCHEK2"))
							or MID == R_TextureNumForName("GHZWALL6")
								side.midtexture = R_TextureNumForName("SHALE1")
							end					
						end
						if side.bottomtexture
							local BOT = side.bottomtexture
							if BOT >= R_TextureNumForName("GFZROCK") and BOT <= R_TextureNumForName("GFZCHEK2")
								side.bottomtexture = R_TextureNumForName("SHALE1")				
							elseif BOT == R_TextureNumForName("GHZWALL7")
							or BOT == R_TextureNumForName("GHZWALL7")
								side.bottomtexture = R_TextureNumForName("RCZWLL5")
							elseif BOT == R_TextureNumForName("GHZWALL6")
								side.bottomtexture = R_TextureNumForName("RCZWLL3")
							end
						end	
					end
					P_SwitchWeather(PRECIP_STORM_NORAIN)
					P_SetupLevelSky(22, true)
					
					sectors[4].ceilingheight = 476<<16 --Change up a little bit of stage geometry for a twist!
					sectors[61].ceilingheight = 400<<16
					sectors[61].floorpic = "JNGGRS02"
					sectors[69].ceilingheight = 300<<16
					sectors[69].floorheight = 12<<16
					for i = 86,89 if i==88 continue end --What a waste of a loop
						sectors[i].ceilingheight = 350<<16
					end
					sectors[3].special = 0
					sectors[57].special = 13 					
				end
			else
				for SEC in sectors.iterate --GFZ1 weather change
					if SEC.lightlevel != nil
						SEC.lightlevel = max(32, $-31)
					end
					if SEC.ceilingpic == "GFS_CLD1" or SEC.ceilingpic == "GFS_CLD2" or SEC.ceilingpic == "GFS_CLD3"
						SEC.ceilingpic = "GFS_CLDD" --Use these modified cloud textures!
					end
				end
				P_SwitchWeather(PRECIP_STORM)
				P_SetupLevelSky(20, true)
			end
		end
	end
end

--Second part of spawn, right after the map boot function.
SAM.StartSpawn2 = function(p,s)
	local SAMUS = ((YouAreSamus(s)) or (SAM.HUNTERS(s)))
	if SAMUS
		p.weapondelay = max($, 9)
		p.currentweapon = 0
		s.spawnsamuscolors = 6
		s.missiletrns = 0
		s.supermissiletrns = 0
		s.pwbtrns = 0
		p.sams_morphcd = 2
		p.sams_usecd = 2
		s.scale = 90000 --Samus is sized 1.4x vanilla Sonic. She should be bigger, tbh, but gameplay gets weird.
		s.samusscaled = true
		s.destscale = s.scale
		
		if SAM_FirstPerson(p, true) --remember between levels what your FPS preference was.
		or not (SAM_displayplayer(p) and CV_FindVar("chasecam").value)
			if not twodlevel and not (s.flags2 & MF2_TWOD)
			and not p.sammorphed
			--	SamCam(p, camera.chase, nothing)
			--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
				SAM_CMD(p, "nil", "lol", "false", "15")
			--	SamCam(p, false, false)
			--	p.sam_prevcam = nil
			else
				SAM_CMD(p, "1", "lol", "true", "15")
			end
		end			
	end
	
	p.samtoken = 0
	p.samustimeshow = 0	
	if p.sam_energy and (p.sam_energy < 50) and not p.samusrespawnfunc
		p.sam_energy = 50
	end
	
	SetSamusColor(s, p) 
	
	if (gametype != GT_COOP)
		p.sam_fullypoweredsuit = false
		if SAMUSDIFFICULTY == 2
			SAMUSDIFFICULTY = 1
		end
		p.speedrunoverride = false
		p.sams_completiontime = 0
		p.sam_gameover = nil
		s.samspawnprotect = 150
		s.testhyperbeam = nil
		--Is that hyper dude still running around?
		for z in players.iterate
			if z.hyperbeam
				s.testhyperbeam = true
			end
		end
		if s.testhyperbeam
			s.testhyperbeam = nil
			p.sam_hyperbeampanic = 84
		/*	if z.mo and not s.sam_scanpowerup
				DoAreaScan(p, z.mo)
			end */
			if not p.sammissiles or (p.sammissiles < 10)
				p.sammissiles = 10
			end
			if not p.nosammusic
				SAM_COM_BufInsertText(p, "tunes -none; wait 1; tunes SAMUSH")
			end	
		end
	
		if (gametype == GT_RACE)
			p.sam_energytanksmax = 0
			p.sam_energy = 99
		elseif not p.samchallenger and G_GametypeHasSpectators() --New for v1.5
			p.sam_power_grip = true
		end
	elseif not p.gameoverready and p.lives
		p.gameoverready = true
	end
	
	if p.sammorphed and not ((s.samspinpad) or (p.readyreadyready))
		SAM.UnMorph(s)
	end
	if p.sammissiles != nil
		if p.buffbottomtier
		and (p.sammissiles < 20)
			p.sammissiles = 20
		elseif (p.sammissiles < 5)
			p.sammissiles = 5
		end
	end
	if p.samsupermissiles != nil and p.buffbottomtier
		if (p.samsupermissiles < 2) --Damn, the noobs have it made.
			p.samsupermissiles = 2
		end
	end
	if p.sam_energytanksmax == nil
		p.sam_energytanksmax = 0
	end
	s.sam_ldclmb = 0
	if G_GametypeHasSpectators() and not (gametype == GT_RACE) and p.sam_energytanksmax != nil
		if not (p.samusmatch and (p.samusmatch == 1))
			p.sam_energytanksmax = p.sam_energytanksstart
			if (leveltime and (leveltime < 350)) and not (p.sam_energytanksmax != nil and (p.sam_energytanksmax < 2))
				p.sam_energy = (p.sam_energytanksmax*50)-1
			else
				p.sam_energy = 99+(p.sam_energytanksmax*50)
			end
		end
		if (leveltime < 350) and not (p.sam_energytanksmax !=nil and (p.sam_energytanksmax < 2))
			p.sam_energy = (p.sam_energytanksmax*50)-1
		else
			p.sam_energy = 99+(p.sam_energytanksmax*50)
		end
		p.sam_energytanks = p.sam_energytanksmax
		if p.sam_hyperbeam
			p.sam_hyperbeam = false
		end
	elseif p.matchtanks
		p.sam_energytanksmax = 0
		p.sam_energytanks = 0
	end
	if p.sam_gametype == nil --Our first gametype!
		p.sam_gametype = gametype
	end
	
	if (p.sam_gametype != gametype) --Start with nothing in these gamemodes.
	and not ( 
	G_GametypeHasSpectators() and p.samusmatch
	or (gametype == GT_RACE)
	)
	
		p.samspbs = false
		p.sambsbl = false
		p.sam_spiderball = false
		p.sam_screwattack = false
		p.sam_gravitysuit = 0
		SetSamusColor(s, p) 
		p.sam_highjump = false
		p.sam_bombs = false
		p.sam_spacejump = false
		p.sam_spazerbeam = false
		p.sam_wavebeam = false
		p.sam_icebeam = false
		p.sam_plasmabeam = false
		p.sam_powerbeamcombo = false
		p.sam_spazerbeamcombo = false
		p.sam_wavebeamcombo = false
		p.sam_icebeamcombo = false
		p.sam_plasmabeamcombo = false
		p.sam_hyperbeam = false
		p.sammissilesmax = 5
		p.samsupermissilesmax = 0
		p.sampwmax = 0
		p.sam_fullypoweredsuit = false
		if not G_GametypeHasSpectators()
			if not (gametype == GT_RACE)
				p.sam_chargebeam = false
				p.sammissilesmax = 0
			end
			p.sam_ammodigitizer = 1
			p.sam_autotank = nil
			p.sam_scanvisor = false
			p.sam_energytanksmax = 0
			p.sam_energytanks = 0
		end
		
		SamResetBeam(p)
		if (leveltime < 350) and not (p.sam_energytanksmax != nil and (p.sam_energytanksmax < 2))
			p.sam_energy = (p.sam_energytanksmax*50)-1
		else
			p.sam_energy = 99+(p.sam_energytanksmax*50)
		end
		if not (SAM.HUNTERS(s))
			hud.enable("stagetitle")
		end
		p.sam_gametype = gametype
	end
	if (p.sam_energy <= 0)
		if p.samusrespawnfunc
			p.sam_energy = p.samusrespawnfunc
		else
			p.sam_energy = 99+(p.sam_energytanksmax*50)
		end							
	end
	
	s.samusjustspawned = true
	SamSpiderCharge(p, s, 103)
	
	if (gametype != GT_COOP) or (gamemap == 25)
		p.sam_fpsmsg = 0
	end
	
	p.sams_morphcd = 0
	p.bsblboost = 0
	p.bsblboostattack = 0
	p.samspbscharge = 0
	p.sam_shinespark = 0
	CancelScrewAttack(s,p)
	p.samshieldhp = 3
	p.sam_shinesparkfly = 0
	p.samspbschargefull = false
	p.samushasatimer = nil
	p.morphanim = false
	p.sam_beamswitch = 2
	p.sams_supermissileready = 0
	p.sams_mshotcd = 10
	p.sam_powerbeammeltdown = 0
	p.sam_spazerbeammeltdown = 0
	p.sam_icebeammeltdown = 0
	p.sam_wavebeammeltdown = 0
	p.sam_plasmabeammeltdown = 0
	p.sams_beamcombocharge = 0
	p.sam_hyperbeampanic = 0

	if p.samusrespawnfunc
		P_SamFP(p, PAL_WHITE, 6)
		S_StartSound(s, sfx_samspa)
		P_PlayRinglossSound(s)
		s.sam_systemreboot = 9
		p.samusrespawnfunc = nil
	else
		--Save your ammo and reload if you die!
		if not p.starposttime and (gametype == GT_COOP) and gamemap
			if (p.sam_lastplaymap == nil or gamemap == p.sam_lastplaymap)
			and p.samuschosefile
				if p.sam_lastmissiles and p.sammissiles != nil and p.sam_lastmissiles > p.sammissiles
					p.sammissiles = p.sam_lastmissiles
				end
				if p.sam_lastsupermissiles and p.samsupermissiles != nil and p.sam_lastsupermissiles > p.samsupermissiles
					p.samsupermissiles = p.sam_lastsupermissiles
				end
				if p.sam_lastpw and p.sampw != nil
					if (p.sam_lastpw > p.sampw)
						p.sampw = p.sam_lastpw
					end
				end						
			end
			p.sam_lastplaymap = gamemap
			p.sam_lastmissiles = p.sammissiles
			p.sam_lastsupermissiles = p.samsupermissiles
			p.sam_lastpw = p.sampw
		end			
	end
	
	if SAMUS
		p.powers[pw_shield] = SH_NONE
		if not P_IsObjectOnGround(s) and p.panim == PA_IDLE 
		and not (s.eflags & (MFE_SPRUNG|MFE_APPLYPMOMZ)) and not p.sammorphed
			s.state = S_PLAY_FALL
		end
	end
	--Check if you still have your beams?
	if (p.sam_spazerbeamequip and not p.sam_spazerbeam)
	or (p.sam_wavebeamequip and not p.sam_wavebeam)
	or (p.sam_icebeamequip and not p.sam_icebeam)
	or (p.sam_plasmabeamequip and not p.sam_plasmabeam)
	or (p.sam_hyperbeamequip and not p.sam_hyperbeam)
		SamResetBeam(p)
	end
	if not p.sam_power_grip --Remove object incase.
		SAM_RemoveLDgrp(s)
	end
	if G_GametypeHasSpectators()
		if not (HOST and HOST.valid)
			HOST = (SAM.PickHost(0))
		end
		if (HOST and HOST.valid)
			local TOPSCORE = (HOST.sam_topscore) or 0
			local SCORE = (p.score) or 0
			if not s.sam_scanpowerup and SAMUS
				SAM.DoAreaScan(s, p, false, "skipplayers")
			end
			if (SCORE+35 < TOPSCORE)
				local FAILTIER = (SCORE+800<TOPSCORE) and 3 or (SCORE+400<TOPSCORE) and 2 or 1	
				local TIER = FAILTIER
				if (FAILTIER > 1) --Gotta be behind by a LOT before you get freebies.
					if not p.sam_bombs and SAMUS
						P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_MHBM) --Super basic stuff.
					end
					if (leveltime > 4050) --Get some equipment after 2 minutes and when considerably behind.
						if (TIER>2) --doing TERRIBLY.
							if (p.sammissilesmax < 35)
								p.sammissilesmax = 35
							end
							if SAMUS 
								if not p.sampwmax and (leveltime > 6300)
									P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_PTNK)	
								elseif not p.sam_beamcombosrestrict and not p.sam_powerbeamcombo
									P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_CHBM)												
								elseif not p.samspbs
									P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_SPBS)
								elseif not p.sam_spazerbeam
									P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_SPBM)
								elseif not p.sam_highjump
									P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_SPBL)	
								end
							end
						elseif (p.sammissilesmax < 25)
							p.sammissilesmax = 25
						end

						if not p.samsupermissilesmax and SAMUS
							P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_STNK)
						elseif (p.samsupermissilesmax < (TIER*2))
							p.samsupermissilesmax = TIER*2
						end
					elseif (leveltime > 2000) --After 1 minute, you can get some minor boosts!
						if (p.sammissilesmax < 5*(TIER+1))
							p.sammissilesmax = 5*(TIER+1)
						end
						if SAMUS
							if not p.samsupermissilesmax and (TIER>2)
								P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_STNK)
							elseif not p.sam_beamcombosrestrict and not p.sam_powerbeamcombo
								P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_CHBM)					
							elseif not p.samspbs and (TIER>2)
								P_SpawnMobjFromMobj(s,s.momx/2,s.momy/2,0, MT_SPBS)			
							end
						end
					end
				end
				local MISSILES = p.sammissiles or 0
				local SUPERS = p.samsupermissiles or 0
				local PW = p.sampw or 0
				p.sammissiles = max(MISSILES, 10*FAILTIER)
				p.samsupermissiles = max(SUPERS, (FAILTIER==1) and 1 or 2*FAILTIER)
				p.sampw = max(PW, FAILTIER-1)
			end
		end	
	end	
	SetSamusColor(s, p)	
end

--At the start of a map, see if you can spawn your gunship
SAM.SpawnShip = function(p,s)
	if s.sam_sprstship
	and not ((gametype == GT_TAG) or (gametype == GT_HIDEANDSEEK) or (p.powers[pw_carry] == CR_NIGHTSMODE))
		if not (netgame) and (gametype == GT_COOP)
			if p.samuschosefile == nil or p.sam_saveselect
				if YouAreSamus(s) 
					p.spawnsship,s.sam_sprstship = false,false return --
				end
			end
		end	
		p.spawnsship = true
		ActivateHyperMode(p, 7, s) --Third arguments puts in player.mo and checks for boss/metal.
		local SEC = s.subsector and s.subsector.sector
		if SEC
			if gamemap==103 and SEC.lightlevel == 0
			or gamemap==40 and SEC.floorheight == -1024<<16	
			
			or SEC.ceilingpic == "PIT" and SEC.floorpic == "PIT"  and (SEC.lightlevel < 64)
			and SEC != sectors[200] and SEC != sectors[205] and SEC != sectors[210] and SEC != sectors[208]
				s.samhudgimmick = true
				if (gamemap == 40 and SEC.floorheight == -1024<<16)
					s.saminfhealth = true
				end
			end
		end
		if s.sam_sprstship
			if not (HOST and HOST.valid)
				HOST = (SAM.PickHost(0))
			end	
			if not p.nogunshipspawn 
				if p.spawnsship
					if multiplayer or YouAreSamus(s)
						if not s.samhudgimmick
						and not G_IsSpecialStage(gamemap) and not (gamemap==812) --812 is ACZ4.
							if HOST and HOST.valid and p==HOST
							and not (p.samusshipspawn and p.samusshipspawn.valid)
								p.samusshipspawn = P_SpawnMobj(
								s.x+FixedMul(-65000, cos(s.angle)), 
								s.y+FixedMul(-65000, sin(s.angle)), s.z, MT_SAMUSSHIP)
								p.samusshipspawn.tracer = s
								p.samusshipspawn.angle = s.angle
								
								if mapheaderinfo[gamemap].lvlttl == "Greenflower" and (gamemap == 01)
									if (gametype == GT_COOP) and (leveltime < 99)
										p.samusshipspawn.dying = true --Crashed ship on GFZ1.
									end
								end
								
								for z in players.iterate --GUYS! I'm ALREADY here!!
									if z.mo and z.mo.sam_sprstship
										z.mo.sam_sprstship = false
										z.spawnsship = false
									end
								end
							end
						end
					elseif p.jointime == 0 and p == server
						p.shipMSG = 300
					end
				end
			end
		end
		p.spawnsship = false
		s.sam_sprstship = false
	end
end

--Apply "shading" to your first person arm cannon depending on your area.
SAM.ApplyBeamLight = function(p,s)
	if (s.eflags & MFE_UNDERWATER)
		if (s.eflags & MFE_TOUCHLAVA) //(P_PlayerTouchingSectorSpecial(p, 1, 3))
			p.sambeamlightcolor = SKINCOLOR_ORANGE
			p.sambeamlight2 = FF_TRANS40
		elseif (s.eflags & MFE_GOOWATER) --(P_PlayerTouchingSectorSpecial(p, 1, 2)) or 
			p.sambeamlightcolor = SKINCOLOR_MAGENTA
			p.sambeamlight2 = FF_TRANS60
		else
			p.sambeamlightcolor = SKINCOLOR_BLUE
			p.sambeamlight2 = FF_TRANS70
		end
	end	
	local SEC = s.subsector and s.subsector.sector
	if SEC
		local FOFLIGHT = nil
		for fof in SEC.ffloors()
			if fof and (fof.flags & FF_EXISTS) 
				if not (fof.flags & (FF_NOSHADE|FF_DOUBLESHADOW)) and (s.z < fof.bottomheight)
					FOFLIGHT = fof.toplightlevel
				elseif (fof.flags & FF_CUTSPRITES)
					if ((s.z >= fof.bottomheight) and (s.z+(s.height/2) < fof.topheight))
						FOFLIGHT = fof.toplightlevel+20
					end
				end
			end
		end 
		local LIGHT = (FOFLIGHT) and FOFLIGHT or SEC.lightlevel
		if LIGHT == nil or (LIGHT > 224)
			p.sambeamlight = nil
		elseif (LIGHT > 224)
			p.sambeamlight = FF_TRANS90
		elseif (LIGHT > 192)
			p.sambeamlight = FF_TRANS80
		elseif (LIGHT > 160)
			p.sambeamlight = FF_TRANS70
		elseif (LIGHT > 140)
			p.sambeamlight = FF_TRANS60
		elseif (LIGHT > 120)
			p.sambeamlight = FF_TRANS50
		elseif (LIGHT > 100)
			p.sambeamlight = FF_TRANS40
		elseif (LIGHT > 80)
			p.sambeamlight = FF_TRANS30
		else
			p.sambeamlight = FF_TRANS20
		end
		return true --
	end p.sambeamlight = nil
end
--What have you DONE?!
SAM.SamusIsFuckingDead = function(p,s)
	p.sam_energy = 0
	p.sam_hyperbeamammo = 0
	P_SetObjectMomZ(s, 500)
	s.flags = $|MF_NOGRAVITY
	if p.sammorphed
		p.morphanim = false
		SAM.UnMorph(s)
		s.state = S_PLAY_DEAD
	end
	if not p.lives and netgame and (gametype == GT_COOP) --Revive mechanic
		if (p.deadtimer > 277)
			p.deadtimer = 276
		end
		if not (p.samnetcon and (p.samnetcon > 2))
			if (p.cmd.buttons & BT_CUSTOM3)
				if p.samnetcon == nil
					p.samnetcon = 1
				else 
					p.samnetcon = $+1
				end
			
				p.lives = 3
				P_SamFP(p, PAL_MIXUP, 10)
				CONS_Printf(p, "\x82"+"Used up your stage revive!")
				p.playerstate = PST_REBORN
				p.samnetrestart = 3
				return
			end
		end
	end
	if (s.state == S_PLAY_DEAD)
		if not (s.metroiddust or s.plasmadust)
		s.state = S_SAMDEAD1
		P_SamFP(p, PAL_NUKE, 11)
		P_PlayerEmeraldBurst(p)
		P_PlayerFlagBurst(p)
		P_PlayerWeaponAmmoBurst(p)
		end
		if p.sam_hyperbeampanic and p.sam_hyperbeam
			for z in players.iterate
				if not z.nosammusic
				SAM_COM_BufInsertText(z, "tunes -default")
				end
			z.sam_hyperbeampanic = 0
			end
		end
	end
	if (s.state == S_SAMDEAD1)
		P_SpawnMobj(s.x+((P_RandomRange(FixedMul(-55, s.scale), FixedMul(55, s.scale)))<<16), 
		s.y+((P_RandomRange(FixedMul(-55, s.scale), FixedMul(55, s.scale)))<<16), s.z+((P_RandomRange(FixedMul(1, s.scale), FixedMul(49, s.scale)))<<16), MT_BOSSEXPLODE)
	elseif (s.state == S_SAMDEAD2)
		and not (s.metroiddust or s.plasmadust)
		A_SAMPARTICLE(s, MT_MPR2, 4, 7, 10, 7, s.color)
		A_SAMPARTICLE(s, MT_MPR3, 4, 6, 10, 6, s.color)
	elseif (s.state == S_SAMDEAD3)
	and not (s.metroiddust or s.plasmadust)
		if not (s.ghs7 and s.ghs7.valid)
			s.ghs7 = P_SpawnGhostMobj(s)
			s.ghs7.fuse = 60
			s.ghs7.frame = D|FF_FULLBRIGHT|FF_TRANS90
			s.ghs7.scalespeed = $/2
			s.ghs7.destscale = 99<<16
		end
	end
end

SAM.Exiting = function(p,s)
	if s.state == S_ZEROSUITANIM0
		if s.animfade == nil s.animfade = 20 end
		if s.animfade
			s.animfade = max($-1,0)
			
			local ghs = P_SpawnMobj(s.x, s.y,s.z-s.height/11, MT_OVERLAY)
			ghs.target = s
			ghs.sprite = SPR_ZSSA
			if s.animfade
				ghs.frame = (s.animfade > 12 and H|FF_TRANS10) or
				(s.animfade > 8 and H|FF_TRANS30) or
				(s.animfade > 4 and H|FF_TRANS50) or
				H|FF_TRANS70
			end
			ghs.tics = 2
		end
	end
	if s.samuszerorun //Zero Suit Samus cameo
		if s.health and YouAreSamus(s)
	
			SAM.UnMorph(s)
			s.z = s.floorz
			p.pflags = $ & ~(PF_JUMPED|PF_SPINNING|PF_STARTDASH)
			s.flags = $|MF_NOGRAVITY
			s.eflags = $ & ~MFE_JUSTHITFLOOR
			p.sammorphed = false
			p.sams_morphcd = 35
			p.sams_beamcombocharge = 0
			p.sams_shotcd = 22
			p.samspbschargefull = false
			p.samspbscharge = 0
			p.sam_shinesparkstop = 0
			p.sambsblchargefull = false
			s.samunmorphed = 4
			s.samslopespin = 0
			s.sambsblchargelvl = 0
			p.bsblboost = 0
			p.bsblboostattack = 0
			s.samspinpad = 0
			s.scale = 90000
			P_SamFP(p, PAL_MIXUP, 5)
			S_StartSound(nil, sfx_nxbump)
			S_StartSound(s, sfx_nxbump)
			S_StartSound(s, sfx_s3k66)
			
			local ghs = P_SpawnMobj(s.x-1, s.y-1, s.z+s.height, MT_THOK)
			ghs.flags = $|MF_NOCLIPHEIGHT|MF_NOCLIP
			ghs.momz = -9<<16
			ghs.color = 27
			ghs.tics = 36
			ghs.scalespeed = $*4
			ghs.destscale = s.scale*99
				
			A_SAMUSEXPLOSIONS(s, 20, MT_SPARK, 65<<16, 6000)
			A_SAMUSEXPLOSIONS(s, 10, MT_IVSP, 75<<16, 199000)
			A_SAMUSEXPLOSIONS(s, 17, MT_IVSP, 5<<16, 900)
			A_SAMUSEXPLOSIONS(s, 18, MT_SPARK, 5<<16, 100)
			A_SAMUSEXPLOSIONS(s, 23, MT_SPARK, 30<<16, 8000)
			A_SAMUSEXPLOSIONS(s, 16, MT_SPARK, 54<<16, 15000)
			A_SAMUSEXPLOSIONS(s, 12, MT_SPARK, 67<<16, 20000)
			s.momx,s.momy,s.momz = 0,0,0
			s.state = S_ZEROSUITANIM0
		--	SamCam(p, camera.chase, nothing)
		--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
			SAM_CMD(p, "nil", "false", "true", "lol")
		--	SamCam(p, true, true)
			p.sammorphed = false
		end
		s.samuszerorun = nil
	end		
	if p.samtoken --This takes place rapidly every frame.
		if not (All7Emeralds(emeralds))
			local gems = emeralds
			local GOTEMERALD = 1
			for i = 1,7
				if not (emeralds & GOTEMERALD)
					emeralds = emeralds|GOTEMERALD break --We don't have this one, so add it!
				end
				GOTEMERALD = $*2
			end
			if gems ~= emeralds
				S_StartSound(nil, sfx_cgot)
				CONS_Printf(p, "You received a\x83 Chaos Emerald")
			end
		end
		p.samtoken = max($-1,0)
	end
end

--Encompassed most of the High Jump Ability (not spring ball)
SAM.HighJumpAbility = function(p,s)
	if P_IsObjectOnGround(s) --Reset High Jump charge
	
		p.sam_highjumpcharge = 4
	
	elseif (p.pflags & PF_STARTJUMP) and p.sam_highjumpcharge and (p.pflags & PF_JUMPED) --High Jump effects
	
		if p.sam_highjumpcharge == 4 and (s.z < s.floorz+50*s.scale)
			local ghs = SamShinySplat(s,SKINCOLOR_SUPERSILVER5, 6)
			ghs.scale = $/10
			ghs.destscale = $*99
			ghs.sprite = SPR_MPR9
			ghs.frame = A|FF_TRANS80|FF_FULLBRIGHT
		end
		
		local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_SAMWINDLINE)
		ghs.scale = 35000
		
		if leveltime % 2 == 0
			ghs.momx,ghs.momy = s.momx,s.momy
			ghs.momz = s.momz*2/3
		else
			ghs.momx,ghs.momy,ghs.momz = s.momx/2,s.momy/2,s.momz/2
		end
		P_InstaThrust(ghs, (s.angle+ANGLE_45)+(ANGLE_90*p.sam_highjumpcharge), 18<<16)
		ghs.flags2 = $|MF2_SHADOW
		ghs.rollangle = ANGLE_90
		ghs.blendmode = AST_ADD
		ghs.destscale = $*99
		ghs.fuse = 15	
		--And afterimages to boot, like Zero Mission
		ghs = P_SpawnGhostMobj(s)
		ghs.blendmode = AST_ADD
		ghs.destscale = ghs.scalespeed
		if SAM_displayplayer(p) and not CV_FindVar("chasecam").value
			ghs.flags2 = $|MF2_DONTDRAW
		end	
		
		p.sam_highjumpcharge = $-1					
	end
end

--Encompasses most of the SpiderBall ability.
SAM.SpiderBallAbility = function(p,s)

	if s.spiderbcharge == nil
		s.spiderbcharge = 103
	end
	if (s.spiderbcharge < 103)
		if p.powers[pw_carry] or P_IsObjectOnGround(s)
			SamSpiderCharge(p, s, 103)
			s.spiderbanim = 7
			if p.sammorphed
				S_StartSound(s, sfx_s3k7c)
				local ZHEIGHT = (s.eflags & MFE_VERTICALFLIP) and s.height or s.height/10
				local ghs = P_SpawnMobjFromMobj(s,0,0,ZHEIGHT, MT_SAMUSZAP)
				ghs.blendmode = AST_ADD
				ghs.momx,ghs.momy,ghs.momz = s.momx,s.momy,s.momz
				ghs.color = SKINCOLOR_MOSS
				ghs.morning = 4
			end
		end
	end
	if (p.powers[pw_carry])
		return --
	end	
	
	//New Spider Ball wall-climbing code!
	if not s.spiderballing
		S_StopSoundByID(s, sfx_spdrbl)
	else
		p.camerascale = 196071 //261427
		s.thesamcam = 1
		if (p.pflags & PF_ANALOGMODE)
			p.sam_forceanalogoff = 2
			p.pflags = $ & ~PF_ANALOGMODE
		end
		if s.spideronce
			for d = 1,30 --Inch closer to the wall if possible.
				if not P_TryMove(s, s.x+FixedMul(FRACUNIT, cos(s.angle)), s.y+FixedMul(FRACUNIT, sin(s.angle)), true)
					break --
				end
			end 
			SamusTutorial(s, "spiderball", true) --You did it!
		end
		if p.sambsblchargefull
			p.camerascale = 261427
			s.thesamcam = 1
		end
		local VISORCOLOR = (p.sam_gravitysuit==2) and p.samvisorcolor or SKINCOLOR_EMERALD
		
		--Shiny stuff is all the rage
		local ghs = P_SpawnMobjFromMobj(s,0,0, (s.height/2)+s.momz, MT_THOK)
		ghs.sprite = SPR_OILF
		ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
		ghs.blendmode = AST_ADD
		ghs.tics = 2
		if (leveltime%2==0)
			ghs.scale = $*20/19
			ghs.frame = A|FF_TRANS80
			ghs.colorized = true
			ghs.color = VISORCOLOR
		else
			ghs.frame = A|FF_TRANS90
		end		
		if not (s.spiderthok and s.spiderthok.valid)
			s.spiderthok = P_SpawnMobj(s.x, s.y, s.z-s.height/3, MT_SAMUSTHOK)
			local ghs = s.spiderthok
			if ghs and ghs.valid
				ghs.sprite = SPR_YGTL
				ghs.renderflags = $|RF_NOCOLORMAPS|RF_FULLBRIGHT
				ghs.tics = 2
				ghs.color = VISORCOLOR
				
				if (s.spiderbcharge and s.spiderbcharge < 35)
					ghs.color = ((VISORCOLOR==SKINCOLOR_RED) or (VISORCOLOR==SKINCOLOR_CRIMSON)) and SKINCOLOR_BLACK or SKINCOLOR_RED
				else
					ghs.color = VISORCOLOR
				end
				ghs.scale = s.scale*10/8
				ghs.destscale = s.scale*4
				ghs.momz = s.momz	
				P_Thrust(ghs, s.angle, 1)
			end
		else
			s.spiderthok = nil
		end
		
		if not s.spiderbsound or s.spiderbsound == 1
			s.spiderbsound = 44
			S_StopSoundByID(s, sfx_spdrbl)
			S_StartSound(s, sfx_spdrbl)
		else
			s.spiderbsound = $-1
			if not S_SoundPlaying(s, sfx_spdrbl)
				S_StartSound(s, sfx_spdrbl)
			end
		end
		
		local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
		if ghs and ghs.valid			
			ghs.z = $-(s.scale*8*P_MobjFlip(s))			
			ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
		end
		P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
		if s.spideronce
			if ghs and ghs.valid
				P_Thrust(ghs, s.angle, 16<<16)
			end
			P_InstaThrust(s, s.angle, 19<<16)
			s.spideronce = $-1
		end
		s.angle = s.spiderballing
		p.drawangle = s.spiderballing
		s.momx,s.momy = 0,0
		if not s.bombjump
			if p.cmd.forwardmove
				if s.spiderbcharge
					if (s.spiderbcharge > 48) or (leveltime%2)
						s.spiderbcharge = $-1
					end
				end
				if (leveltime%3==0)
					P_SpawnMobj(s.x, s.y, s.z-s.height/2, MT_SPARK)
				end
				P_SetObjectMomZ(s, FixedDiv(p.cmd.forwardmove<<16, 4<<16), false)
				p.speed = 28<<16
			else
				if (leveltime % 7 == 0) and s.spiderbcharge
					s.spiderbcharge = $-1
				end
				s.momz = 0
			end
		end
		if s.spiderbwait
			s.spiderbwait = $-1
		end
		if s.spiderballgo or s.spiderballgo == 0
			s.spiderballgo = nil
		else
			if P_IsObjectOnGround(s) or not s.spiderbcharge
				s.spiderballing = 0
				s.spiderbsound = 0
				P_Thrust(s, s.angle, -3<<16)
				s.momz = $/2
				S_StopSoundByID(s, sfx_spdrbl)
	
			elseif not s.spiderballstillgood
				s.spiderballing = 0
				s.spiderbsound = 0
				P_InstaThrust(s, s.angle, 8<<16)
				s.momz = 0
				S_StopSoundByID(s, sfx_spdrbl)
			
			elseif s.bombjump or p.powers[pw_flashing] or (p.powers[pw_carry] == CR_ZOOMTUBE)
				p.pflags = $|PF_JUMPED
				s.spiderballing = 0
				s.spiderbsound = 0
				S_StopSoundByID(s, sfx_spdrbl)
				
			elseif (p.cmd.buttons & BT_USE) or not p.sammorphed
				s.spiderballing = 0
				s.spiderbsound = 0
				P_Thrust(s, s.angle, -9<<16)
				s.momz = 2
				p.pflags = $|PF_JUMPED
				S_StartSound(s, sfx_sballf)
				p.sams_morphcd = 35
				S_StopSoundByID(s, sfx_spdrbl)
			
			elseif (p.cmd.buttons & BT_JUMP) and not s.spiderbwait and not (p.sams_jumpcd > 2) or p.bsblboost
				s.spiderballing = 0
				s.spiderbsound = 0
				s.angle = $+ANGLE_180
				p.pflags = $|PF_JUMPED
				p.sams_jumpcd = 10
				P_InstaThrust(s, s.angle, 14<<16)
				S_StopSoundByID(s, sfx_spdrbl)
			
				if p.sam_highjump and not p.bsblboost
					S_StartSound(s, sfx_sballj)
					P_SetObjectMomZ(s, 9<<16, false)
				else
					P_SetObjectMomZ(s, FRACUNIT, false)
					if p.bsblboost
						if s.spiderbcharge < 103							
							SamSpiderCharge(p, s, 103)
							s.spiderbanim = 7
						end
						P_InstaThrust(s, s.angle, 80<<16)
						P_SetObjectMomZ(s, 7<<16, false)
						local ghs = P_SpawnMobj(s.x, s.y, s.z-((s.height/10)*P_MobjFlip(s)), MT_SAMUSZAP)
						ghs.blendmode = AST_ADD							
						ghs.scale = s.scale
						ghs.eflags = s.eflags
						ghs.momx = s.momx ghs.momy = s.momy ghs.momz = s.momz
						ghs.color = SKINCOLOR_MOSS
						ghs.morning = 4
						S_StartSound(s, sfx_s3k7c)
					end
					p.bsblboostangle = s.angle
				end
			end
		end
	end			

	if s.spiderbcharge 
		if not ( ((p.pflags & PF_STARTJUMP) and ((s.momz > 1*P_MobjFlip(s)) and not (s.eflags & MFE_VERTICALFLIP)) ) ) 
		and not p.gotflag and not p.powers[pw_nocontrol]
			if ( (p.sam_highjump and (p.cmd.buttons & BT_JUMP) and not (p.sams_jumpcd > 3)) or ((p.sams_jumpcd >= 1) and (p.sams_jumpcd < 5) and not p.sam_highjump) ) 
			and not p.powers[pw_flashing] and not s.bombjump and not s.spiderballing
			or s.spiderballdoublecheck
				if (p.pflags & PF_ANALOGMODE) and P_IsObjectOnGround(s)
				and not p.sam_highjump
					P_SetObjectMomZ(s, 2<<16, true)
				elseif (p.pflags & PF_DIRECTIONCHAR)
					p.drawangle = s.angle
				end
				
				s.spiderthok = P_SpawnMobj(s.x, s.y, s.z-s.height/3, MT_THOK) --Don't turn into a local variable.
				s.spiderthok.sprite = SPR_YGTL
				s.spiderthok.tics = 1
				s.spiderthok.scale = s.scale*10/8
				s.spiderthok.destscale = s.scale*4
				s.spiderthok.momz = s.momz
				s.spiderthok.momx = s.momx+1
				s.spiderthok.momy = s.momy+1
				
				if p.samvisorcolor and p.sam_gravitysuit==2 and s.spiderthok and s.spiderthok.valid
					s.spiderthok.color = p.samvisorcolor
				elseif s.spiderthok and s.spiderthok.valid
					s.spiderthok.color = SKINCOLOR_GREEN
				end
				
				s.spiderthok.tics = 2
				s.spiderfirstcheck = true
				
				local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
				P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
				
				if ghs and ghs.valid
					P_Thrust(ghs, s.angle, 20<<16)
				end
				s.spideronce = 4
				
			if s.spiderballgo and not s.spiderballdoublecheck
				s.spiderballdoublecheck = 2
				s.spiderballgo = 0
				local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
				P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
					if ghs and ghs.valid
					P_Thrust(ghs, s.angle, 20<<16)
					end
				s.spideronce = 4

			elseif s.spiderballgo and s.spiderballdoublecheck
			
				P_InstaThrust(s, s.angle, 19<<16)
				p.bsblboost = 0 
				p.sams_jumpcd = 3
				p.pflags = $|PF_JUMPDOWN & ~PF_JUMPED
				P_SetObjectMomZ(s, 5<<16, false)
				S_StartSound(s, sfx_spdrbl)
			
				if (s.angle == 0)
				s.spiderballing = 1
				else
				s.spiderballing = s.angle
				end
				
				s.spiderbwait = 10
				s.spiderballdoublecheck = 0
				s.spiderballgo = 0
			end	
			
			/*	if s.spiderballgo == 3
					if not s.spiderballdoublecheck
						s.spiderballdoublecheck = 2
						local ghs = P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
						P_SPMAngle(s, MT_SAMWALLJUMP, s.angle)
						if ghs and ghs.valid
							P_Thrust(ghs, s.angle, 20<<16)
						end
						s.spideronce = 4
					else--if s.spiderballdoublecheck
						P_InstaThrust(s, s.angle, 19<<16)
						p.bsblboost = 0 
						p.sams_jumpcd = 3
						p.pflags = $|PF_JUMPDOWN & ~PF_JUMPED
						P_SetObjectMomZ(s, 5<<16, false)
						S_StartSound(s, sfx_spdrbl)
					
						s.spiderballing = (s.angle==0) and 1 or s.angle
						s.spiderbwait = 10
						s.spiderballdoublecheck = 0
					end
					if s.spiderballgo == true
						s.spiderballgo = 0
					else
						s.spiderballgo = max($-1,0)
					end
				end */
			elseif p.powers[pw_flashing] and (p.cmd.buttons & BT_JUMP) and not (p.sams_jumpcd > 1)
				S_StartSound(s, sfx_sdenid)
			end
		end
	end
end

local function ScrewAttackLandingGFX(s,p)
	local ghs = SamShinySplat(s,SKINCOLOR_SUPERGOLD5, 12)
	ghs.frame = A|FF_TRANS30|FF_FULLBRIGHT
	ghs.scale = $*3
	ghs.momx = s.momx/2
	ghs.momy = s.momy/2
	for d = -2,2,1
		local ghs = P_SpawnMobjFromMobj(s,0,0,s.height/5, MT_THOK)
		ghs.angle = (s.angle+ANGLE_90)+(ANG10*d)
		P_InstaThrust(ghs, ghs.angle-ANGLE_90, p.speed)
		P_SetObjectMomZ(ghs, s.scale)
		ghs.sprite = SPR_PHAZ
		ghs.spriteyscale = 42000
		ghs.spritexscale = 85000
		ghs.color = SKINCOLOR_SUPERGOLD5+2-(d*3)
		ghs.colorized = true
		ghs.tics = 25
		ghs.fuse = 15
		ghs.frame = J|FF_TRANS30|FF_PAPERSPRITE|FF_FULLBRIGHT
		ghs.blendmode = AST_ADD
		ghs.destscale = $*99	
	end
end
local function ScrewAttackBonk(s,p)
	if P_IsObjectOnGround(s) or ( (p.speed < (FixedMul(22<<16, s.scale))) and not ((s.momz > (FixedMul(13<<16, s.scale)) or (s.momz < (FixedMul(-13<<16, s.scale))))))
		P_SetObjectMomZ(s, 4<<16)
		P_SamFP(p, PAL_NUKE, 6)
		s.momx = $/3
		s.momy = $/3
	
		if P_IsObjectOnGround(s) --Screw Attack ground slam!
			ScrewAttackLandingGFX(s,p)
		elseif (p.speed < (FixedMul(22<<16, s.scale)))
			P_Thrust(s, s.angle, -14<<16)
			if (p.cmd.buttons & BT_JUMP)
			s.momz = ($*3)/2
			end
		end
	
		if not (p.powers[pw_carry] == CR_MACESPIN)
		and not p.sammorphed
			s.state = S_PLAY_FALL
		end
		
		A_Samuskillstuff(s, 265<<16, 150<<16, s, true) --Do this first

		if not (gametyperules & GTR_POINTLIMIT)
			P_RadiusAttack(s, s, 320<<16)
		end

		CancelScrewAttack(s,p)
		p.sam_c1ready = 0
		p.sams_screwattackcd = 45
		for d = 1,20
			local t = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_MINECARTSPARK)
			t.blendmode = AST_ADD
			t.scale = s.scale/12
			t.fuse = 30
			P_InstaThrust(t, P_RandomRange(1,359)*ANG1, P_RandomRange(12,24)<<16)
			t.momx = $+(s.momx*2) t.momy = $+(s.momy*2)
			t.momz = P_RandomRange(4,7)<<16
		end	
		A_SAMPARTICLE(s, MT_MPR1, 30, 18, -1, 5, SKINCOLOR_YELLOW, 35000, true)
		A_SAMPARTICLE(s, MT_MPR1, 50, 14, -1, 6, SKINCOLOR_WHITE, 23000, true)
		A_SAMPARTICLE(s, MT_MPR1, 50, 15, -1, 8, SKINCOLOR_GREEN, 23000, true)
		A_SAMPARTICLE(s, MT_MPR1, 50, 12, -1, 8, SKINCOLOR_GREEN, 23000, true)
		A_SAMPARTICLE(s, MT_MPR5, 50, 14, -1, 16, SKINCOLOR_WHITE, 89355)
		A_SAMPARTICLE(s, MT_MPR4, 50, 22, -1, 8, SKINCOLOR_GREEN, 99999)
		A_SAMPARTICLE(s, MT_MPR4, 50, 11, -1, 8, SKINCOLOR_EMERALD, 94955)
		A_SAMPARTICLE(s, MT_MPR5, 40, 15, -1, 16, s.color, 98999)
		A_SAMPARTICLE(s, MT_MPR5, 50, 16, -1, 16, SKINCOLOR_WHITE, 93999)
		A_SAMPARTICLE(s, MT_MPR4, 50, 22, -1, 8, SKINCOLOR_GREEN, 99000)
		A_SAMPARTICLE(s, MT_MPR4, 50, 19, -1, 8, SKINCOLOR_EMERALD, 96000)
		A_SAMUSEXPLOSIONS(s, 12, MT_SAMMISSILESMOKE, 25<<16, 400000)
		A_SAMUSEXPLOSIONS(s, 26, MT_SAMMISSILESMOKE, false, 80000)
		S_StartSound(s, sfx_satkh)
	end
end
local function ScrewAttackParticles(s,p)
	if (leveltime % 2 == 0)
		local ghs = P_SpawnMobj(s.x, s.y, s.z+(s.height/2), MT_PBEXPANDW)
		if ghs
			ghs.blendmode = AST_ADD
			ghs.scale = $*P_RandomRange(1,3)
			ghs.scalespeed = $*P_RandomRange(1, 8)
			ghs.destscale = $*20
		end
		ghs = P_SpawnMobj(s.x+FixedMul(-150<<16, cos(s.angle)), s.y+FixedMul(-150<<16, sin (s.angle)), (s.z+(s.height/2))-(s.momz*2), MT_PBEXPAND)
		if ghs
			ghs.blendmode = AST_ADD
			ghs.scale = $*P_RandomRange(1,2)
			ghs.scalespeed = $*P_RandomRange(2, 4)
			ghs.destscale = $*25
			return ghs
		end
	else
		A_SAMPARTICLE(s, MT_MPR4, 35, 4, -4, 4, SKINCOLOR_GREEN, P_RandomRange(25355, 48355)+50000)
		local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPANDI)
		if ghs
			ghs.blendmode = AST_ADD
			ghs.scale = $*P_RandomRange(1,3)
			ghs.scalespeed = $*P_RandomRange(3, 9)
			ghs.destscale = $*25
			return ghs
		end
	end
end
--The start for the complex Screw Attack ability
SAM.ScrewAttackAbility = function(p,s)
	if p.sam_screwattack
		local STARTSA = 0
		if (p.cmd.buttons & BT_CUSTOM1) and not p.c1c2disable and (not p.sams_c1cd or p.sams_c1cd  == 1)
			STARTSA = "CUSTOM1"
		elseif (p.cmd.buttons & BT_JUMP) and (not p.sams_jumpcd or p.sams_jumpcd  == 1)
			STARTSA = "JUMP"
		end
		
		if STARTSA != 0
		and (p.pflags & PF_JUMPED)
		and not (p.sam_screwattacking or s.sam_screwattackfling)
		and not p.sams_morphcd and not p.powers[pw_nocontrol] 
		and not p.exiting and not p.gotflag
		and not p.sams_screwattackcd
			
			local DOSCREWATTACK
			if STARTSA == "JUMP"
				if not p.sam_j1ready
					if not p.sam_spacejump
					or p.sam_spacejump and p.sam_spacejumped 
					and not (p.sam_spacejumpedboost and (p.sam_spacejumpedboost > 4))
						p.sam_j1ready = 11
						p.sam_c1ready = 0
					end
				elseif p.sam_j1ready
					if (s.eflags & MFE_UNDERWATER) and not p.sam_gravitysuit==2
					or p.sam_gravitysuitjustgot
						S_StartSound(nil, sfx_sdenid, p)
					else
						DOSCREWATTACK = true
					end
				end
			else --if STARTSA == "CUSTOM1"
				if not p.sam_c1ready
					p.sam_c1ready = 11
					p.sam_j1ready = 0
					if s.sam_spbshack and not p.autospeedbooster --waa5
						s.sam_spbshack = 11
					end
				elseif p.sam_c1ready
					if (s.eflags & MFE_UNDERWATER) and p.sam_gravitysuit != 2
					or p.sam_gravitysuitjustgot
						S_StartSound(nil, sfx_sdenid, p)
					else
						DOSCREWATTACK = true
					end
				end
			end
			if DOSCREWATTACK
				p.sam_c1ready,p.sam_j1ready = 0,0
				p.sam_screwattacking = 1
				p.sams_jumpcd = 99
				s.sam_bufferjump = 0
				SamusTutorial(s, "screwattack", true)
				p.pflags = $ & ~PF_JUMPED
				p.prescrewcolor = s.color
				s.state = S_PLAY_ROLL
				P_SamFP(p, PAL_MIXUP, 2)
				S_StartSound(s, sfx_satkc)
							
				local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_THOK)
				ghs.sprite = SPR_MXP4
				ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.blendmode = AST_ADD
				ghs.frame = W|FF_TRANS10
				P_SetObjectMomZ(ghs, FRACUNIT, true)
				ghs.tics,ghs.fuse = 39,14
				ghs.color = SKINCOLOR_SUPERGOLD5
				ghs.colorized = true
				ghs.scalespeed = $*3
				ghs.destscale = $*99
				ghs.dispoffset = 3
				SAM_RemoveLDgrp(s)
			end
		end

		if (p.sam_screwattacking or s.sam_screwattackfling) and p.prescrewcolor
			s.tempsamdye = s.color
			s.tempsamdyetr = FF_TRANS10
			s.colorized = true
			s.color = P_RandomRange(SKINCOLOR_SUPERGOLD1, SKINCOLOR_SUPERPERIDOT5)
			p.noprimerun = 9
			s.sam_supertilt = 3
			p.pflags = $|PF_JUMPDOWN
			if not ((p.sam_screwattacking > 26) and s.crystalflashtime and (s.crystalflashtime % 2 == 0))
			p.sam_screwattacking = $+1
				if s.sam_waveoverload and (p.sam_screwattacking < 25)
				p.sam_screwattacking = 25
					local angshift = P_RandomRange(27,80)
					if leveltime % 2 == 0
						angshift = $*-1
					end
					s.angle = $+(angshift*ANG1)
				end
			end
			local ghs = P_SpawnGhostMobj(s)
			ghs.blendmode = AST_ADD
			ghs.destscale = ghs.scalespeed+1
			A_SAMPARTICLE(s, MT_MPR1, 30, 3, -3, 5, SKINCOLOR_SUPERGOLD4, 35000, true)
			A_SAMPARTICLE(s, MT_MPR1, 50, 4, -4, 6, SKINCOLOR_WHITE, 23000, true)
			p.sams_morphcd = 30
			p.sams_firecd = 0
			p.sams_shotcd = 35
			p.sams_mshotcd = 35
			
			if p.samspbschargefull or (p.samspbscharge > 140)
			or s.sam_screwattackspbs 
			or s.sam_screwattackfling and (s.sam_screwattackfling.speed > 60)
			or s.sam_spbshack and not p.autospeedbooster
				s.sam_afterboost = 7
				if s.sam_spbshack
					s.sam_spbshack = 11
				end
				s.sam_screwattackspbs = true
				p.samspbschargefull = false
			end
			p.samspbscharge = 0
			p.sam_spacejumped = true
			p.sams_supermissileready = 0
			if not (p.panim == PA_ROLL)
				s.state = S_PLAY_ROLL
			end			
			if (leveltime % 4 == 0)
			and ((p.sam_screwattacking < 44) or s.sam_screwattackfling)
				local ZHEIGHT = (s.eflags & MFE_VERTICALFLIP) and s.height*5/6 or s.height/6
				local ghs = P_SpawnMobjFromMobj(s,0,0,ZHEIGHT, MT_SAMUSZAP)
				ghs.blendmode = AST_ADD
				ghs.scale = (s.sam_screwattackfling) and $/2 or s.scale*30/41
				ghs.momx,ghs.momy,ghs.momz = s.momx,s.momy,s.momz
				ghs.color = s.color
				ghs.morning = 4
				if (p.sam_screwattacking > 24)
					ghs = P_SpawnMobjFromMobj(s, 0,0,(s.height/6)*P_MobjFlip(s), MT_SAMUSZAP)
					ghs.scale = (s.sam_screwattackfling) and $*2/3 or $
					ghs.color = s.color
					ghs.morning = 4
				end
			end

		--Wallfling Screw Attack Launch!

			if s.sam_screwattackfling
				local yu = s.sam_screwattackfling
				yu.timer = $+1
				p.powers[pw_noautobrake] = 2
				p.sam_screwattacking = 30
				s.spriteyscale = FRACUNIT
				s.spritexscale = FRACUNIT						
				s.sam_flashfade = 4
				s.sam_flashfadecolor = SKINCOLOR_SUPERGOLD3
				if (yu.timer < 4)
					local ghs = ScrewAttackParticles(s,p)
					if ghs and ghs.valid
					ghs.flags2 = $|MF2_SHADOW
					end
					if yu.speedboosted
						P_Thrust(s, yu.angle, 15000)
					end
				end
				S_StopSoundByID(s, sfx_swljp)
				if not yu.chainsaw
					S_StartSound(s, sfx_satkrl)
				end							
				if yu.speedboosted
					SAM.SpeedBoosterGhosts(s, p)
					if leveltime % 2 == 0
						s.color = SKINCOLOR_SKY
					end
				end
				if not P_IsObjectOnGround(s)
				yu.momz = s.momz
					if (p.cmd.buttons & BT_SPIN) and not (p.sams_usecd > 99000)
						s.spriteyscale = 74555
						s.spritexscale = 50010
						
						if (p.sams_usecd == 1) and not yu.diddive
							yu.walljumpavailable = false
							yu.diddive = true 
							S_StartSound(s, sfx_satkf)
							
							local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_THOK)
							ghs.fuse = 6
							ghs.scalespeed = $*3
							ghs.destscale = FRACUNIT*99
							ghs.sprite = SPR_ICXP
							ghs.frame = E|FF_TRANS20|FF_FULLBRIGHT
							ghs.color = SKINCOLOR_RED

							if (s.momz*P_MobjFlip(s) > 0)
								P_SetObjectMomZ(s, -8<<16, false)
							else
								P_SetObjectMomZ(s, -8<<16, true)
							end
							if (p.speed < 50*s.scale)
								P_InstaThrust(s, s.angle, 50<<16)
							else
								if p.speed > 70*s.scale
									P_Thrust(s, yu.angle, 27000)
								else
									P_Thrust(s, yu.angle, FRACUNIT*4)
								end
							end
							
							for d = 1,3
								local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_PBEXPANDW)
								if ghs
									ghs.scale = $*d
									ghs.blendmode = AST_ADD
									ghs.colorized = true
									ghs.color = SKINCOLOR_RED+1
									ghs.scalespeed = ($*3)*d
									ghs.destscale = $*99
									ghs.momx = s.momx*d ghs.momy = ghs.momy*d
									ghs.momz = 7<<16
								end
							end
						end
						local rng = P_RandomRange(-220,220)
						local ghs = P_SpawnMobjFromMobj(s,
						rng<<16,
						P_RandomRange(-220,220)<<16,
						8<<16, MT_SAMWINDLINE)
						ghs.scale = 35000+(rng*210)
						if leveltime % 2 == 0
							P_SetObjectMomZ(ghs, 20*ghs.scale)
							ghs.flags2 = $|MF2_SHADOW
							ghs.momx = s.momx ghs.momy = s.momy
						else
							ghs.momx = s.momx/2 ghs.momy = s.momy/2
							P_SetObjectMomZ(ghs, 16*ghs.scale+(rng*300))
						end
						ghs.rollangle = ANGLE_90
						ghs.blendmode = AST_ADD
						ghs.destscale = $*99
						ghs.fuse = (51+rng)/23							
						if leveltime % 2 == 0
							s.color = SKINCOLOR_RED
						end

						P_SetObjectMomZ(s, -41000, true)
						P_Thrust(s, s.angle, 19000)
							
					elseif (p.cmd.buttons & BT_JUMP)
					
						if yu.walljumpavailable
							if (s.eflags & MFE_UNDERWATER)
								P_SetObjectMomZ(s, 3800, true)
							else
								P_SetObjectMomZ(s, 10000, true)
							end
						
							if leveltime % 6 == 0
								local ghs = P_SpawnMobjFromMobj(s, 0, 0, s.momz*-1, MT_THOK)
								ghs.scale = 1
								ghs.spritexscale = 40000
								ghs.fuse = 9
								ghs.tics = 20
								ghs.sprite = SPR_HBXP
								ghs.frame = C|FF_TRANS70|FF_FULLBRIGHT
								ghs.destscale = FRACUNIT*99
								ghs.blendmode = AST_ADD
								ghs.color = s.color
								P_SetObjectMomZ(ghs, -5<<16)
							end
							if not (p.sams_jumpcd > 2)
								samwallcheck(s, p)
							end
						end
						
						s.momx = FixedDiv(FixedMul($, 70), 71)
						s.momy = FixedDiv(FixedMul($, 70), 71)
					end
					
					--Do regardless of button input...
					if (p.speed < yu.speed<<16)
						if yu.speedboosted
							P_Thrust(s, s.angle, FRACUNIT/4)
						end
						s.momx = FixedDiv(FixedMul($, 80), 79)
						s.momy = FixedDiv(FixedMul($, 80), 79)
					end
					
					
				else --if P_IsObjectOnGround(s) on the ground checks.
					
					if not (p.powers[pw_carry])
						p.pflags = $|PF_JUMPDOWN
					end
					
					--Cancel conditions
					if not ((p.cmd.buttons & BT_SPIN) or yu.chainsaw)
					or (p.speed < 22*s.scale)
					
						p.speed = 5
						if yu.chainsaw or (yu.momz*P_MobjFlip(s) < -25<<16)
							ScrewAttackBonk(s,p)
						else
							CancelScrewAttack(s,p)
							S_StartSound(s, sfx_skid)
							if (p.speed > 39*s.scale) and (p.samspbscharge < 50)
								p.samspbscharge = 50
							end
						end
						
					else --Chainsaw! Time to cut some grass. 
						if (p.cmd.buttons & BT_SPIN)
							s.spriteyscale = 74555
							s.spritexscale = 50010
							yu.diddive = false
							yu.timer = $+1000
							yu.walljumpavailable = false
							if (p.speed < 92<<16)
								if (s.eflags & MFE_JUSTHITFLOOR) 
									local smomz = abs(yu.momz)
									ScrewAttackLandingGFX(s,p)
									P_SamFP(p, PAL_RECYCLE, 2)
									P_NukeEnemies(s, s, 0)
									P_RadiusAttack(s, s, 290*s.scale)
									S_StartSound(s, sfx_s3k4e)
									if (p.speed < smomz) --Go faster the harder you land!
										P_InstaThrust(s, s.angle, (smomz*7/6))
									else
										P_Thrust(s, s.angle, 6<<16)
									end
								else
									s.friction = max($,FRACUNIT)
									P_Thrust(s, s.angle, 235355)
								end
							end										
							if not noquake --No quaking!		
								for z in players.iterate
									if z.mo
										if (FixedHypot(s.x-z.mo.x, s.y-z.mo.y) < 1000<<16)
											if quakestrength
											A_samquake(z.mo, quakestrength<<16, 1, 8)
											else
											A_samquake(z.mo, 22<<16, 1, 8)
											end
										end
									end
								end
							end
							local rng = P_RandomRange(-35,35)
							local ghs = P_SpawnMobjFromMobj(s, rng<<16,rng<<16,0, MT_METROIDDROOL)
							if ghs and ghs.valid
								ghs.state = S_ROCKCRUMBLEA
								ghs.scale = FRACUNIT*2/(P_RandomRange(2,6))
								ghs.momx = s.momx ghs.momy = s.momy
								P_Thrust(ghs, s.angle+(rng*ANG1), -30<<16)
								ghs.tics = 130
								ghs.flags = $|MF_NOCLIPTHING & ~MF_NOGRAVITY
								ghs.momz = FRACUNIT+(rng*(ghs.scale/20))
								ghs.omgrock = true
							end
							local ghs = ScrewAttackParticles(s,p)
							if ghs and ghs.valid
							ghs.flags2 = $|MF2_SHADOW
							end
							
							if (yu.timer > 50000) --Okay, stop!
							
								p.speed = 5
								P_SetObjectMomZ(s, 6<<16, true)
								ScrewAttackBonk(s,p)
								
							elseif not yu.chainsaw
							
							yu.chainsaw = true --We're a chainsaw now!
							p.sams_usecd = 99000
							
							elseif not (p.sams_usecd > 2) --Morph from the chainsaw roll?
								CancelScrewAttack(s,p)
								SamMorphSwitch(p, s)
								S_StartSound(s, sfx_smorph)
								S_StartSound(s, sfx_zoom)
								if p.sambsbl
									if (p.pflags & PF_DIRECTIONCHAR)
										p.drawangle = s.angle
									end
									p.sams_c1cdjlg = 0
									p.sams_firecdjlg = 0
									s.bsblboostcspeed = p.speed
									P_InstaThrust(s, s.angle, 90<<16)
									p.bsblboostangle = s.angle
									p.bsblboost = 9
									p.bsblboostattack = 18
									if s.samslopespin
										s.samslopespin = 1
									end
								end
							end
						elseif yu.chainsaw and (p.speed > 15*s.scale)
							s.momx = FixedDiv(FixedMul($, 5), 6)
							s.momy = FixedDiv(FixedMul($, 5), 6)									
						end
						if (p.cmd.buttons & BT_JUMP)
						and not (p.sams_jumpcd > 2)
						and P_IsObjectOnGround(s)
							p.speed = 120*s.scale
							CancelScrewAttack(s,p)
							P_DoJump(p, true)
							SpaceJumpGFX(s, SKINCOLOR_SKY, 2, L|FF_TRANS20)
							p.sam_walljumping = 13
							p.pflags = $|PF_JUMPED
							s.state = S_PLAY_ROLL
							if (p.speed > 40*s.scale)
								P_InstaThrust(s, R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy), 40<<16)
							end
							p.sam_spacejumped = false
							p.sams_jumpcd = 10
							p.sam_c1ready = 11
							p.sam_j1ready = 0
						end
					end
				end
				--Aww, no fun allowed.
				if (s.eflags & MFE_UNDERWATER)
				and not (p.sam_gravitysuit == 2)
					CancelScrewAttack(s,p)
					s.momx,s.momy,s.momz = $/2,$/2,$/2
					s.state = S_PLAY_SPRING
				end
				
		--Regular Screw Attack Launch!	
		
			elseif (p.sam_screwattacking < 25) --Screw Attack startup. Cancel start a walljump from here.
			
			
				p.pflags = $ & ~PF_JUMPED
				s.momx = (p.sam_screwattacking<3) and $/9 or $*20/21
				s.momy = (p.sam_screwattacking<3) and $/9 or $*20/21
				P_SetObjectMomZ(s, 55000)
				local maxfade = 7
				if not ((p.sam_screwattacking/4) > maxfade)
					maxfade = p.sam_screwattacking/4
				end
				s.sam_flashfade = maxfade
				s.sam_flashfadecolor = SKINCOLOR_SUPERGOLD5						
				if (p.cmd.buttons & BT_JUMP) and not (p.sams_jumpcd > 2)
					samwallcheck(s, p)
				end
				
			elseif (p.sam_screwattacking == 25) --Magic initiation frame
			
				p.sam_shinesparkdirect = s.angle
				p.sam_satkoriginalz = s.z
				S_StartSound(s, sfx_satkf)
				P_SamFP(p, PAL_MIXUP, 3)	
			
				if (p.cmd.buttons & BT_JUMP)
				or (((s.flags2 & MF2_TWOD) or twodlevel) and (p.cmd.forwardmove) > 0)
					p.aiming = 3600<<16*P_MobjFlip(s)
					p.samscrewedbefore = true
				elseif (p.cmd.buttons & BT_USE)
				or (((s.flags2 & MF2_TWOD) or twodlevel) and (p.cmd.forwardmove) < 0)
					p.aiming = -3600<<16*P_MobjFlip(s)
					p.samscrewedbefore = true
				end
			
				s.momz = $+FixedMul(FixedMul(45<<16, s.scale), sin(p.aiming))
				P_Thrust(s, s.angle, FixedMul(FixedMul(45<<16, s.scale), cos(p.aiming)))
				p.sam_screwattacking = 26
				if not (gametyperules & GTR_POINTLIMIT)
					P_RadiusAttack(s, s, 180<<16)
				end
				
			elseif (p.sam_screwattacking < 46) --In the middle of our big attack

				if (p.speed > 18*s.scale) --and (abs(s.momz) < 9*s.scale)
					local MINZ = -77*P_MobjFlip(s)
					local RNG1 = P_RandomRange(32, 255)
					local ADDSCALE = (p.sam_screwattacking<40) and 65000 or 0
					SAM.SpeedBoosterWindLines(s, RNG1*s.scale, 
					{XY = P_RandomRange(50, 198,s)*s.scale, EZ = P_RandomRange(77*P_MobjFlip(s),MINZ)*s.scale},
					(ADDSCALE) and FF_TRANS40 or (leveltime%2) and FF_TRANS50 or FF_TRANS60, 90000+(RNG1*750)+ADDSCALE,
					(RNG1/14)+5, (leveltime%3==0) and SKINCOLOR_SUPERGOLD3 or SKINCOLOR_MINT)
				end
			
				s.angle = p.sam_shinesparkdirect
				P_SetObjectMomZ(s, 12000, true)
				s.sam_flashfade = 4
				s.sam_flashfadecolor = SKINCOLOR_SUPERGOLD3

				if ((s.z > p.sam_satkoriginalz+185<<16) and not (s.eflags & MFE_VERTICALFLIP)) or ((s.z < p.sam_satkoriginalz-185<<16) and (s.eflags & MFE_VERTICALFLIP))
				and not s.crystalflashtime
					p.sam_screwattacking = 99
				end

			ScrewAttackParticles(s,p)
			
			elseif (p.sam_screwattacking >= 46) or p.gotflag --Okay, timer's up, cancel the Screw Attack.
				s.momx,s.momy = $/5,$/5
				s.momz = (s.momz*P_MobjFlip(s) > -2<<16) and $/17 or $/5
				if not (p.powers[pw_carry] == CR_MACESPIN) and not p.sammorphed
					s.state = S_PLAY_FALL
				end
				CancelScrewAttack(s,p)
			end
			--Global situations in which to cancel.
			if p.powers[pw_carry]
			or (p.panim == PA_PAIN) or (s.state == S_PLAY_RIDE)
				CancelScrewAttack(s,p)
			elseif ((p.sam_screwattacking > 26) and not s.sam_screwattackfling) or p.gotflag
				ScrewAttackBonk(s,p)
			end
		end
	elseif p.sam_screwattacking
		CancelScrewAttack(s,p) --Don't be screwattacking without the powerup now...
	end
end

--Zero Mission and Fusion started this one, but no reason 3D games can't use it.
SAM.PowerGripAbility = function(p,s)
	if not (s.sam_pwgrp and s.sam_pwgrp.valid)
		s.sam_pwgrp = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_PWGRPLD)
	end
	if not (s.sam_pwgrpS and s.sam_pwgrpS.valid)
		s.sam_pwgrpS = P_SpawnMobj(s.x, s.y, s.z, MT_PWGRPLD)
	end
	
	if s.sam_pwgrp and s.sam_pwgrp.valid
	and s.sam_pwgrpS and s.sam_pwgrpS.valid
	
		s.sam_pwgrp.flags2 = $|MF2_DONTDRAW
		s.sam_pwgrp.target = s
		s.sam_pwgrp.scale = s.scale
		s.sam_pwgrp.tics = 3 
		s.sam_pwgrp.fuse = 3
	
		if (s.eflags & MFE_VERTICALFLIP)
			P_SetOrigin(s.sam_pwgrp, s.x, s.y, s.z-(s.height*5/3))
			s.sam_pwgrp.eflags = $|MFE_VERTICALFLIP
		else
			P_SetOrigin(s.sam_pwgrp, s.x, s.y, s.z+(s.height*5/3))
			s.sam_pwgrp.eflags = $ & ~MFE_VERTICALFLIP
		end
		
		s.sam_pwgrpS.flags2 = $|MF2_DONTDRAW
		s.sam_pwgrpS.target = s
		s.sam_pwgrpS.scale = FRACUNIT
		s.sam_pwgrpS.tics = 3
		s.sam_pwgrpS.fuse = 3
	
		if (s.eflags & MFE_VERTICALFLIP)
			P_SetOrigin(s.sam_pwgrpS, s.x, s.y, s.z-(s.height*5/4))
			s.sam_pwgrpS.eflags = $|MFE_VERTICALFLIP
		else
			P_SetOrigin(s.sam_pwgrpS, s.x, s.y, s.z+(s.height*5/4))
			s.sam_pwgrpS.eflags = $ & ~MFE_VERTICALFLIP
		end

		if (s.momz*P_MobjFlip(s) < -(s.scale*2/3))
		or ((p.cmd.buttons & BT_JUMP) and (p.sams_jumpcd == nil or p.sams_jumpcd < 11) and not ((p.pflags & PF_STARTJUMP) and s.momz*P_MobjFlip(s) > 0) )
		
			if ((p.cmd.forwardmove > 38) or (p.pflags & PF_ANALOGMODE) and (abs(p.cmd.sidemove) > 25 or abs(p.cmd.forwardmove) > 25) )
			and (p.panim != PA_PAIN)
			and not (P_IsObjectOnGround(s) or s.sam_ldclmb or p.powers[pw_carry] or p.sam_shinespark)
			and not (p.pflags & (PF_SPINNING|PF_STARTDASH|PF_SLIDING|PF_FULLSTASIS|PF_JUMPSTASIS))
			and not (s.sam_automob and s.sam_automob.valid)
			and not p.exiting
			and not p.beampain
			and not p.sam_shinesparkfly 
			and not s.crystalflashanim 
			and not p.sam_intoship
			and not p.sam_screwattacking
			and not s.sam_screwattackfling

			local ledgeang = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))	
		
				if ((s.flags2 & MF2_TWOD) or twodlevel) 
					if (p.cmd.sidemove > 0) 
						ledgeang = 0
					else
						ledgeang = ANGLE_180
					end
				end
				
				P_TryMove(s.sam_pwgrp, s.x+FixedMul(28*s.scale, cos(ledgeang) ), s.y+FixedMul(28*s.scale, sin (ledgeang) ), true)
				if (s.eflags & MFE_VERTICALFLIP)
					if ( (s.sam_pwgrp.z+31*s.scale) > s.sam_pwgrp.ceilingz)
						s.sam_pwgrp.z = s.sam_pwgrp.ceilingz
					else
						s.sam_pwgrp.z = $+(31*s.scale)
					end
				else
					if ( (s.sam_pwgrp.z-31*s.scale) < s.sam_pwgrp.floorz)
						s.sam_pwgrp.z = s.sam_pwgrp.floorz
					else
						s.sam_pwgrp.z = $-(31*s.scale)
					end
				end
				
				P_TryMove(s.sam_pwgrpS, s.x+FixedMul(36<<16, cos(ledgeang) ), s.y+FixedMul(36<<16, sin (ledgeang) ), true)
				if (s.eflags & MFE_VERTICALFLIP)
					if ( (s.sam_pwgrpS.z+56<<16) > s.sam_pwgrpS.ceilingz)
						s.sam_pwgrpS.z = s.sam_pwgrpS.ceilingz
					else
						s.sam_pwgrpS.z = $+(56<<16)
					end
				else
					if ( (s.sam_pwgrpS.z-56<<16) < s.sam_pwgrpS.floorz)
						s.sam_pwgrpS.z = s.sam_pwgrpS.floorz
					else
						s.sam_pwgrpS.z = $-(56<<16)
					end
				end
			end
		end
	end
end

SAM.CheckForShineSpark = function(s, p) --Enter the shinespark state?
	local TWOD = (twodlevel or (s.flags2 & MF2_TWOD)) and true or false
	if not TWOD
		if not p.skidtime
			return false --
		end
	elseif not (p.cmd.forwardmove < -9)
		return false --
	end
	
	if (p.sam_energy and p.sam_energy > 29)
 	and not s.samspinpadconfirmed
		p.samspbscharge = 0
		p.sampbschargefull = false
		s.ghs = P_SpawnMobj(s.x, s.y, s.z, MT_EXPLODE)
		s.ghs.scale = s.scale
		p.bsblboost = 0
		p.bsblboostattack = 0
		p.sam_shinespark = 80
		S_StartSound(s, sfx_sprnp)
		if TWOD
			p.pflags = $ & ~PF_SPINNING
			P_InstaThrust(s, s.angle, 0)
			p.powers[pw_nocontrol] = $+4
		else
			P_InstaThrust(s, s.angle, FixedMul(9<<16, s.scale))
		end
		return true --
	end return false --
end
--Shinespark behaviour
SAM.ShineSparkAbility = function(p,s)
	if p.sam_shinespark and (p.samspbs or s.crystalflashtime)
		if (p.sam_shinespark % 16 == 0)
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPANDI)
			if ghs and ghs.valid
				ghs.color = SKINCOLOR_AZURE
				ghs.scale = s.scale+5<<16
				ghs.momz = s.momz*10/11
				ghs.momy = s.momy*10/11
				ghs.momx = s.momx*10/11
				ghs.scalespeed = $*11
				ghs.destscale = $*45
			end
		end

		if ( ( (p.sam_shinespark % 2 == 0)
		or p.sam_shinespark == 1) )
		and not s.crystalflashtime
			s.flags2 = $ & ~MF2_DONTDRAW
				s.speedghost = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_OVERLAY)
				s.speedghost.target = s
				s.speedghost.skin = s.skin
				s.speedghost.sprite = s.sprite
				s.speedghost.sprite2 = s.sprite2
				s.speedghost.frame = s.frame|FF_TRANS50|FF_FULLBRIGHT
				s.speedghost.angle = s.angle
				s.speedghost.tics = 2
				s.speedghost.scale = s.scale
				s.speedghost.flags2 = s.flags2
				s.speedghost.eflags = s.eflags
				if s.crystalflashtime
				s.speedghost.color = SKINCOLOR_SUPERSILVER1
				else
				s.speedghost.color = SKINCOLOR_SUPERSKY3
				end
				s.speedghost.colorized = true
				
				if (s.eflags & MFE_VERTICALFLIP)
				s.speedghost = P_SpawnMobj(s.x, s.y, s.z-s.height*5/13, MT_THOK)
				else
				s.speedghost = P_SpawnMobj(s.x, s.y, s.z, MT_THOK)
				end
				s.speedghost.skin = s.skin
				s.speedghost.sprite = s.sprite
				s.speedghost.sprite2 = s.sprite2
				s.speedghost.frame = s.frame|FF_TRANS40|FF_FULLBRIGHT
				s.speedghost.angle = s.angle
				s.speedghost.tics = 4
				s.speedghost.scale = s.scale
				s.speedghost.flags2 = s.flags2
				s.speedghost.eflags = s.eflags
				s.speedghost.colorized = true
				if s.speedghost and s.speedghost.valid and ( ((P_RandomRange(1, 2)) == 2) or s.crystalflashtime)
					s.speedghost.color = SKINCOLOR_WHITE
				elseif s.speedghost and s.speedghost.valid
					s.speedghost.color = SKINCOLOR_SUPERSKY3
				end
				
			if s.crystalflashtime
			A_SAMPARTICLE(s, MT_MPR1, 30, 3, -2, 3, SKINCOLOR_SUPERRED2, 36000, true)
			else
			A_SAMPARTICLE(s, MT_MPR1, 30, 3, -2, 3, SKINCOLOR_BLUE, 36000, true)
			end

		elseif not (p.sam_shinespark % 2 == 0)
			s.flags2 = $|MF2_DONTDRAW
		end

		if (p.sam_energy > 29)
		and not ((p.pflags & PF_SLIDING) or (s.state == S_PLAY_PAIN))
		and not p.gotflag
		and not ((s.eflags & MFE_UNDERWATER) and not (p.sam_gravitysuit == 2))
			if ((p.cmd.buttons & BT_JUMP) and (p.pflags & PF_JUMPED))
			and not ((p.cmd.sidemove) or (p.cmd.forwardmove))
			and not ( ((p.sams_jumpcd > 9) and (p.pflags & PF_ANALOGMODE)) or ((p.sams_jumpcd > 1) and not (p.pflags & PF_ANALOGMODE)) )
			p.samspbscharge = 0
			p.sampbschargefull = false
			p.sam_shinespark = 0
			p.sam_shinesparkfly = 1
			S_StartSound(s, sfx_spbsc)
			local ghs = P_SpawnMobj(s.x, s.y, s.z+((s.height*3/5)*P_MobjFlip(s)), MT_PBEXPAND)
			ghs.scale = s.scale*2
			ghs.scalespeed = $*9
			ghs.destscale = s.scale*25
			if s.plexpand and s.plexpand.valid
			s.plexpand.state = S_NULL
			end
			end
		end
	end
	if p.sam_shinesparkfly
	and not ((p.pflags & PF_SLIDING) or (s.state == S_PLAY_PAIN))
			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

		if (p.sam_shinesparkfly < 18)
		p.pflags = $ & ~PF_JUMPED
		s.momx = 0
		s.momy = 0
		P_SetObjectMomZ(s, 155000)
		
		s.sam_flashfade = p.sam_shinesparkfly/4
		s.sam_flashfadecolor = SKINCOLOR_SAPPHIRE
			if (twodlevel or (s.flags2 & MF2_TWOD))
				p.sam_shinesparkdirect = s.angle
				if (p.cmd.forwardmove > 0) or not (p.cmd.sidemove)
				p.sam_shinesparkdirectz = 28<<16
				else
				p.sam_shinesparkdirectz = 0
				end
				if (p.cmd.sidemove)
				p.sam_shinesparkdirectx = 80<<16
				else
				p.sam_shinesparkdirectx = 0
				end
			else
				if ((p.cmd.forwardmove > 0) or ((p.pflags & PF_ANALOGMODE) and ((p.cmd.forwardmove) or (p.cmd.sidemove)) and not (p.cmd.buttons & BT_USE)))
				p.sam_shinesparkdirect = s.angle
				if p.sammorphed
				p.sam_shinesparkdirectx = FixedMul(FRACUNIT*140, s.scale)
				else
				p.sam_shinesparkdirectx = FixedMul(FRACUNIT*66, s.scale)
				end
				p.sam_shinesparkdirectz = 0 
				elseif (p.cmd.forwardmove < 0) or (p.cmd.buttons & BT_USE)
				p.sam_shinesparkdirect = s.angle
				if p.sammorphed
				p.sam_shinesparkdirectx = FixedMul(FRACUNIT*120, s.scale)
				else
				p.sam_shinesparkdirectx = FixedMul(FRACUNIT*57, s.scale)
				end
				p.sam_shinesparkdirectz = 25<<16
				else
				p.sam_shinesparkdirect = s.angle
				p.sam_shinesparkdirectx = 0
				p.sam_shinesparkdirectz = 38<<16
				end
			end
		elseif (p.sam_shinesparkfly == 18)
			P_SetObjectMomZ(s, p.sam_shinesparkdirectz*p.sampers)
			s.angle = p.sam_shinesparkdirect
			P_InstaThrust(s, p.sam_shinesparkdirect, p.sam_shinesparkdirectx)
			P_SpawnGhostMobj(s)
			p.pflags = $|PF_JUMPED & ~PF_STARTJUMP
			P_SamFP(p, PAL_MIXUP, 3)
			s.sam_flashfade = 11
			s.sam_flashfadecolor = SKINCOLOR_RED				
			S_StartSound(s, sfx_s3k4e)
			S_StartSound(s, sfx_sprnsp)
		elseif (p.sam_shinesparkfly > 18)
		--Point Blank explosion range		
			if not G_GametypeHasSpectators() 
				if (p.sam_shinesparkfly < 21)
				P_RadiusAttack(s, s, 280<<16)
				else
				P_RadiusAttack(s, s, 100<<16)
				end
			elseif (p.sam_shinesparkfly < 20)
				for z in players.iterate
					if z and z.mo and (FixedHypot(FixedHypot((s.x+s.momx)-z.mo.x, (s.y+s.momy)-z.mo.y), s.z-z.mo.z) < 170<<16)
					and not ((G_GametypeHasTeams() and (p.ctfteam == z.ctfteam)) or (z.mo == s))
					P_DamageMobj(z.mo, s, s)
					s.angle = R_PointToAngle2(s.x, s.y, z.mo.x, z.mo.y)
					p.sam_shinesparkstop = 5
					end
				end
			end
			if leveltime % 2 == 0		
				s.tempsamdye = SKINCOLOR_RED
			else
				s.tempsamdye = SKINCOLOR_ORANGE
			end
			s.tempsamdyetr = FF_TRANS10
			if ( ( (p.speed < FixedMul(39<<16, s.scale) ) and (p.sam_shinesparkdirectx != 0) and not p.sammorphed) or ( p.sammorphed and (p.speed < 60<<16 ) and (p.sam_shinesparkdirectx != 0)) )
			or ( ( (p.sam_shinesparkdirectz < 0) and (s.momz > FixedMul(p.sam_shinesparkdirectz, s.scale)+FixedMul(11<<16, s.scale)) ) or ( (p.sam_shinesparkdirectz > 0) and (s.momz < FixedMul(p.sam_shinesparkdirectz, s.scale)-FixedMul(11<<16, s.scale)) ) )
			or (p.sam_energy <= 29) 
			or p.powers[pw_carry]
				if p.sam_shinesparkstop == nil
					p.sam_shinesparkstop = 0
				end
				if (p.sam_shinesparkstop > 3)
					p.sam_spacejumped = false
					p.sam_shinesparkfly = 0
					p.sam_shinespark = 0
					s.flags = $ & ~MF_BOUNCE
					P_RadiusAttack(s, s, 300<<16)
					s.momx = 0
					s.momy = 0
					p.sam_shinesparkstop = 0
					s.state = S_PLAY_FALL
					P_SetObjectMomZ(s, 4<<16*p.sampers)
					P_SamFP(p, PAL_NUKE, 2)
					S_StartSound(s, sfx_sprnh)
					if s.sam_deathball
						local sdb = P_SpawnMobj(s.x, s.y, s.z, MT_SAMSUPERMISSILE)
						if sdb and sdb.valid and sdb.health
							sdb.target = s
							sdb.scale = 2<<16
							P_ExplodeMissile(sdb)
						end
					end
					if not p.powers[pw_flashing] 
					p.powers[pw_flashing] = 30 
					end	
				else
					if (s.z > s.floorz+20<<16)
						p.sam_shinesparkstop = $+5
					else
						p.sam_shinesparkstop = $+1
					end
				end
			end
		end
		if (p.sam_shinesparkfly > 18) and not (leveltime%2==0)
			SAM.AttractPickUps(s, 750<<16, 4)
			P_SetObjectMomZ(s, p.sam_shinesparkdirectz*p.sampers)
			s.angle = p.sam_shinesparkdirect
			p.powers[pw_nocontrol] = 2
			P_InstaThrust(s, p.sam_shinesparkdirect, p.sam_shinesparkdirectx)
			P_SpawnGhostMobj(s)
			if not p.sam_shinesparkdirectx
				local ZOFFSET = FixedMul(s.height*5/7,s.scale)*P_MobjFlip(s)
				for i = -1,1,2
					local ghs = P_SpawnMobj(
					s.x+FixedMul(-25<<16, cos(s.angle+(ANG10+ANG2*i))), 
					s.y+FixedMul(-25<<16, sin (s.angle+(ANG10+ANG2*i))), 
					s.z+ZOFFSET, MT_SAMCHARGEGFX)
					ghs.scale = s.scale/SAM.RNG(s,10-(i*2),20+i)
					ghs.color = SKINCOLOR_SKY
					ghs.momx,ghs.momy = s.momx/2,s.momy/2
				end
			else
				if not p.sammorphed
					s.sams_shineframe = 5
					s.tics = 3
				end							
				local ghs = P_SpawnMobj(s.x, s.y, s.z+((s.height/2)*P_MobjFlip(s)), MT_PBEXPANDW)
				ghs.scale = s.scale*2
				ghs.scalespeed = $*(P_RandomRange(2,10))
				ghs.destscale = s.scale*25
			end
			if not (p.sam_energy <= 29) and not (p.exiting or (p.pflags & PF_FINISHED))
				if SAMUSDIFFICULTY == 2
					if (leveltime % 5 == 0) --In Fusion Mode your energy drains slower. An actually positive effect!
						p.sam_energy = $-1
					end
				else
					p.sam_energy = $-1
				end
			end
			if (p.speed >= FixedMul(33<<16, s.scale)) and (s.z == s.floorz)
				if p.sammorphed and not s.morphedmachactive
					P_InstaThrust(s, s.angle, 75<<16)
					s.smmachball = p.speed
					s.smmachballspbs = true
				else
					s.state = S_PLAY_WALK
					p.normalspeed = 75<<16						
				end
				p.sam_shinesparkfly = 0
				p.sam_shinesparkstop = 0
				p.sam_shinespark = 0
				p.samspbscharge = 250
				p.sampbschargefull = true
			end
		end
	end
end

--MockBallAbility, A Super Metroid callback!
SAM.MachBallExploit = function(p,s)
	if s.smmachball 
		if (s.smmachball < 38<<16)
		s.smmachballwait = 0
		s.smmachball = 0
		s.smmachballspbs = false
		
		elseif p.sammorphed 
		and (((s.eflags & MFE_JUSTHITFLOOR) 
		or (((s.z < s.floorz+30<<16) and not (s.eflags & MFE_VERTICALFLIP)) or ((s.z > s.ceilingz-30<<16) and (s.eflags & MFE_VERTICALFLIP)))
		and (s.momz*P_MobjFlip(s) < 2<<16) and not P_IsObjectOnGround(s)))	
		
		s.morphedmachspeed = s.smmachball
		s.morphedmachactive = true
		s.smmachball = 0
		s.smmachballwait = 0
		s.initialmockbspeed = p.speed
		s.smmachballpw = 0
		P_Thrust(s, s.angle, 20<<16) --initial boost!
		P_NukeEnemies(s, s, 0)
		S_StartSound(s, sfx_sballf)
			for d = -4,4
				local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PARTICLE)
				P_Thrust(ghs, s.angle+ANGLE_45*d, 10<<16) 
				ghs.fuse = 10
			end
		end
		
		if not s.smmachballwait
			s.smmachballwait = s.smmachballwait and $+1 or 1
		elseif s.smmachballwait > 3 --We'll give you a 4 tic window! Slightly higher than Super Metroid's.
			s.smmachballwait = 0
			s.smmachball = 0
			s.smmachballspbs = false
		elseif s.smmachballwait
			s.smmachballwait = $+1		
		end
	elseif s.smmachballwait
		s.smmachballwait = 0
	end
	if s.morphedmachspeed and s.morphedmachactive					
	
		if p.samspbs and s.smmachballspbs
			if SAM.CheckForShineSpark(s, p)
				s.morphedmachspeed = 0
				s.morphedmachactive = false
			end
		end
		
		p.normalspeed = s.morphedmachspeed*14/9
		
		if p.samspbs and s.smmachballspbs
			p.samspbscharge = 250
			p.sampbschargefull = true
		end

		if (p.speed < (s.initialmockbspeed/2)) or (p.pflags & PF_STARTJUMP) or P_PlayerInPain(p)
		or p.powers[pw_carry] or p.bsblboost // or (p.cmd.sidemove == 0 and p.cmd.forwardmove == 0) 
			s.morphedmachspeed = 0			
			s.smmachballpw = 0
		else 
			if (p.speed > 38<<16)
				if s.smmachballpw
					s.smmachballpw = $-1
					s.omegarushpanic = 2
					local ghs = P_SpawnMobj(s.x, s.y, s.z+((s.height/2)*P_MobjFlip(s)), MT_PBEXPANDW)
					ghs.scale = s.scale*P_RandomRange(2,4)
					ghs.scalespeed = $*(P_RandomRange(1,20))
					ghs.destscale = $*25
				end
				if p.samspbs and s.smmachballspbs
					SAM.SpeedBoosterGhosts(s, p)
				else
					local ghs = P_SpawnGhostMobj(s)
					ghs.tics = 3
					ghs.color = (leveltime % 2 == 0) and SKINCOLOR_WAVE or SKINCOLOR_GREY				
					ghs.colorized = true
				end
			end
		end
	end
end

--Metroid Prime style Lock On Behaviour. Practically required in 3rd person or if using a controller.
SAM.LockOnAbility = function(p,s)
	if p.sam_lockonpower and not (p.sam_lockontoggle and s.sam_automob and s.sam_automob.valid)
	and ( p.sams_c1cd == 1 and (p.cmd.buttons & BT_CUSTOM1) and p.sam_lockonpower == 1
	or (p.cmd.buttons & BT_CUSTOM3) and not p.sams_c3cd )
		if not p.powers[pw_nocontrol] and not p.exiting and not p.sam_screwattacking and not p.beampain
		and not p.sam_shinesparkfly and not s.crystalflashanim and not p.sam_intoship
			s.sam_lockseek = 3
			s.sam_lockchosen = nil
			s.sam_automob = nil
			s.sam_lockedon = false
			for d = 1,12
				s.sam_lock = P_SpawnMobj(s.x+FixedMul((600<<16)*d, cos(s.angle)),s.y+FixedMul((600<<16)*d, sin(s.angle)), s.z, MT_SAMUSLOCKSEEK)
				if s.sam_lock and s.sam_lock.valid
					s.sam_lock.tics = 1
					s.sam_lock.target = s
					s.sam_lock.flags2 = $|MF2_DONTDRAW
				end					
			end
		end
	elseif s.sam_lockseek
		s.sam_lockseek = $-1
		if s.sam_lockchosen 
			if s.sam_lockchosen.valid 
				if P_CheckSight(s, s.sam_lockchosen)
					s.sam_automob = s.sam_lockchosen
					s.sam_lockchosen = nil
					s.sam_lockedon = true
					s.sam_lockseek = 3
					s.sam_sighttime = 0
					s.sam_faillock = false
					SamusTutorial(s, "lockon", true)
					if p.sam_lockontoggle
						p.sams_c1cd = 4
						p.sams_c3cd = p.sams_c3cd or 1
					end
				end
			else
				s.sam_lockchosen  = nil
			end
		end
		--Here's our target, let's do behaviour.
		if s.sam_automob and s.sam_automob.valid
			local t = s.sam_automob	
			if t.player
				t.sam_automobed = 3
			end
			
			--Cursor
			if not (p.automobf and p.automobf.valid)
				p.automobf = P_SpawnMobj(t.x, t.y, t.z+t.height/6, MT_SAMUSLOCKGFX)
				p.automobf.scale = max(5000, (t.height/24)*3)
				p.automobf.scalespeed = (t.height/300)*4
				p.automobf.color,p.automobf.colorized = SKINCOLOR_SKY,true
				S_StartSound(s, sfx_samtm8)
				if s.sam_automob.player
					S_StartSound(nil, sfx_samtm8, s.sam_automob.player)
				end
			end
			
			if (p.automobf and p.automobf.valid)
				p.automobf.sprite = SPR_MPR1
				local DESTSCALE = max(99, min(FRACUNIT*16,t.height/24) )
				if p.automobf.scale != DESTSCALE
					p.automobf.frame = (Z+1)|FF_TRANS60|FF_FULLBRIGHT
					p.automobf.destscale = DESTSCALE
				else
					p.automobf.frame = (Z+1)|FF_TRANS40|FF_FULLBRIGHT
				end
				p.automobf.rollangle = $+ANG20
				p.automobf.tics = 3
				P_MoveOrigin(p.automobf, t.x, t.y, t.z)
				s.sam_beamroll = 0
			end
			
		--Aiming adjustment.
			if p.sam_lockontoggle
				if ( (((p.cmd.buttons & BT_CUSTOM1) and not (p.sams_c1cd and p.sams_c1cd > 2)) and p.sam_lockonpower == 1)
				or ((p.cmd.buttons & BT_CUSTOM3) and not p.sams_c3cd) )
					s.sam_faillock = true
				else
					s.sam_lockseek = 3
				end
			else
				if ((p.cmd.buttons & BT_CUSTOM1) and p.sam_lockonpower == 1)
				or (p.cmd.buttons & BT_CUSTOM3) --Continue lock on
					s.sam_lockseek = 3
				end
			end
			
			--Vertical aiming

			p.aiming = R_PointToAngle2(0, 0, R_PointToDist2(s.x, s.y, t.x, t.y), ((t.z+(t.height/5)) - s.z)	)					
			
			
			--The higher 2020 is, the more the aim vertically overcompensates. 
			if t.superbrak
			p.aiming = $+1500<<16
			end
			
			if p.aiming > 11500<<16 or p.aiming < -11500<<16
			or p.sam_screwattacking 
				s.sam_faillock = true
			else
			
				if (p.pflags & PF_ANALOGMODE)
				and not (p.pflags & PF_DIRECTIONCHAR)
					if not p.sam_forcedirectcharoff --old analogmode fix. console: directionchar 0, configanalog 1
					//	p.pflags = $ & ~PF_DIRECTIONCHAR & ~PF_ANALOGMODE
						SAM_COM_BufInsertText(p, "configanalog 1; directionchar 1")
					end
					p.sam_forcedirectcharoff = 2
				end
				if p.sam_forcedirectcharoff --Refresh infinitely.
					p.sam_forcedirectcharoff = 2
				end							
				s.angle = R_PointToAngle2(s.x, s.y, t.x, t.y)
				p.drawangle = s.angle
			end
			
		--Fail conditions	
			if (leveltime % 5 == 0) --periodic checks.
				local distcheck = FixedHypot(t.x-s.x, t.y-s.y)
				--Don't stay out of sight too long.
				if not P_CheckSight(s,t)
					s.sam_sighttime = s.sam_sighttime and $+2 or 2
				elseif s.sam_sighttime
					s.sam_sighttime = $-1
				end
				
				if (distcheck < 40<<16 or distcheck > 9000<<16)
				or (s.state == S_PLAY_PAIN) and not (p.pflags & PF_SLIDING)
				or p.powers[pw_nocontrol] or p.sammorphed
				or p.sam_shinesparkfly or s.crystalflashanim
				or s.sam_wavestunned or s.sam_systemreboot
				or s.sam_sighttime and s.sam_sighttime >= 17
				or ((t.flags & MF_MONITOR) and (t.flags2 & MF2_DONTDRAW))
				or (t.flags2 & MF2_FRET) and (t.flags & MF_BOSS) and not t.superbrak
					s.sam_faillock = true
				end
			end
		end
		if not s.sam_lockseek
		or s.sam_faillock
		or s.sam_automob and not s.sam_automob.valid
		or s.sam_automob and not s.sam_automob.health
			SAM.CancelLockOn(p,s) --
		end
	end
end

--Calculations for Samus' energy.
SAM.EnergySystem = function(p,s)
	local ENERGY = (p.sam_energy) or 0
	local LIMIT = 99+(p.sam_energytanks*50)
	if (ENERGY <= 0)
		p.sam_energy = 1
		p.sam_energytanks = 0
		p.sam_hudenergy = 0
	elseif (ENERGY <= 99)
		p.sam_energytanks = 0
		if not (p.sam_energy > LIMIT) 
			p.sam_hudenergy = p.sam_energy
		end
	elseif (ENERGY < 149)
		p.sam_energytanks = 1
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-100
		end
	elseif (ENERGY <= 199)
		p.sam_energytanks = 2
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-100
		end
	elseif (ENERGY <= 249)
		p.sam_energytanks = 3
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-200
		end
	elseif (ENERGY <= 299)
		p.sam_energytanks = 4
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-200
		end
	elseif (ENERGY <= 349)
		p.sam_energytanks = 5
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-300
		end
	elseif (ENERGY <= 399)
		p.sam_energytanks = 6
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-300
		end
	elseif (ENERGY <= 449)
		p.sam_energytanks = 7
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-400
		end
	elseif (ENERGY <= 499)
		p.sam_energytanks = 8
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-400
		end
	elseif (ENERGY <= 549)
		p.sam_energytanks = 9
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-500
		end
	elseif (ENERGY <= 599)
		p.sam_energytanks = 10
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-500
		end
	elseif (ENERGY <= 649)
		p.sam_energytanks = 11
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-600
		end
	elseif (ENERGY <= 699)
		p.sam_energytanks = 12
		if not (p.sam_energy > LIMIT)
			p.sam_hudenergy = p.sam_energy-600
		end
	end --Stop using the local ENERGY now.
	if (p.sam_energy <= 29) --Low Energy Alarm sound.
		if s.SAM_CanPlayAlarm
			s.SAM_CanPlayAlarm = max($-1,0)
			if not s.samemecd
				s.samemecd = 33
				S_StopSoundByID(s, sfx_sameme)
				if not p.exiting	
					if (s.SAM_CanPlayAlarm < 70) --Get progressively quieter.
						S_StartSoundAtVolume(s, sfx_sameme, (s.SAM_CanPlayAlarm<35) and 105 or 150)
					else
						S_StartSound(s, sfx_sameme)
					end
				end
			else
				s.samemecd = max($-1,0)
			end
		else
			s.SAM_CanPlayAlarm = nil
		end
	end
	p.sam_energytanksmax = min($,12) --12 max!	
	p.sam_energytanks = min($, p.sam_energytanksmax)
	
	if (p.sam_energy > (p.sam_energytanksmax*50)+99) 
		if p.sam_hyperbeam
			local ADD = (p.sam_energy-(p.sam_energytanks*50)-99) 
			if G_GametypeHasSpectators() and (p.sam_energy == (p.sam_energytanksmax*50)+100) 
				local TOTAL = 0
				for z in players.iterate
					if z and z.mo
						TOTAL = $+1
						if TOTAL > 4 break end --
					end
				end
				if TOTAL > 4
					ADD = 2
				end
			end
			p.sam_hyperbeamammo = min(99, $+ADD)
			p.sams_hbdenid = 33
		end
		p.sam_energy = 99+(p.sam_energytanksmax*50)
	end
	p.sam_hyperbeamammo = max(0, min(99, $))
end


SAM.SPCheatKit = function(p,s)
	if (p.cmd.buttons & BT_CUSTOM3) and (p.cmd.buttons & BT_CUSTOM2)
		if not netgame
			p.samspbs = true
			p.sambsbl = true
			p.sam_spiderball = true
			p.sam_highjump = true
			p.sam_bombs = true
			p.sam_spacejump = true
			p.sam_chargebeam = true
			p.sam_spazerbeam = true
			p.sam_wavebeam = true
			p.sam_icebeam = true
			p.sam_plasmabeam = true
			p.sam_powerbeamcombo = true
			p.sam_spazerbeamcombo = true
			p.sam_wavebeamcombo = true
			p.sam_icebeamcombo = true
			p.sam_plasmabeamcombo = true
			p.sam_gravitysuit = 2
			p.sam_screwattack = true
			p.sam_power_grip = true
			p.sam_gravitysuitjustgot = 75
			p.sammissiles = 100
			p.sammissilesmax = 100
			p.samsupermissiles = 10
			p.samsupermissilesmax = 10
			p.sampw = 5
			p.sampwmax = 5
			p.sam_energytanksmax = 12
			p.sam_energy = (p.sam_energytanksmax*50)-1
			p.samcheat = 30
			P_SamFP(p, PAL_MIXUP, 9)
			S_StartSound(s, sfx_mtnk)
		end
	elseif (p.cmd.buttons & BT_CUSTOM3) and not (p.cmd.buttons & BT_CUSTOM2)
		if not netgame
			p.samspbs = true
			p.sambsbl = true
			p.sam_bombs = true
			p.sam_spacejump = true
			p.sam_chargebeam = true
			p.sam_power_grip = true
			p.sam_powerbeamcombo = true
			p.sam_gravitysuit = 1
			p.sam_gravitysuitjustgot = 75
			p.sammissiles = 15
			p.sammissilesmax = 15
			p.samsupermissiles = 0
			p.samsupermissilesmax = 2
			p.sam_energytanksmax = 2
			p.sam_energy = (p.sam_energytanksmax*50)-1
			p.samcheat = 30
			P_SamFP(p, PAL_MIXUP, 9)
			S_StartSound(s, sfx_mtnk)
		end
	end
end

--Correct Samus' Shield Powerup.
local SAMUSSHIELDCORRECT = function(p,s, SHIELD)
	if SHIELD == 37|SH_PROTECTFIRE|SH_PROTECTSPIKE|SH_PROTECTWATER --SA-Sonic's Golden Shield!
		return false --Fine, you can have it.
	elseif SHIELD == SH_PITY
		if not (G_GametypeHasSpectators() and p.boxammospawns)
			local samRNG = P_RandomRange(1, 20)
			if (samRNG < 11)
				if (p.sammissilesmax < 25)
					P_SamFP(p, PAL_RECYCLE, 7)
					S_StartSound(s, sfx_mtnk)
					CONS_Printf(p, "You've obtained a bonus Missile Tank! Press FIRE to blast away!")
					p.sammissilesmax = $+5
					p.sammissiles = $+3
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_CRIMSON
					p.samitemgetname = "Missiles"
					p.samitemscale = 70000
				elseif not (p.sammissiles == p.sammissilesmax)
					S_StartSound(s, sfx_mpku)
					p.sammissiles = $+2
				end
			elseif (samRNG < 12)
				if not p.samsupermissilesmax
					P_SamFP(p, PAL_RECYCLE, 9)
					S_StartSound(s, sfx_spwup)
					CONS_Printf(p, "You've obtained a bonus Super Missile Tank! Hold C2/NormalFire, then release!")
					p.samsupermissilesmax = $+2
					p.samsupermissiles = $+1
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_CRIMSON
					p.samitemgetname = "Super Missiles"
					p.samitemscale = 95000
				elseif not (p.samsupermissiles == p.samsupermissilesmax)
					S_StartSound(s, sfx_mpku)
					p.samsupermissiles = $+1
				end
			elseif (samRNG < 13)
				if not (p.sampw == p.sampwmax)
					S_StartSound(s, sfx_mpku)
					p.samsupermissiles = $+1
				end
			elseif (samRNG < 14) and not p.sam_spacejump
				P_SamFP(p, PAL_RECYCLE, 9)
				CONS_Printf(p, "You've obtained a Bonus Space Jump! You can jump once more in midair.")
				S_StartSound(s, sfx_spwup)
				p.sam_spacejump = true
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_GREEN
				p.samitemgetname = "Space Jump"
				p.samitemscale = 81000
			elseif (samRNG < 16) and not p.sam_spazerbeam
				if not p.sam_spazerbeam
					P_SamFP(p, PAL_RECYCLE, 9)
					CONS_Printf(p, "You've obtained a Bonus Spazer Beam! The beam widens as it travels.")
					S_StartSound(s, sfx_spwup)
					p.sam_spazerbeam = true
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_BLACK
					p.samitemgetname = "Spazer Beam"
					p.samitemscale = 81000
				end
			elseif (samRNG < 17) and not p.sam_highjump
				if not p.sam_highjump
					P_SamFP(p, PAL_RECYCLE, 9)
					CONS_Printf(p, "You've obtained a Bonus Hi-Jump! You jump higher, AND unlock the spring ball!")
					S_StartSound(s, sfx_spwup)
					p.sam_highjump = true
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_GREEN
					p.samitemgetname = "High Jump"
					p.samitemscale = 70000
				end
			elseif (samRNG < 19) and not p.sam_wavebeam
				if not p.sam_wavebeam
					P_SamFP(p, PAL_RECYCLE, 9)
					CONS_Printf(p, "You've obtained a Bonus Wave Beam! The tricky beam bounces once.")
					S_StartSound(s, sfx_spwup)
					p.sam_wavebeam = true
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_BLACK
					p.samitemgetname = "Wave Beam"
					p.samitemscale = 77000
				end
			elseif (samRNG < 20) and not p.sam_icebeam
				if not p.sam_icebeam
					P_SamFP(p, PAL_RECYCLE, 9)
					CONS_Printf(p, "You've obtained a Bonus Ice Beam! This explosive beam freezes foes.")
					S_StartSound(s, sfx_spwup)
					p.sam_icebeam = true
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_BLACK
					p.samitemgetname = "Ice Beam"
					p.samitemscale = 74000
				end
			elseif not p.samspbs --(samRNG >= 20) and 
				if not p.samspbs
					P_SamFP(p, PAL_RECYCLE, 9)
					CONS_Printf(p, "You've obtained a Bonus Speed Booster! Hold C1 to Dash.")
					S_StartSound(s, sfx_spwup)
					p.samspbs = true
					p.samitemgettimer = 80
					p.samitemcolor = SKINCOLOR_GREEN
					p.samitemgetname = "Speed Booster"
					p.samitemscale = 99000
				end
			end
		end

	elseif SHIELD == SH_JUMP
		if not p.sam_spacejump
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained the Space Jump! Now you can jump once more in midair.")
			S_StartSound(s, sfx_spwup)
			p.sam_spacejump = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_GREEN
			p.samitemgetname = "Space Jump"
			p.samitemscale = 79000
		elseif not p.sam_icebeam
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained the Ice Beam! This explosive beam freezes foes.")
			S_StartSound(s, sfx_spwup)
			p.sam_icebeam = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_BLACK
			p.samitemgetname = "Ice Beam"
			p.samitemscale = 74000
		end

	elseif SHIELD == SH_ELEMENTAL
	
		if not p.sam_spazerbeam
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained the Spazer Beam! This beam spreads as it travels")
			S_StartSound(s, sfx_spwup)
			p.sam_spazerbeam = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_BLACK
			p.samitemgetname = "Spazer Beam"
			p.samitemscale = 83000
		end

	elseif SHIELD == SH_ATTRACT
		if not p.sam_wavebeam
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained the Wave Beam! This tricky beam bounces once and paralyzes foes.")
			S_StartSound(s, sfx_spwup)
			p.sam_wavebeam = true
		end

	elseif SHIELD == SH_BOMB
		if gamemap == 13 and p.samsupermissilesmax
			p.samsupermissiles = $+1
		else
			P_SamFP(p, PAL_MIXUP, 7)
			CONS_Printf(p, "You've obtained a Super Missile Tank! Shoot them by holding the FIRE button, then release!")
			S_StartSound(s, sfx_mtnk)
			p.samsupermissilesmax = $+2
			p.samsupermissiles = $+2
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_CRIMSON
			p.samitemgetname = "Super Missiles"
			p.samitemscale = 99000
		end
	elseif SHIELD == SH_FORCE or SHIELD == SH_FORCE+1 or (SHIELD == SH_FORCE|1)
		if not p.sam_chargebeam
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained the Charge Beam! Charge your arm cannon by holding C2/NormalFire!")
			S_StartSound(s, sfx_spwup)
			p.sam_chargebeam = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_BLACK
			p.samitemgetname = "Charge Beam"
			p.samitemscale = 82000
		elseif not p.sam_bombs
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained Bombs! Drop them in Morph Ball mode with C2/NormalFire!")
			S_StartSound(s, sfx_spwup)
			p.sam_bombs = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_BROWN
			p.samitemgetname = "Morph Bombs"
			p.samitemscale = 83000
		else
			P_SamFP(p, PAL_MIXUP, 7)
			S_StartSound(s, sfx_spwup)
			p.sammissilesmax = $+5
			p.sammissiles = $+5
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_CRIMSON
			p.samitemgetname = "Missiles"
			p.samitemscale = 70000
		end

	elseif (SHIELD & SH_FIREFLOWER)
		if not p.sam_plasmabeam
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained the Plasma Beam! This powerful mid-range beam pierces enemies!")
			S_StartSound(s, sfx_spwup)
			p.sam_plasmabeam = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_BLACK
			p.samitemgetname = "Plasma Beam"
			p.samitemscale = 84000

		elseif not p.samsupermissilesmax
			P_SamFP(p, PAL_MIXUP, 9)
			S_StartSound(s, sfx_spwup)
			CONS_Printf(p, "You've obtained Super Missiles! Hold FIRE, then release!")
			p.samsupermissilesmax = $+2
			p.samsupermissiles = $+2
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_CRIMSON
			p.samitemgetname = "Super Missiles"
			p.samitemscale = 99000
		elseif not p.sam_bombs
			P_SamFP(p, PAL_MIXUP, 9)
			CONS_Printf(p, "You've obtained Bombs! Drop them in Morph Ball mode with C2/NormalFire!")
			S_StartSound(s, sfx_spwup)
			p.sam_bombs = true
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_BROWN
			p.samitemgetname = "Morph Bombs"
			p.samitemscale = 81000
		else
			P_SamFP(p, PAL_MIXUP, 7)
			S_StartSound(s, sfx_mtnk)
			p.samsupermissilesmax = $+2
			p.samsupermissiles = $+2
			p.samitemgettimer = 80
			p.samitemcolor = SKINCOLOR_CRIMSON
			p.samitemgetname = "Super Missiles"
			p.samitemscale = 99000
		end
		s.color = p.skincolor
	end
end

--Samus doesn't use standard powerups. "PowerConvert" "Shieldconvert"
SAM.PowerUpConvert = function(p,s)
	local TOTAL = 0
	if p.powers[pw_automaticring] or p.powers[pw_scatterring] or p.powers[pw_bouncering]
	or p.powers[pw_explosionring] or p.powers[pw_railring] or p.powers[pw_grenadering]
		if p.sam_hyperbeam and (p.samchallenger and (p.samchallenger > 3))
			p.sammissiles = $+5*p.sam_ammodigitizer
		end
		if p.sam_hyperbeam and not (p.sam_hyperbeamammo >= 99)
		or (p.sammissiles >= p.sammissilesmax)
			P_GivePlayerRings(p, 1)
		else
			for z in players.iterate
				if z and z.mo TOTAL = $+1 if (TOTAL>7) break end end
			end
			local ADD = (TOTAL>6) and 2 or 1
			p.sammissiles = $+(ADD*p.sam_ammodigitizer)
			if p.buffbottomtier
				p.sammissiles = $+(ADD*p.sam_ammodigitizer)
			end
		end
		p.powers[pw_automaticring] = 0 p.powers[pw_scatterring] = 0 p.powers[pw_bouncering] = 0
		p.powers[pw_explosionring] = 0 p.powers[pw_railring] = 0 p.powers[pw_grenadering] = 0
	end
	if p.powers[pw_infinityring] or p.ringweapons
		if TOTAL == 0
			for z in players.iterate
				if z and z.mo TOTAL = $+1 if (TOTAL>7) break end end
			end
		end
		if p.sam_hyperbeam and not (p.sam_hyperbeamammo >= 99)
		or (p.sammissiles >= p.sammissilesmax)
			P_GivePlayerRings(p, 1)
		else
			local MORE = (p.powers[pw_infinityring]) and 3 or 2
			if (TOTAL>7) MORE = $*2 end
			p.sammissiles = $+(MORE*p.sam_ammodigitizer)
		end
		if (p.sammissiles < 6) and (TOTAL > 6)
			p.sammissiles = $+1*p.sam_ammodigitizer
		end
		if p.buffbottomtier --You get extra benefits to catch up.
			local ADD = (TOTAL > 0) and 1 or 0
			p.sammissiles = $+(2+ADD)*p.sam_ammodigitizer
			
			if not P_RandomRange(0,9) and not p.nosuperpowert
				if not p.sampwmax --Lucky dog....
					P_SamFP(p, PAL_MIXUP, 9)
					S_StartSound(s, sfx_spwup)
					CONS_Printf(p, "You've obtained a \x84Power Bomb!\x80 Hold C2/NormalFire as the Morph Ball, then release!")
					SamusTutorial(s, "pw")	
					p.sampwmax = 1
					p.sampw = p.sampwmax
					NewSamPickup(s, "PTNKD0", 55355)	
					ItemGetPopup(p, 80, SKINCOLOR_RED, "Power Bombs", 88355)
				else
					p.sampw = $+1
				end
			elseif p.samsupermissilesmax 
			
				p.samsupermissiles = (p.samsupermissiles) and $+(1+ADD) or 1+ADD
				
			else --Perhaps you not having Super Missiles is the reason you've fallen this far behind.
				--Likely the player joined late.
				P_SamFP(p, PAL_MIXUP, 9)
				CONS_Printf(p, "You've obtained \x84Super Missiles!\x80 Hold FIRE until it clicks, then release!")
				S_StartSound(s, sfx_spwup)
				SamusTutorial(s, "supermissiles")
				p.samsupermissilesmax = $+2
				p.samsupermissiles = p.samsupermissilesmax
				NewSamPickup(s, "STNKD0", 55355)	
				ItemGetPopup(p, 80, SKINCOLOR_CRIMSON, "Super Missiles", 105355)
			end
		end
		p.powers[pw_infinityring] = 0
		p.ringweapons = 0
	end

	if p.powers[pw_shield] and (SAMUSSHIELDCORRECT(p,s, SHIELD)) != false
		P_RemoveShield(p)
		p.powers[pw_shield] = SH_NONE
	end
end

--Unmorph from Morph Ball.
SAM.UnMorph = function(s, QUIET)
	local p = s.player
	if not p
	or (s and s.samspinpad and s.samspinpad < 5)
	or p.sugoigolfmode
	or (p.powers[pw_carry] == CR_ZOOMTUBE)
	or (p.powers[pw_carry] == CR_MACESPIN)
		return --
	end
	p.visorclosein = 15
	p.sammorphed = false
	p.sams_usecd = 9
	p.sams_morphcd = 35
	p.sams_notyet = 3
	p.sams_jumpcd = 10
	p.sams_firecd = 0
	p.sams_beamcombocharge = 0
	p.sams_shotcd = 22
	p.samspbschargefull = false
	p.sam_spacejumped = false
	p.samspbscharge = 0
	p.pflags = $ & ~(PF_STARTDASH|PF_SPINNING)
	p.sam_shinesparkstop = 0
	p.sambsblchargefull = false
	p.sams_supermissileready = 0
	
	local SKININFO = skins[s.skin]
	p.normalspeed = SKININFO.normalspeed
	p.acceleration = SKININFO.acceleration
	p.charflags = $ & ~SF_RUNONWATER
	
	s.samunmorphed = 4
	s.samslopespin = 0
	s.samunmx,s.samunmy,s.samunmz = s.x,s.y,s.z --Where we unmorphed.
	SamSpiderCharge(p, s, 103)
	s.sam_mbspeedf = nil
	s.friction = 59392 --This is the default SRB2 friction value. Slightly under FRACUNIT, which would be 0 friction.
	s.sambsblchargelvl = 0
	s.morphedmachactive = false
	s.morphedmachspeed = 0
	s.scale = max($, 90000) --I'm forgoing custom scales with Samus, but that's just how things be.	
	s.flags = $ & ~MF_BOUNCE
	s.momx,s.momy = $*5/8,$*5/8
	p.sam_framejump = 0
	
	if s.spiderbcharge
		s.spiderbcharge = min($,103)
	end
	if p.bsblboost and p.samspbs
		p.samspbscharge = 65
	end
	if s.sam_deathball
		p.sams_firecd = 99
	end
	if not QUIET
		S_StartSound(s, sfx_morphb)
		if SAM_FirstPerson(p, true)
		--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
			SAM_CMD(p, "nil", "true", "false", "15")	
		else
			SAM_CMD(p, "lol", "lol", "true", "lol")	
		end
	end	
	s.state = (P_IsObjectOnGround(s) or p.powers[pw_carry]) and S_PLAY_RUN or S_PLAY_FALL
	p.bsblboost = 0
	p.bsblboostattack = 0
	
	if s.samspinpad 
		s.samspinpad = 0
	end
		
	--We did it, bois! We finally stopped Samus getting stuck in walls when unscaling. Praise space jesus!
	if not (P_TryMove(s, s.x, s.y, false)) --If we can't move to the spot we're already in, then we're stuck in a wall!	
		for d = 1,18
			if (P_TryMove(s, 
				s.x+FixedMul(-20<<16, cos(ANG20*d)),
				s.y+FixedMul(-20<<16, sin (ANG20*d)), false)
				)
			return --We can just use return instead of break since it's the end of the function anyway!
			end
		end
	end	
end

--Entire Morph Ball code in 1 function.
SAM.MorphBall = function(p,s)
	p.powers[pw_noautobrake] = 2 --No autobrake with morphball. Preferably none in general, but enjoy your bad taste...
	
	if p.sam_screwattacking
		CancelScrewAttack(s,p)
	elseif s.sam_automob --Cancel lock on
		SAM.CancelLockOn(p,s)
	end

	--Do the rolling morphtrail		
	if (p.speed > 74*s.scale)
	or (p.speed >= 40*s.scale) and P_IsObjectOnGround(s)
	or (abs(s.momz) > 12*s.scale)
	or (p.pflags & PF_STARTJUMP) and (s.momz*P_MobjFlip(s)>0)
	or p.powers[pw_carry] and (p.powers[pw_carry] != CR_ZOOMTUBE)
		if s.prevz2 == nil
			s.prevz2 = s.z
		end
		SamMorphTrail(p, s, (p.sam_gravitysuit == 2) and p.samvisorcolor or SKINCOLOR_EMERALD)
		s.prevz2 = s.z
		s.morphtrailwait = s.morphtrailwait and $-1 or 0
		if (p.powers[pw_carry] == CR_MACESPIN)
			if (p.cmd.buttons & BT_JUMP) and p.sams_jumpcd == 1
			or (p.cmd.buttons & BT_SPIN) and p.sams_usecd == 2
				p.powers[pw_carry] = 0
				p.dragdownball = 20
			end
		end		
	else
		s.morphtrailwait = 2
	end
		
	if (p.pflags & (PF_STARTDASH|PF_SPINNING))
		if not s.samspinpad
		and not (p.charability2 == CA2_SPINDASH)  and not p.sugoigolfmode
			p.pflags = $ & ~(PF_STARTDASH|PF_SPINNING)	
		elseif (p.pflags & PF_SPINNING)
			if not (p.pflags & PF_STARTDASH) --Break stuff.`
				P_SpawnPlayerMissile(s, MT_SAMMONBREAKER)
				if s.minormorphboost 
					if s.minormorphboost != 1
						s.momx,s.momy = $*2,$*2 --Calling P_InstaThrust on purpose after this, not a mistake.
						P_InstaThrust(s, s.angle, s.minormorphboost) --Go really, really fast.
					else
						s.momx,s.momy = $*5/4,$*5/4
					end
					s.minormorphboost = 0
				end
			end
		end	
	end
	if (p.gotflag or not p.sam_highjump)
		if not (p.powers[pw_carry])
			p.pflags = $|PF_JUMPDOWN
		end
	end

	p.sampers = 2 --Adaptive multiplier to equal your speed in morph ball, since you're scaled around half size.
	
	if (s.sam_forcemorphslopeattach or s.sam_forcemorphslope)
		if not ((p.pflags & PF_JUMPED) or (p.cmd.buttons & BT_JUMP)) --waluigi
		and not (s.eflags & MFE_VERTICALFLIP)
			if not P_IsObjectOnGround(s)
				if p.powers[pw_justlaunched] and (s.momz > FRACUNIT) and s.sam_forcemorphslopeattach
					s.sam_mang,s.sam_mspd = nil,nil
					s.sam_forcemorphslopeattach,s.sam_forcemorphslope = 0,0
					if not p.bsblboost
						s.momx,s.momy = $*11/12,$*11/12
					end
					s.momz = $*3/4						
				elseif not (s.momz > 0)
				and not ((s.z-(p.speed+(15<<16))) > s.floorz) --The game's trying to kick us off. Force us back on.
					s.z = s.floorz 
					P_SetObjectMomZ(s, -2<<16, true)
				end
			else
				if s.sam_forcemorphslopeattach --Kill SRB2's attempts to glitch us.
				and s.sam_mspd and (p.speed < s.sam_mspd)
				and s.sam_mang != nil
				and not p.bsblboost
					s.z = s.floorz+4<<16
					P_InstaThrust(s, s.sam_mang, s.sam_mspd)
				end
			end
			--Remember what we were doing
			if s.standingslope and (p.speed > 33<<16) and not (s.standingslope.flags & SL_NOPHYSICS)
				s.sam_mang = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
				s.sam_mspd = p.speed
			else
				s.sam_mang,s.sam_mspd = nil,nil					
			end	
		end
	end

	//Make a little smokecloud and bounce when dropping from a height

	if P_IsObjectOnGround(s)
		//Specially designed to raise/lower spin-only platforms.
		if s.sam_falldmg
			s.sam_falldmg = 0 --Stop, pls.
		end
		if s.bombjump != 28
			s.bombjump = 0
			if not p.speed --Boostball chargeup on the spot, kind of like a spindash
			and not p.cmd.forwardmove and not p.cmd.sidemove			
				local FIREBUTTON = (p.swapfire) and BT_FIRENORMAL or BT_ATTACK
				if (p.cmd.buttons & BT_CUSTOM1) and not p.c1c2disable
				or (p.cmd.buttons & FIREBUTTON)
					p.pflags = $|PF_STARTDASH|PF_SPINNING
					p.speed = 32<<16
					p.drawangle = s.angle
				end
			end						
		end
		if (s.eflags & MFE_JUSTHITFLOOR) 
		and not (s.eflags & (MFE_TOUCHLAVA|MFE_GOOWATER|MFE_APPLYPMOMZ|MFE_SPRUNG))
			if s.morphbo and (s.morphbo < -8<<16*P_MobjFlip(s)) 
				if not p.bsblboost
				and not (s.morphedmachactive and s.smmachbal)
					if s.standingslope and (abs(s.standingslope.zdelta) > 6000)
						local MORPHBOOST = s.morphbo / (FRACUNIT*2*P_MobjFlip(s)*-1)
						P_Thrust(s, s.standingslope.xydirection, MORPHBOOST*(s.standingslope.zdelta*P_MobjFlip(s)) )
						p.pflags = $|PF_SPINNING & ~(PF_THOKKED|PF_STARTJUMP)
						s.samslopespin = (((s.morphbo>>16)/2)*P_MobjFlip(s))*-1
					else
						if (s.eflags & MFE_UNDERWATER)
							s.momz = (s.morphbo*-1)/12
						else
							s.momz = (s.morphbo*-1)/6
							p.dragdownball = 17
						end
					end
					S_StopSoundByID(s, sfx_sballr)
					s.rpsnd = 11
					s.morphbo = 0
					S_StartSound(s, sfx_sballf)
					local ghs
					local ANG = (leveltime%2) and s.angle or s.angle+ANGLE_45
					for i = 1,4
						ghs = P_SpawnMobj(
						s.x + FixedMul(40<<16, cos(ANG+(ANGLE_90*i))),
						s.y + FixedMul(40<<16, sin(ANG+(ANGLE_90*i))),
						s.z, MT_PARTICLE)
						if ghs and ghs.valid
							ghs.fuse = 10
							ghs.momz = P_RandomRange(1, 10)*25000
						end
					end
				end
			end
		end
		 --Play morph ball rolling sounds if you're moving.
		if (p.speed > 20<<16) 
			s.rpsnd = s.rpsnd and $+1 or 1
			if (s.rpsnd > 7)
				S_StopSoundByID(s, sfx_sballr)
				S_StartSound(s, sfx_sballr)
				s.rpsnd = 0
			elseif not S_SoundPlaying(s, sfx_sballr)
				S_StartSound(s, sfx_sballr)
			end
		end					
		
	else --if NOT on p_objectonground
		s.morphbo = s.momz
		
		if (p.pflags & PF_SPINNING) and not p.powers[pw_nocontrol]
			P_SetObjectMomZ(s, 5000, true)
		end
		if s.bombjump
			if (s.bombjump > 25)
				P_SetObjectMomZ(s, -12000, true)
				if s.bombjump == 28 and s.bombjumpangle != nil and s.bombjumpdist != nil
					local DIST = (s.z <= s.floorz+20<<16) and s.bombjumpdist/4 or s.bombjumpdist/6
					P_Thrust(s, s.bombjumpangle, DIST)
				end
				local ghs = P_SpawnGhostMobj(s)
				ghs.blendmode = AST_ADD
				ghs.destscale = 1
			elseif (s.bombjump > 4)
				P_SetObjectMomZ(s, (s.bombjump > 21) and -165000 or -4000, true)						
			else
				p.pflags = $|PF_JUMPED
				P_SetObjectMomZ(s, -9000, true)
			end
			if s.powerbombjump
				s.powerbombjump = 0
				if p.sammorphed --Do a ridiculous Samus Returns-esque superjump!
					s.momx,s.momy,s.momz = $*2,$*2,$*10/6
				end
			end
			s.bombjump = $-1
		else--if s.rpsnd
			s.rpsnd = s.rpsnd and $+1 or 1
		end
	end
/*	local MORPHSTATE = ((s.state >= S_SAMUMB1) and (s.state <= S_SAMUMB4)) and true or false
	p.morphanim = MORPHSTATE */
	if (s.state >= S_SAMUMB1) and (s.state <= S_SAMUMB4)
		p.morphanim = true
	else
		p.morphanim = false
	end
	
	local BOMBJUMP = (s.bombjump) or 0
	local DRAGDOWN = (p.dragdownball) or 0
	
	if P_IsObjectOnGround(s) and not ((p.sam_spiderball and not p.sam_highjump) and p.sams_jumpcd)
	or (BOMBJUMP > 8) and (BOMBJUMP < 24)
	or (DRAGDOWN > 24)
	or p.thrustfactor == 20
		if not p.sam_spiderball and not (s.samspinpad and s.samspinpad > 35)
			s.flags = $|MF_BOUNCE --Morph Ball bounces around.
		end
		if not s.sam_mbspeedf
			s.friction = max($, 61777)
		end
		if (BOMBJUMP > 8) and (BOMBJUMP < 24)
		or (DRAGDOWN > 24) and (p.pflags & PF_STARTJUMP) and (p.speed < 13<<16) and (p.cmd.buttons & BT_JUMP)
			p.thrustfactor = 20
		else
			local UWBOOST = ((s.eflags & MFE_UNDERWATER) and (p.sam_gravitysuit == 2)) and true or false
			p.normalspeed = (UWBOOST) and 117<<16 or 58<<16
			p.acceleration = (UWBOOST) and 46 or 41
			p.thrustfactor = (s.eflags & MFE_UNDERWATER) and 4 or 3					
		end
	else
		s.flags = $ & ~MF_BOUNCE
		if not s.sam_mbspeedf
			s.friction = 59392
		end
		local UWBOOST = ((s.eflags & MFE_UNDERWATER) and (p.sam_gravitysuit == 2)) and true or false
		p.normalspeed = (UWBOOST) and 40<<16 or 18<<16
		p.acceleration = (UWBOOST) and 50 or 32					
		if not p.morphanim
			p.morphanim = true
			s.state = S_SAMUMB1
		end
		if (p.pflags & PF_JUMPED) and (p.speed > 16<<16)
			s.momx = FixedDiv(FixedMul($, 100), 101)
			s.momy = FixedDiv(FixedMul($, 100), 101)
		end
	end

	if (p.speed < FRACUNIT) and (s.tics == 1 or s.tics == 2)
		s.tics = $+1
	end

	if (p.sams_normfcdjlg or p.sams_c2cdjlg) and not (p.sams_morphbombcd and (p.sams_morphbombcd > 70))
	and not p.sams_shotcd and not p.powers[pw_nocontrol] and not p.exiting
	or s.waveoverbomb
		if not p.sams_powerbombready
			if not p.sam_bombs
				S_StartSound(s, sfx_sdenid)
			else
				p.sams_shotcd = 3
				if not s.crystalflashtime
					p.sams_morphbombcd = $+31
				end
				s.waveoverbomb = false
				s.mbb = P_SpawnPlayerMissile(s, MT_SAMMORPHBOMB)
				SamusTutorial(s, "bombs", true)
				if s.mbb
					P_TryMove (s.mbb, s.x+FixedMul(-35355, cos(s.angle)), s.y+FixedMul(-35355, sin (s.angle)), true)
				end
				s.sambsblchargelvl = 0
				p.sams_firecd = 10
				p.sams_c1cd = 10
				S_StartSound(s, sfx_mbbmb)
			end
		elseif p.sampw and (p.sampw >= 1*p.samadrain) and not p.sams_morphcd 
			p.sams_shotcd = 20
			p.sampw = $-1*p.samadrain
			s.PWBOMBDrain = 4
			s.sambsblchargelvl = 0
			p.sams_powerbombready = 0
			SamusTutorial(s, "pw", true)
			P_SpawnPlayerMissile(s, MT_SAMMBOP, MF2_SUPERFIRE)
			S_StartSound(s, sfx_mbop)
		end
	end

	if s.scale != 42001 or p.powers[pw_carry] --Other unmorph piece.
		if not (leveltime < 4 and s.samspinpad)
		and not p.sams_notyet
		and (p.powers[pw_carry] != CR_MACESPIN) and (p.powers[pw_carry] != CR_ZOOMTUBE) 
			p.sammorphed,p.morphanim = false,false
			p.sams_morphcd = 35
			p.normalspeed = skins[s.skin].normalspeed
			p.acceleration = skins[s.skin].acceleration
			if SAM_FirstPerson(p, true)
			--	SamCam(p, camera.chase, nothing)
			--	SAM_CMD(p, PREVCAM, FIRSTPERSON, CAMERAdotCHASE, VISORCLOSEIN)
				SAM_CMD(p, "nil", "true", "false", "15")
			else
				SAM_CMD(p, "nil", "lol", "lol", "lol")	
			end
			s.friction = 59392
			S_StartSound(s, sfx_morphb)
			s.flags = $ & ~MF_BOUNCE
			s.state = P_IsObjectOnGround(s) and S_PLAY_RUN or S_PLAY_FALL
		end
	end
	if p.morphanim
	or not (p.panim == PA_ROLL and not (p.sam_walljumping or p.sam_screwattacking))
		if not p.sams_notyet
			s.state = S_SAMUMB1
		end
	end
	
	local USECD = (p.sams_usecd) or 0
	if (p.cmd.buttons & BT_USE) and not (USECD > 1) --Unmorphing?
	or not s.health
	or p.exiting and not s.exitedmorph
	or leveltime==1
		if not p.sams_morphcd and not s.spiderballing 
		and not (p.powers[pw_carry] == CR_MACESPIN)
			if not ( s.ceilingz < s.z + (66<<16*P_MobjFlip(s)) )
				p.morphanim = false
				SAM.UnMorph(s)
			else
				S_StopSoundByID(s, sfx_sdenid)
				S_StartSound(s, sfx_sdenid)
			end
			if p.exiting
				s.exitedmorph = true
			end
		end
	end
	if p.powers[pw_carry]
		p.sam_framejump = 0
		s.prevsz,s.prevssp = nil,nil
		if (p.powers[pw_carry] == CR_ZOOMTUBE)
			if s.discomsgprep
				if (s.x > -13000<<16) and (s.x < -12200<<16)
				and (s.y < 10500<<16)
				and (s.ceilingz < 925<<16) and (s.floorz > 885<<16)
					s.discomsgprep = false
					SamusDialogue(s, "What.", nil, "SAMDEF", 2, 0, 200)
				end
			end
		elseif (p.powers[pw_carry] == CR_MACESPIN)
			p.sams_c1cd = 0
			p.sams_shotcd = 5
			p.sambsblchargefull = false		
		elseif (p.powers[pw_carry] == CR_MINECART)
		or (p.powers[pw_carry] == CR_ROLLOUT)
		or (p.powers[pw_carry] == CR_PLAYER)
		or (p.powers[pw_carry] == CR_GENERIC)
		or (p.powers[pw_carry] == CR_ROPEHANG)
			p.panim = PA_WALK
			p.sams_notyet = 3
			s.state = S_PLAY_STND
			SAM.UnMorph(s)
		end
	elseif s.standingslope and not (s.standingslope.flags & SL_NOPHYSICS)
		if not s.samspinpad
			if s.prevsz == nil
				s.prevsz = s.z
			end
			if s.prevssp == nil
				s.prevssp = p.speed
			end
			s.ansl = AngleFixed((s.standingslope.xydirection)-s.angle) 
			
			if not (p.pflags & PF_SPINNING) and not p.sam_spiderball
				local MULT = (p.speed > 17<<16) and 3 or (p.speed >= 6<<16) and 2 or 1 
				P_Thrust(s, s.standingslope.xydirection, MULT*(s.standingslope.zdelta)*(P_MobjFlip(s)) )
			end
			if (abs(s.standingslope.zdelta) > 7000)
				if (p.speed > 33<<16)
					for i = 1,1 --Huh...this is a somewhat clever way of using a for loop, no?
						if not (s.eflags & MFE_VERTICALFLIP)
							if not (s.z < s.prevsz-233333) break end --
						elseif not (s.z > s.prevsz+233333) break end
						p.pflags = $|PF_SPINNING
						s.samslopespin = ((p.speed>>16)/3)
						if s.sam_forcemorphslope
							s.sam_forcemorphslopeattach = 5
							s.sam_forcemorphslope = $+1
						end
					end
				elseif (p.speed < 9<<16) and (abs(s.standingslope.zdelta) > 30000)
				and (s.prevssp and (s.prevssp > 21<<16)) and not (p.cmd.forwardmove < 0)
					s.z = s.z+((10<<16)*(P_MobjFlip(s)))
					if (s.prevssp > 69<<16)
						P_SetObjectMomZ(s, (s.prevssp*10/16), true)
						P_Thrust(s, s.standingslope.xydirection, (s.prevssp/2))
					elseif (s.prevssp > 49<<16)
						P_SetObjectMomZ(s, (s.prevssp/2), true)
						P_Thrust(s, s.standingslope.xydirection, (s.prevssp*10/13))
					else
						P_SetObjectMomZ(s, (s.prevssp*10/13), true)
						P_Thrust(s, s.standingslope.xydirection, (s.prevssp*10/11))
					end
					p.bsblboost,p.bsblboostattack = 0,0				
				end
			end
		end
		s.prevssp = p.speed
		s.prevsz = s.z
	elseif s.prevsz
		s.prevsz,s.prevssp = nil,nil
	end
	s.sam_mbspeedf = nil
end

--Sync with another player!
SAM.JoinSync = function(p,s) if not (p and p.valid) return end --

	local SERV
	if not (HOST and HOST.valid)
		HOST = (SAM.PickHost(0))
		SERV = HOST
	end
	
	if not (SERV and SERV.valid)
		for z in players.iterate
			if z and z.valid SERV = z break end --
		end
	end
	if SERV and SERV.valid and p != SERV
		p.nogunshipspawn = SERV.nogunshipspawn
		p.sam_respawnboxer =  SERV.sam_respawnboxer
		p.tokensrb2style = SERV.tokensrb2style
		p.samescapehud = SERV.samescapehud
--		p.crazysamusmobs = SERV.crazysamusmobs
--		p.fusionmode = SERV.fusionmode
--		p.samworldevents = SERV.samworldevents
--		p.metroidvisuals  =  SERV.metroidvisuals
		p.sam_beamcombosrestrict = SERV.sam_beamcombosrestrict
		p.hypernetgo = SERV.hypernetgo
		p.nosuperpowert = SERV.nosuperpowert
		p.morphcoop = SERV.morphcoop
		p.coopboxrespawn = SERV.coopboxrespawn
		p.boxammospawns = SERV.boxammospawns
		p.sammatchmonitors = SERV.sammatchmonitors
		p.sammatchchars = SERV.sammatchchars
		p.samdoubleammo = SERV.samdoubleammo
		p.samusragdolls = SERV.samusragdolls	
		
		p.speedrunoverride = SERV.speedrunoverride
		if p.speedrunoverride
			p.sams_completiontime = SERV.sams_completiontime
		end
		
		p.sam_energytanksstart = (SERV.sam_energytanksstart) or $
--		if SERV.sam_netsaves != nil
--			p.sam_netsaves = SERV.sam_netsaves
--		end
		p.samusmatch = SERV.samusmatch
		
		local TANKSTART = p.sam_energytanksstart
		if TANKSTART == nil TANKSTART = 2 end
		
		if p.samusmatch == 1 and not (gametype == GT_RACE) --Standard mode.
			p.sam_energytanks = p.sam_energytanksmax
			if (leveltime < 350) and not (p.sam_energytanksmax < 2)
				p.sam_energy = (p.sam_energytanksmax*50)-1
			else
				p.sam_energy = 99+(p.sam_energytanksmax*50)
			end
			
		elseif p.samusmatch and ((p.samusmatch == 2) or (gametype == GT_RACE)) --Start with all equipment! (Mostly!)
		
			p.samspbs = true
			p.sambsbl = true
			p.sam_spiderball = true
			p.sam_gravitysuit = 2
			p.sam_highjump = true
			p.sam_bombs = true
			p.sam_spacejump = true
			p.sam_chargebeam = true
			p.sam_spazerbeam = true
			p.sam_wavebeam = true
			p.sam_icebeam = true
			p.sam_plasmabeam = true
			p.sam_screwattack = true
			p.sam_powerbeamcombo = false
			p.sam_spazerbeamcombo = false
			p.sam_wavebeamcombo = false
			p.sam_icebeamcombo = false
			p.sam_plasmabeamcombo = false
			p.sam_hyperbeam = false
			p.sam_fullypoweredsuit = false
			p.sammissilesmax = 10
			p.sammissiles = 10
			p.sampw = 0
			p.sampwmax = 1
			p.sampw = 0
			p.samsupermissilesmax = 2
			p.samsupermissiles = 0

		elseif p.samusmatch == 5 --Start with the basics!

			if not (gametype == GT_RACE)
				p.sam_energytanksmax = TANKSTART
				p.sam_energytanks = p.sam_energytanksmax
				p.sam_energy = 99+(p.sam_energytanksmax*50)
			end
			p.samspbs = true
			p.sambsbl = true
			p.sam_spiderball = false
			p.sam_gravitysuit = 1
			p.sam_gravitysuitjustgot = 0
			p.sam_highjump = false
			p.sam_spacejump = true
			p.sam_chargebeam = true
			p.sam_spazerbeam = false
			p.sam_wavebeam = false
			p.sam_icebeam = false
			p.sam_plasmabeam = false
			p.sam_ranchoice = (P_RandomRange(1,7))
			if p.sam_ranchoice
				if p.sam_ranchoice <= 2
					p.sam_spazerbeam = true
				elseif p.sam_ranchoice <= 4
					p.sam_wavebeam = true
				elseif p.sam_ranchoice <= 6
					p.sam_icebeam = true
				elseif p.sam_ranchoice >= 7
					p.sam_plasmabeam = true
				end
			end
			p.sam_bombs = true
			p.sam_screwattack = false
			p.sam_powerbeamcombo = false
			p.sam_spazerbeamcombo = false
			p.sam_wavebeamcombo = false
			p.sam_icebeamcombo = false
			p.sam_plasmabeamcombo = false
			p.sam_hyperbeam = false
			p.sam_fullypoweredsuit = false
			p.sammissilesmax = 10
			p.sammissiles = 5
			p.sampwmax = 0
			p.sampw = 0
			p.samsupermissilesmax = 2
			p.samsupermissiles = 0

		elseif p.samusmatch == 9 --"Traditional FPS" style!

			if not (gametype == GT_RACE)
				if (p.sam_energytanksstart != nil)
					p.sam_energytanksmax = p.sam_energytanksstart
				else
					p.sam_energytanksmax = 2
				end
				p.sam_energytanks = p.sam_energytanksmax
				p.sam_energy = 99+(p.sam_energytanksmax*50)
			end
			p.samspbs = false
			p.sambsbl = false
			p.sam_spiderball = false
			p.sam_gravitysuit = 0
			p.sam_gravitysuitjustgot = 0
			p.sam_highjump = false
			p.sam_spacejump = true
			p.sam_chargebeam = true
			p.sam_spazerbeam = true
			p.sam_wavebeam = true
			p.sam_icebeam = true
			p.sam_plasmabeam = true
			p.sam_bombs = false
			p.sam_screwattack = false
			p.sam_powerbeamcombo = (not p.sam_beamcombosrestrict) and true or false
			p.sam_spazerbeamcombo = false
			p.sam_wavebeamcombo = false
			p.sam_icebeamcombo = false
			p.sam_plasmabeamcombo = false
			p.sam_hyperbeam = false
			p.sam_fullypoweredsuit = false
			p.sammissilesmax = 10
			p.sammissiles = 5
			p.sampwmax = 0
			p.sampw = 0
			p.samsupermissilesmax = 0
			p.samsupermissiles = 0

		elseif (p.samusmatch == 4) --Morph Ball focused!

			if not (gametype == GT_RACE)
				if (p.sam_energytanksstart != nil)
					p.sam_energytanksmax = p.sam_energytanksstart
				else
					p.sam_energytanksmax = 2
				end
				p.sam_energytanks = p.sam_energytanksmax
				p.sam_energy = 99+(p.sam_energytanksmax*50)
			end
			p.samspbs = false
			p.sambsbl = true
			p.sam_spiderball = true
			p.sam_gravitysuit = 0
			p.sam_gravitysuitjustgot = 0
			p.sam_highjump = true
			p.sam_spacejump = false
			p.sam_chargebeam = true
			p.sam_spazerbeam = false
			p.sam_icebeam = false
			p.sam_plasmabeam = false
			p.sam_bombs = true
			p.sam_screwattack = false
			p.sam_powerbeamcombo = false
			p.sam_spazerbeamcombo = false
			if not p.sam_beamcombosrestrict
				p.sam_wavebeam = true
				p.sam_wavebeamcombo = true
			else
				p.sam_wavebeam = false
				p.sam_wavebeamcombo = false
			end
			p.sam_icebeamcombo = false
			p.sam_plasmabeamcombo = false
			p.sam_hyperbeam = false
			p.sam_fullypoweredsuit = false
			p.sammissilesmax = 15
			p.sammissiles = 5
			p.sampwmax = 3
			p.sampw = 1
			p.samsupermissilesmax = 0
			p.samsupermissiles = 0
		end
	end
/*	if (isdedicatedserver) --Going to make some assumptions for dedicated servers.
		if not (IsPlayerAdmin(p) or (p == server))
			if p == HOST or p == players[0] or p == players[1]
				local TOTAL = 0
				for z in players.iterate
					if z TOTAL = $+1 
						if (TOTAL>2) break end --
					end
				end	
				if (TOTAL<2) --You're the ONLY player, so you decide our rules!
					p.sam_joinsync = true
					if SAMUSCAMPAIGN == false
				--		p.samworldevents,p.crazysamusmobs = true,true
						G_SetCustomExitVars(gamemap,1)
						G_ExitLevel()
					elseif not SAMUSDIFFICULTY
				--		p.crazysamusmobs = true
						SAM.SetHyperMode(p, m, true)
					end
				end
			end
		end
	end */
	p.sam_joinsync = true
end

--Total Items Collected are..?
SAM.Completion = function(p,s, UPDATE)
	if not paused and leveltime and not UPDATE --Show items obtained percentage and total time! Don't just copy leveltime, count everything except pauses!
		p.sams_completiontime = p.sams_completiontime and $+1 or 1
	end
	if p.samustimeshow == 245 and p.sams_completiontime
	or (leveltime%50==0) and not (p.samustimeshow and p.samustimeshow < 245)
	or UPDATE
	
		local ITEMRATE = 0
		local function iR(i) ITEMRATE = $+i end --It counts up everytime!
		
		local TIME = (p.sams_completiontime) or 0		
		local MISSILES = (p.sammissilesmax) or 0
		local SUPERS = (p.samsupermissilesmax) or 0
		local PWBOMBS = (p.sampwmax) or 0
		local ETANKS = (p.sam_energytanksmax) or 0
		local SUIT = (p.sam_gravitysuit==1) and 2 or (p.sam_gravitysuit==2) and 6 or 0
		
		local HOURS = G_TicsToHours(TIME)
		local MINUTES = G_TicsToMinutes(TIME, false)
		local SECONDS = G_TicsToSeconds(TIME)	
		
		iR(p.sam_bombs and 1 or 0) --Bombs are 1%.
		iR(p.sambsbl and 1 or 0) --Boost Ball is 1%
		iR(p.samspbs and 2 or 0) --Speed Booster is 2%
		iR(p.sam_screwattack and 3 or 0) --Screw Attack is 3%.
		iR(p.sam_power_grip and 1 or 0) --Power Grip is 1%
		iR(p.sam_highjump and 1 or 0) --High Jump/Spring Ball is 1%
		iR(p.sam_spacejump and 3 or 0) --Space Jump is 3%
		iR(p.sam_chargebeam and 1 or 0) --Charge Beam is 1%.
		iR(p.sam_spazerbeam and 2 or 0) --Spazer is 2%
		iR(p.sam_wavebeam and 2 or 0) --Wave Beam is 2%.
		iR(p.sam_icebeam and 2 or 0) --Ice Beam is 2%
		iR(p.sam_plasmabeam and 3 or 0) --Plasma Beam is 3%
		iR(SUIT) --The Varia Suit alone is 2%. Having the Gravity Suit too makes it 6%.
		if MISSILES
			iR(min(20, MISSILES/5)) --Can get up to 20% from missiles! Each tank is 1%.
		end
		iR(min(10, SUPERS)) --Can get up to 10% from Super Missiles! Each tank adds 1%.
		iR(min(15, PWBOMBS)) --Can get up to 15% from Power Bombs! Each tank adds 3%.
		iR(min(12, ETANKS)) --Can get up to 12% from Energy Tanks. Each tank pickup adds 1%.
		iR(p.sam_powerbeamcombo and 1 or 0)	--Power Combo(Super Missile) is 1%.
		iR(p.sam_spazerbeamcombo and 2 or 0) --Spazer Combo(Force Crasher) is 2%.
		iR(p.sam_wavebeamcombo and 3 or 0) --Wave Combo(Wave Buffer+Death Ball) is 3%
		iR(p.sam_icebeamcombo and 3 or 0) --Ice Combo(Blizzard Burst) is 3%.
		iR(p.sam_plasmabeamcombo and 3 or 0) --Plasma Combo(Gattling Vortex) is 3%
		iR(p.sam_hyperbeam and 10 or 0) --The Ultimate Weapon is completely unavailable for low % achievements
		
/*		if p.sambsbl
			itemcounter = $+1 end
		if p.samspbs
			itemcounter = $+2 end 
		if p.sam_screwattack
			itemcounter = $+2 end
		if p.sam_gravitysuit
			if p.sam_gravitysuit == 2  
				itemcounter = $+4
			else
				itemcounter = $+2
			end
		end
		if p.sam_highjump
			itemcounter = $+1 end
		if p.sam_power_grip
			itemcounter = $+1 end
		if p.sam_bombs
			itemcounter = $+1 end
		if p.sam_spacejump
			itemcounter = $+2 end
		if p.sam_spazerbeam
			itemcounter = $+2 end
		if p.sam_wavebeam
			itemcounter = $+2 end
		if p.sam_icebeam
			itemcounter = $+2 end
		if p.sam_plasmabeam
			itemcounter = $+2 end 
		if p.sam_hyperbeam
			itemcounter = $+10 end 
		if p.sammissilesmax 
			if (p.sammissilesmax > 100)
				itemcounter = $+20
			else
				itemcounter = $+(p.sammissilesmax/5)
			end
		end
		if p.samsupermissilesmax 
			if (p.samsupermissilesmax > 10)
				itemcounter = $+10
			else
				itemcounter = $+p.samsupermissilesmax
			end
		end 
		if p.sam_energytanksmax
			itemcounter = $+p.sam_energytanksmax
		end
		if p.sam_chargebeam
		itemcounter = $+1 end
		if p.sampwmax
			if (p.sampwmax > 5)
				itemcounter = $+15
			else
				itemcounter = $+p.sampwmax*3
			end
		end
		if p.sam_spazerbeamcombo
		itemcounter = $+2 end
		if p.sam_wavebeamcombo
		itemcounter = $+2 end
		if p.sam_icebeamcombo
		itemcounter = $+2 end
		if p.sam_plasmabeamcombo
		itemcounter = $+2 end
		if p.sam_powerbeamcombo
		itemcounter = $+2 end */
		
		if not UPDATE
			p.sams_completiontimehours = HOURS
			p.sams_completiontimeminutes = MINUTES
			p.sams_completiontimeseconds = SECONDS	
			p.sams_itemcompletion = min(100, ITEMRATE) --And our item completion rate iiiis...?
		end
		return min(100,ITEMRATE),HOURS,MINUTES,SECONDS --
		
	elseif p.sams_completiontimehours == nil
		p.sams_completiontimehours,p.sams_completiontimeminutes,p.sams_completiontimeseconds,p.sams_itemcompletion = 0,0,0,0
	end
end

--Escape Scene!
SAM.BlackCoreEscape = function(p,s)
	if gamemap==25 and mapheaderinfo[gamemap].lvlttl == "Black Core"
		if multiplayer or s.health
			p.samescape = $-1
		end
		if (p.samescape%105==0)
			S_StartSound(nil, sfx_alarm)
		end
		local ghs
		local EX = s.x + FixedMul(2300<<16, cos(s.angle)) + (s.momx*9)
		local EY = s.y + FixedMul(2300<<16, sin(s.angle)) + (s.momy*9)
		
		if s.floorz != nil and s.ceilingz != nil
			local rockRNG = P_RandomRange(1, 10)
			if (rockRNG < 3)
				P_StartQuake(6<<16, 1)
				ghs = P_SpawnMobj(
				EX + P_RandomRange(2000,-2002)<<16,
				EY + P_RandomRange(2000,-2002)<<16,
				s.z+ SAM.RNG(s, s.floorz>>16, s.ceilingz>>16)<<16,
				MT_CYBRAKDEMON_MISSILE)
				if ghs and ghs.valid
					ghs.target = s
					P_ExplodeMissile(ghs)
				end
			elseif (rockRNG < 6)
				P_StartQuake(4<<16, 1)
				ghs = P_SpawnMobj(
				EX+ P_RandomRange(2000,-2002)<<16,
				EY+ P_RandomRange(2000,-2002)<<16, 
				s.floorz, MT_CYBRAKDEMON_VILE_EXPLOSION)
				if ghs and ghs.valid
					ghs.target = s
				end
			else
				for i = 1,((leveltime%2) and 2 or 1)
					P_StartQuake(2<<16, 1)
					ghs = P_SpawnMobj(
					EX+ P_RandomRange(2000,-2002)<<16,
					EY+ P_RandomRange(2000,-2002)<<16, 
					s.ceilingz-25<<16, MT_FALLINGROCK)
					if ghs and ghs.valid
						ghs.shadowscale = FRACUNIT
						ghs.flags = $ & ~MF_PAIN
						ghs.scale = P_RandomRange(1,3)<<16
						ghs.target = s
					end
				end
			end
		
			ghs = P_SpawnMobj(
			EX+ P_RandomRange(6000,-6000)<<16, 
			EY+ P_RandomRange(8000,-7000)<<16, 
			s.z+ P_RandomRange(1500,-1500)<<16, MT_SONIC3KBOSSEXPLODE)
			if ghs and ghs.valid 
				ghs.flags = $|MF_NOCLIPTHING|MF_NOBLOCKMAP
				ghs.scale = P_RandomRange(1, 4)<<16		
				if ghs.z < ghs.floorz or ghs.z > ghs.ceilingz
					ghs.z = ghs.ceilingz
				end
			end
			
			ghs = P_SpawnMobj(
			EX+P_RandomRange(-4000,4000)<<16, 
			EY+P_RandomRange(-4000, 4000)<<16, 
			s.z+SAM.RNG(s,-900,900)<<16, MT_BOSSEXPLODE)		
			if ghs and ghs.valid
				ghs.flags = $|MF_NOCLIPTHING|MF_NOBLOCKMAP
				ghs.scale = P_RandomRange(1, 4)<<16
				if ghs.z < ghs.floorz or ghs.z > ghs.ceilingz
					ghs.z = ghs.ceilingz
				end
			end
			
			ghs = P_SpawnMobj(
			EX+P_RandomRange(-2000, 2000)<<16, 
			EY+P_RandomRange(2000, -2000)<<16,
			s.z+(P_RandomRange((s.floorz>>16), (s.ceilingz>>16)))<<16, MT_SONIC3KBOSSEXPLODE)
			if ghs and ghs.valid
				ghs.flags = $|MF_NOCLIPTHING|MF_NOBLOCKMAP
				ghs.scale = P_RandomRange(1,4)<<16
			end
		end
		
		--Somewhat intensive code here...
		if p.samescape==1
			for z in players.iterate
				if z.mo and not (z.exiting and not multiplayer)
					P_SamFP(z, PAL_NUKE, 26)
					p.samescape = 3281
					z.samescapehud = 0
					P_KillMobj(z.mo, z.mo, z.mo)
				end
			end	
		end
		for z in players.iterate
			if z.starpostnum 
			or z.exiting and not multiplayer
				P_SamFP(z, PAL_RECYCLE, 8)
				p.samescapehud = 0
				p.samescape = 0
				z.samescape = 0
				z.samescapehud = 0
			end
		end
	else --Shouldn't have this!!
		p.samescapehud = 0
		p.samescape = 0		
	end
end

//Set up Samus' quake chained to a thinkframe. Samus' quake is slightly different from regular P_StartQuake, with an epicenter.
//Var1 = Intensity, Var2 = Duration, Var3 = Distance(optional), Var4 = Don't overwrite existing quakes
/*function A_samquake(s, var1, var2, var3, var4)
	if not (var1 and var2)
	or s.player and s.player.sam_sensitive
	or var4 and s.samqtime //Already a quake active? Don't start another if var4 is there.
		return --
	end
	s.samqlvl = var1
	s.samqtime = var2
	s.samqdist = (var3) or 850
end */

--Create a quake for any nearby players that haven't opted out of the effect. 
--DIST is optional. If DIST is set to 0, it'll only play for the calling player. Otherwise it defaults to 700<<16
function A_samquake(s, INTENSITY, TICS, DIST)
	if displayplayer and displayplayer.mo and not displayplayer.sam_sensitive
		if (displayplayer.mo == s)
			P_StartQuake(INTENSITY, TICS)
		elseif s and DIST != 0 and s.valid
			DIST = (DIST) or 700<<16
			local m = displayplayer.mo
			if ( (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) <= DIST)	
				P_StartQuake(INTENSITY, TICS)
			end
		end
	end
end

--Screen is crackling with static!
SAM.OverLoadStatus = function(p,s)
	if s.waveoverfire
		s.waveoverfire = nil
	end
	s.sam_waveoverload = $-1
	
	p.sams_morphcd = 5
	p.sams_powerbombready = 0
	p.sams_supermissileready = 0

	local ghs = P_SpawnGhostMobj(s)
	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(s)
	if leveltime % 4 == 0
		A_SAMPARTICLE(s, MT_MPR1, 4, 4, -2, 6, SKINCOLOR_GOLD, P_RandomRange(9355, 30355))
		A_SAMPARTICLE(s, MT_MPR1, 5, 3, -3, 6, SKINCOLOR_MAGENTA, P_RandomRange(35355, 65354))					
		ghs.color = P_RandomRange(SKINCOLOR_SUPERPURPLE1, SKINCOLOR_SUPERPURPLE5)
	else
		ghs.color = SKINCOLOR_GRAVITYSUIT
	end

	if (leveltime % 30 == 0)
	S_StartSound(s, sfx_wvbc)
		ghs = P_SpawnGhostMobj(s)
		ghs.tics = 20
		ghs.scalespeed = $*4
		ghs.destscale = $*50
		ghs.color = SKINCOLOR_SUPERGOLD5
		ghs.colorized = true
		ghs = P_SpawnMobj(s.x, s.y, s.z, MT_SAMUSZAP)
		if ghs and ghs.valid
			ghs.scale = s.scale*2
	 		ghs.color = SKINCOLOR_SUPERGOLD4
	 		ghs.morning = 4
		end
	end

	if p.sams_shotcd > 10
		p.sams_shotcd = 10
		p.sams_mshotcd = 10
	elseif not p.sams_shotcd  --Spam attacks
		if (s.sam_waveoverload % 5 == 0)
			local rng = P_RandomRange(1,8)				
			if rng == 6 and p.sammissiles and (p.sammissiles >= 50)	and not p.sammorphed and (s.sam_waveoverload < 22) --Sudden beamcombo!
				P_FlashPal(p, PAL_NUKE, 3)
				p.sams_chargetime = 42
				p.sams_shotcd = 0
				p.cmd.buttons = $|BT_FIRENORMAL|BT_ATTACK & ~BT_CUSTOM2
				p.sams_firecd = 1
				s.sam_waveoverload = 0
			else --Swap beams!
				p.sams_shotcd = 0
				p.cmd.buttons = $|BT_WEAPONPREV|BT_WEAPONNEXT
				p.sam_beamswitch = 0
				A_SAMBEAMSWITCH(p)
				p.sam_beamswitch = 0
			end
		else
			if p.sammorphed
				s.waveoverfire = nil
				s.waveoverbomb = true
				p.sams_shotcd = 6
				p.sams_mshotcd = 6
				p.sams_morphbombcd = $+31
				p.sams_powerbombready = 0
			elseif p.sammissiles and not P_RandomRange(0,2)
				p.sammissiles = $-1*p.samadrain
				SamusBeamFire(s, MT_SAMMISSILE)
				S_StartSound(s, sfx_mssh2)
				S_StartSound(s, sfx_mssh2)
				p.sams_shotcd = 2
				p.sams_mshotcd = 7
				if p.sammissiles < 0
					p.sammissiles = 0
				end
			else
				s.waveoverfire = true
				p.sams_shotcd = 0
				p.sams_mshotcd = 2							
			end
			p.sams_firecdjlg = 1
			p.sams_firecd = 1
			p.sams_chargetime = 0
		end
	end
	if not s.sam_waveoverload
		s.waveoverfire = false
		s.waveoverbomb = false
		s.samusmission = nil
	end
end

--Scan for people and apply some stuff.
--Sometimes gets applied to trackers as well, not just monitors.
SAM.ApplyMonitorSettings = function(m)
	local TOTAL = 0
	if METROIDSKINS == true
		m.SAM_metroidvisuals = true
	end
	for z in players.iterate
		if z and z.valid
			TOTAL = $+1
			if (IsPlayerAdmin(z) or (z == server)) --Only care if they're an admin. 
				if z.sammatchmonitors 
					m.SAM_matchmonitors = true
				end
				if z.nosuperpowert
					m.SAM_nosuperpowert = true
				end
				if z.coopboxrespawn
					m.SAM_coopboxrespawn = z.coopboxrespawn --2 means respawn in coop. Otherwise, no.
				end
				if z.sam_respawnboxer
					m.SAM_respawnboxer = z.sam_respawnboxer --This is allowed to be nil!
				end
			end
		end
	end
	if TOTAL == 0 --No players...? Uhh, do defaults, I guess.
		m.SAM_matchmonitors = false
		m.SAM_metroidvisuals = true
		m.SAM_nosuperpowert = false
		m.SAM_coopboxrespawn = 2
	elseif (SAM.HUNTERS(s))
		m.SAM_metroidvisuals = true
	end
	m.SAM_matchmonitors = (m.SAM_matchmonitors) or false
	m.SAM_metroidvisuals = (m.SAM_metroidvisuals) or false
	m.SAM_nosuperpowert = (m.SAM_nosuperpowert) or false
end

--Change what this monitor is?
SAM.MonitorRandomize = function(m, RETURNTYPE)
	if not (m.type == MT_EGGMAN_BOX) and not (m.type == MT_EGGMAN_GOLDBOX)
	and not (m.type == MT_RING_REDBOX)
	and not (m.type == MT_RING_BLUEBOX)	
		local boxrespawn = P_RandomRange(1, 120)
		local TYPE = MT_RING_BOX
		if (boxrespawn < 60)
 			TYPE = MT_RING_BOX
		elseif (boxrespawn < 64)
 			TYPE = MT_PITY_BOX 
		elseif (boxrespawn < 73)
 			TYPE = MT_FORCE_BOX
		elseif (boxrespawn < 81)
 			TYPE = MT_WHIRLWIND_BOX
		elseif (boxrespawn < 88)
 			TYPE = MT_ELEMENTAL_BOX 
		elseif (boxrespawn < 94)
 			TYPE = MT_ATTRACT_BOX 
		elseif (boxrespawn < 100)
 			TYPE = MT_ARMAGEDDON_BOX
		elseif (boxrespawn < 102)
 			TYPE = MT_INVULN_BOX 
		elseif (boxrespawn < 118)
 			TYPE = MT_SNEAKERS_BOX
		elseif (boxrespawn < 119)
 			TYPE = MT_MIXUP_BOX
		else
 			TYPE = MT_RECYCLER_BOX
		end
		if not RETURNTYPE --Don't change anything in this case, just report back the chosen type!
			m.type = TYPE
		end 
		if m and m.valid and m.health
			m.state = mobjinfo[m.type].spawnstate
			if m and m.valid and (m.type == MT_PITY_BOX) 
				m.triedspawn = true
			end
		end
		return TYPE --
 	end
end

--With Metroid Visuals, Monitors turn into Metroid Style Item Spheres.
--Still, we recolor the inner glow to use these colors for each Monitor!
local ItemSphereColors = {
[MT_FORCE_BOX] = SKINCOLOR_BLUE,
[MT_ARMAGEDDON_BOX] = SKINCOLOR_RED,
[MT_ELEMENTAL_BOX] = SKINCOLOR_EMERALD,
[MT_FLAMEAURA_GOLDBOX] = SKINCOLOR_FLAME,
[MT_BUBBLEWRAP_GOLDBOX] = SKINCOLOR_AQUA,
[MT_THUNDERCOIN_GOLDBOX] = SKINCOLOR_BRONZE,
[MT_ATTRACT_BOX] = SKINCOLOR_GOLDENROD,
[MT_WHIRLWIND_BOX] = SKINCOLOR_SKY,
[MT_PITY_BOX] = SKINCOLOR_MOSS,
[MT_INVULN_BOX] = SKINCOLOR_WHITE,
[MT_EGGMAN_BOX] = SKINCOLOR_BLACK, --Don't open those!
[MT_EGGMAN_GOLDBOX] = SKINCOLOR_BLACK,
[MT_SNEAKERS_BOX] = SKINCOLOR_MAGENTA,
[MT_MIXUP_BOX] = "skip",
}
--Changes a Monitor to a Metroid Chozo Item Sphere, and colors them appropriately too. 
SAM.MonitorToSphere = function(m)
	if (m.health or (m.flags & MF_SHOOTABLE))
		if not (m.type == MT_1UP_BOX) --Note these types can have changed earlier.
		and not ( (m.type >= MT_PITY_GOLDBOX) and (m.type <= MT_THUNDERCOIN_GOLDBOX) ) --Ignore gold boxes.
			m.state,m.metroidvisual = S_METBOX1,true
			local SPHERE = ItemSphereColors[m.type] 
			if SPHERE
				if SPHERE != "skip" --Skip recoloring entirely. Mixup Monitors use special behaviour!
					m.color = SPHERE
				end
			else
				m.color = SKINCOLOR_ORANGE
			end
		end
	end
end

--Updates the current winner of Matches!
SAM.UpdateScoreBracket = function(HOST, START)
	if START --At the beginning, let Challengers upgrade or lose commendations.
		if HOST.sam_winningchallenger
			for z in players.iterate
				if z.samchallenger
					local p = z
					local CHALLENGER = (p.samchallenger) or 0
					if z == HOST.sam_winningchallenger
						if (CHALLENGER < 4)
							S_StartSound(nil, sfx_nxbump)
							print("\x82"+p.name+" has gained a rank \x86"+(CHALLENGER)+"\x82 hunter's commendation for winning as a challenger!")
							p.samchallenger = CHALLENGER+1
							if (p.samchallenger >= 4)
								S_StartSound(nil, sfx_bgxpld)
								S_StartSound(nil, sfx_bejet1)
								for ns in players.iterate
									P_SamFP(ns, PAL_RECYCLE, 4)
								end
								if displayplayer and displayplayer != p
									print("\x89"+p.name+" has gained\x82 MAX\x89 rank for winning in challenger mode! Do\x85 not\x89 let them get the emeralds!")
								end
								CONS_Printf(p, "Congratulations! You're at\x83 MAX commendations!\x80 At this rank, you can use the exclusive\x82 HYPER BEAM COMBO!")
							end
						else
							S_StartSound(nil, sfx_bgxpld)
							S_StartSound(nil, sfx_bejet1)
							S_StartSound(nil, sfx_kc5a)
							print("\x81"+p.name+" is still a\x83 MAX-rank\x81 challenger! Break their winning streak of\x82 "+CHALLENGER-1)
							p.samchallenger = CHALLENGER+1
						end
					elseif (CHALLENGER > 1)
						p.samchallenger = 1
						S_StartSound(s, sfx_kc59, p)
						CONS_Printf(p, "\x85"+"Your commendations have been reset!")
					end					
				end
			end
		end
		HOST.sam_winningchallenger = nil
	end
	if HOST and HOST.valid
		local TOPSCORE = nil
		for z in players.iterate
			if z and z.valid and z.score != nil and (TOPSCORE == nil or (z.score >= TOPSCORE))
				TOPSCORE = z.score
				HOST.sam_topscore = z.score
				HOST.sam_topscoreman = z
				if z.samchallenger
					HOST.sam_winningchallenger = z
				end
			end
		end
	end
end

SAM.SpeedBoosterGhosts = function(s, p, cf) --Spawn Speed Booster ghosts.
	local ghs
	if cf
		if cf == "dontsave"
			ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_OVERLAY)
		else
			s.speedghost = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_OVERLAY)
			ghs = s.speedghost
		end
		ghs.target = s
		ghs.state = S_THOK
		ghs.skin = s.skin
		ghs.sprite = s.sprite
		ghs.sprite2 = s.sprite2
		ghs.frame = s.frame|FF_TRANS60|FF_FULLBRIGHT
		ghs.angle = p.drawangle
		ghs.tics,ghs.fuse = 3,3
		ghs.blendmode = AST_ADD
		ghs.scale = s.scale
		ghs.flags2 = s.flags2	
		ghs.eflags = s.eflags
		ghs.color = SKINCOLOR_SUPERRED2
		ghs.colorized = true
		if SAM_displayplayer(p) and not CV_FindVar("chasecam").value and not netgame --Don't render in first person, it'll just clutter your view.
			ghs.flags2 = $|MF2_DONTDRAW
		end
		return ghs --
	end
					
	if (leveltime % 2 == 0)
		s.speedghost = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_OVERLAY)
		s.speedghost.target = s
		s.speedghost.skin = s.skin
		s.speedghost.sprite = s.sprite
		s.speedghost.sprite2 = s.sprite2
		s.speedghost.frame = s.frame|FF_TRANS70|FF_FULLBRIGHT
		s.speedghost.angle = p.drawangle
		s.speedghost.tics = 2
		s.speedghost.blendmode = AST_ADD
		s.speedghost.scale = s.scale
		s.speedghost.flags2 = s.flags2
		s.speedghost.eflags = s.eflags
		s.speedghost.color = SKINCOLOR_SUPERSKY3
		s.speedghost.colorized = true
		if SAM_displayplayer(p) and not CV_FindVar("chasecam").value
			s.speedghost.flags2 = $|MF2_DONTDRAW
		end		
	end

	if (s.eflags & MFE_VERTICALFLIP)
		s.speedghost = P_SpawnMobj(s.x, s.y, s.z-s.height*5/13, MT_THOK)
	else
		s.speedghost = P_SpawnMobj(s.x, s.y, s.z, MT_THOK)
	end
	s.speedghost.skin = s.skin
	s.speedghost.sprite = s.sprite
	s.speedghost.sprite2 = s.sprite2
	s.speedghost.frame = s.frame|FF_TRANS90|FF_FULLBRIGHT
	s.speedghost.angle = p.drawangle
	s.speedghost.tics = 7
	s.speedghost.scale = s.scale
	s.speedghost.blendmode = AST_ADD
	s.speedghost.flags2 = s.flags2
	s.speedghost.eflags = s.eflags
	s.speedghost.colorized = true
	if SAM_displayplayer(p) and not CV_FindVar("chasecam").value
		s.speedghost.flags2 = $|MF2_DONTDRAW
	end	
	
	if s.speedghost and s.speedghost.valid and (leveltime % 3 == 0 )
		s.speedghost.color = SKINCOLOR_ICY
		s.speedghost.frame = s.frame|FF_TRANS60|FF_FULLBRIGHT
	elseif s.speedghost and s.speedghost.valid
		s.speedghost.color = SKINCOLOR_SUPERSKY3
	end
end

--Samus exclusive timers.
SAM.SamusTimers = function(p,s)
	if p.heysamusstopyourhudforthismanytics --Want Samus to stop her HUD functions for a while? Use this.
		p.heysamusstopyourhudforthismanytics = $-1
	end
	if p.encatchupflash
		p.encatchupflash = $-1
	end
	if p.micatchupflash
		p.micatchupflash = $-1
	end
	if p.smcatchupflash
		p.smcatchupflash = $-1
	end
	if p.pbcatchupflash
		p.pbcatchupflash = $-1
	end
	if p.sam_energyflash
		p.sam_energyflash = $-1
	end
	if p.sams_beamanim
		p.sams_beamanim = $-1
	end
	if p.sams_morphcd
		p.sams_morphcd = max($-1,0)
	end
	if p.sam_spbsgrace
		p.sam_spbsgrace = max(0, min(16,$-1))
	end	
	if p.sams_notyet
		p.sams_notyet = max($-1,0)
	end
	if p.SAM_RevengeBountyTime 
		p.SAM_RevengeBountyTime = $-1
		if not p.SAM_RevengeBountyTime
			p.SAM_RevengeBounty,p.SAM_RevengeBountyTime = nil,nil
		end
	end
	if p.visorclosein and not p.sam_saveselect
		p.visorclosein = $-1
	end
	if s.SAM_didlockon
		s.SAM_didlockon = $-1
	end
	if s.samslopespin
		s.samslopespin = max($-1,0)
		if p.sammorphed
			if P_IsObjectOnGround(s)
				p.pflags = $|PF_SPINNING
				P_SpawnPlayerMissile(s, MT_SAMMONBREAKER)
			end
			if (p.speed > 35<<16) and ( s.standingslope == nil or ( s.standingslope and ( (s.standingslope.zdelta < 3000) and (s.standingslope.zdelta > -3000) ) ) )
				s.momx,s.momy = $*80/81,$*80/81
			end
			if ( s.samslopespin == 1 or (p.speed < 35<<16) and (p.cmd.forwardmove or p.cmd.sidemove) ) and not s.samspinpad 
				s.samslopespin = 0
				p.pflags = $ & ~PF_SPINNING
			end
		end
	end		
	if p.sam_spiderball
		local CHARGE = s.spiderbcharge or 0
		if (CHARGE < 102)
			if not s.spiderballrecharged
				s.spiderballrecharged = true
			end
		elseif (CHARGE >= 102) --Minor HUD notification.
			if s.spiderballrecharged == true
				s.spiderballrecharged = 1
			end
		end
		if s.spiderballrecharged and s.spiderballrecharged != true
			s.spiderballrecharged = $+1
			if (s.spiderballrecharged > 19)
				s.spiderballrecharged = nil
			end
		end
	end
	--More s timers
	if p.lavaflash	
		p.lavaflash = $-1
		if not p.powers[pw_flashing] and p.lavaflash and not p.powers[pw_nocontrol] and not (p.pflags & PF_FORCESTRAFE)
			if (p.lavaflash % 2 == 0)
				s.flags2 = $|MF2_DONTDRAW
			elseif (s.flags2 & MF2_DONTDRAW)
				s.flags2 = $ & ~MF2_DONTDRAW
			end
		end
	end
	
	if s.SAM_StartBooster
		s.SAM_StartBooster = $-1
	end
	if s.SAM_PSFX
		s.SAM_PSFX = $-1
	end
	if s.MissileAmmoDrain
		s.MissileAmmoDrain = $-1
	end
	if s.SuperAmmoDrain
		s.SuperAmmoDrain = $-1
	end
	if s.PWBOMBDrain
		s.PWBOMBDrain = $-1
	end	
	if s.SAM_scoreboost
		s.SAM_scoreboost = $-1
	end
	if s.spawnsamuscolors --Force colors for a while.
		s.spawnsamuscolors = $-1
		SetSamusColor(s, p)
		S_StopSoundByID(s, sfx_cgot) --Don't play this for a bit.
		if not s.spawnsamuscolors
			SamusTutorial(s, "beams")
			SamusTutorial(s, "monitorhunt")
			SamusTutorial(s, "lockon")					
			if (p.pflags & PF_GODMODE)
				p.pflags = $ & ~(PF_INVIS|PF_GODMODE|PF_FORCESTRAFE)
			end
			if (gametype != GT_COOP)
				SamusTutorial(s, "scanvisor")
				SamusTutorial(s, "chargebeam")
				if G_GametypeHasSpectators() and not p.sam_hyperbeam
					for z in players.iterate
						if z.mo and z.sam_hyperbeam
							SAM.DoAreaScan(s, p, nil, "skipmonitors")
						end
					end
				end			
			end
		end
	end		
	if s.sam_forcemorphslope
		s.sam_forcemorphslope = $-1
	end
	if s.sam_forcemorphslopeattach
		s.sam_forcemorphslopeattach = $-1
	end	
	if s.sam_afterboost
		if p.samspbschargefull != true --Gradual cancel
			if not p.sam_walljumping and not s.sam_screwattackfling and not p.sam_screwattacking
				s.sam_afterboost = $-1
			end
		end
		--Instant cancel.
		if p.powers[pw_carry]
		or P_PlayerInPain(p)
		or p.sammorphed
		or not YouAreSamus(s)
			s.sam_afterboost = 0
		end
	end
	if s.sam_spbshack
		s.sam_spbshack = $-1
	end
	if s.sam_scansymbol
		s.sam_scansymbol = $-1
	end
	if s.sam_reflectface
		s.sam_reflectface = $-1
	end	
	if s.sam_spbsstart
		if (s.sam_spbsstart % 8 == 0) and (p.speed > 30<<16)
			local ghs = P_SpawnMobjFromMobj(s, 0,0,-12*s.scale, MT_SAMUSTHOK)
			ghs.sprite = SPR_MXP4
			ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.frame = V|FF_TRANS60
			ghs.blendmode = AST_ADD
			ghs.scale = s.scale/5
			ghs.momz = (-7<<16)*P_MobjFlip(ghs)
			ghs.tics,ghs.fuse = 30,18
			ghs.scalespeed = $*2
			ghs.destscale = $*99	
		end
		s.sam_spbsstart = $-1
	end
	if s.sam_supertilt
		s.sam_supertilt = $-1
	end
	if s.sam_stopmult
		s.sam_stopmult = $-1
	end
	if s.sam_sidejump --Walljump tracker. > 0 is right, < 0 is left.
		if P_IsObjectOnGround(s)
		or p.sam_screwattacking
		or P_PlayerInPain(p)
		or p.powers[pw_carry]
		or p.sammorphed
			s.sam_sidejump = 0
		elseif (p.pflags & PF_JUMPED) and (p.sam_walljumpsound and p.sam_walljumpsound > 3)
			P_TryMove(s, s.x+(s.momx/2), s.y+(s.momy/2), true)
			p.drawangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
		end
	end			
	if s.sam_flashfade
		if not s.sam_flashfadecolor
			s.sam_flashfadecolor = SKINCOLOR_SUPERSILVER1
		end
		s.sam_flashfade = $-1
	end
	if s.sam_stunimmune
		s.sam_stunimmune = $-1
	end	
	if s.samspawnprotect
		s.samspawnprotect = $-1
	end
	if s.spiderbanim
		s.spiderbanim = $-1
	end
	if s.sam_automobed
		s.sam_automobed = $-1
	end
	if s.sam_unstuck
		s.sam_unstuck = $-1
	end
	if s.sam_emstress --If this goes over 200, you drop your emeralds.
		s.sam_emstress = $-1
	end
	--Where are or will you be getting hit from?
	if s.sam_combowarn
	s.sam_combowarn = $-1		
		if s.sam_combowarntarget and s.sam_combowarntarget.valid
			s.sam_combowarnang = R_PointToAngle2(s.x,s.y, s.sam_combowarntarget.x, s.sam_combowarntarget.y)-(p.cmd.angleturn << 16)
		else
			s.sam_combowarn = 0
			s.sam_combowarntarget = nil
			s.sam_combowarnang = nil
		end
		if not s.sam_combowarn
			s.sam_combowarntarget = nil
			s.sam_combowarnang = nil
		end
	end
	
	if s.sam_hitwarn
		s.sam_hitwarn = $-1
		if not s.sam_hitwarn
			s.sam_hitwarnang = nil
			s.sam_hitwarntarget = nil					
		elseif s.sam_hitwarntarget and s.sam_hitwarntarget.valid --Only calculate once here.
			s.sam_hitwarnang = R_PointToAngle2(s.x,s.y, s.sam_hitwarntarget.x, s.sam_hitwarntarget.y)-(p.cmd.angleturn << 16)
			s.sam_hitwarntarget = nil
		end
	end
	if s.samradaranim
		if s.samradaranimd
			s.samradaranim = (s.samradaranim<9) and $+1 or 0
		elseif not s.samradaranimd
			s.samradaranim = $-1
		end
	end
	--When you're in this animation, use Samus' rolling frames to indicate a "transition" into the morph ball!
	if s.sammorphedghs
		s.sammorphedghs = $-1
		local ghs = P_SpawnMobj(s.x, s.y, s.z+(((s.height/5)-(s.sammorphedghs*10<<16))*P_MobjFlip(s)), MT_THOK)
		ghs.skin = s.skin
		ghs.color = s.color
		ghs.flags = $|MF_NOCLIPHEIGHT
		ghs.eflags = s.eflags
		ghs.sprite = SPR_PLAY
		ghs.sprite2 = SPR2_ROLL
		ghs.frame = (D-s.sammorphedghs)
		if ghs.frame <= A
			ghs.frame = A
		end
		ghs.frame = $|(FF_TRANS30+(s.sammorphedghs<<16))
		ghs.tics = 7-s.sammorphedghs
		ghs.momx = s.momx*10/14 ghs.momy = s.momy*10/14 ghs.momz = s.momz*10/14
		ghs.angle = p.drawangle
		ghs.scale = ((s.scale*s.sammorphedghs)*5)/4
	end
	if p.sam_lockmorphball --Lock the morph ball until it's obtained? (For custom levels)
		p.sams_morphcd = 3
		if p.sammorphed
			SAM.UnMorph(s, true)
		end
	end
	if s.sam_refusewalljump
		s.sam_refusewalljump = $-1
	end
	if s.sam_dustcd 
		s.sam_dustcd = $-1
	end	
	if s.sam_scanpowerup
		if not p.sam_hyperbeampanic and not (s.wavebuffering or s.crystalflashtime)
			s.sam_scanpowerup = $-1
		end
		if not s.sam_scanpowerup
			s.samradaranim = 9
			s.samradaranimd = false
			p.scannedmons = nil
			p.scannedplays = nil
			S_StopSoundByID(s, sfx_sscan1)
			S_StartSound(s, sfx_samtm7)
			s.sam_scanpowerup = 0
		end
	end	
	if s.samvisordrop
		s.samvisordrop = $-1
		if s.samvisordrop >= 17
			p.samvisordropdist = p.samvisordropdist2/2
		else
			p.samvisordropdist = (p.samvisordropdist2*s.samvisordrop)/12
		end
	elseif p.samvisordropdist
		p.samvisordropdist = 0
	end	
	if s.pbshotsmoke
		s.pbshotsmoke = $-1
		if (s.pbshotsmoke > 240)
			s.pbshotsmoker = 250
			s.pbshotsmoke = 0
		end
		if s.pbshotsmoker2
			s.pbshotsmoker2 = $-1
		end
	end
	if p.sams_morphbombcd
		p.sams_morphbombcd = $-1
	end
	if p.sams_shotcd
		p.sams_shotcd = $-1
	end
	if p.sams_hbdenid
		p.sams_hbdenid = $-1
		if p.sams_hbdenid == 30
			p.sams_hbdenid = 0
		end
	end
	if p.sams_mshotcd
		p.sams_mshotcd = $-1
	end
	if p.sams_chargetimecd
		p.sams_chargetimecd = $-1
	end
	if p.sams_firecdjlg
		p.sams_firecdjlg = $-1
	end
	if p.sam_hithud
		p.sam_hithud = $-1
	end
	if p.sam_crithud
		p.sam_crithud = $-1
	end
	if p.sam_resisthud
		p.sam_resisthud = $-1
	end
	if p.sam_walljumpsound
		p.sam_walljumpsound = $-1
	end
	if s.powerbombjump
		s.powerbombjump = $-1
	end
	if s.samunmorphed
		s.samunmorphed = $-1
	end
	if s.wallnopejump
		s.wallnopejump = $-1
	end
	--For Samus' HUD, when she picks up items!
	if s.sampickuptime
		s.sampickuptime = $-1
		if (s.sampickuptime < 40)
			if (s.sampickuptime % 4 == 0)
				s.sampickuptrns = s.sampickuptrns and min(FF_TRANS90, $+FF_TRANS10) or FF_TRANS10
			end
		elseif s.sampickupoffset
			s.sampickupoffset = $-FRACUNIT
		end			
	end
	if s.sampickuptime2
		s.sampickuptime2 = $-1
		if (s.sampickuptime2 < 40)
			if not s.sampickuptime -- Migrate down to the bottom...
				s.sampickupname = s.sampickupname2
				s.sampickupscale = s.sampickupscale2
				s.sampickuptime = s.sampickuptime2
				s.sampickupoffset = s.sampickupoffset2
				s.sampickuptrns = s.sampickuptrns2
				s.sampickupcolor = s.sampickupcolor2
				s.sampickuptime2 = 0
			elseif (s.sampickuptime2 % 4 == 0)
				s.sampickuptrns2 = s.sampickuptrns2 and min(FF_TRANS90, $+FF_TRANS10) or FRACUNIT		
			end			
		elseif s.sampickupoffset2
			s.sampickupoffset2 = $-FRACUNIT
		end
	end
	if s.sampickuptime3
		s.sampickuptime3 = $-1
		if (s.sampickuptime3 < 40)
			if not s.sampickuptime2 -- Migrate down to the bottom...
				s.sampickupname2 = s.sampickupname3
				s.sampickupscale2 = s.sampickupscale3
				s.sampickuptime2 = s.sampickuptime3
				s.sampickupoffset2 = s.sampickupoffset3
				s.sampickuptrns2 = s.sampickuptrns3
				s.sampickupcolor2 = s.sampickupcolor3
				s.sampickuptime3 = 0
			elseif (s.sampickuptime3 % 4 == 0)
				s.sampickuptrns3 = s.sampickuptrns3 and min(FF_TRANS90, $+FF_TRANS10) or FRACUNIT
			end				
		elseif s.sampickupoffset3
			s.sampickupoffset3 = $-FRACUNIT
		end			
	end
	if s.sams_shineframe	
		s.tempsamdye =  (leveltime%2==0) and SKINCOLOR_RED or SKINCOLOR_ORANGE
		s.tempsamdyetr = FF_TRANS10
		if not s.health or P_IsObjectOnGround(s)
			s.sams_shineframe = 0
		else
			s.sams_shineframe = $-1
			if not p.sammorphed
				s.sprite2 = SPR2_FLT
				s.frame = (s.frame & ~FF_FRAMEMASK)
			end
		end
	end		
	if s.samspinpadconfirmed
		s.samspinpadconfirmed = $-1
		p.skidtime = 0
	end
	if s.samspinpad
		s.samspinpad = $-1
		if (s.samspinpad > 47) and ((p.powers[pw_flashing] > 7) and (p.powers[pw_flashing] < 10))
			s.samspinpad = 47
			if not p.powers[pw_nocontrol] --lol, seriously?
				A_CustomPower(s, 21, 32774)
			end
			p.bsblboost = 0
			p.sams_beamcombocharge = 0
			p.pflags = $ & ~PF_JUMPED
			s.samspinpadconfirmed = 2
			if not p.sammorphed
				SamMorphSwitch(p, s)
				S_StartSound(s, sfx_smorph)
				S_StartSound(s, sfx_zoom)
			end
			P_SpawnPlayerMissile(s, MT_SAMMONBREAKER)
			s.momx,s.momy = $*20/19,$*20/19
			CancelScrewAttack(s,p)
		end
		if (s.samspinpad < 48)
			s.samspinpad = (s.samspinpadconfirmed) and $ or 0	
			s.delayedghost = 1
			p.pflags = $|PF_SPINNING
			p.sams_notyet = 3
			
			if (p.pflags & PF_JUMPED) or not p.sammorphed
				s.samspinpadconfirmed,s.samspinpad = 0,0
				p.charflags = $ & ~SF_RUNONWATER
				if not p.sammorphed  or p.bsblboost or (p.speed < 2<<16) or s.samspinpad == 1
					p.pflags = $ & ~PF_SPINNING
				end
			else
				s.samspinpadconfirmed = 2
				p.charflags = $|SF_RUNONWATER
				if (s.eflags & MFE_TOUCHWATER) and not (s.eflags & (MFE_UNDERWATER|MFE_SPRUNG))
					P_SetObjectMomZ(s, 8<<16, false)
					s.momx,s.momy = $*5/6,$*5/6
					S_StartSound(s, sfx_wslap)
				end
			end
			if p.bsblboost or (p.speed < 2<<16) or s.samspinpad == 1
				s.samspinpadconfirmed,s.samspinpad = 0,0
				p.pflags = $ & ~PF_SPINNING
			end
		end
	end
	if p.bsblboost
		p.bsblboost = $-1
	end
	if p.bsblboostattack
		p.bsblboostattack = $-1
		if (p.bsblboostattack > 6)
			if not (s.bsblflame and s.bsblflame.valid)
				s.bsblflame = P_SpawnMobj(s.x, s.y,s.z-s.height/11, MT_OVERLAY)
			end
			local ghs = s.bsblflame
			ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.blendmode = AST_ADD
			ghs.target = s
			ghs.state = S_THOKGLOW
			ghs.tics = 3
			if (p.sam_gravitysuit==2) and p.samvisorcolor
				ghs.color = p.samvisorcolor
			else
				ghs.color = SKINCOLOR_EMERALD
			end	
			if ghs and ghs.valid
				s.tempsamdye = ghs.color
				if (p.bsblboostattack > 16)
					ghs.frame = A|FF_TRANS10
					s.tempsamdyetr = FF_TRANS10
				elseif (p.bsblboostattack > 14)
					ghs.frame = A|FF_TRANS40
					s.tempsamdyetr = FF_TRANS40
				elseif (p.bsblboostattack > 12)
					ghs.frame = A|FF_TRANS70
					s.tempsamdyetr = FF_TRANS70
				elseif (p.bsblboostattack > 6)
					ghs.frame = A|FF_TRANS90
					s.tempsamdyetr = FF_TRANS90
				end
			end 
		end
	end
	if p.sam_spacejumpedboost
		p.sam_spacejumpedboost = $-1
	end
	if p.sam_shinespark
		p.sam_shinespark = $-1
	end	
	if p.sams_screwattackcd
		p.sams_screwattackcd = $-1
	end
	if s.spiderballstillgood
		s.spiderballstillgood = $-1
	end
	if s.spiderballdoublecheck
		s.spiderballdoublecheck = $-1
	end
	if s.pbshotsmoker
		s.pbshotsmoker = $-1
		if p.sam_powerbeamequip
		and not p.sammorphed
			local ZHEIGHT = (s.eflags & MFE_VERTICALFLIP) and (s.height*4/11) or (s.height*2/3)
			ZHEIGHT = $ + (FixedMul(FixedMul(50<<16, s.scale), sin(p.aiming)))
			local RAD,ANG = max(FRACUNIT, s.radius*5/2),s.angle-(ANG2*2)
			if not s.pbshotsmoker2
				local ghs = P_SpawnMobj(s.x+FixedMul(RAD, cos(ANG)), s.y+FixedMul(RAD, sin(ANG)), s.z+ZHEIGHT, MT_SAMCHARGEGFX)
				ghs.scale = s.scale/(P_RandomRange(12,24))
				ghs.color = SKINCOLOR_SILVER
				ghs.flags2 = $|MF2_SHADOW
				ghs.momx = s.momx/2
				ghs.momy = s.momy/2
				ghs.eflags = s.eflags
				ghs.target = s
			end
		else
			s.pbshotsmoke,s.pbshotsmoker,s.pbshotsmoker2 = 0,0,0
		end
	end
	if p.sam_powerbeammeltdown
		s.pbshotsmoker = 0
		if p.sam_fullypoweredsuit or s.crystalflashtime
			p.sams_mshotcd = 10
			p.sam_powerbeammeltdown = 0	
		else
			p.sam_powerbeammeltdown = max($-1,0)
			if p.sam_powerbeammeltdown == 1
				S_StartSound(s, sfx_bcrs)
			end
		end
	end
	if p.sam_spazerbeammeltdown
		if p.sam_fullypoweredsuit or s.crystalflashtime
			p.sams_mshotcd = 10
			p.sam_spazerbeammeltdown = 0
		else
			p.sam_spazerbeammeltdown = $-1
			if p.sam_spazerbeammeltdown== 1
				S_StartSound(s, sfx_bcrs)
			end
		end
	end
	if p.sam_icebeammeltdown
		p.sam_icebeammeltdown = $-1
		if p.sam_icebeammeltdown== 1
			S_StartSound(s, sfx_bcrs)
		end
		if p.sam_fullypoweredsuit or s.crystalflashtime
			p.sams_mshotcd = 10
			p.sam_icebeammeltdown = 0
		end
	end
	if p.sam_wavebeammeltdown
		p.sam_wavebeammeltdown = $-1
		if p.sam_wavebeammeltdown== 1
			S_StartSound(s, sfx_bcrs)
		end
		if p.sam_fullypoweredsuit or s.crystalflashtime
			p.sams_mshotcd = 10
			p.sam_wavebeammeltdown = 0
		end
	end
	if p.sam_plasmabeammeltdown
		p.sam_plasmabeammeltdown = $-1
		if p.sam_plasmabeammeltdown== 1
			S_StartSound(s, sfx_bcrs)
		end
		if p.sam_fullypoweredsuit or s.crystalflashtime
			p.sams_mshotcd = 10
			p.sam_plasmabeammeltdown = 0
		end
	end
	if p.dragdownball --From Samus.Timers.
		p.dragdownball = $-1
		local DRAGDOWN = p.dragdownball
		if p.sammorphed and (p.pflags & PF_JUMPED)
			if s.bombjump or P_IsObjectOnGround(s)
				p.dragdownball = 0
			end
			if (DRAGDOWN > 25)
				if (p.pflags & PF_STARTJUMP)
					s.delayedghost = 1
				else
					p.dragdownball = 16
				end				
			elseif (DRAGDOWN > 20) and (DRAGDOWN < 24)
				P_SetObjectMomZ(s, -65355, true)
			elseif (DRAGDOWN < 10) 
				P_SetObjectMomZ(s, (DRAGDOWN > 7) and -9500 or -15355, true)
			end
		end
	end
	if p.sam_walljumping
		p.sam_walljumping = $-1
		if p.sam_walljumping > 7
			if (p.speed > 8*s.scale) and p.sam_walljumpsound
				if not p.sammorphed
					s.state = S_PLAY_FLOAT
					s.sprite2 = SPR2_FLT_
				end
				s.frame = s.frame & ~FF_FRAMEMASK
				if not (p.pflags & PF_ANALOGMODE)
					p.drawangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
				end
			end
		else
			if p.sam_walljumping == 7
				if not p.sam_shinesparkfly and (s.state == S_PLAY_FLOAT or s.state == S_PLAY_FLOAT_RUN)
					s.state = S_PLAY_ROLL
				end
			elseif p.sam_walljumping == 1 and p.panim == PA_ROLL
				s.state = S_PLAY_FALL
				p.sam_walljumping = 0
			end
		end
	end	
	if s.sam_deathball
		if not (s.wavebuffering or s.crystalflashtime)
		or not p.sammorphed
			s.sam_deathball = nil
		end
	end
	if p.sam_shinesparkfly
		p.sam_shinesparkfly = (p.sam_shinesparkfly < 300) and $+1 or 0
		if (p.speed > 28*s.scale) -- and (abs(s.momz) < 9*s.scale)
			local MINZ = -65*P_MobjFlip(s)
			local MAXZ = (abs(s.momz)>9*s.scale) and 116*P_MobjFlip(s) or 46*P_MobjFlip(s)
			local RNG1 = P_RandomRange(32, 255)
			local ADDSCALE = (p.sam_shinesparkfly<50) and 65000 or 0
			
			SAM.SpeedBoosterWindLines(s, RNG1*s.scale, 
			{XY = P_RandomRange(50, 190,s)*s.scale, EZ = P_RandomRange(MAXZ,MINZ)*s.scale},
			(ADDSCALE) and FF_TRANS30 or (leveltime%2) and FF_TRANS40 or FF_TRANS50, 90000+(RNG1*750)+ADDSCALE,
			(RNG1/14)+5, (leveltime%3==0) and SKINCOLOR_FLAME or SKINCOLOR_SUPERGOLD2)
		end
	end
	if p.sam_beamswitch
		if p.sam_beamswitch == 11
			S_StartSound(s, sfx_besw)
		end
		p.sam_beamswitch = $-1
		if (p.sam_beamswitch > 9)
			p.sam_beamcolor = SKINCOLOR_GREY
		elseif (p.sam_beamswitch > 3)
			p.sam_beamcolor = SKINCOLOR_BLACK
		elseif (p.sam_beamswitch >= 1)
			p.sam_beamcolor = SKINCOLOR_GREY
		end
	end
	if p.prescrewcolor and not p.sam_screwattacking
		s.color = p.prescrewcolor
		p.prescrewcolor = nil
	end
	if (p.samspbscharge <= 130)
		p.samspbschargefull = false
	end
end

--You switched from Samus to another character! "skinswap" "swapcharacter" ".otherchar" "SamusSwitch" "SwitchSamus"
SAM.SwitchFromSam = function(p,s)
	if p.heysamusstopyourhudforthismanytics --Want Samus to stop her HUD functions for a while? Use this.
		p.heysamusstopyourhudforthismanytics = 0
	end
	S_StopSoundByID(s, sfx_sscan1)
	
	if p.encatchupflash
		p.encatchupflash = 0
	end
	if p.micatchupflash
		p.micatchupflash = 0
	end
	if p.smcatchupflash
		p.smcatchupflash = 0
	end
	if p.pbcatchupflash
		p.pbcatchupflash = 0
	end
	if p.sam_energyflash
		p.sam_energyflash = 0
	end
	if p.sams_beamanim
		p.sams_beamanim = 0
	end
	if p.sams_morphcd
		p.sams_morphcd = 0
	end
	if p.sam_spbsgrace
		p.sam_spbsgrace = 0
	end	
	if p.sams_notyet
		p.sams_notyet = 0
	end
	if p.visorclosein and not p.sam_saveselect
		p.visorclosein = 0
	end	
	if p.lavaflash	
		p.lavaflash = 0
	end	
	if s.sam_forcemorphslope 
		s.sam_forcemorphslope = 0
	end
	if s.sam_forcemorphslopeattach
		s.sam_forcemorphslopeattach = 0
	end
	if s.sam_afterboost
		s.sam_afterboost = 0
	end
	if s.VisorDrip
		s.VisorDrip = nil
	end
	if s.SAM_didlockon
		s.SAM_didlockon = nil
	end
	if s.VisorDrips
		s.VisorDrips = nil
	end
	if s.starSAM
		if (p.sam_intoship or p.sam_exitship) and p.sam_st and p.sam_st.valid
			--
		else
			s.starSAM = nil
		end
	end
	if s.samslopespin
		s.samslopespin = 0
	end
	if s.SAM_StartBooster
		s.SAM_StartBooster = nil
	end
	if s.SAM_PSFX
		s.SAM_PSFX = nil
	end
	if s.MissileAmmoDrain
		s.MissileAmmoDrain = nil
	end
	if s.SuperAmmoDrain
		s.SuperAmmoDrain = nil
	end
	if s.PWBOMBDrain
		s.PWBOMBDrain = nil
	end	
	if s.spiderballrecharged then s.spiderballrecharged = nil end
	if s.sam_spbshack then s.sam_spbshack = 0 end
	if s.sam_scansymbol then s.sam_scansymbol = 0 end
	if s.sam_reflectface then s.sam_reflectface = 0 end
	if s.sam_spbsstart then s.sam_spbsstart = 0 end
	if s.sam_supertilt then s.sam_supertilt = 0 end
	if s.sam_stopmult then s.sam_stopmult = 0 end
	if s.sam_sidejump then s.sam_sidejump = 0 end
	if s.sam_flashfadecolor then s.sam_flashfadecolor = nil end
	if s.sam_flashfade then s.sam_flashfade = 0 end
	if s.sam_stunimmune then s.sam_stunimmune = 0 end
	if s.samspawnprotect then s.samspawnprotect = 0 end
	if s.spiderbanim then s.spiderbanim = 0 end
	if s.sam_unstuck then s.sam_unstuck = 0 end
	if s.sam_combowarn then s.sam_combowarn = 0 end
	if s.sam_combowarntarget then s.sam_combowarntarget = nil end
	if s.sam_combowarnang then s.sam_combowarnang = nil end
	if s.sam_hitwarn then s.sam_hitwarn = 0 end
	if s.sam_hitwarnang then s.sam_hitwarnang = nil end
	if s.sam_hitwarntarget then s.sam_hitwarntarget = nil end
	if s.sammorphedghs then s.sammorphedghs = 0 end
	if s.sam_refusewalljump then s.sam_refusewalljump = 0 end
	if s.samradaranim then s.samradaranim = 0 end
	if s.samradaranimd then s.samradaranimd = false end
	if p.scannedmons then p.scannedmons = nil end
	if p.scannedplays then p.scannedplays = nil end
	if s.sam_scanpowerup then s.sam_scanpowerup = 0 end
	if p.sams_hbdenid then p.sams_hbdenid = 0 end
	if p.sam_hithud then p.sam_hithud = 0 end
	if p.sam_crithud then p.sam_crithud = 0 end
	if p.sam_resisthud then p.sam_resisthud = 0 end
	if s.powerbombjump then s.powerbombjump = 0 end
	if s.samunmorphed then s.samunmorphed = 0 end
	if s.wallnopejump then s.wallnopejump = 0 end
	if s.sampickuptime then s.sampickuptime = 0 end
	if s.sampickuptime2 then s.sampickuptime2 = 0 end
	if s.sampickuptime3 then s.sampickuptime3 = 0 end
	if s.sams_shineframe then s.sams_shineframe = 0 end
	if s.samspinpadconfirmed then s.samspinpadconfirmed = 0 end
	if s.samspinpad then s.samspinpad = 0 end
	if p.sams_notyet then p.sams_notyet = 0 end
	if p.bsblboost then p.bsblboost = 0 end
	if p.bsblboostattack then p.bsblboostattack = 0 end
	if s.bsblflame then s.bsblflame = nil end
	if p.sam_spacejumpedboost then p.sam_spacejumpedboost = 0 end
	if p.sam_shinespark then p.sam_shinespark = 0 end
	if s.spiderballstillgood then s.spiderballstillgood = 0 end
	if s.spiderballdoublecheck then s.spiderballdoublecheck = 0 end
	if p.dragdownball then p.dragdownball = 0 end
	if p.sam_walljumping then p.sam_walljumping = 0 end
	if p.sam_walljumpsound then p.sam_walljumpsound = 0 end
	if s.sam_deathball then s.sam_deathball = nil end
	if p.sam_shinesparkfly then p.sam_shinesparkfly = 0 end
	if p.sam_beamswitch then p.sam_beamswitch = 0 end
	if p.samspbscharge then p.samspbscharge = 0 end
	if p.samspbschargefull then p.samspbschargefull = false end
	
	if p.prescrewcolor and not p.sam_screwattacking
		s.color = p.prescrewcolor
		p.prescrewcolor = nil
	end
	if p.sams_screwattackd
		p.sams_screwattackcd = 0
	end
	if s.pbshotsmoke or s.pbshotsmoker or s.pbshotsmoker2
		s.pbshotsmoke,s.pbshotsmoker,s.pbshotsmoker2 = 0,0,0
	end
end

--Cancels LockOn.
SAM.CancelLockOn = function(p,s)
	if s.sam_automob
		p.aiming = 0
		s.sam_automob = nil
	end
	if (p.automobf and p.automobf.valid)
		p.automobf.color = SKINCOLOR_SILVER
		p.automobf.destscale = $*10
		p.automobf.scalespeed = $*2
		p.automobf.tics = 8
		p.automobf.cancellock = true
		p.automobf.frame = (Z+1)|FF_TRANS80|FF_FULLBRIGHT
		p.automobf = nil
	end
	s.sam_faillock = false
	s.sam_lockedon = false
	s.sam_lockseek = 0
	s.sam_sighttime = 0
	s.sam_lockclosest = nil
	s.sam_lockchosen = nil	
end

addHook("NetVars", function(network) WEATHERC = network($) end)
