local GUN = GUN_Troops

--#============================================================================================================================#
--This is the code for the GUN Beetle, a relatively simpler enemy!
--#============================================================================================================================#

--Set up the GUN trooper's object Table? This is basically their MobjSpawn function!
GUN.SetupBeetle = function(s, SPAWNDEFAULT)
	if s.GUN_BeetleTable return end -- Table already exists, cancel!

	local WEAPON = nil
	local DEFENSE = nil
	local AMBUSH = 0
	local FLIGHTPATH = nil
	local CHASE = nil
	local SEARCHTYPE = 0 
	local HEARING = 1//500*FRACUNIT
	local VIEWDIST = 1500*FRACUNIT
	local VIEWCONE = ANG10*11
	local EYEGLOW = SKINCOLOR_RED
	local COLOR = SKINCOLOR_GUNHUNTER
	local COLORIZED = false
	local GOLDENBEETLE = false
	local SCALE = s.scale*6/5
	
	local spn = s.spawnpoint --Add spawnpoint parameters if available!
	if spn and spn.valid
		if spn.options != nil
		
			--BINARY map options!
			if ((udmf) != true) --Binary map options!
			
				FLIGHTPATH = "auto" --Welp, this is unfortunate. Let's optimize it the best I can.
				
				if (spn.options & MTF_EXTRA) -- Flag 1: TURRET!
					if (spn.options & MTF_OBJECTSPECIAL) --Combine with BOMBER for a SPRING Beetle!
						WEAPON = "spring" --Spring!
						EYEGLOW = 0
					else
						WEAPON = "turret" --Turret!
						EYEGLOW = SKINCOLOR_RED
					end
				elseif (spn.options & MTF_OBJECTSPECIAL) --Flag 4. BOMBER!
					WEAPON = "bomber" --Bomber!
					EYEGLOW = SKINCOLOR_SKY
				end
				
				--AMBUSH! Beetles will appear out of nowhere.
				if (spn.options & MTF_AMBUSH)
					AMBUSH = 9
					FLIGHTPATH = nil
				end
				
				--Create a Golden Beetle?
				if (spn.extrainfo == 7)
					GOLDENBEETLE = true
					COLOR = SKINCOLOR_GOLDENROD
					COLORIZED = true
					EYEGLOW = SKINCOLOR_SILVER
					VIEWDIST = 500*FRACUNIT
					HEARING = 500*FRACUNIT
					VIEWCONE = ANG10*17
				end
				
			elseif spn.args != nil --UDMF specific options!

---------------------------------------------------------------------------
				for i = 1,1 --Only doing this so I can use "break"
---------------------------------------------------------------------------	

				if spn.scale
					if spn.scale != FRACUNIT and (spn.scale != SCALE)
						SCALE = (spn.scale*5)/6
					end
				end	
				
				--What weapon are wielding?
				if spn.args[0] -- bruh. why was there an arg mismatch here. -garrean
					if spn.args[0] == 1						
						WEAPON = "turret"
					elseif spn.args[0] == 2					
						WEAPON = "bomber"
						EYEGLOW = SKINCOLOR_SKY
					elseif spn.args[0] == 3
						WEAPON = "spring"
						EYEGLOW = 0											
					end
				end
				
				--Defensive Measures? Zapper, Armor(need a strong attack to defeat), or a projectile Reflector?
				if spn.args[1]			
					if spn.args[1] == 1 
						DEFENSE = "zapper"	
					elseif spn.args[1] == 2
						DEFENSE = "armor"					
					elseif spn.args[1] == 3 
						DEFENSE = "reflector"	
					end
				end

				--Follow a flightpath?
				if spn.args[2]
					FLIGHTPATH = spn.args[2]
				end

				--AMBUSH! Teleport in from nowhere!
				if spn.args[3]
					AMBUSH = 9
					FLIGHTPATH = nil
					VIEWDIST = 900*FRACUNIT --Use a simpler search function.
					VIEWCONE = 360
					HEARING = 1
				end
				
				--Golden Beetle?
				if spn.args[4]
					GOLDENBEETLE = true
					COLOR = SKINCOLOR_GOLDENROD -- why was this sky -garrean
					COLORIZED = true
					EYEGLOW = SKINCOLOR_SILVER
				end
				
				--Viewing Range. How far you can see!
				if spn.args[5]
					VIEWDIST = spn.args[5]*FRACUNIT				
				end
				
				--View cone. How broad is your field of vision? 
				--If it's 360, see all around and skip P_CheckSight checks!
				if spn.args[6]
					VIEWCONE = (spn.args[6] >= 360) and 360 or spn.args[6]*ANG1				
				end
				
				--Hearing Range! If set to 1, the mech is deaf!
				if spn.args[7]
					HEARING = (spn.args[7] == 1) and 1 or spn.args[7]*FRACUNIT
				end
				
				--Target players, enemies, both, or do both with a preference for one or the other?
				if spn.args[8]
					if spn.args[8] == 1 or spn.args[8] == 3 or spn.args[8] == 4
						SEARCHTYPE = spn.args[8]
					else
						SEARCHTYPE = 2 --Default to 2, which is "both".
					end
				end
				
				--Give the GUN Beetles a custom eyeglow?
				if spn.pitch
					if (spn.pitch > #skincolors-1) --Default to red if color is unavailable.
						EYEGLOW = SKINCOLOR_RED
					else
						EYEGLOW = spn.pitch
					end
				end
				
----------------------------------------------------------				
				end --End "for i" loop.
----------------------------------------------------------

				--Give your GUN Beetle a custom paint job? Not allowed for Golden Beetles.
				if not GOLDENBEETLE
					if spn.args[9]
						if not (spn.args[9] > #skincolors-1) --Invalid color!
							COLOR = spn.args[9]
						end
					end
					--Colorize the entire Gun Hunter?
					if spn.roll == 180 or spn.roll == ANGLE_180 or spn.roll == FRACUNIT*180 --If it's 180, then colorize!
						COLORIZED = true
					end
				end
			end
		end
				
	elseif not (SPAWNDEFAULT) --Do code for random spawning?
	
		if (leveltime % 6 == 0)
			DEFENSE = "zapper"
			if (leveltime % 30 == 0)
				DEFENSE = "armor"
			end
		end
		local RNG = P_RandomRange(1,99)
		if (RNG > 60)	
			if (RNG < 72)
				WEAPON = "spring"
				EYEGLOW = 0
			elseif (RNG < 87)
				WEAPON = "turret"
				EYEGLOW = SKINCOLOR_RED
			else
				WEAPON = "bomber"
				EYEGLOW = SKINCOLOR_SKY
			end
		elseif (RNG < 6)
			GOLDENBEETLE = true
			COLOR = SKINCOLOR_GOLDENROD
			COLORIZED = true
			EYEGLOW = SKINCOLOR_SILVER
			VIEWDIST = 500*FRACUNIT
			VIEWCONE = ANG10*17
			HEARING = 500*FRACUNIT
		end
	end
	
	s.GUN_BeetleTable = {
	looktimer = 7, --Tics down, then looks for a player.
	searchtype = 0, --Who do we look for? Players, enemies, or both?
	lookdist = VIEWDIST, --From how far away can we see targets?
	distpref = 0, --Preference for distance?
	lostsight = 0, --How many tics we can have lost sight for before the mech forgets about the target.
	cone = VIEWCONE, --Vision cone for seeing foes.
	hearing = (HEARING != 1) and HEARING or 0, --Hearing range, for when vision fails! By default Beetles are deaf.
	
	charge = 0, --How long you're charging.
	shotcd = 0, --Firerate cooldown.
	weapon = WEAPON, --nil, "turret", "spring", and "bomber" are options.
	defense = DEFENSE, --nil, "zapper", "reflector", "armor" are options for defense.
	ambush = AMBUSH, --Teleport in from nowhere?
	goldenbeetle = GOLDENBEETLE, --Are we a Golden Beetle?
	eyeglow = EYEGLOW, --Red glare from eye? (Can be other colors)
	realscale = SCALE,
	flightpath = FLIGHTPATH, --Use a flightpath?
	chase = CHASE, --Chase your foe or match their height?
	
	spawnx = s.x,
	spawny = s.y,
	spawnz = s.z,
	lastx = s.x,
	lasty = s.y,
	lastz = s.z,
	}
	local yu = s.GUN_BeetleTable
	
	s.GUNally = true
	s.color = COLOR
	s.colorized = (COLORIZED)
	s.scale = SCALE --Scale them slightly bigger to satisfy Metalwario's OCD.
	s.destscale = SCALE
	s.spritexscale = FRACUNIT
	s.spriteyscale = FRACUNIT
	s.shadowscale = FRACUNIT-25000
	--If we're not ambushing, then appear!
	if not AMBUSH
		s.state = S_GUNB_MONOEYE --Default.
		s.flags2 = $ & ~MF2_DONTDRAW
		if yu.weapon
			if yu.weapon == "turret"
				s.state = S_GUNB_TURRET
			elseif yu.weapon == "bomber"
				s.state = S_GUNB_BOMBER
			elseif yu.weapon == "spring"
				s.state = S_GUNB_SPRING
				s.flags = $|MF_SPRING --We're a spring now!
				s.radius = $+(5*s.scale) --Slightly bigger hitbox!
				s.height = $+(5*s.scale) 
			end
		end
	else
		s.state = S_GUNB_AMBUSH
	end
end

--#============================================================================================================================#
--Main MobjThinker calling most of the functions and performing the actions.
--#============================================================================================================================#

addHook("MobjThinker", function(s)
	if not (s.valid and s.health) return end
	if not s.GUN_BeetleTable GUN.SetupBeetle(s) end 
	local yu = s.GUN_BeetleTable
	
	if (s.state == S_GUNB_AMBUSH) 
		s.flags = $|MF_NOCLIPTHING & ~(MF_ENEMY|MF_SHOOTABLE)
	else
		s.scale = yu.realscale
		--Spawn the crimson eyeglow?
		if yu.eyeglow
			GUN.CrimsonEye(s, nil, yu)
		end
		--Wind lines with high vertical speed.
		if (abs(s.momz) > 12*s.scale)
			GUN.zwind(s, (abs(s.momz) > 24*s.scale) and 4 or 2)
		end	
		s.flags = $|MF_ENEMY|MF_SHOOTABLE & ~MF_NOCLIPTHING
	end
	
--#============================================================================================================================#	
	--Target interaction code.
--#============================================================================================================================#
	
	--Looking phase!
	if not (s.target and s.target.valid)
		if not S_SoundPlaying(s, sfx_ghsfxf) and not (s.state == S_GUNB_AMBUSH) 
			S_StartSoundAtVolume(s, sfx_ghsfxf, 60)
		end	
		if not yu.looktimer
			local t,CLOSEST = GUN.SearchTarget(s, 1024 * FRACUNIT, yu.searchtype, yu.cone, yu.hearing, yu.distpref) --garrean
			--Adjust how often to search depending on how far our last potential target was to save on resources.
			if not (t and t.valid) and CLOSEST != nil
			
				yu.looktimer = 
				(CLOSEST < (yu.lookdist or 2000*FRACUNIT)) and 5 or
				(CLOSEST < (yu.lookdist*2 or 3300*FRACUNIT)) and 11 or
				min((CLOSEST/130/FRACUNIT), 69)	
				
				if yu.cone == 360 --This is less intensive, so do it more often.
					yu.looktimer = max(1, $/2)
				end
			else
				if t and t.valid
					s.target = t --You're our target now!
					
					--Appear from nowhere?	
					if yu.ambush
						s.flags2 = $ & ~MF2_DONTDRAW
						s.flags = $|MF_SHOOTABLE|MF_ENEMY
						if yu.ambush == 9 or yu.ambush == 1
							GUN.SpawnDust(s, nil, nil, true)
							yu.charge = 0
							
							/* -- this looks jank -garrean
							local ghs = P_SpawnMobjFromMobj(s, s.momx,s.momy,s.momz, MT_EXPLODE)
							ghs.spriteyscale = $*3
							ghs.spritexscale = $*3
							ghs.dispoffset = 3
							S_StartSound(ghs, sfx_s236)
							*/
							
							S_StartSound(s, sfx_s236)
							S_StartSound(s, sfx_s3k52)
							S_StartSoundAtVolume(s, sfx_s254, 110)
							if (yu.ambush == 9)
								GUN.GradualTurn(s, t, ANGLE_90)
								s.angle = $+ANGLE_135
						--	else
						--		GUN.GradualTurn(s, t, ANGLE_90) --Harsh turn!
							end
						end
						if (s.state == S_GUNB_AMBUSH)
							s.state = S_GUNB_MONOEYE
							if yu.weapon
								if yu.weapon == "turret"
									s.state = S_GUNB_TURRET
								elseif yu.weapon == "bomber"
									s.state = S_GUNB_BOMBER
								elseif yu.weapon == "spring"
									s.state = S_GUNB_SPRING
								end
							end
						end
					else
						S_StartSoundAtVolume(s, sfx_ghsfx1, 60)
					end
					S_StopSoundByID(s, sfx_ghsfxf)
					GUN.GradualTurn(s, t)
				end
				yu.looktimer = 9
			end
		end	
		
--#============================================================================================================================#
	else --We've got a confirmed and valid target! Shall we do something with it?
--#============================================================================================================================#
		local t = s.target	
		
		if t.valid --Aaatack!	
		
			local TURNSPEED = (yu.shotcd) and ANG1*3 or (not P_IsObjectOnGround(s)) and ANG30 or (yu.charge) and ANG20 or ANG1*12
			
			if (s.state != S_GUNB_AMBUSH) --We're fighting!
				GUN.GradualTurn(s, t, TURNSPEED) --Gradually face target, a bit slower.
				
				if (yu.weapon == "turret" or yu.weapon == "bomber") and not yu.shotcd
					if not yu.charge --Play charging sound on start.
						S_StartSound(s, sfx_ghsfx4) --4 is the default laser charge.
					end
					yu.charge = $+1
					local CHARGEMAX = 36 --Laser needs less charge
					
					--Grenade behaviour.
					if (yu.weapon == "bomber")
						CHARGEMAX = 50
						if s.subsector and s.subsector.sector --Spawn it over the floor.
							local secT = s.subsector.sector
						
							local TRANS = (yu.charge < 8) and (10*FRACUNIT-(yu.charge*FRACUNIT)) or (yu.charge < 40) and FF_TRANS30 or FF_TRANS10
						
							local ghs = GUN.FloorTarget(s, (yu.charge > 40) and SKINCOLOR_PURPLE or 0, 2, max(FRACUNIT+48000, FRACUNIT*7-(yu.charge*7500)),
							(yu.charge > 40) and AST_ADD or nil, TRANS)
							
							if ghs and ghs.valid
								ghs.z = (s.eflags & MFE_VERTICALFLIP) and secT.ceilingheight-s.scale or secT.floorheight+s.scale
								if (yu.charge < 40)
									ghs.rollangle = leveltime*ANG10
								end
								ghs.momx = s.momx/3
								ghs.momy = s.momy/3
							end
						end
					end
					if (yu.charge >= CHARGEMAX) //and (yu.cone == 360 or P_CheckSight(s,t)) --Wait until they show themselves, then fire immediately!
					
						S_StopSoundByID(s, sfx_ghsfx5)
						S_StopSoundByID(s, sfx_ghsfx4)				
						yu.charge = 0
						yu.shotcd =  (yu.weapon == "bomber") and 110 or TICRATE -- holy shit nerf this please -garrean
						GUN.GradualTurn(s, t, ANGLE_45)
						
						if yu.weapon == "bomber"
							GUN.HunterGrenade(s, t, true) --Drop a grenade down!
						else
							GUN.HunterLaser(s, t, true) --Fire a basic laser!
						end
					end
				else
					yu.charge = 0
				end
			elseif not yu.shotcd
				GUN.GradualTurn(s, t, TURNSPEED)
			end
		end
		
		--Are we losing the target? Check only every so often to save resources.
		if not yu.looktimer
			local VIEWDIST = (yu.lookdist > 3000*FRACUNIT) and yu.lookdist or 3000*FRACUNIT
			
			if not t.health --They're dead, Jimmy...
				yu.lostsight = FRACUNIT*999
			elseif (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) > VIEWDIST)
				yu.lostsight = $+60 --REALLY far away...! Lose sight quickly.
			elseif not GUN.CanDetect(s,t)
				yu.lostsight = $+12 --Gradually lose target if they're close-by, but not within sight.
			end
			if (yu.lostsight > 100) --If yu.lostsight is above this, undo target.
				s.target = nil
				yu.lostsight = 0
				yu.looktimer = 3
			end
		end
	end
	
	--Timers.
	if yu.looktimer
		yu.looktimer = $-1
	end
	--Different from GUN Hunters, it's an animation timer here.
	if yu.ambush
		if ((s.state != S_GUNB_AMBUSH) or (yu.ambush < 9))
			s.flags2 = $ & ~MF2_DONTDRAW
			s.spritexscale = (FRACUNIT*(yu.ambush/2)) or FRACUNIT
			s.spriteyscale = (FRACUNIT/yu.ambush)+9999
			yu.ambush = $-1
		
			if true -- not yu.ambush -- this looks jank -garrean
				s.spritexscale = FRACUNIT
				s.spriteyscale = FRACUNIT
			end
			
			if leveltime % 5 == 0 then -- less overt -garrean
				local ghs = P_SpawnGhostMobj(s)
				ghs.blendmode = AST_ADD
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.spritexscale = s.spriteyscale -- cleaner scaling -garrean
				ghs.spriteyscale = s.spritexscale -- cleaner scaling -garrean
				ghs.fuse = 10
				ghs.tics = 99
				ghs.colorized = true
			end
		end
	else
		--Record our last coordinates!
		yu.lastx = s.x
		yu.lasty = s.y
		yu.lastz = s.z
		if yu.lostsight
			yu.lostsight = $-1
		end		
		if yu.weapon == "spring"
			s.flags = $|MF_SPRING
		end
		if yu.shotcd
			yu.shotcd = $-1
		end
		if yu.defensecd
			yu.defensecd = $-1
		end
		if yu.sprung
			yu.sprung = $-1	
			if not yu.sprung
				s.momx = 0
				s.momy = 0
				s.momz = 0
			else
				s.momx = FixedDiv(FixedMul($,10),11)
				s.momy = FixedDiv(FixedMul($,10),11)
				s.momz = FixedDiv(FixedMul($,10),11)
			end
		end	
		if yu.goldenbeetle and (s.state != S_GUNB_AMBUSH)
			local RNG = GUN.RNG(-40,40,s)
			local RNG2 = GUN.RNG(-38,39,s)
			local RNGZ = GUN.RNG(0,79,s)
			if (leveltime%2) RNG=$*-1 RNG2=$*-1 end
			local ghs = P_SpawnMobjFromMobj(s, RNG*s.scale,RNG2*s.scale,RNGZ*s.scale, MT_GUNAUTOFRAME)
			ghs.sprite = SPR_NSPK
			ghs.frame = (leveltime%3==0) and B or A		
			ghs.fuse = 9 ghs.tics = 99
			ghs.sttfade = true
			ghs.sttfinalframe = (ghs.frame & FF_FRAMEMASK)
			ghs.spriteyscale = FRACUNIT+GUN.RNG(-20000,20000,s)
			ghs.spritexscale = ghs.spriteyscale 
			ghs.colorized = true
			-- this is a seizure warning -garrean
			ghs.color = SKINCOLOR_GOLDENROD -- (leveltime%2) and SKINCOLOR_GOLDENROD or SKINCOLOR_SILVER
			ghs.destscale = $*99
			ghs.scalespeed = $*2
			
			-- this is a seizure warning -garrean
			/*
			if (leveltime % 5 == 0) --Flashing effect.
				local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_GUNOVERLAY)
				ghs.tracer = s
				ghs.frame = FF_TRANS50
				ghs.renderflags = RF_FULLBRIGHT
				ghs.blendmode = AST_ADD
				ghs.fusefade,ghs.fuse = 3,3
				ghs.colorized = true
				ghs.color = SKINCOLOR_WHITE
				ghs.copyframe = true
				GUN.OverLayThink(ghs)
			end
			*/
		end		
	end
end, MT_GUNBEETLE)

--Ignore certain instances of damage?
addHook("MobjDamage", function(s, i, so, dmg, dmgtype)
	if so and so.valid and s.GUN_BeetleTable
		local yu = s.GUN_BeetleTable
		
		if yu.weapon == "spring" and (so == i) and so.player
		local p = so.player
			if p.homing return true end --
			if (p.pflags & (PF_SPINNING|PF_JUMPED))
			and not P_IsObjectOnGround(so)
				if not p.hypermysticsonic
				and (FixedHypot(FixedHypot(so.x-s.x, so.y-s.y), so.z-s.z) < 750*FRACUNIT)
					if (s.eflags & MFE_VERTICALFLIP)
						if (s.z-5*s.scale >= so.z+so.momz) 
							return true --
						end
					elseif (so.z+so.momz >= s.z+5*s.scale)
						return true --
					end
				end
			end
		end	
		if yu.defense == "armor" and (GUN.TargetPower(so) == 0)
			return true --You can't even scratch me!
		end
	end
end, MT_GUNBEETLE)

--Argh, not the bees!!
addHook("MobjDeath", function(s, i, so, dmgtype)
	local yu = s.GUN_BeetleTable

	--Electricity aftereffects.
	if (dmgtype == DMG_ELECTRIC)
		GUN.ElectricBody(s, 33)
	elseif (dmgtype == DMG_FIRE)
		local ghs = GUN.SA2Explosion(s, FRACUNIT*2, SKINCOLOR_FLAME)
		ghs.frame = $+FRACUNIT*2
		ghs.spritexscale = $+34444
		ghs.spriteyscale = $+34444
	end

	if i and i.valid
		if yu
			GUN.gibs(s, i)	
		end				
		--Add a little bit of resistance, but not that much compared to GUN Hunters.
		if (i == so) and i.player and not i.player.homing
			if (GUN.TargetPower(i) == 0)	
				i.momx = FixedDiv(FixedMul($,3),4)
				i.momy = FixedDiv(FixedMul($,3),4)
			end
			if (i.player.cmd.buttons & BT_JUMP)
			and (i.momz*P_MobjFlip(s) > -13*i.scale) and (abs(i.momz) < 13*i.scale)
			and (i.player.pflags & (PF_JUMPED|PF_SPINNING)) and not P_IsObjectOnGround(i)
				i.momz = 13*i.scale*P_MobjFlip(i)
			end
		end
		S_StartSound(s, sfx_ghsfx6)
	end
	if yu and yu.goldenbeetle
		if so 
			if so.player
				local p = so.player
				-- Changed for SA2:Blast scoring -garrean
				-- P_AddPlayerScore(so.player, 800) -- Changed for SA2:Blast scoring -garrean 
				-- P_GivePlayerRings(so.player, 10)
				-- S_StartSound(so, sfx_itemup)
			end
			local SPEED = max(abs(so.momx)+abs(so.momy), 12*FRACUNIT)
			/* -- Changed for SA2:Blast scoring -garrean
			for d = -4,3
				local ghs = P_SpawnMobjFromMobj(s, so.momx,so.momy,s.height/5, MT_FLINGRING)
				ghs.angle = s.angle+(d*ANGLE_45)
				P_InstaThrust(ghs, ghs.angle, (SPEED/6))
				P_SetObjectMomZ(ghs, 9*FRACUNIT, true)
				ghs.momx = $+so.momx
				ghs.momy = $+so.momy
				ghs.momz = $+(so.momz/3)
				ghs.fuse = 350
			end
			*/
		end
		local ghs = GUN.LightFlash(s, SKINCOLOR_GOLDENROD, 32, FRACUNIT+15000)
		ghs.frame = $+FRACUNIT
		local ghs = GUN.WindBlast(s, SKINCOLOR_GOLDENROD, AST_ADD)
		if ghs and ghs.valid
			ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.fuse = $*2
			ghs.sttfade = 8
		end
	end

	--Impact effect
	GUN.Quake(s, 50*FRACUNIT, 5, 450*FRACUNIT)
	GUN.SA2Explosion(s)
	local SfX = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
	SfX.flags2 = MF2_DONTDRAW SfX.tics = 70
	S_StartSound(SfX, sfx_yuedth)
	
end, MT_GUNBEETLE)