AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")

function ENT:Initialize()
	self.Entity:SetModel("models/weapons/W_missile_closed.mdl") 
	self.Entity:PhysicsInit(SOLID_VPHYSICS)
	self.Entity:SetMoveType(MOVETYPE_FLYGRAVITY)
	self.Entity:SetSolid(SOLID_VPHYSICS)
	self.Entity:SetCollisionGroup(COLLISION_GROUP_NPC)
	self.Entity:SetGravity(0.3)
	self.Entity:SetDTInt(0, 1)
	self.Entity.RocketSpeed = 2000
	local phys = self.Entity:GetPhysicsObject()

	if phys and phys:IsValid() then
		phys:Wake()
	end
	
	self.Entity.RocketSound = CreateSound(self.Entity, "weapons/rpg/rocket1.wav")
	self.Entity.RocketSound:SetSoundLevel(95)
	self.Entity.RocketSound:Play()
	
	timer.Simple(6, function()
		if ValidEntity(self.Entity) then
			self.Entity:SetDTInt(0, 0) -- oh fuck, we're out of fuel!
			local vel = self.Entity:GetVelocity()
			
			self.Entity:PhysicsInit(SOLID_VPHYSICS)
			self.Entity:SetMoveType(MOVETYPE_VPHYSICS)
			self.Entity:SetSolid(SOLID_VPHYSICS)
			self.Entity:SetCollisionGroup(COLLISION_GROUP_NPC)
			local phys = self.Entity:GetPhysicsObject()

			if phys and phys:IsValid() then
				phys:Wake()
				phys:SetMass(5)
				phys:SetVelocity(vel)
			end
			
			self.Entity.RocketSound:FadeOut(0.3)
			
			local owner = self.Entity:GetOwner()
			
			if ValidEntity(owner) and owner:Alive() then
				owner.CanReload = true
			end
		end
	end)
end

function ENT:OnTakeDamage(dmginfo)
	return false
end

function ENT:Use(activator, caller)
	return false
end

function ENT:Think()
	if SERVER then
		if self.Entity:GetDTInt(0) == 1  then
			local owner = self.Entity:GetOwner()
			local pos = self.Entity:GetPos()
			
			if self.Entity.MissileType == 1 then
				self.Entity.RocketSpeed = 1750
				
				if not self.Entity.TargetedEntity then
					for k, v in pairs(ents.FindInSphere(pos, 1024)) do
						if (v:IsPlayer() and v:Alive()) or v:IsNPC() then
							local DotProduct = self.Entity:GetForward():DotProduct((v:GetPos() - pos):Normalize())
							
							if DotProduct >= 0.7 and v != owner then
								local traceDir = (v:GetPos() - pos):Normalize()
								
								local td = {}
								
								td.start = pos
								td.endpos = td.start + traceDir * 1024 + Vector(0, 0, 30) -- make sure we're not running the trace at the entity's feet
								td.filter = {}
								
								for k2, v2 in pairs(ents.FindByClass("trigger_soundscape")) do
									table.insert(td.filter, v2)
								end
								
								table.insert(td.filter, self.Entity)
								
								local trace = util.TraceLine(td)
								
								if trace.Entity == v then
									self.Entity.TargetedEntity = v
									break
								end
							end
						end
					end
				end
				
				if not self.Entity.TargetedEntity or self.Entity.TargetedEntity:GetClass() != "ent_missile" then
					for k, v in pairs(ents.FindInSphere(pos, 1024)) do
						if v:GetClass() == "ent_missile" and v != self.Entity then
							local DotProduct = self.Entity:GetForward():DotProduct((v:GetPos() - pos):Normalize())
							
							if DotProduct >= 0.7 then
								local traceDir = (v:GetPos() - pos):Normalize()
								
								local td = {}
								
								td.start = pos
								td.endpos = td.start + traceDir * 1024 + Vector(0, 0, 30) -- make sure we're not running the trace at the entity's feet
								td.filter = {}
								
								for k2, v2 in pairs(ents.FindByClass("trigger_soundscape")) do
									table.insert(td.filter, v2)
								end
								
								table.insert(td.filter, self.Entity)
								
								local trace = util.TraceLine(td)
								
								if trace.Entity == v then
									self.Entity.TargetedEntity = v
									self.Entity.RocketSpeed = 2000
									break
								end
							end
						end
					end
				end
				
				if ValidEntity(self.Entity.TargetedEntity) then
					if not self.Entity.Velocity then
						self.Entity.Velocity = self.Entity:GetVelocity()
					else
						self.Entity.Velocity = LerpVector(0.4, self.Entity.Velocity, (self.Entity.TargetedEntity:GetPos() - pos):Normalize() * self.Entity.RocketSpeed)
					end
					
					self.Entity:SetLocalVelocity(self.Entity.Velocity)
				end
				
				if self.Entity.TargetedEntity and not ValidEntity(self.Entity.TargetedEntity) then
					self.Entity.TargetedEntity = nil
					self.Entity.MissileType = 0
				end
					
			elseif self.Entity.MissileType == 2 and owner:Alive() then
				self.Entity.RocketSpeed = 1500
				local ownerVel = owner:GetVelocity():Length()
				local aimVec = owner:GetAimVector()
				
				local td = {}
				td.start = owner:GetShootPos()
				td.endpos = td.start + aimVec * 8192
				td.filter = {}
								
				for k2, v2 in pairs(ents.FindByClass("trigger_soundscape")) do
					table.insert(td.filter, v2)
				end
								
				table.insert(td.filter, self.Entity)
				table.insert(td.filter, owner)
				
				local trace = util.TraceLine(td)
				
				if not self.Entity.Velocity then
					self.Entity.Velocity = (trace.HitPos - self.Entity:GetPos()):Normalize() * self.Entity.RocketSpeed
				else
					self.Entity.Velocity = LerpVector(0.4, self.Entity.Velocity, (trace.HitPos - self.Entity:GetPos()):Normalize() * self.Entity.RocketSpeed)
				end

				local randomShake 
				local random = math.random(-1, 1)
				
				if ownerVel > 0 then
					randomShake = Vector(random, random, random) * (ownerVel * 0.35)
				else
					randomShake = Vector(0, 0, 0)
				end

				self.Entity:SetLocalVelocity(self.Entity.Velocity + randomShake)
			end
			
			self.Entity:SetAngles(self.Entity:GetVelocity():Angle())
		end
	end
end

function ENT:Touch(ent)
	local owner = self.Entity:GetOwner()
	
	if ent != owner and ent:GetClass() != "trigger_soundscape" then
		self.Entity.MissileType = 0
		self.Entity:Explode()
	end
end

function ENT:PhysicsCollide(data, physobj)
	self.Entity.MissileType = 0
	self.Entity:Explode()
end

function ENT:OnRemove()
	self.Entity.RocketSound:Stop()
end

function ENT:Explode()
	if self.Entity.BlewUp then
		return
	end
	
	local owner = self.Entity:GetOwner()
	
	local ED = EffectData()
	ED:SetOrigin(self.Entity:GetPos())
	
	util.Effect("Explosion", ED)
	
	ParticleEffect("rpg7_explosion_full", self.Entity:GetPos(), Angle(0, 0, 0), nil)
	
	if ValidEntity(owner) and owner:Alive() then
		owner.CanReload = true
	end
	
	for k, v in pairs(ents.FindInSphere(self.Entity:GetPos(), 256)) do
		if ValidEntity(v) then
			if not v:IsPlayer() or not v:IsNPC() and (v:GetClass() == "prop_physics" or v:GetClass() == "prop_ragdoll") then
			
				local phys = v:GetPhysicsObject()
				
				if ValidEntity(phys) then
					local distance = self.Entity:GetPos():Distance(v:GetPos())
					local relation = math.Clamp((256 - distance) / 256, 0, 1)
					local forceDir = ((v:GetPos() - self.Entity:GetPos()):GetNormal() * 1000) * relation
					constraint.RemoveAll(v)
					
					phys:Wake()
					phys:EnableMotion(true)
					
					phys:AddAngleVelocity(Vector(1000, 1000, 200) * relation)
					phys:SetVelocity(forceDir)
				end
				
			end
		end
	end
	
	util.BlastDamage(self.Entity, owner, self.Entity:GetPos(), 512, 120)
	
	SafeRemoveEntity(self.Entity)
end