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

ENT.model = "models/buildables/dispenser_light.mdl"
ENT.distance = 120

ENT.health = 150
ENT.AutomaticFrameAdvance = true 

function ENT:SpawnFunction( ply, tr )
	if ( !tr.Hit ) then return end
	local SpawnPos = (tr.HitPos + tr.HitNormal * 16) -Vector( 0, 0, 17 )
	self.Spawn_angles = ply:GetAngles()
	self.Spawn_angles.pitch = 0
	self.Spawn_angles.roll = 0
	self.Spawn_angles.yaw = self.Spawn_angles.yaw + 180
	
	local ent = ents.Create( "obj_dispenser" )
	ent:SetPos( SpawnPos )
	ent:SetAngles( self.Spawn_angles )
	ent.owner = ply
	ent.built = true
	ent:SetNetworkedEntity( "owner", ent.owner )
	ply:SetNetworkedEntity( "dispenser", obj )
	ply.dispenser = ent
	ent:Spawn()
	ent:Activate()
	
	return ent
end

function ENT:KeyValue( key, value )
	if( key == "TeamNum" ) then
		if value == "3" then
			self.team = 1
		else
			self.team = 2
		end
		self.built = true
		self.mapentity = true
		self.rechargedelay = CurTime() +5
	end
	if( key == "health" ) then
		self.health = value
	end
	if( key == "spawnflags" ) then
		self.spawnflags = tonumber(value)
		self:CheckSpawnflags()
	end
end

function ENT:CheckSpawnflags()
	local spawnflags = { 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 }
	for k, v in pairs( spawnflags ) do
		if v <= self.spawnflags and !self.used then
			local value_a = v
			local value_b = self.spawnflags -v
			if table.HasValue( spawnflags, value_a ) then
				self:GetSpawnflag( value_a )
			end
			if self.spawnflags != v then
				if table.HasValue( spawnflags, value_b ) then
					self.used = true
					self:GetSpawnflag( value_b )
				else
					self.spawnflags = value_b
					self.used = false
					self:CheckSpawnflags()
				end
			else
				self.used = true
			end
		end
	end
end

function ENT:GetSpawnflag( value )
	local spawnflags = { 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 }
	if !table.HasValue( spawnflags, value ) then return false end
	if value == 2 then
		self.invulnerable = true
	end
	return true
end

function ENT:Initialize()
	self:SetModel( self.model )
	self:SetMoveType( MOVETYPE_NONE )
	self:SetSolid( SOLID_BBOX )
	self:SetHealth(self.health)
	self:SetMaxHealth(self.health)
	self:SetCollisionBounds( Vector( -20, 22, 0 ), Vector( 20, -22, 75 ) )	
	
	self.dispensing = {}

	self.rechargedelay = CurTime() +6
	
	self.idlesound = CreateSound( self, "weapons/dispenser_idle.wav" )
	if self.built then self.idlesound:Play() end
	
	self.healsound = CreateSound( self, "weapons/dispenser_heal.wav" )
	
	if !self.team then
		if self.owner and ValidEntity(self.owner) then
			self.team = self.owner:Team()
		else
			self.team = 0
		end
	end
	if self.team == 1 then
		self:SetSkin(1)
		self.healeffect = "dispenser_heal_blue"
	else
		self.healeffect = "dispenser_heal_red"
	end
	self:SetUp()
	
	self:SetNetworkedInt( "health", self:Health() )
	self.metal = 0
	self.dispensedelay = CurTime()
end

function ENT:SetUp()
	if self.built then self.setupdelay = 0; return end
	self:SetModel( "models/buildables/dispenser.mdl" )
	self:ResetSequence( self:LookupSequence( "build" ) )
	self:SetPlaybackRate( 0.5 )

	self.settingup = true
	self.setupdelay = CurTime() +self:SequenceDuration() *2
	self.totalseqduration = self:SequenceDuration() *2
end

function ENT:Charge()
	self:EmitSound( "weapons/dispenser_generate_metal.wav", 100, 100 )
	if self.metal +40 <= 400 then
		self.metal = self.metal +40
	else
		self.metal = 400
	end
	self:SetNetworkedInt("resources", self.metal /4)
end

function ENT:SpeedUp()
	timer.Destroy( tostring(self) .. "_speeduptimer" )
	self:SetPlaybackRate( 1 )
	local buildtime = (self:SequenceDuration() *2 -(self.setupdelay -CurTime())) /2
	self.setupdelay = CurTime() +(self:SequenceDuration() -buildtime)
	self.totalseqduration = self:SequenceDuration()
	self.speedup = true
	
	local function SpeedDown()
		if !self or !ValidEntity(self) or self.built then return end
		self:SetPlaybackRate( 0.5 )
		local buildtime = (self:SequenceDuration() -(self.setupdelay -CurTime())) *2
		self.setupdelay = CurTime() +(self:SequenceDuration() *2 -buildtime)
		self.totalseqduration = self:SequenceDuration() *2
		self.speedup = false
	end
	timer.Create( tostring(self) .. "_speeduptimer", 1, 1, SpeedDown )
end

function ENT:Think()
	if self.setupdelay then
		if CurTime() > self.setupdelay then
			self:SetModel( self.model )
			self.setupdelay = nil
			self.settingup = false
			self.totalseqduration = nil
			self.built = true
			self:SetNetworkedBool( "building", false )
			self.idlesound:Play()
			self.metal = 25
			self.rechargedelay = CurTime() +5
			if self:Health() >= 145 then self:SetHealth(150);self:SetNetworkedInt("health",150) end
		else
			self:SetHealth(((self.totalseqduration -(self.setupdelay -CurTime())) /self.totalseqduration) *self.health)
			self:SetNetworkedInt("health", self:Health())
		end
	end
	
	if !self.built or self.sapped then self:NextThink( CurTime() +0.1 ); return true end

	if self.metal < 400 and CurTime() > self.rechargedelay then
		self.rechargedelay = CurTime() +5
		self:Charge()
	end
	
	for k, v in pairs( ents.FindInSphere( self:GetPos(), self.distance ) ) do
		if ValidEntity(v) and v:IsPlayer() and v:Health() > 0 and v:Team() == self.team and !self.dispensing[v] and self:GetPos():Distance(v:GetPos()) <= self.distance then
			v:SetName( v:GetName() )
			local particle = ents.Create( "info_particle_system" )
			particle:SetKeyValue( "effect_name", self.healeffect )
			particle:SetKeyValue( "cpoint1", v:GetName() )
			particle:SetPos( self:GetPos() )
			particle:SetParent( self )
			particle:Spawn()
			particle:Activate()
			particle:Fire( "SetParentAttachment", "heal_origin", 0 )
			particle:Fire( "Start", "", 0 )
		
			self.dispensing[v] = particle
			v[self] = CurTime() +0.15
			
			//self:EmitSound( "weapons/dispenser_heal.wav", 100, 100 )
			if self.mapentity then self.healsound = CreateSound( self, "weapons/dispenser_heal.wav" ) end
			self.healsound:Stop()
			self.healsound:Play()
		end
	end
	
	for k, v in pairs( self.dispensing ) do
		if !ValidEntity( k ) or k:Health() <= 0 or self:GetPos():Distance(k:GetPos()) > self.distance then
			v:Fire( "Stop", "", 0 )
			v:Fire( "Kill", "", 0.1 )
			local ply = k
			local new_tbl = {}
			for k, v in pairs(self.dispensing) do
				if k != ply then
					new_tbl[k] = v
				end
			end
			self.dispensing = new_tbl
		end
		
		if CurTime() > k[self] then
			k[self] = CurTime() +0.15
			if k:Health() < k:GetMaxHealth( ) then
				k:SetHealth( k:Health() +1 )
			end
			if self.metal > 0 then
				local class = k:GetNetworkedInt("tf_class")
				if CurTime() >= self.dispensedelay then
					self.dispensedelay = CurTime() +2
					k:RefreshAmmo()
					if k:GetNetworkedInt( "ammo_metal" ) < 200 and (class == 0 or class == 6) then
						local metaltogive
						if self.metal >= 40 then
							metaltogive = 40
						else
							metaltogive = self.metal
						end
					
						local metalgiven
						if k:GetNetworkedInt( "ammo_metal" ) +metaltogive <= 200 then
							k:SetNetworkedInt( "ammo_metal", k:GetNetworkedInt( "ammo_metal" ) +metaltogive )
							metalgiven = metaltogive
						else
							metalgiven = 200 -k:GetNetworkedInt( "ammo_metal" )
							k:SetNetworkedInt( "ammo_metal", 200 )
						end
						k:EmitSound("items/ammo_pickup.wav", 100, 100 )
						self.metal = self.metal -metalgiven
						self:SetNetworkedInt("resources", self.metal /4)
					end
				end
			end
		end
		
	end
	if table.Count( self.dispensing ) == 0 then self.healsound:Stop() end
end

function ENT:DamageLevel(dmglvl)
	if self.dmgparticle and self.dmgparticle.lvl == dmglvl then return false end
	if self.dmgparticle and self.dmgparticle.lvl > dmglvl then self.dmgparticle:Remove(); self.dmgparticle = nil; return false end
	if self.dmgparticle and ValidEntity(self.dmgparticle) then self.dmgparticle:Remove(); self.dmgparticle = nil end
	self.dmgparticle = ents.Create( "info_particle_system" )
	self.dmgparticle:SetKeyValue( "effect_name", "dispenserdamage_" .. dmglvl )
	self.dmgparticle:SetKeyValue( "start_active", "1" )
	self.dmgparticle:SetPos( self:GetPos() )
	self.dmgparticle:SetParent( self )
	self.dmgparticle:Spawn()
	self.dmgparticle:Activate()
	self.dmgparticle.lvl = dmglvl
	return true
end

function ENT:CheckDamageLevel()
	if self:Health() == self:GetMaxHealth() then self:DamageLevel(0); return end
	if self:Health() <= self:GetMaxHealth() -(self:GetMaxHealth() *0.25) and self:Health() > self:GetMaxHealth() -(self:GetMaxHealth() *0.5) then
		self:DamageLevel(1)
	elseif self:Health() <= self:GetMaxHealth() -(self:GetMaxHealth() *0.5) and self:Health() > self:GetMaxHealth() -(self:GetMaxHealth() *0.75) then
		self:DamageLevel(2)
	elseif self:Health() <= self:GetMaxHealth() -(self:GetMaxHealth() *0.75) and self:Health() > self:GetMaxHealth() -(self:GetMaxHealth() *0.85) then
		self:DamageLevel(3)
	elseif self:Health() <= self:GetMaxHealth() -(self:GetMaxHealth() *0.85) then
		self:DamageLevel(4)
	end
end

function ENT:OnTakeDamage( dmg )
	if self.invulnerable then return end
	local attacker = dmg:GetAttacker()
	if attacker and ValidEntity(attacker) and attacker:IsPlayer() and attacker:Team() == self.team and self.team != 1001 then return end
	if self.owner and self:Health() == 150 and self:Health() -dmg:GetDamage() > 0 then self.owner:ConCommand("playgamesound misc/hud_warning.wav"); timer.Simple(2, function() if self and ValidEntity(self) and self:Health() > 0 and self:Health() < 150 and self.owner and ValidEntity(self.owner) then self.owner:ConCommand("playgamesound misc/hud_warning.wav") end end ) end
	self:SetHealth(self:Health() - dmg:GetDamage())
	self:CheckDamageLevel()
	self:SetNetworkedInt( "health", self:Health() )
	if self:Health() <= 0 and !self.broken then
		self.broken = true
		self:Explode()
	end
end

function ENT:Sap()
	self.sapper:SetParent( self )
	self.sapper:Fire( "SetParentAttachment", "build_point_0", 0 )
	self.sapper:SetModel( "models/buildables/sapper_dispenser.mdl" )
	
	self.sapped = true
	self:SetNetworkedBool("sapped", true)
	
	if self.owner and ValidEntity( self.owner ) and self.owner:Health() > 0 then
		self.owner:EmitSound( "vo/engineer_autoattackedbyspy02.wav", 100, 100 )
	end
	
	for k, v in pairs( self.dispensing ) do
		v:Fire( "Stop", "", 0 )
		v:Fire( "Kill", "", 0.1 )
		local ply = k
		local new_tbl = {}
		for k, v in pairs(self.dispensing) do
			if k != ply then
				new_tbl[k] = v
			end
		end
		self.dispensing = new_tbl
	end
	self.healsound:Stop()
end

function ENT:Explode()
	for i = 1,5 do
		local gib = ents.Create( "obj_gib" )
		gib:SetModel( "models/buildables/Gibs/dispenser_Gib" .. i .. ".mdl" )
		
		gib:SetPos( self:GetPos() )
		gib:SetAngles( self:GetAngles() )
		gib.AmmoToGive = 10
		gib:Spawn()
		gib:Activate()
		gib:GetPhysicsObject():ApplyForceCenter( Vector(0,0,500) )
		gib:SetSkin(self:GetSkin())
	end

	self:EmitSound( "weapons/dispenser_explode.wav", 100, 100 )
	local explosion = ents.Create( "info_particle_system" )
	explosion:SetKeyValue( "effect_name", "ExplosionCore_buildings" )
	explosion:SetPos( self:GetPos() +self:OBBCenter() ) 
	explosion:SetAngles( self:GetAngles() )
	explosion:Spawn()
	explosion:Activate() 
	explosion:Fire( "Start", "", 0 )
	explosion:Fire( "Kill", "", 0.1 )
	self:Remove()
end

function ENT:OnRemove()
	self.idlesound:Stop()
	self.healsound:Stop()
	
	if self.dmgparticle and ValidEntity(self.dmgparticle) then self.dmgparticle:Remove() end
	
	if self.owner and ValidEntity(self.owner) then self.owner:SetNetworkedEntity( "dispenser", NULL ) end
	
	for k, v in pairs( self.dispensing ) do
		if ValidEntity( v ) then v:Remove() end
	end
end

