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

ENT.model = "models/buildables/teleporter_light.mdl"
ENT.distance = 40

ENT.health = 150
ENT.AutomaticFrameAdvance = true 

function ENT:SpawnFunction( ply, tr )
	if ( !tr.Hit or (ply.tp_entrance and ValidEntity(ply.tp_entrance)) ) 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_teleporter_entrance" )
	ent:SetPos( SpawnPos )
	ent:SetAngles( self.Spawn_angles )
	ent.owner = ply
	ent:SetNetworkedEntity( "owner", ent.owner )
	ent.settingup = true
	ent.built = true
	ent.sb_spawn = true
	ent:SetModel( "models/buildables/teleporter.mdl" )
	ply:SetNetworkedEntity( "tp_entrance", ent )
	ply.tp_entrance = 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.settingup = true
		self.sb_spawn = true
		self:SetModel( "models/buildables/teleporter.mdl" )
	end
	if( key == "health" ) then
		self.health = value
	end
	if( key == "tpexit" ) then
		self.tp_exit = 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()
	if !self.sb_spawn then self:SetModel( self.model ) end
	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, 12 ) )	
	
	self.idlesound = CreateSound( self, "weapons/teleporter_spin.wav" )
	if self.mapentity then self.idlesound:Play() end
	
	self.teleportsound = CreateSound( self, "weapons/teleporter_send.wav" )
	
	if self.tp_exit then self.tp_exit = ents.FindByName(self.tp_exit)[1]; self.tp_exit.tp_entrance = self end
	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.teleporteffect = "blue"
	else
		self.teleporteffect = "red"
	end
	
	self.charged_effect = ents.Create( "info_particle_system" )
	self.charged_effect:SetKeyValue( "effect_name", "teleporter_" .. self.teleporteffect .. "_charged" )
	self.charged_effect:SetPos( self:GetPos() )
	self.charged_effect:SetParent( self )
	self.charged_effect:Spawn()
	self.charged_effect:Activate()
	self.charged_effect:Fire( "SetParentAttachment", "centre_attach", 0 )
	
	self.idle_effect = ents.Create( "info_particle_system" )
	self.idle_effect:SetKeyValue( "effect_name", "teleporter_" .. self.teleporteffect .. "_entrance" )
	self.idle_effect:SetPos( self:GetPos() )
	self.idle_effect:SetParent( self )
	self.idle_effect:Spawn()
	self.idle_effect:Activate()
	self.idle_effect:Fire( "SetParentAttachment", "centre_attach", 0 )
	
	self.teleport_effect = ents.Create( "info_particle_system" )
	self.teleport_effect:SetKeyValue( "effect_name", "teleported_" .. self.teleporteffect )
	self.teleport_effect:SetPos( self:GetPos() )
	self.teleport_effect:SetParent( self )
	self.teleport_effect:Spawn()
	self.teleport_effect:Activate()
	self.teleport_effect:Fire( "SetParentAttachment", "centre_attach", 0 )
	
	self.teleport_flash = ents.Create( "info_particle_system" )
	self.teleport_flash:SetKeyValue( "effect_name", "teleported_flash" )
	self.teleport_flash:SetPos( self:GetPos() )
	self.teleport_flash:SetParent( self )
	self.teleport_flash:Spawn()
	self.teleport_flash:Activate()
	self.teleport_flash:Fire( "SetParentAttachment", "centre_attach", 0 )

	self:SetUp()
	
	self:SetNetworkedInt( "health", self:Health() )
end

function ENT:SetUp()
	if self.built then self.setupdelay = 0; return end
	self:SetModel( "models/buildables/teleporter.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: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:Sap()
	self.sapper:SetParent( self )
	self.sapper:Fire( "SetParentAttachment", "build_point_0", 0 )
	self.sapper:SetModel( "models/buildables/sapper_teleporter.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_autoattackedbyspy01.wav", 100, 100 )
	end
	
	self.idlesound:Stop()
end

function ENT:Teleport( target )
	if (target:Team() != self.team and (target:Team() == 1 or target:Team() == 2)) then return end
	local tele_pos = self.tp_exit:GetPos()
	tele_pos.z = tele_pos.z +(target:GetPos().z -self:GetPos().z) +1
	target:SetPos( tele_pos )
	target:SetEyeAngles( Angle(0, self.tp_exit:GetAngles().y, 0) )
	
	self.allowteleport = false
	self.teleporting = false
	self.charged_effect:Fire( "Stop", "", 0 )
	self.playbackrate = 0.5
	self.pitchrate = 6
	self.speeddelay = CurTime() +0.3
	
	self.teleport_flash:Fire( "Stop", "", 0 )
	self.teleport_flash:Fire( "Start", "", 0.05 )
	
	local ply_fov = target:GetFOV()
	target:SetFOV( ply_fov +5, 0 )
	target:SetFOV( ply_fov, 1 )
	
	self.rechargedelay = CurTime() +0.1
	self.recharge = 0
	
	self.tp_exit.playbackrate = 0.5
	self.tp_exit.pitchrate = 6
	self.tp_exit.speeddelay = CurTime() +0.3
	
	self.tp_exit.rechargedelay = CurTime() +0.1
	self.tp_exit.recharge = 0
	
	self.tp_exit.teleport_effect:Fire( "Stop", "", 0 )
	self.tp_exit.teleport_effect:Fire( "Start", "", 0.05 )
	
	if target != self.owner then
		if self.owner and ValidEntity(self.owner) and string.find(GAMEMODE.Name, "Fortress" ) then
			self.owner:AddTeleports(1)
			self.owner:AddFrags(0.5)
			self.owner:AddScoreRound(0.5)
		end
		self:SetNetworkedInt("teleportamt", self:GetNetworkedInt("teleportamt") +1)
	end
	if target.teleport_effect then return end
	target.teleport_effect = ents.Create( "info_particle_system" )
	target.teleport_effect:SetKeyValue( "effect_name", "player_recent_teleport_" .. self.teleporteffect )
	target.teleport_effect:SetKeyValue( "start_active", "1" )
	target.teleport_effect:SetPos( target:GetPos() )
	target.teleport_effect:SetParent( target )
	target.teleport_effect:Spawn()
	target.teleport_effect:Activate()
	target.teleport_effect:Fire( "Kill", "", 13 )
	timer.Simple( 13, function() if target and ValidEntity(target) then target.teleport_effect = nil end end )
	
	self.rechargestart = CurTime()
end

function ENT:Ready()
	self.allowteleport = true
	self.charged_effect:Fire( "Start", "", 0 )
	self.idle_effect:Fire( "Start", "", 0 )
	self:SetBodygroup( 1,1 )
end

function ENT:Think()
	self:NextThink( CurTime() +0.1 )
	if self.sapped then return true end
	if self.recharge and self.recharge < 100 and !timer.IsTimer("RechargeTimer" .. self:EntIndex()) then
		timer.Create( "RechargeTimer" .. self:EntIndex(), 0.05, 0, function()
		if self and ValidEntity(self) then
			self.recharge = self.recharge +1;
			self:SetNetworkedInt( "recharge", self.recharge )
			if self.recharge == 40 then self.spinup = true end;
			if self.recharge == 100 then timer.Destroy( "RechargeTimer" .. self:EntIndex() ) end;
		else
			timer.Destroy( "RechargeTimer" .. self:EntIndex() )
		end
		end)
	elseif self.recharge == 100 then
		self:EmitSound( "weapons/teleporter_ready.wav", 100, 100 )
		self.recharge = false
		self.rechargedelay = nil
		self.charged_effect:Fire( "Start", "", 0 )
	end

	if self.speeddelay and CurTime() > self.speeddelay then
		if !self.spinup then
			if self.playbackrate > 0 then
				self.speeddelay = CurTime() +0.3
				self:SetPlaybackRate( self.playbackrate )
				self.idlesound:ChangePitch( 100 -self.pitchrate )
				if tostring(self.playbackrate) == "0.1" then self.idlesound:FadeOut( 1.8 ) end
				self.playbackrate = self.playbackrate -0.05
				self.pitchrate = self.pitchrate +6
				if tostring(self.playbackrate) == "0.45" then self:SetBodygroup( 1,0 ) end
			else
				self.pitchrate = nil
				self.playbackrate = nil
				self.speeddelay = nil
			end
		else
			if self.playbackrate < 0.6 then
				self.speeddelay = CurTime() +0.3
				self:SetPlaybackRate( self.playbackrate )
				self.idlesound:ChangePitch( 100 -self.pitchrate )
				if tostring(self.playbackrate) == "0.1" then self.idlesound:FadeOut( 1.8 ) end
				self.playbackrate = self.playbackrate +0.05
				self.pitchrate = self.pitchrate -6
				if tostring(self.playbackrate) == "0.5" then self:SetBodygroup( 1,1 ) end
			else
				self.allowteleport = true
				self.spinup = nil
				self.pitchrate = nil
				self.playbackrate = nil
				self.speeddelay = nil
			end
		end
	end

	if self.setupdelay then
		if CurTime() > self.setupdelay then
			self:SetModel( self.model )
			self.settingup = false
			self.setupdelay = nil
			self:ResetSequence( self:LookupSequence( "running" ) )
			self:SetPlaybackRate( 0 )
			self.built = true
			self:SetNetworkedBool("building", false)
			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 then return true end
	if !self.gotexit and !self.sapped and ((self.owner and self.owner.tp_exit and self.owner.tp_exit.built and !self.owner.tp_exit.sapped) or (self.tp_exit and !self.tp_exit.sapped)) then
		if !self.tp_exit then
			self.tp_exit = self.owner.tp_exit
		end
		self.gotexit = true
		self:SetNetworkedBool( "gotexit", true )
		self:EmitSound( "weapons/teleporter_ready.wav", 100, 100 )
		self.idlesound:Play()
		self:ResetSequence( self:LookupSequence( "running" ) )
		self:SetPlaybackRate( 0.6 )
		self:Ready()
		self:SetBodygroup( 2,1 )
	end
	
	if self.gotexit then
		if ( !ValidEntity( self.tp_exit ) or self.tp_exit:Health() <= 0 or self.sapped or self.tp_exit.sapped ) then
			self.gotexit = false
			self:SetNetworkedBool( "gotexit", false )
			self.playbackrate = 0.5
			self.pitchrate = 6
			self.speeddelay = CurTime() +0.3
			self.charged_effect:Fire( "Stop", "", 0 )
			self.idle_effect:Fire( "Stop", "", 0 )
			self:SetBodygroup( 2,0 )
		else
			local angle = (self.tp_exit:GetPos() -self:GetPos()):Angle()
			angle.y = self:GetAngles().y +(angle.y *-1) -180
			if angle.y >= 180 then
				angle.y = -180 +(angle.y -180)
			elseif angle.y < -180 then
				angle.y = 180 +(angle.y +180)
			end
			self:SetPoseParameter("direction", angle.y)
		end
	end


	if self.tele_target and self.tele_target.teleport_effect and ValidEntity( self.tele_target.teleport_effect ) then
		if !ValidEntity(self.tele_target) or self.tele_target:Health() < 0 then
			target.teleport_effect:Remove()
			self.tele_target = nil
		end
	end
	
	if !self.gotexit or !self.allowteleport then return true end

	if self.tele_delay and CurTime() > self.tele_delay then
		if table.HasValue( ents.FindInSphere( self:GetPos(), self.distance ), self.tele_target ) and (self.tele_target:Team() == self.team or (self.tele_target:Team() != 1 and self.tele_target:Team() != 2)) then
			if self.mapentity then self.teleportsound = CreateSound( self, "weapons/teleporter_send.wav" ) end
			self.teleportsound:Stop()
			self.teleportsound:Play()
			self.teleport_effect:Fire( "Stop", "", 0 )
			self.teleport_effect:Fire( "Start", "", 0.05 )
			timer.Simple(0.3, function() if self and ValidEntity(self) then self:Teleport(self.tele_target) end end )
			//self.tele_target = nil
			self.tele_delay = nil
		else
			self.teleporting = false
			self.tele_delay = nil
		end
	end
	
	for k, v in pairs( ents.FindInSphere( self:GetPos(), self.distance ) ) do
		if ValidEntity(v) and v:IsPlayer() and v:Health() > 0 and !self.teleporting then
			self.teleporting = true
			self.tele_target = v
			self.tele_delay = CurTime() +0.4
		end
	end
	return true
end

function ENT:AcceptInput(name)
	self.lolangles = tonumber(name)
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", "tpdamage_" .. 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:Explode()
	for i = 1,3 do
		local gib = ents.Create( "obj_gib" )
		gib:SetModel( "models/buildables/Gibs/teleporter_Gib" .. i .. ".mdl" )
		gib:SetPos( self:GetPos() )
		gib:SetAngles( self:GetAngles() )
		gib:Spawn()
		gib:Activate()
		gib:GetPhysicsObject():ApplyForceCenter( Vector(0,0,500) )
		gib:SetSkin(self:GetSkin())
	end

	self:EmitSound( "weapons/teleporter_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()
	if self.owner then self.owner.teleport_entrance = nil end
	if ValidEntity( self.charged_effect ) then self.charged_effect:Remove() end
	if ValidEntity( self.idle_effect ) then self.idle_effect:Remove() end
	if ValidEntity( self.teleport_effect ) then self.teleport_effect:Remove() end
	if ValidEntity( self.teleport_flash ) then self.teleport_flash:Remove() end
	
	if self.tp_exit then self.tp_exit.tp_entrance = nil end
	if self.owner and ValidEntity(self.owner) then self.owner:SetNetworkedEntity( "tp_entrance", NULL ) end
	
	if self.dmgparticle and ValidEntity(self.dmgparticle) then self.dmgparticle:Remove() end
	self.idlesound:Stop()
	self.teleportsound:Stop()
end

