//Weed
SWEP.base = "weapon_base"
SWEP.Category = "Drugs"
SWEP.Author = "Hobo_Gus; cleveland steamer"
SWEP.Contact = ""
SWEP.Purpose = "Restores health by 50 points while temporarily impairing the user's perception."
SWEP.Instructions = "PRIMARY ATTACK KEY - Toke"
SWEP.PrintName = "Weed"
SWEP.Slot = 5;
SWEP.SlotPos = 420;
SWEP.DrawCrosshair = false;
SWEP.DrawAmmo = false;
SWEP.ViewModel = "models/weapons/cstrike/c_knife_t.mdl";
SWEP.WorldModel = "models/joint/joint.mdl";
SWEP.ShowWorldModel = false
SWEP.ViewModelFOV = 65;
SWEP.UseHands = true;
SWEP.HoldType = "normal"
SWEP.Spawnable = true;
SWEP.AdminSpawnable = true;
SWEP.Weight = 0;
--SWEP.AutoSwitchTo = true;SWEP.AutoSwitchFrom = true;
SWEP.FiresUnderwater = false;

SWEP.Primary.ClipSize = -1;
SWEP.Primary.DefaultClip = -1;
SWEP.Primary.Recoil = 1;
SWEP.Primary.Spread = 0.1;
SWEP.Primary.Delay = 0.8;
SWEP.Primary.Automatic = true;
SWEP.Primary.Ammo = "none";
SWEP.Primary.Sound = "none";
SWEP.Primary.TakeAmmo = 1;
SWEP.ShotEffect = "hg_weed"

SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = -1
SWEP.Secondary.Ammo = "none"

SWEP.IronSightsPos = Vector(-4.12, -9.447, -1.591)
SWEP.IronSightsAng = Vector(-1.407, -40.102, -2.814)

SWEP.ViewModelBoneMods = {
	["v_weapon.Knife_Handle"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
	["ValveBiped.Bip01_R_UpperArm"] = { scale = Vector(1, 1, 1), pos = Vector(30, 0, 0), angle = Angle(0, 0, 0) }
}

-- drugs drugs drugs --

local LASTINGEFFECT = 30
local TRANSITION_TIME = 6
local HASHIGH = true

--self.Owner:DoHigh("durgz_weed", SWEP.LASTINGEFFECT, SWEP.TRANSITION_TIME)
local function DoHigh(activator, class, lastingeffect, transition_time)
		print(activator:Name()..", you called?")
		--if you're transitioning to the end and you take another, smoothen it out
		--print(tostring(activator:GetNetworkedFloat(class.."_high_start")))
		if activator:GetNetworkedFloat(class.."_high_end") && activator:GetNetworkedFloat(class.."_high_end") > CurTime() && activator:GetNetworkedFloat(class.."_high_end") - transition_time < CurTime() then
			--set the high start in such a way to where it doesn't snap to the start time, goes smoooothly.
			local set = CurTime() - ( activator:GetNetworkedFloat(class.."_high_end") - CurTime() );
			activator:SetNetworkedFloat(class.."_high_start", set);
			
			
		--if you're not high at all
		elseif( !activator:GetNetworkedFloat(class.."_high_start") || activator:GetNetworkedFloat(class.."_high_end") < CurTime() )then
			activator:SetNetworkedFloat(class.."_high_start", CurTime());
			print("high should start here")
		end
		
		--high is done
		local ctime;
		if( !activator:GetNetworkedFloat(class.."_high_end") || activator:GetNetworkedFloat(class.."_high_end") < CurTime() )then
			ctime = CurTime();
		--you're already high on the drug,  add more highness
		else
			ctime = activator:GetNetworkedFloat(class.."_high_end") - lastingeffect/3;
		end
		activator:SetNetworkedFloat(class.."_high_end", ctime + lastingeffect);
end
-- give em all to me --

if ( CLIENT ) then
	
end

SWEP.VElements = {
	["weed"] = { type = "Model", model = "models/joint/joint.mdl", bone = "ValveBiped.Bip01_L_Hand", rel = "", pos = Vector(4.6, 2.2, 2), angle = Angle(-160, 85, 140), size = Vector(1.299, 1.299, 1.299), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
}
SWEP.WElements = {
	["weed"] = { type = "Model", model = "models/joint/joint.mdl", bone = "ValveBiped.Bip01_Head1", rel = "", pos = Vector(-.5, 5, -0.301), angle = Angle(-8, 0, 220), size = Vector(1.299, 1.299, 1.299), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
}

local IRONSIGHT_TIME = 0.5
function SWEP:GetViewModelPosition( pos, ang )

	if ( !self.IronSightsPos ) then return pos, ang end

	local bIron = self.Weapon:GetNetworkedBool( "Ironsights" )
	
	if ( bIron != self.bLastIron ) then
	
		self.bLastIron = bIron 
		self.fIronTime = CurTime()
		
		if ( bIron ) then 
			self.SwayScale 	= 0.3
			self.BobScale 	= 0.1
		else 
			self.SwayScale 	= 1.0
			self.BobScale 	= 1.0
		end
	
	end
	
	local fIronTime = self.fIronTime or 0

	if ( !bIron && fIronTime < CurTime() - IRONSIGHT_TIME ) then 
		return pos, ang 
	end
	
	local Mul = 1.0
	
	if ( fIronTime > CurTime() - IRONSIGHT_TIME ) then
	
		Mul = math.Clamp( (CurTime() - fIronTime) / IRONSIGHT_TIME, 0, 1 )
		
		if (!bIron) then Mul = 1 - Mul end
	
	end

	local Offset	= self.IronSightsPos
	
	if ( self.IronSightsAng ) then
	
		ang = ang * 1
		ang:RotateAroundAxis( ang:Right(), 		self.IronSightsAng.x * Mul )
		ang:RotateAroundAxis( ang:Up(), 		self.IronSightsAng.y * Mul )
		ang:RotateAroundAxis( ang:Forward(), 	self.IronSightsAng.z * Mul )
	
	
	end
	
	local Right 	= ang:Right()
	local Up 		= ang:Up()
	local Forward 	= ang:Forward()
	
	

	pos = pos + Offset.x * Right * Mul
	pos = pos + Offset.y * Forward * Mul
	pos = pos + Offset.z * Up * Mul

	return pos, ang
	
end

function SWEP:PrimaryAttack()

if ( !self.IronSightsPos ) then return end
bIronsights = !self.Weapon:GetNetworkedBool( "Ironsights", false )

self.Weapon:SetNextPrimaryFire(CurTime() + 3)
self:SetIronsights( bIronsights )
    self.Owner:SetAnimation( PLAYER_ATTACK1 )
	self.Weapon:EmitSound("420se/smoke weed everyday.mp3") -- had to match casing cos nobody gives a fuck about linux users
	timer.Simple(2, function()
		local smoke = EffectData()
		smoke:SetEntity(self.Weapon)
		smoke:SetOrigin(self.Owner:GetShootPos())
		smoke:SetNormal(self.Owner:GetAimVector())
		smoke:SetAttachment("2")
		util.Effect( "weed_smoke" ,smoke)
	end)
	timer.Simple(1.7, function() 
		self.Weapon:SetNetworkedBool( "Ironsights", false )
		local fx = EffectData()
		fx:SetEntity(self.Weapon)
		fx:SetOrigin(self.Owner:GetShootPos())
		fx:SetNormal(self.Owner:GetAimVector())
		fx:SetAttachment("1")
			util.Effect( self.ShotEffect ,fx)
		self.Owner:SetHealth(self.Owner:Health() + 50)
		DoHigh(self.Owner,"durgz_weed", LASTINGEFFECT, TRANSITION_TIME)
		
	end)
	if (SERVER) then timer.Simple(2.2,function()self.Owner:StripWeapon("weapon_durgz_weed")end) end
end

function SWEP:SetIronsights( b )

	self.Weapon:SetNetworkedBool( "Ironsights", b )

end

function SWEP:SecondaryAttack()
self.AnimTest = Vector(0, 0, 0)
end

function SWEP:Deploy()
	self:SendWeaponAnim( ACT_VM_DRAW )
	self:SetNextPrimaryFire( CurTime() + self:SequenceDuration() )
	self.Weapon:EmitSound("weapons/draw_melee.wav")

	return true
end 
 
function SWEP.Think()

end

function SWEP:Initialize()
	if(CLIENT)then
		self:SetWeaponHoldType( self.HoldType )	
		-- Create a new table for every weapon instance
		self.VElements = table.FullCopy( self.VElements )
		self.WElements = table.FullCopy( self.WElements )
		self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )

		self:CreateModels(self.VElements) // create viewmodels
		self:CreateModels(self.WElements) // create worldmodels
		
		-- init view model bone build function
		if IsValid(self.Owner) then
			local vm = self.Owner:GetViewModel()
			if IsValid(vm) then
				self:ResetBonePositions(vm)
			end
		end
		
		-- weed fx
		--killicon.Add("durgz_weed","killicons/durgz_weed_killicon",Color( 255, 80, 0, 255 ))	
		--local HIGH_INTENSITY = 0.77; --1 is max, 0 is nothing at all
		local HIGH_INTENSITY = 1; --1 is max, 0 is nothing at all
		hook.Add(
			"RenderScreenspaceEffects",
			"durgz_weed_high",
			function()
				local pl = LocalPlayer();
				
				
				local tab = {}
				tab[ "$pp_colour_addr" ] = 0
				tab[ "$pp_colour_addg" ] = 0
				tab[ "$pp_colour_addb" ] = 0
				//tab[ "$pp_colour_brightness" ] = 0
				//tab[ "$pp_colour_contrast" ] = 1
				tab[ "$pp_colour_mulr" ] = 0
				tab[ "$pp_colour_mulg" ] = 0
				tab[ "$pp_colour_mulb" ] = 0
				
				
				if( pl:GetNWFloat("durgz_weed_high_start") && pl:GetNWFloat("durgz_weed_high_end") > CurTime() )then
				
					if( pl:GetNWFloat("durgz_weed_high_start") + TRANSITION_TIME > CurTime() )then
						timer.Simple(2, function() pl:SetDSP(6) end)
						
						local s = pl:GetNWFloat("durgz_weed_high_start");
						local e = s + TRANSITION_TIME;
						local c = CurTime();
						local pf = (c-s) / (e-s);
						
						tab[ "$pp_colour_colour" ] =   1 - pf*0.3 //pf*4*HIGH_INTENSITY + 1
						tab[ "$pp_colour_brightness" ] = -pf*0.11
						tab[ "$pp_colour_contrast" ] = 1 + pf*1.62
						DrawMotionBlur( 0.03, pf*HIGH_INTENSITY, 0);
						DrawColorModify( tab ) 
						
					elseif( pl:GetNWFloat("durgz_weed_high_end") - TRANSITION_TIME < CurTime() )then
					
						local e = pl:GetNWFloat("durgz_weed_high_end");
						local s = e - TRANSITION_TIME;
						local c = CurTime();
						local pf = 1 - (c-s) / (e-s);
						
						pl:SetDSP(1)
						
						tab[ "$pp_colour_colour" ] = 1 - pf*0.3
						tab[ "$pp_colour_brightness" ] = -pf*0.11
						tab[ "$pp_colour_contrast" ] = 1 + pf*1.62
						DrawMotionBlur( 0.03, pf*HIGH_INTENSITY, 0);
						DrawColorModify( tab ) 
						
					else
						
						tab[ "$pp_colour_colour" ] = 0.77//5*HIGH_INTENSITY
						tab[ "$pp_colour_brightness" ] = -0.11
						tab[ "$pp_colour_contrast" ] = 2.62
						DrawMotionBlur( 0.03, HIGH_INTENSITY, 0);
						DrawColorModify( tab ) 
						pl:SetDSP(6);
						
					end
				end
			end
		)
	end
	
	
end
function SWEP:Holster()
	
	if CLIENT and IsValid(self.Owner) then
		local vm = self.Owner:GetViewModel()
		if IsValid(vm) then
			self:ResetBonePositions(vm)
		end
	end
	
	return true
end

function SWEP:OnRemove()
	self:Holster()
end

if CLIENT then

	SWEP.vRenderOrder = nil
	function SWEP:ViewModelDrawn()
		
		local vm = self.Owner:GetViewModel()
		if !IsValid(vm) then return end
		
		if (!self.VElements) then return end
		
		self:UpdateBonePositions(vm)

		if (!self.vRenderOrder) then
			
			// we build a render order because sprites need to be drawn after models
			self.vRenderOrder = {}

			for k, v in pairs( self.VElements ) do
				if (v.type == "Model") then
					table.insert(self.vRenderOrder, 1, k)
				elseif (v.type == "Sprite" or v.type == "Quad") then
					table.insert(self.vRenderOrder, k)
				end
			end
			
		end

		for k, name in ipairs( self.vRenderOrder ) do
		
			local v = self.VElements[name]
			if (!v) then self.vRenderOrder = nil break end
			if (v.hide) then continue end
			
			local model = v.modelEnt
			local sprite = v.spriteMaterial
			
			if (!v.bone) then continue end
			
			local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
			
			if (!pos) then continue end
			
			if (v.type == "Model" and IsValid(model)) then

				model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
				ang:RotateAroundAxis(ang:Up(), v.angle.y)
				ang:RotateAroundAxis(ang:Right(), v.angle.p)
				ang:RotateAroundAxis(ang:Forward(), v.angle.r)

				model:SetAngles(ang)
				//model:SetModelScale(v.size)
				local matrix = Matrix()
				matrix:Scale(v.size)
				model:EnableMatrix( "RenderMultiply", matrix )
				
				if (v.material == "") then
					model:SetMaterial("")
				elseif (model:GetMaterial() != v.material) then
					model:SetMaterial( v.material )
				end
				
				if (v.skin and v.skin != model:GetSkin()) then
					model:SetSkin(v.skin)
				end
				
				if (v.bodygroup) then
					for k, v in pairs( v.bodygroup ) do
						if (model:GetBodygroup(k) != v) then
							model:SetBodygroup(k, v)
						end
					end
				end
				
				if (v.surpresslightning) then
					render.SuppressEngineLighting(true)
				end
				
				render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
				render.SetBlend(v.color.a/255)
				model:DrawModel()
				render.SetBlend(1)
				render.SetColorModulation(1, 1, 1)
				
				if (v.surpresslightning) then
					render.SuppressEngineLighting(false)
				end
				
			elseif (v.type == "Sprite" and sprite) then
				
				local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
				render.SetMaterial(sprite)
				render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
				
			elseif (v.type == "Quad" and v.draw_func) then
				
				local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
				ang:RotateAroundAxis(ang:Up(), v.angle.y)
				ang:RotateAroundAxis(ang:Right(), v.angle.p)
				ang:RotateAroundAxis(ang:Forward(), v.angle.r)
				
				cam.Start3D2D(drawpos, ang, v.size)
					v.draw_func( self )
				cam.End3D2D()

			end
			
		end
		
	end

	SWEP.wRenderOrder = nil
	function SWEP:DrawWorldModel()
		
		if (self.ShowWorldModel == nil or self.ShowWorldModel) then
			self:DrawModel()
		end
		
		if (!self.WElements) then return end
		
		if (!self.wRenderOrder) then

			self.wRenderOrder = {}

			for k, v in pairs( self.WElements ) do
				if (v.type == "Model") then
					table.insert(self.wRenderOrder, 1, k)
				elseif (v.type == "Sprite" or v.type == "Quad") then
					table.insert(self.wRenderOrder, k)
				end
			end

		end
		
		if (IsValid(self.Owner)) then
			bone_ent = self.Owner
		else
			// when the weapon is dropped
			bone_ent = self
		end
		
		for k, name in pairs( self.wRenderOrder ) do
		
			local v = self.WElements[name]
			if (!v) then self.wRenderOrder = nil break end
			if (v.hide) then continue end
			
			local pos, ang
			
			if (v.bone) then
				pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
			else
				pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
			end
			
			if (!pos) then continue end
			
			local model = v.modelEnt
			local sprite = v.spriteMaterial
			
			if (v.type == "Model" and IsValid(model)) then

				model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
				ang:RotateAroundAxis(ang:Up(), v.angle.y)
				ang:RotateAroundAxis(ang:Right(), v.angle.p)
				ang:RotateAroundAxis(ang:Forward(), v.angle.r)

				model:SetAngles(ang)
				//model:SetModelScale(v.size)
				local matrix = Matrix()
				matrix:Scale(v.size)
				model:EnableMatrix( "RenderMultiply", matrix )
				
				if (v.material == "") then
					model:SetMaterial("")
				elseif (model:GetMaterial() != v.material) then
					model:SetMaterial( v.material )
				end
				
				if (v.skin and v.skin != model:GetSkin()) then
					model:SetSkin(v.skin)
				end
				
				if (v.bodygroup) then
					for k, v in pairs( v.bodygroup ) do
						if (model:GetBodygroup(k) != v) then
							model:SetBodygroup(k, v)
						end
					end
				end
				
				if (v.surpresslightning) then
					render.SuppressEngineLighting(true)
				end
				
				render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
				render.SetBlend(v.color.a/255)
				model:DrawModel()
				render.SetBlend(1)
				render.SetColorModulation(1, 1, 1)
				
				if (v.surpresslightning) then
					render.SuppressEngineLighting(false)
				end
				
			elseif (v.type == "Sprite" and sprite) then
				
				local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
				render.SetMaterial(sprite)
				render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
				
			elseif (v.type == "Quad" and v.draw_func) then
				
				local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
				ang:RotateAroundAxis(ang:Up(), v.angle.y)
				ang:RotateAroundAxis(ang:Right(), v.angle.p)
				ang:RotateAroundAxis(ang:Forward(), v.angle.r)
				
				cam.Start3D2D(drawpos, ang, v.size)
					v.draw_func( self )
				cam.End3D2D()

			end
			
		end
		
	end

	function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
		
		local bone, pos, ang
		if (tab.rel and tab.rel != "") then
			
			local v = basetab[tab.rel]
			
			if (!v) then return end
			
			// Technically, if there exists an element with the same name as a bone
			// you can get in an infinite loop. Let's just hope nobody's that stupid.
			pos, ang = self:GetBoneOrientation( basetab, v, ent )
			
			if (!pos) then return end
			
			pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
			ang:RotateAroundAxis(ang:Up(), v.angle.y)
			ang:RotateAroundAxis(ang:Right(), v.angle.p)
			ang:RotateAroundAxis(ang:Forward(), v.angle.r)
				
		else
		
			bone = ent:LookupBone(bone_override or tab.bone)

			if (!bone) then return end
			
			pos, ang = Vector(0,0,0), Angle(0,0,0)
			local m = ent:GetBoneMatrix(bone)
			if (m) then
				pos, ang = m:GetTranslation(), m:GetAngles()
			end
			
			if (IsValid(self.Owner) and self.Owner:IsPlayer() and 
				ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
				ang.r = -ang.r // Fixes mirrored models
			end
		
		end
		
		return pos, ang
	end

	function SWEP:CreateModels( tab )

		if (!tab) then return end

		// Create the clientside models here because Garry says we can't do it in the render hook
		for k, v in pairs( tab ) do
			if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and 
					string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
				
				v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
				if (IsValid(v.modelEnt)) then
					v.modelEnt:SetPos(self:GetPos())
					v.modelEnt:SetAngles(self:GetAngles())
					v.modelEnt:SetParent(self)
					v.modelEnt:SetNoDraw(true)
					v.createdModel = v.model
				else
					v.modelEnt = nil
				end
				
			elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite) 
				and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
				
				local name = v.sprite.."-"
				local params = { ["$basetexture"] = v.sprite }
				// make sure we create a unique name based on the selected options
				local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
				for i, j in pairs( tocheck ) do
					if (v[j]) then
						params["$"..j] = 1
						name = name.."1"
					else
						name = name.."0"
					end
				end

				v.createdSprite = v.sprite
				v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
				
			end
		end
		
	end
	
	local allbones
	local hasGarryFixedBoneScalingYet = false

	function SWEP:UpdateBonePositions(vm)
		
		if self.ViewModelBoneMods then
			
			if (!vm:GetBoneCount()) then return end
			
			// !! WORKAROUND !! //
			// We need to check all model names :/
			local loopthrough = self.ViewModelBoneMods
			if (!hasGarryFixedBoneScalingYet) then
				allbones = {}
				for i=0, vm:GetBoneCount() do
					local bonename = vm:GetBoneName(i)
					if (self.ViewModelBoneMods[bonename]) then 
						allbones[bonename] = self.ViewModelBoneMods[bonename]
					else
						allbones[bonename] = { 
							scale = Vector(1,1,1),
							pos = Vector(0,0,0),
							angle = Angle(0,0,0)
						}
					end
				end
				
				loopthrough = allbones
			end
			// !! ----------- !! //
			
			for k, v in pairs( loopthrough ) do
				local bone = vm:LookupBone(k)
				if (!bone) then continue end
				
				// !! WORKAROUND !! //
				local s = Vector(v.scale.x,v.scale.y,v.scale.z)
				local p = Vector(v.pos.x,v.pos.y,v.pos.z)
				local ms = Vector(1,1,1)
				if (!hasGarryFixedBoneScalingYet) then
					local cur = vm:GetBoneParent(bone)
					while(cur >= 0) do
						local pscale = loopthrough[vm:GetBoneName(cur)].scale
						ms = ms * pscale
						cur = vm:GetBoneParent(cur)
					end
				end
				
				s = s * ms
				// !! ----------- !! //
				
				if vm:GetManipulateBoneScale(bone) != s then
					vm:ManipulateBoneScale( bone, s )
				end
				if vm:GetManipulateBoneAngles(bone) != v.angle then
					vm:ManipulateBoneAngles( bone, v.angle )
				end
				if vm:GetManipulateBonePosition(bone) != p then
					vm:ManipulateBonePosition( bone, p )
				end
			end
		else
			self:ResetBonePositions(vm)
		end
		   
	end
	 
	function SWEP:ResetBonePositions(vm)
		
		if (!vm:GetBoneCount()) then return end
		for i=0, vm:GetBoneCount() do
			vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
			vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
			vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
		end
		
	end

	/**************************
		Global utility code
	**************************/

	// Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
	// Does not copy entities of course, only copies their reference.
	// WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
	function table.FullCopy( tab )

		if (!tab) then return nil end
		
		local res = {}
		for k, v in pairs( tab ) do
			if (type(v) == "table") then
				res[k] = table.FullCopy(v) // recursion ho!
			elseif (type(v) == "Vector") then
				res[k] = Vector(v.x, v.y, v.z)
			elseif (type(v) == "Angle") then
				res[k] = Angle(v.p, v.y, v.r)
			else
				res[k] = v
			end
		end
		
		return res
		
	end
	
end