local GUN = GUN_Troops
--#=================================================#
--Collection of Mobj and Line Collission hooks for various reasons.
--#=================================================#

addHook("MobjSpawn", function(s)
	s.renderflags = RF_NOCOLORMAPS|RF_FULLBRIGHT
	s.blendmode = AST_ADD
	s.spriteyscale = FRACUNIT-20000
	s.spritexscale = FRACUNIT-20000
	s.color = SKINCOLOR_GOLDENROD
	s.colorized = true
	s.Init = 1
	s.fuse = 200 --These don't have infinite range!
end, MT_GUNHUNTER_LASER)
addHook("MobjThinker", function(s)
	if (s.state == S_GUNH_LASEREXPLODE) --We've exploded!
		if not (s.flags2 & MF2_DEBRIS)
			if (s.Init > 5) --It'll still be flashing otherwise.
				local ghs = GUN.LightFlash(s, s.color)
				ghs.frame = H|FF_TRANS20
				ghs.scalespeed = $*2
				
				local ghs = GUN.LightFlash(s, s.color, nil, FRACUNIT-28000)
				ghs.frame = H|FF_TRANS10
				ghs.rollangle = ANG30
				ghs.scalespeed = $*2
			end
			local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK) --Explosion sound.
			ghs.flags2 = MF2_DONTDRAW ghs.tics = 60
			S_StartSoundAtVolume(ghs, sfx_ghsfx2, 40)
			
			GUN.particles(s, 60, 10, 5)
			s.destscale = FRACUNIT*999
			s.scalespeed = FRACUNIT/4
			s.fuse = 18
			s.flags2 = $|MF2_DEBRIS|MF2_SHADOW
			if s.snipershot and (s.scale >= 5*FRACUNIT)
				S_StartSound(ghs, sfx_brakrx)
				local ghs = GUN.LightFlash(s, SKINCOLOR_RED)
				ghs.frame = H|FF_TRANS10
				ghs.scalespeed = $*5		
				GUN.Quake(s, 90*FRACUNIT, 12, 850*FRACUNIT)
			end
		end
	else --Still alive and kicking!
		if (s.Init < 6) --Gradually speed up!
			if (s.Init == 2)
				local ghs = GUN.LightFlash(s, s.color, 7)
				ghs.frame = A|FF_TRANS20
				ghs.colorized = true
				ghs.tracer = s
				ghs.ditchtracer = 4
				ghs.scalespeed = FRACUNIT
			elseif (s.Init % 2) --Speed up!
				s.momx = FixedDiv(FixedMul($, 13), 12)
				s.momy = FixedDiv(FixedMul($, 13), 12)
				s.momz = FixedDiv(FixedMul($, 13), 12)
			end
		else
		--	if (s.Init % 2)
				local ghs = P_SpawnGhostMobj(s)
				ghs.blendmode = s.blendmode
				ghs.renderflags = RF_FULLBRIGHT
				ghs.destscale = 500
				ghs.scalespeed = $*2
				ghs.fuse = 24
				ghs.tics = 99
		--	elseif (abs(s.momx)+abs(s.momy) > 16*FRACUNIT)
		--		GUN.GhostTrail(s, s.color, 20, FF_TRANS30, FRACUNIT-7500, 1, SPR_G1FX, I, 16*FRACUNIT)
		--	end
		end
		if s.snipershot and not S_SoundPlaying(s,sfx_gravch)				
			S_StartSound(s, sfx_gravch)
			S_StartSound(s, sfx_rail1)
			S_StartSound(s, sfx_rail2)
			S_StartSound(s, sfx_s3k57)
			if (s.scale >= 5*FRACUNIT)
				S_StartSound(s, sfx_brakrx)
			end
		end
	end
	s.Init = $+1
end, MT_GUNHUNTER_LASER)
local function GunHunter_LaserCollide(s, v)
	if not (v and v.valid) return end
	if v.player
		local p = v.player
		if p.homing and (p.pflags & PF_JUMPED)
			return false --
		elseif (p.charability == CA_TWINSPIN) and (p.panim >= PA_ABILITY)
			if (v != s.target)
			and (s.z+s.height+s.momz+(99*v.scale) > v.z) and (s.z+s.momz < v.z+v.height+(99*v.scale))
				GUN.Reflect(s, v, SKINCOLOR_ROSY) --Reflection"!
			end 
			return false --
		end
	elseif (v.type == s.type)
		return false --
	end 
end
addHook("MobjCollide", GunHunter_LaserCollide, MT_GUNHUNTER_LASER)
addHook("MobjMoveCollide", GunHunter_LaserCollide, MT_GUNHUNTER_LASER)

addHook("MobjSpawn", function(s)
	s.renderflags = RF_SEMIBRIGHT
	s.Init = 1
	s.spritexscale = FRACUNIT*3-18000 --Big sprites.
	s.spriteyscale = FRACUNIT*3-18000 
	s.shadowscale = FRACUNIT+11999
	s.RollD = GUN.RNG(0,1,s) or -1
end, MT_GUNHUNTER_GRENADE)
addHook("MobjDeath", function(s)
	s.blendmode = AST_ADD
	s.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
	s.color = SKINCOLOR_GOLDENROD
	s.colorized = true
	s.shadowscale = 0
end, MT_GUNHUNTER_GRENADE)
addHook("MobjThinker", function(s)
	if s.SearchType == nil
		if s.target and s.target.valid
		local t = s.target
			if t.GUN_HunterTable and t.GUN_HunterTable.searchtype != nil
				s.SearchType = t.GUN_HunterTable.searchtype
			end
		end
	end
	if (s.state == S_GUNH_LASEREXPLODE) --We've exploded!
		--If we haven't exploded yet, let's do it!
		if not (s.flags2 & MF2_DEBRIS) --Explosion!
			local t = s
			
			--Only calculate the explosion's damaging effects if you've got a valid searchtype or target.
			if s.target and s.target.valid
			or s.SearchType != nil
				t = (s.target and s.target.valid) and s.target or s
				local KILLTYPE = (t.player) and 1 or s.SearchType or 0
				if t.GUN_HunterTable and t.GUN_HunterTable.searchtype
					KILLTYPE = t.GUN_HunterTable.searchtype
				end
				local DIST = 292*t.scale --The explosion radius!
				searchBlockmap("objects",function(s,m)
					if (m.type == MT_FLINGRING) --Fling them away!
						if (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z) < DIST)
							P_Thrust(m, R_PointToAngle2(s.x, s.y, m.x, m.y)	, 18*t.scale)
							P_SetObjectMomZ(m, 5*FRACUNIT, true)
							if m.fuse
								m.fuse = $+70
							end
						end
					elseif (m.type == MT_PLAYER) and (KILLTYPE != 1)
					or (m.flags & (MF_ENEMY|MF_BOSS)) and (KILLTYPE != 0)
						if (m.flags & MF_SHOOTABLE) 
						and m.health
						and not (m.GUNally and not t.player) --It might've been reflected by a player! DO hurt GUN allies in that case!
						and not (m.flags & (MF_MISSILE|MF_MONITOR))
							if (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z) < DIST) --Check vertical distance too.
								P_DamageMobj(m, s, t)
								if m and m.valid and m.health and (m.flags & MF_SHOOTABLE) --Add a bit of extra knockback?
								and ((GUN.TargetPower(m)) == 0)
									local ANGLE = ((abs(s.momx)+abs(s.momy) > 30*s.scale)) and R_PointToAngle2(s.x, s.y, s.x+s.momy, s.y+s.momy) or R_PointToAngle2(s.x, s.y, m.x, m.y)	
									P_Thrust(m, ANGLE, 15*t.scale)
									P_SetObjectMomZ(m, 4*FRACUNIT, true)
								end
							end
						end
					end
				end,s, s.x-DIST,s.x+DIST, s.y-DIST,s.y+DIST)		
			end
			
			GUN.CircleWave(s, 2, SKINCOLOR_RED)
			GUN.SA2Explosion(s, t.scale+35000, SKINCOLOR_GOLDENROD)
			
			--Lightflash and windblast, grounded and non-grounded!
			for i = 1,2
				local ghs = GUN.WindBlast(s, SKINCOLOR_SUPERGOLD2, AST_ADD)
				ghs.spriteyscale = t.scale*2
				ghs.spritexscale = t.scale*2
				ghs.renderflags = $|RF_FULLBRIGHT|((i == 2) and RF_FLOORSPRITE or RF_NOCOLORMAPS)
				ghs.z = $+(3*t.scale*P_MobjFlip(t))
				
				ghs = GUN.LightFlash(s, SKINCOLOR_GOLDENROD, 16, t.scale*2)
				ghs.scalespeed = $*(2*i)
				ghs.spriteyoffset = $-(30*FRACUNIT)+(15*FRACUNIT*i)
				ghs.renderflags = $|RF_FULLBRIGHT|((i == 2) and RF_FLOORSPRITE or RF_NOCOLORMAPS)
				ghs.z = $+(3*t.scale*P_MobjFlip(t))
			end
			GUN.particles(s, 60, 14,8)
			GUN.Quake(s, 58*FRACUNIT, 8, 850*t.scale)

			local SfX = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK) --Play the explosion SFX from a seperate mobj so it doesn't get interrupted.
			SfX.flags2 = MF2_DONTDRAW SfX.tics = 88
			S_StartSound(SfX, sfx_ghsfxc)
			s.fuse = 1
		end
		s.blendmode = AST_ADD
		s.flags2 = $|MF2_DEBRIS|MF2_SHADOW
		s.flags = MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP
		
	--If you're alive...
	else
		s.Init = $+1
		
		--Mess with initial momentum!
		if (s.Init < 9)
			local ANGLE = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
			if (s.Init == 2) 
				S_StartSoundAtVolume(s, sfx_ghsfxh, 120)
				if s.target and s.target.target and (s.target.target.z == s.target.z)
					s.momz = $*2/3
					s.momx = FixedDiv(FixedMul($, 14), 6) s.momy = FixedDiv(FixedMul($, 14), 6)
				else
					s.momx = FixedDiv(FixedMul($, 10), 8) s.momy = FixedDiv(FixedMul($, 10), 8)			
				end
				--Hackiest way ever to pretend we're firing from the barrel.
				P_TryMove(s, s.x+FixedMul(45*s.scale, cos(ANGLE-ANGLE_90)), s.y+FixedMul(45*s.scale, sin(ANGLE-ANGLE_90)), true)
			else
				P_TryMove(s, s.x+FixedMul(6*s.scale, cos(ANGLE+ANGLE_90)), s.y+FixedMul(6*s.scale, sin(ANGLE+ANGLE_90)), true)
			end
		end
		local ROLLSPEED = FixedInt(abs(s.momz*2)+abs(s.momx/2)+abs(s.momy/2))*(ANG1/3)
		s.rollangle = $+((ANG1+ROLLSPEED)*s.RollD)		
		if (abs(s.momz) > s.scale/6)
			local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_SMOKE)
			ghs.spriteyscale = $+GUN.RNG(99,FRACUNIT*5,s)
			ghs.spritexscale = ghs.spriteyscale
			if s.target and s.target.player
				if not s.refl
					s.refl = true
					s.momx = $*3
					s.momy = $*3
				end
				s.spritexscale = FRACUNIT*3-18000
				s.spriteyscale = FRACUNIT*3-18000
			end
			if not (s.eflags & MFE_UNDERWATER)
				local FALLSPEED = (P_GetMobjGravity(s)) or 32678
				P_SetObjectMomZ(s, FALLSPEED, true)
			end	
		elseif P_IsObjectOnGround(s)
			if not s.dust
				GUN.SpawnJumpDust(s)
				s.dust = true
			end
		end
	end
end, MT_GUNHUNTER_GRENADE)

--Explode on touch!
local function GunHunter_GrenadeCollide(s, v) --Ignore homing attacking players.
	if v and v.valid and s.valid and not (s.flags2 & MF2_DEBRIS)
		if v.player 
			local p = v.player
			if (s.SearchType == 1) return false end
			if p.homing and (p.pflags & PF_JUMPED)
				return false --
			elseif (p.charability == CA_TWINSPIN) and (p.panim >= PA_ABILITY)
				if (v != s.target)
				and (s.z+s.height+s.momz+(99*v.scale) > v.z) and (s.z+s.momz < v.z+v.height+(99*v.scale))
					GUN.Reflect(s, v, SKINCOLOR_ROSY)
				end 
				return false --
			else
				P_ExplodeMissile(s) return false --
			end
		elseif (v.flags & (MF_ENEMY|MF_BOSS))
			if not (s.target and s.target.player)
				if v.GUNally 
				or not s.SearchType
					return false --
				end
			end
			P_ExplodeMissile(s) return --
		end
	end 
end
addHook("MobjCollide", GunHunter_GrenadeCollide, MT_GUNHUNTER_GRENADE)
addHook("MobjMoveCollide", GunHunter_GrenadeCollide, MT_GUNHUNTER_GRENADE)

--We're not going over?
GUN.ZCHECK = function(s, v)
	if (s.z+s.height > v.z) and (s.z < v.z+v.height)
		return true --
	end
end

--GUN Hunters can interact with springs and boosters, and have special touch properties at times.
local function GunHunter_Collide(s, v)	
	if v.player
		if s.GUN_HunterTable and s.GUN_HunterTable.flinch return false end --No touchies when flinching
		return --
	elseif (v.flags & MF_MISSILE)
		if v.target and ((v.target == s) or v.target.GUNally) --Don't hurt yourself or allies.
			return false --
		end
		return --
	--Spring Collision detection stuff.	
	elseif (v.flags & MF_SPRING) --Allow spring and booster use!	
		
		if (s.z+s.height+s.momz > v.z) and (s.z+s.momz < v.z+v.height)	
		
			if s.GUN_HunterTable and not s.GUN_HunterTable.sprung
			
				if (v.type == MT_BUMPER) or (v.type == MT_BALLOON) return end --
				
				local yu = s.GUN_HunterTable
				if v.info.mass
					yu.landingcd = 3
					local FLIP = P_MobjFlip(v)
					if P_IsObjectOnGround(s)
						s.z = $+(99*FLIP)
					end
					s.momz = FixedDiv(FixedMul(v.info.mass, v.scale),FRACUNIT)*FLIP
				end
				if v.info.damage
					s.angle = v.angle
					P_InstaThrust(s, v.angle, FixedDiv(FixedMul(v.info.damage, v.scale),FRACUNIT))
					yu.momx = s.momx
					yu.momy = s.momy --why, game
				end
				if v.info.painsound
					S_StartSound(v, v.info.painsound)
					if v.info.raisestate
						v.state = v.info.raisestate
					end
				end
				yu.sprung = 3
			end
		end
	end
end
addHook("MobjCollide", GunHunter_Collide,  MT_GUNHUNTER)
addHook("MobjMoveCollide", GunHunter_Collide,  MT_GUNHUNTER)


--Gun Beetles can collide with springs too, I guess. At the least, they need the friendly fire hack.
local function GunBeetle_Collide(s, v)	

	if (s.state == S_GUNB_AMBUSH) or not s.GUN_BeetleTable return false end --Intangible in this state.
	
	if v.player
		local p = v.player
		if s.GUN_BeetleTable.weapon == "spring" 
		or (s.state == S_GUNB_SPRING)
			if (s.z+s.momz > v.z+v.height+v.momz)
			or (v.z+v.momz > s.z+s.height)
				return
			end
			
			if not (v.eflags & MFE_SPRUNG)
			and not ( (p.panim == PA_PAIN) and p.powers[pw_flashing] )
			and not p.powers[pw_carry]
			
				--Time to do weird collision code.
				if (s.eflags & MFE_VERTICALFLIP)
					if not (v.momz > 0)
						if (s.z+s.momz > v.z+v.momz+(v.height/2))
							v.flags = $ & ~MF_SPRING return --
						end
					end
				elseif not (v.momz < 0)
					if ( v.z+v.height+v.momz  < s.z+s.momz+(s.height/4) )
						v.flags = $ & ~MF_SPRING --Let's see what happens.
						return --
					end
				end	
				
				v.momx = $/2 --Technically you lose ALL momentum in Adventure, but let's keep at least little?
				v.momy = $/2
				P_DoSpring(s, v)
				p.YUKattack = nil
				
				if p.yusonictable
					local yu = p.yusonictable
					yu.hitspring = 2
					yu.yteleport = nil
					yu.airleverage = 0
					yu.homingsetup = false
					yu.sa2jumpdone = false
					yu.airstart = 8
					yu.flighthoming = 0
					yu.superflight = 0					
					if yu.lsaattack
						YuStopLSA(p, s, yu)
					end
				end
				
				if p.yuknuxtable and YKNUX
					YKNUX.ResetGC(p, v, p.yuknuxtable)
				end
				
				if not S_SoundPlaying(s, sfx_spring)
					S_StartSound(s, sfx_spring)
				end
			end
		end
	elseif (v.flags & MF_MISSILE)
		if v.target and (v.target == s or v.target.GUNally) --Don't hurt yourself or allies.
			return false --
		end
	elseif (v.flags & MF_SPRING) --Allow spring and booster use!	
	
		if s.GUN_BeetleTable and not s.GUN_BeetleTable.sprung	
		
			if (s.z+s.momz > v.z+v.height+v.momz)
			or (v.z+v.momz > s.z+s.height)
				return
			end
			if v.info.mass --Has vertical launching properties.
				s.momz = FixedDiv(FixedMul(v.info.mass, v.scale),FRACUNIT)*P_MobjFlip(v)
			end
			if v.info.damage --Horizontal launching.
				s.angle = v.angle
				P_InstaThrust(s, v.angle, FixedDiv(FixedMul(v.info.damage, v.scale),FRACUNIT))
			end
			if v.info.painsound
				S_StartSound(v, v.info.painsound)
				if v.info.raisestate
					v.state = v.info.raisestate
				end
			end
			s.GUN_BeetleTable.sprung = 26
		end
	end
end
addHook("MobjCollide", GunBeetle_Collide,  MT_GUNBEETLE)
addHook("MobjMoveCollide", GunBeetle_Collide,  MT_GUNBEETLE)


//Flung Objects like rocks.
addHook("MobjThinker", function(s)
	if s.Init == nil --Setup section...
		s.Init = 0
		if (s.tics < 30)
			s.tics = 250
		end
		if s.flamespark
			s.GUNrgtimer = tonumber(s.flamespark) or 69
			s.angle = R_PointToAngle(s.x, s.y, s.x+s.momy, s.y+s.momy)+ANGLE_90 --ANGLE_270?
			s.rollangle = $ + ((s.frame & FF_HORIZONTALFLIP) and -ANGLE_45 or ANGLE_45)
			s.flags = $ & ~MF_BOUNCE & ~MF_GRENADEBOUNCE
		else
			if not s.shadowscale --Shadows can be intensive when there's this many, thread carefully.
				if not s.ROCK != 777
					s.shadowscale = 75000
				end
			end
			--How long the debris sticks around.
			local rng = GUN.RNG(200,280,s)
			s.GUNrgtimer = rng
		end
		
		--What direction are we going to rollangle into?
		if s.RollDirection == nil
			s.RollDirection = (GUN.RNG(0,1,s) == 1) and 1 or -1
			if not P_CheckPosition(s, s.x, s.y)
			or not P_TryMove(s, s.x+s.momx, s.y+s.momy, true)
				if s.valid 
					s.flags = $ & ~MF_GRENADEBOUNCE & ~MF_BOUNCE
					local RNG = GUN.RNG(-17000, 17000,s)
					s.spritexscale = FRACUNIT+RNG
					s.spriteyscale = FRACUNIT+RNG
					if s.RollDirection == 1
						s.mirrored = true
					end
				end	
			end
		end			
	end
	
	--Setup done!
	s.Init = $+1
	s.GUNrgtimer = $-1
	
		if (s.GUNrgtimer <= 1) s.state = S_NULL return end	 --Disappear!
		s.trgmom = abs(s.momx)+abs(s.momy)  --Rough (not perfect) estimate of speed.
		
		--We're a flame!
		if s.flamespark 
			if P_IsObjectOnGround(s) or (s.eflags & MFE_TOUCHWATER)
				s.state = S_NULL return --
			end
			s.spritexscale = max(9999, $-450) --Gently shrink overtime.
			s.spriteyscale = max(9999, $-450)
			if (s.trgmom > 37000)
				s.rollangle = $ + ((s.frame & FF_HORIZONTALFLIP) and ANG1/2 or ANG1/-2)
			end
			if s.momz*P_MobjFlip(s) < -5*FRACUNIT
				s.momz = -5*FRACUNIT*P_MobjFlip(s) --Maximum falling speed.
				if s.floorz < s.z+(50*s.scale)
					local trans = min((s.frame & FF_TRANSMASK)+FRACUNIT, FF_TRANS90)
					s.frame = ($ & ~FF_TRANSMASK)|trans
				end
			end
			
		else --Not a flame.
		
			if not s.gentrgsfx --Only play landing sound once!
				if P_IsObjectOnGround(s)
					if P_CheckDeathPitCollide(s) --Nope.
					or (abs(s.floorz-s.ceilingz) < 8*FRACUNIT) --Crushed!
						s.state = S_NULL return --
					elseif (s.Init > 3) --Wait 2 tics first...
						s.gentrgsfx = true
						if s.ROCK				
							if (s.spriteyscale >= 3*FRACUNIT) --Big rocks make impacts!
								local rng = GUN.RNG(sfx_rocks1,sfx_rocks4,s)
								local rvolume = max(50, min(255, s.spritexscale/120))
								if not S_SoundPlaying(s, rng)
									S_StartSoundAtVolume(s, rng, rvolume) 
								end
							end
							P_Thrust(s, GUN.RNG(0,359,s)*ANG1, GUN.RNG(0,90,s)*FRACUNIT/8)	
							P_SetObjectMomZ(s, GUN.RNG(55,130,s)*(FRACUNIT/4), true) --Fake bounce a bit.	
						else
							local rvolume = max(50, min(255, s.spritexscale/250))
							if not S_SoundPlaying(s, sfx_bnce2)
								S_StartSoundAtVolume(s, sfx_bnce2, rvolume)
							end
							P_Thrust(s, GUN.RNG(0,359,s)*ANG1, GUN.RNG(1,999,s)*(FRACUNIT/140))	
							P_SetObjectMomZ(s, GUN.RNG(55,130,s)*(FRACUNIT/33), true)
						end
						s.RollDirection = $*-1				
					end
				end
			end		
			if (s.trgmom > 37000) --Rollspeed is based on your momentum.
				s.rollangle = $+(FixedAngle(s.trgmom)*s.RollDirection)	
			elseif (s.flags & MF_GRENADEBOUNCE)
				s.flags = $ & ~MF_GRENADEBOUNCE
			end
			if s.ROCK --We're a rock!
				if (s.momz*P_MobjFlip(s) > -5*FRACUNIT) and (s.momz*P_MobjFlip(s) > -11*FRACUNIT) and (s.Init > 5) --Fall quicker.
					local fallspeed = FixedDiv(FixedMul(7776, 32678), P_GetMobjGravity(s) or 32678)
					s.momz = $+(fallspeed*P_MobjFlip(s)) --Fall quicker!
				end		
			end
		end
end, MT_GUNDEBRIS)
