--Here I've added the freeslots that were never registered properly. 
--As well as some freeslots that had to be added in Lua in order to work in Lua.
local function SingleFreeSlot(...)
	for _,slot in ipairs({...})
		if not rawget(_G, slot) freeslot(slot) end
	end
end 

--For SingleFreeSlot, you'll need to add "" to the object names so Lua knows it's a string.
--Make sure every object has a comma behind it EXCEPT the final one!
SingleFreeSlot(
"MT_ROBM",
"MT_GOLF",
"MT_PGRD",
"MT_CBRN",
"MT_SWAT",
"MT_SWUT",
"MT_VASE",
"MT_VAAS",
"MT_VPLT",
"MT_TCAM",
"MT_TVDR",
"MT_VECTORSCENERY",
"SPR_FOOD",
"SPR_VECT",
"S_VECTORSCENERY1",
"S_RPVAASF1",
"S_RPFOOD",
"S_PCANDRINK",
"sfx_propel",
"sfx_kbam",
"sfx_swut"

)
sfxinfo[sfx_swut] = {flags = SF_X2AWAYSOUND} --Hear this from 2x as far away.

--For any object you want to create screenshakes on destruction, add its item name to the list below!
--Make sure every object has a comma behind it EXCEPT the last object.
--Also, ensure it's freeslotted in Lua's "SingleFreeSlot" function above, NOT in a SOC file.
local QUAKEOBJECTS = {
MT_VASE,
MT_VAAS,
MT_VPLT,
MT_TCAM,
MT_TVDR
}

local function QuakeCollide(s, v)
	if v and v.valid and v.player and (v.player==displayplayer)
		if s.valid and s.health
			P_StartQuake(v.player, 45<<16, 3)
		end
	end
end
for THING = 1,#QUAKEOBJECTS
	addHook("MobjCollide", QuakeCollide, THING)
	addHook("MobjMoveCollide", QuakeCollide, THING)
end

--Makes SRB2 not punish homing attacks because they lock onto hazards for whatever reason.
addHook("MobjDeath", function(sp, i, s) if not sp.valid return end --
	if s and s.valid and s.player	
		local p = s.player local yu = p.yusonictable
		if p.homing or p.powers[pw_super] or p.hypermysticsonic
		or s.skin == "adventuresonic" and p.yusonictable and p.yusonictable.lsahoming
			if sp and sp.valid
				P_SpawnMobj(sp.x, sp.y, sp.z+sp.height, MT_EXPLODE)
				local gag = P_SpawnMobj(sp.x, sp.y, sp.z+sp.height, MT_THOK)
				gag.sprite = SPR_TVEG
				gag.renderflags = RF_SEMIBRIGHT|RF_NOCOLORMAPS
				gag.frame = C
				gag.tics = -1
				gag.flags = MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING
				gag.rollangle = P_RandomRange(1,359)*ANG1
				gag.fuse = 59
				gag.z = $+10<<16
		
				P_SetObjectMomZ(gag, 14<<16)	
				P_InstaThrust(gag, s.angle, 40<<16)
				S_StartSound(gag, sfx_bowl)
				S_StartSound(gag, sfx_behurt)
		
				sp.health = 0
				sp.flags = $|MF_NOCLIP & ~MF_SOLID
				sp.state = S_ROBMF2 return true --
			end
		end
	end
end, MT_ROBM)

--SRB2's falling rocks were never very well optimized...
addHook("MobjSpawn", function(s) 
	if s.valid and s.flags
		s.flags = $|MF_NOBLOCKMAP
		if not s.fuse or (s.fuse > 133)
			s.fuse = 133
		end
	end
end, MT_FALLINGROCK)

--Simple code to make "swut" bot not spam PRIORITY NUMBER ONE 24/7
local function SwatBotFix(s)
	if s.valid
		if s.health
			if not (s.target and s.target.valid)
				s.PriorityNumberOne = 0
			else
				if s.PriorityNumberOne
					s.PriorityNumberOne = max($-1,0)
				else
					if not S_SoundPlaying(s, sfx_swut)
						S_StartSound(s, sfx_swut)
					end
					s.PriorityNumberOne = 120					
				end
			end
		else
			S_StopSoundByID(s, sfx_swut)
		end
	end
end
addHook("MobjThinker", SwatBotFix, MT_SWUT)
addHook("MobjThinker", SwatBotFix, MT_SWAT)

--Turning this into a cute little gimmick similar to Sonic Advance's flagpoles.
local function BranchLauncher(s, v)
	if v and v.player and s.valid and not (s.cantbegrabbed)
	and not P_IsObjectOnGround(v) and v.momz and not (v.state == S_PLAY_RIDE)
		local p = v.player
		if (p.panim >= PA_IDLE) and (p.panim <= PA_FALL) and (p.panim != PA_PAIN)
		and not p.powers[pw_ignorelatch]
		and not ((p.cmd.buttons & BT_SPIN) and (s.state == S_PLAY_FALL) and not (p.pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED)))
			
			local RVOLUME = min(255, FixedInt(abs(v.momz*16)) )
			
			if not s.LaunchAnim
				s.LaunchAnim = 13
				S_StartSoundAtVolume(s, sfx_wbreak, RVOLUME/2)
				S_StartSoundAtVolume(s, sfx_s251, RVOLUME)
				local ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_EXPLODE)
				ghs.flags2 = $|MF2_SHADOW
			end
			p.pflags = $|PF_JUMPDOWN|PF_USEDOWN & ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED)
			S_StartSoundAtVolume(v, sfx_s1c0, RVOLUME)
			S_StartSoundAtVolume(v, sfx_s3k4a, RVOLUME*2/3)
			v.PREbranch = {momX = v.momx, momY = v.momy, momZ = v.momz, holding = 0} 
			
			if not s.LIST s.LIST = {} end
			
			local NUM = 1
			for z in players.iterate
				if z.mo
					if z.mo==v
						s.LIST[NUM] = z.mo break --
					end
					NUM = $+1
				end
			end
			
		end
	end return true --
end
addHook("TouchSpecial", BranchLauncher, MT_CBRN)

--Makes the branch animate before springing anybody.
addHook("MobjThinker", function(BRANCH) 

	if not BRANCH.valid return end --
	
	if BRANCH.cantbegrabbed
		BRANCH.cantbegrabbed = $-1
	end
	local LAUNCH = BRANCH.LaunchAnim or 0
	
	if BRANCH.LIST
		local FOUNDANYONE = false
		for i = 1,32
			local s = BRANCH.LIST[i] local p = s and s.valid and s.player
			if p and s.health and BRANCH.LaunchAnim != nil
			and not (p.pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED))
			and not (p.panim == PA_PAIN)
			
				p.pflags = $|PF_JUMPDOWN|PF_USEDOWN
				S_StopSoundByID(s, sfx_jump)
				
				if (LAUNCH <= 1) --The launching part!
				
					local LAUNCHPOWER = 20<<16
					if s.PREbranch and s.PREbranch.momZ != nil
						local MOMZ = abs(s.PREbranch.momZ)*2
						--Diminishing returns...
						if (MOMZ > 19<<16)
							P_SpawnGhostMobj(s)						
							if (MOMZ > 25<<16)
								LAUNCHPOWER = max(25<<16, min(33<<16, MOMZ/2))
								local ghs = P_SpawnGhostMobj(s)
								ghs.scale = s.scale
								P_SetObjectMomZ(ghs, 8<<16)
							else
								LAUNCHPOWER = max(19<<16, min(30<<16, MOMZ*2/3))
							end
						else--if (MOMZ < 15<<16)
							LAUNCHPOWER = max(12<<16, min(30<<16, MOMZ*4/3))
						end
						p.powers[pw_ignorelatch] = 33-FixedInt(LAUNCHPOWER)+(1<<15)
					end	
					local RVOLUME = min(255, FixedInt(LAUNCHPOWER*10))
					p.powers[pw_carry] = 0
					s.spriteyoffset = 0
					p.pflags = $ & ~(PF_JUMPSTASIS|PF_JUMPED)
					
					s.z = BRANCH.z+(99*P_MobjFlip(s))
					s.eflags = $|MFE_SPRUNG & ~(MFE_JUSTHITFLOOR|MFE_APPLYPMOMZ)
					s.state = S_PLAY_SPRING
					p.powers[pw_justlaunched] = 2
					p.powers[pw_ignorelatch] = 9+(1<<15)
					S_StartSoundAtVolume(s, sfx_branc, RVOLUME)
					S_StartSoundAtVolume(BRANCH, sfx_branc, RVOLUME)
					
					local forwardmove,sidemove = abs(p.cmd.forwardmove),abs(p.cmd.sidemove)
					local DIRECT = (forwardmove>sidemove) and forwardmove or sidemove
					local TURNANG = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
					if (DIRECT > 2)
						P_Thrust(s, TURNANG, DIRECT*7000)
					end
					P_SetObjectMomZ(s, LAUNCHPOWER)
					s.PREbranch = nil
					BRANCH.cantbegrabbed = 7
					if p == displayplayer
						P_StartQuake(LAUNCHPOWER*2, 3)
					end
					
				else --Hanging on for dear life!
				
					FOUNDANYONE = true
					
					p.powers[pw_carry] = 7730
					s.state = S_PLAY_RIDE
					s.eflags = $ & ~(MFE_JUSTHITFLOOR|MFE_APPLYPMOMZ)
					if not ((s.flags2 & MF2_TWOD) or twodlevel)
						p.drawangle = BRANCH.angle+ANGLE_180
					end
					S_StopSoundByID(s, sfx_jump)
					p.powers[pw_nocontrol] = max(0, LAUNCH-2)
					s.momx,s.momy,s.momz = $*3/4,$*3/4,0
					local X = BRANCH.x+FixedMul(16*s.scale, cos(BRANCH.angle))
					local Y = BRANCH.y+FixedMul(16*s.scale, sin(BRANCH.angle))
					P_MoveOrigin(s, X, Y, BRANCH.z-(18*BRANCH.scale*P_MobjFlip(BRANCH)) )
					s.spriteyoffset = max(-40<<16, $-5<<16)
				end
			else
				BRANCH.LIST[i] = nil
			end
		end
		if FOUNDANYONE == false
			BRANCH.LIST = nil
		end
	end
	if LAUNCH --C>A>B. From highest to lowest.
		BRANCH.frame = (LAUNCH<3) and C or (LAUNCH>20) and A or B
		BRANCH.LaunchAnim = $-1
	end
end, MT_CBRN)

--You're supposed to be launched like a golf ball, sooo...turn players into a ball!
addHook("MobjThinker", function(s)
	if s.valid and s.GolfTarget
		local t = s.GolfTarget local p = t and t.valid and t.player
		if p and (t.eflags & MFE_SPRUNG) and not (p.pflags & (PF_SPINNING|PF_SLIDING))	
			t.state = S_PLAY_ROLL
			p.pflags = $|PF_SPINNING|PF_THOKKED & ~(PF_STARTDASH|PF_JUMPED|PF_NOJUMPDAMAGE) --Apply PF_THOKKED for actual spin control.
			if not S_SoundPlaying(t, sfx_golf)
				S_StartSound(t, sfx_golf)
			end
			if t.skin == "adventuresonic" and p.yusonictable
				local yu = p.yusonictable
				yu.spin = 999<<16
				yu.startdash,yu.spindashhover = 0,0
				yu.nospindrag,yu.noairdrag = 99,99
				yu.noubercontrol,yu.nosarun4 = 7,14
			end
			
			--Allow a little instant control on launch!
			local forwardmove,sidemove = abs(p.cmd.forwardmove),abs(p.cmd.sidemove)
			local DIRECT = (forwardmove>sidemove) and forwardmove or sidemove
			local TURNANG = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
			if (DIRECT > 2)
				P_Thrust(t, TURNANG, DIRECT*6789)
			end	
		end
		s.GolfTarget = nil
	end
end, MT_GOLF)

--Collission code.
local function GolfLauncher(s, v)
	if s.valid and v and v.valid and v.player and v.health
		if (s.z > v.z+v.height)
		or (v.z > s.z+s.height)
			return --
		end
		if s.GolfTarget == v
			return false --
		end
		s.GolfTarget = v
	end
end
addHook("MobjCollide", GolfLauncher, MT_GOLF)
addHook("MobjMoveCollide", GolfLauncher, MT_GOLF)

--Let's give the player a proper reaction to being pushed by these dudes.
local function BouncerLauncher(s, v)
	if s.valid and v and v.valid and v.player and v.health
		local p = v.player
		if (s.z > v.z+v.height)
		or (v.z > s.z+s.height)
		or (p.panim == PA_PAIN)
			return false --
		end
		
		if p.powers[pw_super] or p.hypermysticsonic --lol
			for d = 1,16
				local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_EXPLODE)
				ghs.color = SKINCOLOR_FLAME
				ghs.colorized = true
				ghs.blendmode = AST_ADD
				ghs.spritexscale,ghs.spriteyscale = 3<<16,3<<16
				P_Thrust(ghs, d*ANGLE_22h, 12<<16)
			end
			local SFX = P_SpawnMobjFromMobj(s,0,0,0, MT_THOK)
			SFX.flags2 = MF2_DONTDRAW SFX.fuse,SFX.tics = 144,144
			S_StartSound(SFX, sfx_glas) S_StartSound(SFX, sfx_glass)
			S_StartSound(v, sfx_brakrx)
			for d = 1,18
				local shards = P_SpawnMobj(v.x+(P_RandomRange(-50,50)*v.scale), v.y+(P_RandomRange(-50,50)*v.scale), v.z+(P_RandomRange(5,90)*v.scale), MT_WOODDEBRIS)
				if shards and shards.valid 
					shards.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING
					shards.spritexscale,shards.spriteyscale = 3<<16,3<<16
					P_InstaThrust(shards, v.angle+(P_RandomRange(-25,25)*ANG1), p.speed+8*v.scale)
					P_SetObjectMomZ(shards, (P_RandomRange(2,16)*v.scale)+v.momz, false)
					shards.renderflags = RF_FULLDARK|RF_NOCOLORMAPS
					shards.sprite = SPR_SWAT
					shards.frame = (P_RandomRange(H,I))|FF_TRANS10
					shards.rollangle = P_RandomRange(0,359)*ANG1
				end		
			end
			if p == displayplayer
				P_StartQuake(66<<16, 7)
			end			
			s.state = S_NULL return false --
		end
		
		P_DoPlayerPain(p,s,s)
		P_InstaThrust(v, s.angle, 9<<16) 
		v.momz = $/2
		p.drawangle = s.angle+ANGLE_180
		if s.state == S_PGRD
			s.state = S_PGRDF
			if not S_SoundPlaying(s, sfx_pgrd)
				S_StartSound(s, sfx_pgrd)
			end			
		end		
	end return false --
end
addHook("MobjCollide", BouncerLauncher, MT_PGRD)
addHook("MobjMoveCollide", BouncerLauncher, MT_PGRD)