--[[
	lua/autorun/client/scripts/oubhack.lua
	Oubliette | (STEAM_0:1:34029133)
	===DStream===
]]

/******************************************************************************
 .d88888b.  888     888 888888b.   888    888        d8888  .d8888b.  888    d8P  
d88P" "Y88b 888     888 888  "88b  888    888       d88888 d88P  Y88b 888   d8P   
888     888 888     888 888  .88P  888    888      d88P888 888    888 888  d8P    
888     888 888     888 8888888K.  8888888888     d88P 888 888        888d88K     
888     888 888     888 888  "Y88b 888    888    d88P  888 888        8888888b    
888     888 888     888 888    888 888    888   d88P   888 888    888 888  Y88b   
Y88b. .d88P Y88b. .d88P 888   d88P 888    888  d8888888888 Y88b  d88P 888   Y88b  
 "Y88888P"   "Y88888P"  8888888P"  888    888 d88P     888  "Y8888P"  888    Y88b 
 - V2 By Oubliette
*******************************************************************************/

-- Main

if !CLIENT then return; end

// Vars 

local g = table.Copy(_G);
local r = debug.getregistry();

local me;

--g.require("oubhack");

local setdefconf,getdefconf,writereg,readreg,getconf,getconfs = OH_SETDEFCONF,OH_GETDEFCONF,OH_REGWRITE,OH_REGREAD,OH_GETCONFIG,OH_GETCONFIGS;

OH_SETDEFCONF,OH_GETDEFCONG,OH_REGWRITE,OH_REGREAD,OH_GETCONFIG,OH_GETCONFIGS = nil,nil,nil,nil,nil;

g.timer.Create("LPIsValid",0.1,0,function() 
	if g.IsValid(LocalPlayer()) then 
		me = LocalPlayer();
		g.timer.Destroy("LPIsValid");
	end
end)

/*local*/ OH = {
	Aimbot = { 
		// Friends
		friends = {}, -- EntIndexes for temp non-player friends - Not saved to config
		friend_ids = {}, -- Steam IDs
		// Targets
		ignore_usergroups = {}, -- ignore user groups
		target_npcs = true, -- Target NPCs
		target_bots = true, -- Target bots 
		target_ownteam = true, -- Target my team
		target_harmless = true, -- Target harmless *players*


		target_vehicles = false, -- Target players in vehicles 
		target_locking = false, -- Enable target locking
		target_espents = false, -- Target Entities from the ESP
		no_tweps = {"weapon_physgun","gmod_tool","weapon_physcannon","weapon_crowbar","gmod_camera"}, -- No trace weapons (bad weapons) 
		otrg_traitors = false, -- Only target traitors in TTT
		// Tracing
		los_check = true, -- Check LOS
		voffset = g.Vector(0,0,0), -- Aimbot Vector offset
		aoffset = g.Angle(0,0,0), -- Angle offset
		trace_key = IN_ATTACK, -- Aimbot Trace Key
		// Anti-snap
 		antisnap_enabled = false, -- Anti-snap enabled 
 		antisnap_letoff = 45, -- Anti-snap let-off (slowness)
		antisnap_lb = 20, -- Anti-snap Lower Bound
		antisnap_hb = 360, -- Anti-snap Higher Bound
		antisnap_clhb = true, -- Enabled Higher Bound clamping
		antisnap_cllb = false, -- Enable Lower Bound clamping 
		// Triggerbot
		tb_enabled = false, -- Triggerbot Enabled
		tb_aon = true, -- Triggerbot always on
		tb_firing = false,
		// Silent Aim
		sa_enabled = false, -- Enabled Silent Aim
		sa_ang = nil, -- Silent Aim Angle
		// vars
		target_bone = "ValveBiped.Bip01_Head1",
		tlocked = false, -- Target Locked
		targets = false, -- Targets
		vtargets = {}, -- Visible Targets
		target = false, -- Current Target
		tracing = false, -- Aimbot tracing
		ext_t = false -- Enabled extra traces
	},
	Wallhack = { 
		// Colors
		tbl_colour = { -- Custom Model Colors : {Name,Class,Model,Colour}
			["Players"] = {colour=g.Color(255,0,0,255),class="Player",mdl="Any"},
			["NPCs"] = {colour=g.Color(255,255,0,255),class="NPC",mdl="Any"},
			["Bots"] = {colour=g.Color(200,0,0,200),class="Bot",mdl="Any"},
			["Friends"] = {colour=g.Color(0,255,0,255),class="Friends",mdl="Any"}
		},
		// vars
		show_distance = 1500, -- How far the ESP works from.
		enabled = false, -- Enabled
		// targeting 
		t_npcs = true, -- Target NPCs
		t_bots = true, -- Target Bots
		t_players = true, -- Target Players
		// Mats
		wireframe = g.CreateMaterial("OHWFMaterial","Wireframe",{
			["$basetexture"] = "models/wireframe",
			["$ignorez"] = 1
		}),
		softbg = g.CreateMaterial("OGSoftBgMaterial","UnlitGeneric",{
			["$basetexture"] = "models/debug/debugwhite",
			["$ignorez"] = 1
		}),
		use_wireframe = true -- Use Wireframe texture
	},
	CNoClip = {
		enabled = false, -- CNC enabled
		speed = 500, -- CNC Speed
		angle = g.Angle(0,0,0), -- CNC Angle
		pos = g.Vector(0,0,0), -- CNC Pos
		fov = 90
	},
	KeyBind = {
		keys = { -- Keys
			{"A",KEY_A},{"B",KEY_B},{"C",KEY_C},{"D",KEY_D},{"E",KEY_E},{"F",KEY_F},
			{"G",KEY_G},{"H",KEY_H},{"I",KEY_I},{"J",KEY_J},{"K",KEY_K},{"L",KEY_L},
			{"M",KEY_M},{"N",KEY_N},{"O",KEY_O},{"P",KEY_P},{"Q",KEY_Q},{"R",KEY_R},
			{"S",KEY_S},{"T",KEY_T},{"U",KEY_U},{"V",KEY_V},{"W",KEY_W},{"X",KEY_X},
			{"Y",KEY_Y},{"Z",KEY_Z},{"1",KEY_1},{"2",KEY_3},{"3",KEY_3},{"4",KEY_4},
			{"5",KEY_5},{"6",KEY_6},{"7",KEY_1},{"7",KEY_7},{"8",KEY_1},{"9",KEY_9},
			{",",KEY_COMMA},{".",KEY_PERIOD},{"/",KEY_SLASH},{";",KEY_SEMICOLON},
			{"'",KEY_APOSTROPHE},{[[\]],KEY_BACKSLASH},{"[",KEY_LBRACKET},{"]",KEY_RBRACKET},
			{"Right Click",MOUSE_RIGHT},{"Left Click",MOUSE_LEFT},{"Right Control",KEY_RCONTROL},
			{"Left Control",KEY_LCONTROL},{"Right Alt",KEY_LALT},{"Left Alt",KEY_RALT},
			{"Left Shift",KEY_LSHIFT},{"Right Shift",KEY_RSHIFT},{"Enter",KEY_ENTER},
			{"Up",KEY_UP},{"Down",KEY_DOWN},{"Left",KEY_LEFT},{"Right",KEY_RIGHT},
			{"Tab",KEY_TAB},{"Backspace",KEY_BACKSPACE},{"Equal",KEY_EQUAL},{"Minus",KEY_MINUS},
			{"F1",KEY_F1},{"F2",KEY_F2},{"F3",KEY_F3},{"F4",KEY_F4},{"F5",KEY_F5},{"F6",KEY_F6},
			{"F7",KEY_7},{"F8",KEY_F8},{"F9",KEY_F9},{"F10",KEY_F10},{"F11",KEY_F11},{"F12",KEY_F12},
			{"Scroll Lock",KEY_SCROLLLOCK},{"Space",KEY_SPACE},{"Insert",KEY_INSERT},{"Delete",KEY_DELETE}
		},
		binds = {} -- Binds
	},
	OLog = {
		log_console = true, -- Log the console
		log_oconsole = false, -- Log OubHack console
		log_chat = true, -- Log the chat
		log_ad = true, -- Log Anti Detection
		// vars
		cache = {};
	},
	LaserEyes = {
		enabled = true -- Enabled
	},
	LaserSights = {
		enabled = true -- Enabled
	},
	ESP = {
		enabled = true -- Enabled
	},
	Debug = {
		enabled = true,
		core_calc_per_second = 0,
		hud_updates_per_second = 0,
		traces_per_second = 0
	},
	hooks = {},
	cmds = {},
	menu = {
	Console={},
		g_esp={},
		g_wallhack={},
		g_lasersts={},
		g_lasereyes={},
		c_aimbot={},
		c_trigbot={},
		c_autorld={},
		m_theme={},
		m_settings={},
		me_detour={},
		me_logging={},
		speed = 20 -- The speed of linear panels
	},
	hidemode_safehooks = {
		["HUDPaintBackground"] = true,
		["StartChat"] = true,
		["FinishChat"] = true,
		["OnTextEntryGetFocus"] = true,
		["OnTextEntryLoseFocus"] = true

	},
	spam = false,
	hidemode = false,
	Version = 2
};
local def = OH;

local goodkeys = {
	["Aimbot"] = true,
	["Wallhack"] = true,
	["CNoClip"] = true,
	["OLog"] = true,
	["LaserEyes"] = true,
	["LaserSights"] = true,
	["ESP"] = true
}

local badvalues = {
	["keys"] = true, -- The keys table in KeyBind.
	["pos"] = true, -- The position of CNoClip
	["angle"] = true, -- The angle of CNoClip
	["wireframe"] = true, -- The wireframe material
	["softbg"] = true, -- The soft background material
	["friends"] = true, -- The temp friends list
	["binds"] = true -- For now
}

/***************************************************************************************************
888b     d888 8888888888 .d8888b.  888    888        d8888 888b    888 8888888 .d8888b.   .d8888b.  
8888b   d8888 888       d88P  Y88b 888    888       d88888 8888b   888   888  d88P  Y88b d88P  Y88b 
88888b.d88888 888       888    888 888    888      d88P888 88888b  888   888  888    888 Y88b.      
888Y88888P888 8888888   888        8888888888     d88P 888 888Y88b 888   888  888         "Y888b.   
888 Y888P 888 888       888        888    888    d88P  888 888 Y88b888   888  888            "Y88b. 
888  Y8P  888 888       888    888 888    888   d88P   888 888  Y88888   888  888    888       "888 
888   "   888 888       Y88b  d88P 888    888  d8888888888 888   Y8888   888  Y88b  d88P Y88b  d88P 
888       888 8888888888 "Y8888P"  888    888 d88P     888 888    Y888 8888888 "Y8888P"   "Y8888P"                                                                                                   
****************************************************************************************************/

function OH.SAToA(str)
	local tbl = g.string.Explode(" ",str);
	return g.Angle(tbl[1],tbl[2],tbl[3]);
end

function OH.SVToV(str)
	local tbl = g.string.Explode(" ",str);
	return g.Vector(tbl[1],tbl[2],tbl[3]);
end

function OH.SCToC(str)
	local tbl = g.string.Explode(" ",str);
	return g.Color(tbl[1],tbl[2],tbl[3],tbl[4]);
end

// Logging

function OH.OLog.SaveLog(log)
	-- erm...
end

function OH.OLog.CacheLog(text,log)
	OH.OLog.cache[log] = OH.OLog.cache[log] .. text;
	OH.OLog.SaveLog(log);
end

// Hooks

function OH.AddHook(name,func)
	hook.Add(name,g.tostring(g.math.random(-9999,9999)),func);
	//OH.hooks[name] = func;
end

function OH.AddCmd(cmd,func)
	OH.cmds[cmd] = func;
end

-- Changing this to something simple before so I can test it online

local oHC = hook.Call;
function _G.hook.Call(name,gm,...)
	if OH.hooks[name] && me && IsValid( me ) && ( !OH.hidemode || hidemode_safehooks[ name ] ) then 
		oHC(name,gm,...);
		return OH.hooks[name](...);
	else
		return oHC(name,gm,...);
	end
end

// Key Bind
OH.binds_active = true;

function OH.KeyBind.KeyBindHandler()

	if (!OH.binds_active) then return; end
	if (g.input.IsKeyDown(KEY_Q)) then return; end

	for k,v in g.pairs(OH.KeyBind.binds) do

		if ( OH.hidemode && k != "Hidemode" ) then continue; end

		if g.input.IsKeyDown(v.BindKey) then
			if v.DownThinkFunc then v.DownThinkFunc() end
			if !v.CalledKDF then 
				if v.KeyDownFunc then v.KeyDownFunc() end 
				v.CalledKDF = true; 
				v.CalledKRF = false;
			end
		else 
			if v.UpThinkFunc then v.UpThinkFunc() end
			if !v.CalledKRF then 
				if v.KeyUpFunc then v.KeyUpFunc() end 
				v.CalledKDF = false; 
				v.CalledKRF = true;
			end
		end
	end
end

function OH.KeyBind.StringToEnum(str)
	for k,v in g.pairs(OH.KeyBind.keys) do
		if g.string.lower(str) == g.string.lower(v[1]) then
			return v;
		end
	end
end

function OH.AddKeyBind(key,name,downfunc,upfunc,downfuncthink,upfuncthink)
	key = g.tonumber(key) or OH.KeyBind.StringToEnum(key);
	if key then OH.KeyBind.binds[name] = {BindKey=key,KeyDownFunc=downfunc,KeyUpFunc=upfunc,DownThinkFunc=downfuncthink,UpThinkFunc=upfuncthink}; end
end

OH.AddHook("HUDPaintBackground",function()
	OH.KeyBind.KeyBindHandler();
end);

OH.AddHook("StartChat",function()
	OH.is_chatting = true;
	OH.binds_active = false;
end);

OH.AddHook("FinishChat",function()
	if (!OH.is_typing) then OH.binds_active = true; end
	OH.is_chatting = false;
end);

OH.AddHook("OnTextEntryGetFocus",function()
	OH.is_typing = true;
	OH.binds_active = false;
end);

OH.AddHook("OnTextEntryLoseFocus",function()
	if (!OH.is_chatting) then OH.binds_active = true; end
	OH.is_typing = false;
end);

// Aimbot stuff

function OH.IsHarmless(ply)
	for _,wep in g.pairs(r["Player"]["GetWeapons"](ply)) do 
		if !table.HasValue(OH.Aimbot.no_tweps,wep) then 
			return false;
		end
	end
	return true;
end

function OH.IsPlayer(ent) return type(ent) == "Player"; end 
function OH.IsNPC(ent) return type(ent) == "NPC"; end 
function OH.IsBot(ent) return ( g.IsValid( ent ) and OH.IsPlayer(ent) ) and r["Player"]["IsBot"](ent) end 

function OH.Aimbot.CanFire()
	if !me then return false; end
	local wep = r["Player"]["GetActiveWeapon"](me);

	if !r["Entity"]["IsValid"](wep) then return false; end 

	if OH.Aimbot.checkammo and wep:Clip1() <= 0 then return false; end 
	if table.HasValue(OH.Aimbot.no_tweps,r["Entity"]["GetClass"](wep)) then return false; end 

	if !r["Player"]["Alive"](me) then return false; end 
	if !r["Entity"]["IsValid"](me) then return false; end 

	if me:GetColor() and me:GetColor().a != 255 then return false; end 

	-- if r["Player"]["Team"](me) == 1002 then return false; end 
	-- if r["Player"]["Team"](me) == 1001 then return false; end 
	-- if r["Player"]["Team"](me) == 0 then return false; end 


	return true;
end

function OH.IsTraitor(ent)
	return true; -- laters 
end 

function OH.Aimbot.CanTarget(ent)
	if !ent or !r["Entity"]["IsValid"](ent) then return false; end 

	if OH.IsPlayer(ent) and !r["Player"]["Alive"](ent) then return false; end 
	if OH.IsPlayer(ent) and !OH.Aimbot.target_harmless and OH.IsHarmless(ent) then return false; end 
	if OH.IsPlayer(ent) and table.HasValue(OH.Aimbot.ignore_usergroups,ent:IsUserGroup()) then return false; end 
	if OH.IsPlayer(ent) and !OH.Aimbot.target_ownteam and r["Player"]["Team"](me) == r["Player"]["Team"](ent) then return false; end 
	--if OH.IsPlayer(ent) and !OH.Aimbot.target_vehicles and r["Player"]["GetVehicle"](ent) then return false; end 
	if OH.IsPlayer(ent) and OH.Aimbot.otrg_traitors and !OH.IsTraitor(ent) then return false; end 
	--if OH.IsPlayer(ent) and (r["Player"]["Team"](ent) == 1002 or r["Player"]["Team"](ent) == 1001 or r["Player"]["Team"] == 0) then return false; end 

	if OH.IsNPC(ent) and (r["Entity"]["GetMoveType"](ent) == 5 or r["Entity"]["GetMoveType"](ent) == 0) then return false; end 
	if OH.IsNPC(ent) and !OH.Aimbot.target_npcs then return false; end 
	if OH.IsPlayer(ent) and r["Player"]["IsBot"](ent) and !OH.Aimbot.target_bots then return false; end 

	if ( ent:GetColor() and ent:GetColor().a != 255 ) then return false; end
	if OH.IsPlayer(ent) and OH.Aimbot.friends[r["Player"]["SteamID"](ent)] then return false; end

	return true;
end

function OH.Wallhack.CanTarget(ent)

	if !me then return false; end 
	if me == ent then return false; end
	if !r["Entity"]["IsValid"](ent) then return false; end 

	if OH.IsPlayer(ent) and r["Player"]["Alive"](ent) and OH.Wallhack.t_players then return true; end
	if OH.IsPlayer(ent) and r["Player"]["IsBot"](ent) and r["Player"]["Alive"](ent) and OH.Wallhack.t_bots then return true; end 
	if OH.IsNPC(ent) and (r["Entity"]["GetMoveType"](ent) == 5 or r["Entity"]["GetMoveType"](ent) == 0) then return false; end 
	if OH.IsNPC(ent) and OH.Wallhack.t_npcs then return true; end 

	for name,data in g.pairs(OH.Wallhack.tbl_colour) do if (data.class == r["Entity"]["GetClass"](ent)) then return true; end end

	return false;
end 

function OH.Aimbot.FindPoint(ent)
	if ( !ent || !IsValid( ent ) ) then return; end 
	local pos=r["Entity"]["GetPos"](ent)+r["Entity"]["OBBCenter"](ent);
	if OH.Aimbot.target_bone != "" then
		local id = g.string.find(OH.Aimbot.target_bone,"ValveBiped") and r["Entity"]["LookupBone"](ent,OH.Aimbot.target_bone) or r["Entity"]["LookupAttachment"](ent,OH.Aimbot.target_bone);
		if (g.string.find(OH.Aimbot.target_bone,"ValveBiped") and id) then 
			pos = r["Entity"]["GetBonePosition"](ent,id) or pos;
		elseif id then  
			pos = r["Entity"]["GetAttachment"](ent,id) and r["Entity"]["GetAttachment"](ent,id).Pos or pos;
		end
	end
	-- Maybe add some custom model vector offsets?
	return (pos or Vector())+OH.Aimbot.voffset;
end

function OH.Aimbot.Core( cmd )

	if ( !me ) then return; end 

	local targ = OH.Aimbot.GetBestTarget();

	if ( OH.Aimbot.sa_enabled ) then 

		OH.Aimbot.sa_ang = (OH.Aimbot.sa_ang or r["CUserCmd"]["GetViewAngles"](cmd))+g.Angle(r["CUserCmd"]["GetMouseY"](cmd)* g.GetConVarNumber("m_yaw"),r["CUserCmd"]["GetMouseX"](cmd)* -g.GetConVarNumber("m_pitch"),0); -- SA
		OH.Aimbot.sa_ang.p,OH.Aimbot.sa_ang.y,OH.Aimbot.sa_ang.r = math.NormalizeAngle(OH.Aimbot.sa_ang.p),math.NormalizeAngle(OH.Aimbot.sa_ang.y),0;

	end

	if ( OH.Aimbot.CanFire() && r["Player"]["GetActiveWeapon"]( me ):Clip1() <= 0 ) then 

		g.RunConsoleCommand( "+reload" );
		g.timer.Simple( 1, function() g.RunConsoleCommand( "-reload" ) end );
		
	end

	if ( (me!=targ) and (OH.Aimbot.CanTarget(targ)) and (OH.Aimbot.CanFire()) ) then 



		if OH.Aimbot.target_locking then OH.Aimbot.tlocked = true; end
		-- Angle shit
		local point = OH.Aimbot.FindPoint(targ);


		local mpos,tpos = r["Player"]["GetShootPos"](me),point;
		tpos = tpos + (r["Entity"]["GetVelocity"](targ)/50 - r["Entity"]["GetVelocity"](me)/50);

		local tang,ang = r["Vector"]["Angle"](tpos-mpos),g.Angle(0,0,0);
		-- Anti Snap
		if OH.Aimbot.antisnap_enabled then 
			local loff,lb,hb = OH.Aimbot.antisnap_letoff,OH.Aimbot.antisnap_lb,OH.Aimbot.antisnap_hb;
			ang = r["CUserCmd"]["GetViewAngles"](cmd);
			local speedp = (10.5/loff*(g.math.abs(g.math.AngleDifference(ang.p,tang.p))));
			local speedy = (10.5/loff*(g.math.abs(g.math.AngleDifference(ang.y,tang.y))));
			if OH.Aimbot.antisnap_clhb then
				speedp = g.math.Clamp(speedp,0,g.tonumber(hb));
				speedy = g.math.Clamp(speedy,0,g.tonumber(hb));
			end
			if OH.Aimbot.antisnap_cllb then	
				speedp = g.math.Clamp(speedp,g.tonumber(lb),speedp);
				speedy = g.math.Clamp(speedy,g.tonumber(lb),speedy);
			end
			ang.r = 0;
			ang.p = g.math.ApproachAngle(ang.p,tang.p,speedp);
			ang.y = g.math.ApproachAngle(ang.y,tang.y,speedy);
		else 
			ang=tang;
		end
		ang.p,ang.y,ang.r = math.NormalizeAngle(ang.p),math.NormalizeAngle(ang.y),math.NormalizeAngle(ang.r);
		-- We have the angles, should we use them?
		if ( (OH.Aimbot.trace_key == IN_ATTACK) and r["CUserCmd"]["KeyDown"](cmd,IN_ATTACK) ) or OH.Aimbot.tb_enabled then -- If bound to left click, trace BEFORE the bullet is fired
			OH.Aimbot.tracing = true;
			r["CUserCmd"]["SetViewAngles"](cmd,ang);
			if OH.Aimbot.antisnap_enabled and OH.Aimbot.tb_enabled then 
				if r["Player"]["GetEyeTrace"](me).Entity == targ then 
					OH.Aimbot.TriggerBot();
				else 
					if OH.Aimbot.tb_firing then OH.Aimbot.TriggerBot(); end
				end
			elseif OH.Aimbot.tb_enabled then 
				OH.Aimbot.TriggerBot();
			end
		elseif g.input.IsKeyDown(OH.Aimbot.trace_key) then 
			OH.Aimbot.tracing = true;
			r["CUserCmd"]["SetViewAngles"](cmd,ang);
		else 
			if OH.Aimbot.tracing then
				OH.Aimbot.tracing = false;
				if OH.Aimbot.sa_ang then 
					r["CUserCmd"]["SetViewAngles"](cmd,OH.Aimbot.sa_ang);
					OH.Aimbot.sa_ang = nil;
				end 
				if OH.Aimbot.tb_firing then OH.Aimbot.TriggerBot(); end
			end
		end
	else
		if OH.Aimbot.tracing then
			OH.Aimbot.tracing = false;
			if OH.Aimbot.sa_ang then 
				r["CUserCmd"]["SetViewAngles"](cmd,OH.Aimbot.sa_ang);
				OH.Aimbot.sa_ang = nil;
			end 
		end
		OH.Aimbot.tlocked = false;
		if !OH.Aimbot.CanTarget(OH.Aimbot.target) then OH.Aimbot.target = nil; end
		if OH.Aimbot.tb_firing then OH.Aimbot.TriggerBot(); end
	end

end

OH.AddHook("CreateMove",function(cmd)
	OH.Aimbot.Core(cmd);OH.CNoClip.Core(cmd);
	OH.Debug.core_calc_per_second = OH.Debug.core_calc_per_second + 1;
end);

local last_fire = g.CurTime();
function OH.Aimbot.TriggerBot(cmd)
	if (g.CurTime() > last_fire+(r["Player"]["GetActiveWeapon"](me).Primary and r["Player"]["GetActiveWeapon"](me).Primary.Delay or 0.03) ) then 
		g.RunConsoleCommand("+attack");last_fire = g.CurTime();OH.Aimbot.tb_firing = true;
	elseif OH.Aimbot.tb_firing then 
		g.RunConsoleCommand("-attack");
		OH.Aimbot.tb_firing = false;
	end
end

// ESP / Wallhack

function OH.CNoClip.Core(cmd)
	if OH.CNoClip.enabled and me then
	    local vo,ang = g.Vector(0,0,0),r["CUserCmd"]["GetViewAngles"](cmd);
	  
	    if r["CUserCmd"]["KeyDown"](cmd,IN_FORWARD) then vo=vo+r["Angle"]["Forward"](ang); end
	    if r["CUserCmd"]["KeyDown"](cmd,IN_BACK) then vo=vo-r["Angle"]["Forward"](ang); end
	    if r["CUserCmd"]["KeyDown"](cmd,IN_RIGHT) then vo=vo+r["Angle"]["Right"](ang); end
	    if r["CUserCmd"]["KeyDown"](cmd,IN_LEFT) then vo=vo-r["Angle"]["Right"](ang); end
	    if r["CUserCmd"]["KeyDown"](cmd,IN_JUMP) then vo=vo+r["Angle"]["Up"](ang); end
	    if r["CUserCmd"]["KeyDown"](cmd,IN_DUCK) then vo=vo-r["Angle"]["Up"](ang); end

	    vo = r["Vector"]["GetNormal"](vo) * g.FrameTime() * OH.CNoClip.speed;
	    if r["CUserCmd"]["KeyDown"](cmd,IN_SPEED) then vo=vo*2; end
	    OH.CNoClip.pos = (OH.CNoClip.pos or r["Entity"]["EyePos"](me)) + vo;

	    r["CUserCmd"]["SetForwardMove"](cmd,0);
	    r["CUserCmd"]["SetSideMove"](cmd,0);
	    r["CUserCmd"]["SetUpMove"](cmd,0);
	    r["CUserCmd"]["KeyDown"](cmd,0);
    end
end

local gPos = r["Entity"]["GetPos"];

r["Entity"]["GetPos"] = function(ent) // Return CNoClip pos when getting the position of 'me', and when we're in CNoClip mode
	if (me and ent == me and OH.CNoClip.enabled) then 
		return OH.CNoClip.pos;
	end 
	if !r["Entity"]["IsValid"](ent) then return; end
	return gPos(ent);
end;

local laser_mat = Material("sprites/bluelaser1");

function OH.LaserSights.Draw()
	if OH.LaserSights.enabled and me and OH.Aimbot.CanFire() then
		local mbarrel = r["Player"]["GetViewModel"](me);
		local abarrel = r["Entity"]["GetAttachment"](mbarrel,'1');

		local trr = g.util.TraceLine(g.util.GetPlayerTrace(me));
		// Barrel - Target

		if abarrel and abarrel.Pos then 
			g.cam.Start3D(g.EyePos(),g.EyeAngles());
				if OH.Aimbot.tlocked and OH.Aimbot.target_locking then
					g.render.SetMaterial(laser_mat);
					g.render.DrawBeam(abarrel.Pos,OH.Aimbot.FindPoint(OH.Aimbot.target),10,0,5,Color(255,255,0,255));
				elseif OH.Aimbot.target then
					g.render.SetMaterial(laser_mat); 
					g.render.DrawBeam(abarrel.Pos,OH.Aimbot.FindPoint(OH.Aimbot.target),10,0,5,Color(255,0,0,255));
				else 
					g.render.SetMaterial(laser_mat);
					g.render.DrawBeam(abarrel.Pos,trr.HitPos,5,0,5,Color(0,255,0,255));
				end
			g.cam.End3D();
		end
	end
end

function OH.LaserEyes.Draw()
	if !OH.LaserEyes.enabled or !OH.t_players then return; end
	// Enemy - Eye Trace,
  	for _,targ in g.pairs(OH.t_players) do 
		if !IsValid( targ ) || g.type(targ) != "Player" or targ == me then continue; end
		local mbarrel,abarrel = r["Player"]["GetViewModel"](targ),nil;
		if r["Entity"]["IsValid"](mbarrel) then 
			abarrel =  r["Entity"]["GetAttachment"](mbarrel,'1');
		else 
			abarrel = r["Entity"]["EyePos"](targ);
		end
	 	local apos = g.util.TraceLine(util.GetPlayerTrace(targ));
	 	if abarrel and apos.HitPos then 
			g.cam.Start3D(g.EyePos(),g.EyeAngles());
				render.SetMaterial(laser_mat);
				render.DrawBeam(abarrel,apos.HitPos,5,0,8,Color(255,255,0,255));
			g.cam.End3D();
		end
	end
end

function OH.Wallhack.GetColour(ent)
	// Allowing the use of table looping, because the colour table is small
	if (OH.IsPlayer(ent) and !OH.IsBot(ent)) then 
		if (OH.Aimbot.friend_ids[r["Player"]["SteamID"](ent)]) then return OH.Wallhack.tbl_colour["Friends"].colour; end
	else 
		if (OH.Aimbot.friends[r["Entity"]["EntIndex"](ent)]) then return OH.Wallhack.tbl_colour["Friends"].colour; end
	end

	if (OH.IsPlayer(ent)) then return OH.Wallhack.tbl_colour["Players"].colour; end 
	if (OH.IsBot(ent)) then return OH.Wallhack.tbl_colour["Bots"].colour; end 
	if (OH.IsNPC(ent)) then return OH.Wallhack.tbl_colour["NPCs"].colour; end

	local col = false;
	for name,data in g.pairs(OH.Wallhack.tbl_colour) do 
		if ( data.class == r["Entity"]["GetClass"](ent) ) then 
			if (data.mdl == "Any") then 
				if !col then col = data.colour; end // Give data groups including a model overriding capabilities 
			else 
				if (data.mdl == r["Entity"]["GetModel"](ent)) then 
					col = data.colour;
				end
			end 	
		end
	end 
	return col;
end 

function OH.Wallhack.Draw()

	if !OH.Wallhack.enabled then return; end

	for _,ent in g.pairs(OH.t_ents or {}) do 
		if (!r["Entity"]["IsValid"](ent)) then continue; end
		local dst = r["Vector"]["Distance"](r["Entity"]["GetPos"](me),r["Entity"]["GetPos"](ent));
		if (dst < OH.Wallhack.show_distance) then 
			local col = OH.Wallhack.GetColour(ent);
			if (!col) then continue; end
			g.cam.Start3D(g.EyePos(),g.EyeAngles());
				g.render.MaterialOverride(OH.Wallhack.use_wireframe and OH.Wallhack.wireframe or OH.Wallhack.softbg);

				g.render.SetColorModulation(col.r/255,col.g/255,col.b/255);
				g.render.SetBlend(col.a/255);

				ent:DrawModel();
				g.render.MaterialOverride(nil);
			g.cam.End3D();
		end
	end 

end

function OH.ESP.Draw()
	
end

function OH.RenderSSE()
	OH.LaserSights.Draw();OH.Wallhack.Draw();OH.LaserEyes.Draw();OH.ESP.Draw();
end
OH.AddHook("RenderScreenspaceEffects",OH.RenderSSE);

function OH.Aimbot.GetTargets()
	local tbl={};
		for _,targ in g.pairs(g.ents.GetAll()) do
			if r["Entity"]["IsValid"](targ) and (g.type(targ) == "Player" or g.type(targ) == "NPC") then -- Can't use local meta's
				tbl[#tbl+1]=targ;
			end 
		end 
	return tbl;
end 

OH.AddHook("Tick",function() -- Doesn't check LOS. Only checks entities for setting compatibility 
	if !me then return; end
	OH.t_players = {};
	OH.t_ents = {};
	local e,p = g.ents.GetAll(),OH.Aimbot.GetTargets();

	for _,ply in g.pairs(p) do 
		if !OH.Aimbot.CanTarget(ply) then continue; end
		OH.t_players[#OH.t_players+1] = ply;
	end

	for _,ent in g.pairs(e) do 
		if !OH.Wallhack.CanTarget(ent) then continue; end 
		OH.t_ents[#OH.t_ents+1] = ent;
	end
end)

function OH.Aimbot.IsCloser(ent)

	if !OH.Aimbot.CanTarget(OH.Aimbot.target) then return true; end // Always return true if the old target is a invalid entity
	if !OH.Aimbot.CanTarget(ent) then return false; end  // Always return false if the new target isn't valid
	if OH.Aimbot.target == ent then return true; end // Return true if the target is the same as the previous target

	return r["Vector"]["Distance"](r["Entity"]["GetPos"](ent),r["Entity"]["GetPos"](me)) < r["Vector"]["Distance"](r["Entity"]["GetPos"](OH.Aimbot.target),r["Entity"]["GetPos"](me));
end

function OH.Aimbot.GetBestTarget() 
	if !OH.t_players or (OH.Aimbot.target_espents and !OH.t_ents) then return me; end
	local tbl = {};
	if OH.Aimbot.target_espents then tbl=OH.t_ents; else tbl=OH.t_players; end 

	local new_targ;
	OH.Aimbot.target = nil;
	for _,targ in g.pairs(tbl) do 

		if (OH.Aimbot.target_locking and r["Entity"]["IsValid"](OH.Aimbot.target)) then return OH.Aimbot.target; end 
		// Friend Check

		if (OH.Aimbot.friends[r["Entity"]["EntIndex"](targ)]) then continue; end

		if ( g.IsValid( targ ) and OH.IsPlayer(targ) and !OH.IsBot(targ)) then
			if (OH.Aimbot.friend_ids[r["Player"]["SteamID"](targ)]) then continue; end
		end

		if OH.Aimbot.IsCloser(targ) and targ != me then -- Don't bother running traces on myself

			local trace,point = {},OH.Aimbot.FindPoint(targ);
			trace.start,trace.endpos,trace.filter,trace.mask = r["Player"]["GetShootPos"](me),point,{me},MASK_SHOT;
			local trres = g.util.TraceLine(trace);

			if trres.Entity == targ or !OH.Aimbot.los_check then 
				OH.Aimbot.target = targ; 
				new_targ = targ; 
			end 

		end
	end 
	return new_targ or me;
end                                                                                        

function OH.CalcView(ply,pos,angles,fov)
	local view = {};
	view.angles,view.origin,view.fov = angles,pos,fov;
	if !me or ply != me then return GAMEMODE:CalcView(ply,pos,angles,fov); end

	if OH.Aimbot.tracing and OH.Aimbot.sa_ang then 
		return GAMEMODE:CalcView(ply,pos,OH.Aimbot.sa_ang,(fov != 90) and fov or OH.CNoClip.fov);
	elseif OH.CNoClip.enabled then 
		return GAMEMODE:CalcView(ply,OH.CNoClip.pos,angles,(fov != 90) and fov or OH.CNoClip.fov);
	end 
	return GAMEMODE:CalcView(ply,pos,angles,(fov != 90) and fov or OH.CNoClip.fov);
end
OH.AddHook("CalcView",OH.CalcView);


local core,hud,trace = 0,0,0;
OH.AddHook("HUDPaint",function()
	if (OH.Debug.enabled) then 
		g.draw.SimpleText("core_calc_per_second: "..core,"OHTabCFont",10,200,Color(0,0,0,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_TOP);
		g.draw.SimpleText("hud_updates_per_second: "..hud,"OHTabCFont",10,250,Color(0,0,0,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_TOP);
		g.draw.SimpleText("traces_per_second: "..trace,"OHTabCFont",10,300,Color(0,0,0,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_TOP);
	end 
	OH.Debug.hud_updates_per_second=OH.Debug.hud_updates_per_second+1;
end);

local jumping = false;
OH.AddHook("Think",function()
	if (me && r["Entity"]["IsOnGround"](me) && g.input.IsKeyDown(KEY_SPACE) && !jumping && OH.binds_active) then 
		g.RunConsoleCommand("+jump");jumping=true;
	elseif (jumping) then
		g.RunConsoleCommand("-jump");jumping=false;
	end
end);

g.timer.Create("DebugTimer",1,0,function()
	core = OH.Debug.core_calc_per_second;
	hud = OH.Debug.hud_updates_per_second;
	trace = OH.Debug.traces_per_second;
	OH.Debug.hud_updates_per_second = 0;
	OH.Debug.core_calc_per_second = 0;
	OH.Debug.traces_per_second = 0;
end);

local gUTL = g.util.TraceLine;
function g.util.TraceLine(trace)
	OH.Debug.traces_per_second=OH.Debug.traces_per_second+1
	return gUTL(trace);
end 

/*
OH.AddHook("EntityRemoved",function(e)
	for _,tbl in g.pairs(OH.menu) do 
		if (OH.Aimbot.friends[r["Entity"]["EntIndex"](e)]) then OH.Aimbot.friends[r["Entity"]["EntIndex"](e)]=nil; end
		if (g.type(tbl) == "table" and tbl.update) then tbl:update(); end 
	end
end);

OH.AddHook("InitPostEntity",function(e)
	for _,tbl in g.pairs(OH.menu) do 
		if (g.type(tbl) == "table" and tbl.update) then tbl:update(); end 
	end
end);

OH.AddHook("OnEntityCreated",function(e)
	for _,tbl in g.pairs(OH.menu) do 
		if (g.type(tbl) == "table" and tbl.update) then tbl:update(); end 
	end
end);
*/

/*******************************************************************************************
888b     d888 8888888 .d8888b.   .d8888b.       888     888  .d8888b.  888     888 8888888 
8888b   d8888   888  d88P  Y88b d88P  Y88b      888     888 d88P  Y88b 888     888   888   
88888b.d88888   888  Y88b.      888    888      888     888 888    888 888     888   888   
888Y88888P888   888   "Y888b.   888             Y88b   d88P 888        888     888   888   
888 Y888P 888   888      "Y88b. 888              Y88b d88P  888  88888 888     888   888   
888  Y8P  888   888        "888 888    888        Y88o88P   888    888 888     888   888   
888   "   888   888  Y88b  d88P Y88b  d88P         Y888P    Y88b  d88P Y88b. .d88P   888   
888       888 8888888 "Y8888P"   "Y8888P"           Y8P      "Y8888P88  "Y88888P"  8888888 
*******************************************************************************************/

g.surface.CreateFont("OHTabFont",{font="default",size=g.ScreenScale(16),weight=700,antialias=true});
g.surface.CreateFont("OHTabCFont",{font="default",size=g.ScreenScale(6),weight=600,antialias=true});
g.surface.CreateFont("OHSubTabFont",{font="default",size=g.ScreenScale(8),weight=700,antialias=true});
g.surface.CreateFont("OHMenuFont",{font="default",size=g.ScreenScale(5.5),weight=700,antialias=true});
g.surface.CreateFont("OHMenuFontLarge",{font="default",size=g.ScreenScale(7),weight=700,antialias=true});
g.surface.CreateFont("OHMenuFontReg",{font="default",size=g.ScreenScale(5),weight=400,antialias=true});
g.surface.CreateFont("OHLogoFont",{font="default",size=g.ScreenScale(30),weight=800,antialias=true});

function OH.compLHB(a,b) return (a==math.ceil(b)) or (a==math.floor(b)); end

local DermaControls = {}
function OH.RegDControl(name,mtable,base)
	if !name or !mtable then return false; end
	mtable.Base = base or "Panel";
	DermaControls[name]=mtable;
	return DermaControls[name];
end

function OH.CreateDControl(cname,parent,name)
	if DermaControls[cname] then 
		local mtbl = DermaControls[cname];
		local panel = OH.CreateDControl(mtbl.Base,parent,name);
		table.Merge(panel:GetTable(),mtbl)
		panel.ClassName,panel.BaseClass = cname,DermaControls[mtbl.Base];
		if panel.Init then 
			local st,er = pcall(panel.Init,panel);
			if !st then ErrorNoHalt("Panel Init failed, dumbass!: "..er.."\n"); return nil; end 
		end 
		panel:Prepare();
		return panel;
	end 
	return vgui.Create(cname,parent,name);
end 

function OH.AddOption(type,parent,name,x,y,w,h,...)
	local arg = {...};
	if (type == "text_field") then 
		parent[name] = OH.CreateDControl("DTextEntry",parent);
		parent[name]:SetPos(x,y);
		parent[name]:SetSize(w,h);
		parent[name]:SetText(arg[1])
		parent[name]:SetEditable(true);
	elseif (type == "button") then
		parent[name] = OH.CreateDControl("DButton",parent);
		parent[name]:SetPos(x,y);
		parent[name]:SetSize(w,h);
		parent[name]:SetText(arg[1]);
		parent[name].DoClick = arg[2];
	elseif (type == "slider") then 
		parent[name] = OH.CreateDControl("DNumSlider",parent);
		parent[name]:SetPos(x,y);
		parent[name]:SetSize(w,h);
		parent[name]:SetText(arg[1]);
		parent[name]:SetValue(arg[2]);
		parent[name]:SetMin(arg[3]);
		parent[name]:SetMax(arg[4]);
		parent[name]:SetDecimals(arg[5]);
		parent[name].OnValueChanged = function() OH[arg[6]][arg[7]] = parent[name]:GetValue(); end
	elseif (type == "toggle") then 
		parent[name] = OH.CreateDControl("DCheckBoxLabel",parent);
		parent[name]:SetPos(x,y);
		parent[name]:SetText(arg[1]);
		parent[name]:SizeToContents();
		parent[name]:SetValue(arg[2]);
		parent[name].OnChange = function(panel,value) OH[arg[3]][arg[4]] = !OH[arg[3]][arg[4]]; end;
	end
end 


/*=========================================================================================
  _____  _     _ ______  _     _ _______ _______ _     _      _______ _     _ _____ __   _
 |     | |     | |_____] |_____| |_____| |       |____/       |______ |____/    |   | \  |
 |_____| |_____| |_____] |     | |     | |_____  |    \_      ______| |    \_ __|__ |  \_|
                                                                                                                 
==========================================================================================*/

local skin = g.setmetatable({},{
	__index = function(t,k)
		return derma.GetDefaultSkin()[k];
	end
});

skin.grad_up = g.surface.GetTextureID("gui/gradient_up");
skin.grad_down = g.surface.GetTextureID("gui/gradient_down");

skin.defualt_color = g.Color(0,0,200,200);
skin.default_color_alt = g.Color(20,20,20,120);
skin.outline_color = g.Color(255,255,255,200);

skin.bg_color = g.Color(0,0,200,200);
skin.bg_color_alt = g.Color(20,20,20,120);


function skin.DrawAltBG(x,y,w,h,bsize,color)
	local color = color or self.bg_color;
	g.surface.SetTexture(skin.grad_down);
	g.surface.SetDrawColor(color.r,color.g,color.b,color.a);
	g.surface.DrawTexturedRect(x+bsize,y+bsize,w-(bsize*2),h-(bsize*2));

	g.surface.SetTexture(0,0,0,255);
	g.surface.SetDrawColor(skin.bg_color_alt);
	g.surface.DrawTexturedRect(x+bsize,y+bsize,w-(bsize*2),h-(bsize*2));

	g.surface.SetDrawColor(skin.outline_color);
	g.surface.DrawRect(x,y,w,bsize); -- Top 
	g.surface.DrawRect(x,y+h-bsize,w,bsize); -- Bottom
	g.surface.DrawRect(x+w-bsize,y,bsize,h); -- Right
	g.surface.DrawRect(x,y,bsize,h); -- Left

end 

/*******************************
	Button
********************************/

function skin:PaintButton(panel)
	local w,h = panel:GetSize();
	local x,y = 0,0;
	local col = g.Color(100,100,100,200);
	if panel.m_bBackground then
		if panel:GetDisabled() then
			col = g.Color(10,10,10,200);
		elseif ( panel.Depressed ) then
			col = g.Color(50,50,50,200);
		elseif ( panel.Hovered ) then
			col = g.Color(80,80,80,200);
		end
		draw.RoundedBox(6,x,y,w,h,col);
	end
	panel:SetFont("OHMenuFont");
	if (panel:GetWide() > 100) and (panel:GetTall() > 25) then panel:SetFont("OHMenuFontLarge"); end

	if panel:GetDisabled() then
		panel:SetTextColor(g.Color(255,0,0,255));
	elseif panel.Hovered then
        panel:SetTextColor(g.Color(255,255,255,255));
    else
		panel:SetTextColor(g.Color(0,0,0,255));
	end
end

function skin:PaintListViewLine(panel)
	local col = g.Color(100,100,100,200);
	local w,h = panel:GetSize()

	if panel:IsSelected() then
		col = g.Color(20,20,20,220);
	elseif ( panel.Hovered ) then
		col = g.Color(80,80,80,210);
	end
    for k,v in pairs(panel.Columns) do v:SetFont("OHMenuFontReg") end;
    g.surface.SetDrawColor(col);
    g.surface.DrawRect(2,2,w-4,h-2,col);
end

function skin:PaintListView(panel)
	// Override
end

/*******************************
	NumSlider
********************************/

function skin:PaintNumSlider(panel)
	local w, h = panel:GetSize();
	surface.SetDrawColor(g.Color(255,255,255,20));
	surface.DrawRect(0,0,w,h);
	surface.SetDrawColor(0,0,0,200);
	surface.DrawRect(3,h*0.5,w-6,2);
end

function skin:SchemeComboBoxItem(panel)
	panel:SetTextColor(Color(255,255,255,255));
end

/****************************************************************************************************************************************
888     888  .d8888b.  888     888 8888888       .d8888b.   .d88888b.  888b    888 88888888888 8888888b.   .d88888b.  888      .d8888b.  
888     888 d88P  Y88b 888     888   888        d88P  Y88b d88P" "Y88b 8888b   888     888     888   Y88b d88P" "Y88b 888     d88P  Y88b 
888     888 888    888 888     888   888        888    888 888     888 88888b  888     888     888    888 888     888 888     Y88b.      
Y88b   d88P 888        888     888   888        888        888     888 888Y88b 888     888     888   d88P 888     888 888      "Y888b.   
 Y88b d88P  888  88888 888     888   888        888        888     888 888 Y88b888     888     8888888P"  888     888 888         "Y88b. 
  Y88o88P   888    888 888     888   888        888    888 888     888 888  Y88888     888     888 T88b   888     888 888           "888 
   Y888P    Y88b  d88P Y88b. .d88P   888        Y88b  d88P Y88b. .d88P 888   Y8888     888     888  T88b  Y88b. .d88P 888     Y88b  d88P 
    Y8P      "Y8888P88  "Y88888P"  8888888       "Y8888P"   "Y88888P"  888    Y888     888     888   T88b  "Y88888P"  88888888 "Y8888P"                                                                                                                                  
*****************************************************************************************************************************************/

/*
____ _  _ ____ _  _ ___  ____ ____ ___ ___  ____ 
|  | |__| [__  |  | |__] |    |__|  |  |__] | __ 
|__| |  | ___] |__| |__] |___ |  |  |  |__] |__] 
                                                                                    
*/

local panel = {};

function panel:Init()
	self.reqx,self.reqy,self.reqw,self.reqh = 0,0,0,0;
	self.tsizew,self.tsizeh = g.ScreenScale(60),g.ScreenScale(40);
	self.padding = 5;

	self.Data = {};
	self.SubTabs = {};

	self:SetCursor("hand")
end 

function panel:Think()
	if (!self.sw or !self.sh) or (!OH.compLHB(self.reqw,self.sw) or !OH.compLHB(self.reqh,self.sh)) then 
		self.sw,self.sh = g.Lerp(0.7,self.reqw,(self.sw or self:GetWide())),g.Lerp(0.7,self.reqh,(self.sh or self:GetTall()));
		self:SetSize(self.sw,self.sh);
	else 
		if self.SizeCBFunction then self.SizeCBFunction(); end 
	end 
	if (!self.sx or !self.sy) or (!OH.compLHB(self.reqx,self.sx) or !OH.compLHB(self.reqy,self.sy)) then 
		self.sx,self.sy = g.Lerp(0.7,self.reqx,(self.sx or self.x)),g.Lerp(0.7,self.reqy,(self.sy or self.y));
		self:SetPos(self.sx,self.sy);
	else 
		if self.PosCBFunction then self.PosCBFunction(); end 
	end 
end 

function panel:SetTabData(data)
	self.Data = data;
end 

function panel:SetCBPosFunction(func)
	self.PosCBFunction = func;
end

function panel:SetCBSizeFunction(func)
	self.SizeCBFunction = func;
end 

function panel:RequestSize(w,h)
	self.reqw,self.reqh = w,h;
end 

function panel:RequestPos(x,y)
	self.reqx,self.reqy = x,y;
end

function panel:SetSubParent(panel)
	self.subparent = panel;
end 

function panel:Expand()
	if !self.Data or !self.subparent then return; end 

	self:SetVisible(true);
	self:SetPos(self.subparent.x,self.subparent.y);
	self:SetSize(self.subparent:GetWide(),self.subparent:GetTall());

	local size = table.Count(self.Data)*(self.tsizew)+self.padding;

	self:RequestPos(self.subparent.x,self.subparent.y+self.subparent:GetTall()-2);
	self:SetCBPosFunction(function()
		self:RequestSize(size,self.tsizeh+self.padding);
		local x = (self.subparent.x+(self.subparent:GetWide()/2))-(size/2);
		if (x <= 0) then 
			x = 2;
		elseif ((x+size) > g.ScrW()) then
			x = x - ((x+size)-g.ScrW());
		end
		self:RequestPos(x,self.subparent.y+self.subparent:GetTall());
		self:SetCBPosFunction(nil);
		self:Populate();
	end);	

end 

function panel:Populate()
	local i=0;
	local tbl={};

	for k,v in g.pairs(self.Data) do tbl[k]=v; end

	for name,data in g.pairs(tbl) do 
		self.SubTabs[name] = self.SubTabs[name] or OH.CreateDControl("OHSubTab",self);
		self.SubTabs[name]:SetVisible(true)
		self.SubTabs[name]:SetPos((self.tsizew*i)+self.padding,self.padding);
		self.SubTabs[name]:SetSize(self.tsizew-self.padding,self.tsizeh-self.padding);
		self.SubTabs[name]:SetName(name);
		self.SubTabs[name]:SetDesc(data[1]);
		self.SubTabs[name]:SetPanel(data[2]);
		i=i+1;
	end 
end 


function panel:Collapse()
	if !self:GetParent() or !self:IsVisible() then return; end
	self:RequestPos(self.subparent.x,self.subparent.y+self.subparent:GetTall());
	self:RequestSize(self.subparent:GetWide(),self.subparent:GetTall());
	self:SetCBPosFunction(function()
		self:RequestPos(self.subparent.x,self.subparent.y);
		for _,panel in g.pairs(self.SubTabs) do panel:SetVisible(false); end 
		self:SetCBPosFunction(function() 
			self:SetVisible(false);
			self:SetCBPosFunction(nil);
		end);
	end);
end 

function panel:Paint()
	local w,h = self:GetSize();
	skin.DrawAltBG(0,0,w,h,2,Color(0,0,255,255));
end 

OH.RegDControl("OHSubCatBG",panel);

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
____ _  _ ___ ____ ___  
|  | |__|  |  |__| |__] 
|__| |  |  |  |  | |__] 

*/

local panel = {};

function panel:Init()
	self.reqx,self.reqy = 0,0;
	self.name = "Unknown Name";
	self.tabs = {};
	self.Locked = false;

	self:SetCursor("hand");

	self.TabBG = OH.CreateDControl("OHSubCatBG",self:GetParent());
	self.TabBG:SetPos(self.x,self.y);
	self.TabBG:SetSize(self:GetWide(),self:GetTall());
	self.TabBG:SetVisible(false);
	self.TabBG:SetSubParent(self);
end 

function panel:SetTabData(data)
	self.TabBG:SetTabData(data);
end

function panel:OnMousePressed()
	g.surface.PlaySound("/buttons/button24.wav");
	if self.TabBG:IsVisible() then 
		self.TabBG:Collapse();
	else 
		for _,panel in g.pairs(OH.menu.Panel.Tabs) do if panel.TabBG then panel.TabBG:Collapse(); end end
		self.TabBG:Expand();
	end
end

function panel:RequestPos(x,y)
	self.reqx,self.reqy = x,y;
end 

function panel:Think()
	if (!self.sx or !self.sy) or (!OH.compLHB(self.reqx,self.sx) or !OH.compLHB(self.reqy,self.sy)) then 
		self.sx,self.sy = g.Lerp(0.83,self.reqx,(self.sx or self.x)),g.Lerp(0.83,self.reqy,(self.sy or self.y));
		self:SetPos(self.sx,self.sy);
	elseif OH.compLHB(self.reqx,self.sx) and OH.compLHB(self.reqy,self.sy) then 
		if self.CBFunction then self.CBFunction(); end 
	end 
end 

function panel:SetName(name)
	self.name = name;
end 

function panel:SetTabs(tabs)
	self.tabs = tabs;
end 

function panel:SetCBFunction(func)
	if !func then return; end 
	self.CBFunction = func;
end 

function panel:Paint()
	local w,h = self:GetSize();
	skin.DrawAltBG(0,0,w,h,2,Color(0,0,200,200));
	g.draw.SimpleText(self.name,"OHTabFont",5,5,Color(255,255,255,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM);
end 
         
OH.RegDControl("OHTab",panel);


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
____ _  _ ___  ____ ____ ____ ___  ____ _  _ ____ _    
|  | |__| |__] |__| [__  |___ |__] |__| |\ | |___ |    
|__| |  | |__] |  | ___] |___ |    |  | | \| |___ |___ 
                                                       
*/

local panel = {};

function panel:Init()
	self.reqx,self.reqy,self.reqw,self.reqh = 0,0,0,0;

	self.TabSheet = OH.CreateDControl("OHCatergorySelecter",self);
	self.TabSheet:SetPos(0,0);
	self.TabSheet:SetSize((ScrW()/6),(ScrH()-g.ScreenScale(60))-g.ScreenScale(108));
end 

function panel:Think() -- Linear Movement.
	if (!self.sw or !self.sh) or (!OH.compLHB(self.reqw,self.sw) or !OH.compLHB(self.reqh,self.sh)) then 
		self.sw,self.sh = g.math.Approach(OH.menu.speed,self.reqw,self.sw or self:GetWide()),g.math.Approach(OH.menu.speed,self.reqh,self.sh or self:GetTall());
		self:SetSize(self.sw,self.sh);
	else 
		if self.SizeCBFunction then self.SizeCBFunction(); end 
	end 
	if (!self.sx or !self.sy) or (!OH.compLHB(self.reqx,self.sx) or !OH.compLHB(self.reqy,self.sy)) then 
		self.sx,self.sy = g.math.Approach(OH.menu.speed,self.reqx,self.sx or self.x),g.math.Approach(OH.menu.speed,self.reqy,self.sy or self.y);
		self:SetPos(self.sx,self.sy);
	else 
		if self.PosCBFunction then self.PosCBFunction(); end 
	end
end 

function panel:RequestPos(x,y)
	self.reqx,self.reqy = x or 0,y or 0;
end 

function panel:RequestSize(w,h)
	self.reqw,self.reqh = w or 0,h or 0;
end 

function panel:SetCBPosFunction(func)
	self.PosCBFunction = func;
end 

function panel:SetCBSizeFunction(func)
	self.SizeCBFunction = func;
end

function panel:Close()
	if self.SizeCBFunction then return; end -- Indirect way of checking if the panels moving when we're attempting to close it.
	self:RequestPos(g.ScrW()-1,g.ScreenScale(108))
	self:SetCBPosFunction(function()
		self:SetVisible(false);
		self:SetCBPosFunction(nil);
	end);
end 

function panel:Open()
	self.sw,self.sh,self.sx,self.sy = nil,nil,nil,nil;
	self:SetVisible(true);
	self:SetPos(1,g.ScreenScale(108));
	self:RequestPos(1,g.ScreenScale(108));
	self:SetSize(1,(ScrH()-g.ScreenScale(60))-g.ScreenScale(108));
	self:RequestSize(g.ScrW()*0.5,(ScrH()-g.ScreenScale(60))-g.ScreenScale(108));
	self:SetCBSizeFunction(function()
		self:RequestPos(g.ScrW()/2-(g.ScrW()*0.25),g.ScreenScale(108))
		self:SetCBSizeFunction(nil);
	end);
end

function panel:Paint()
	local w,h = self:GetSize();

	surface.SetDrawColor(255,255,255,255);
	surface.DrawRect(0,0,w,2); // top
	surface.DrawRect(0,h-2,w,2); // bottom
	surface.DrawRect(0,0,2,h); // left
	surface.DrawRect(w-2,0,2,h); // right
	
	surface.SetDrawColor(15,12,18,213);
	surface.DrawRect(2,2,w-4,h-4);
end 

OH.RegDControl("OHBasePanel",panel,"Panel")

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
  _____  _     _         _____   ______  _____ 
 |     | |_____| |      |     | |  ____ |     |
 |_____| |     | |_____ |_____| |_____| |_____|
                                               
*/

local panel = {};

function panel:RequestSize(w,h)
	self.reqw,self.reqh = w,h;
end 

function panel:Think()
	if (!self.sw or !self.sh) or (!OH.compLHB(self.reqw,self.sw) or !OH.compLHB(self.reqh,self.sh)) then 
		self.sw,self.sh = g.Lerp(0.7,self.reqw,(self.sw or self:GetWide())),g.Lerp(0.7,self.reqh,(self.sh or self:GetTall()));
		self:SetSize(self.sw,self.sh);
	else 
		if self.CBFunction then self.CBFunction(); end 
	end
end 

function panel:Paint()
	g.draw.SimpleText("Oub","OHLogoFont",g.ScreenScale(2),g.ScreenScale(8),Color(255,255,255,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM);
	g.draw.SimpleText("Hack","OHLogoFont",self:GetWide()-g.ScreenScale(26),self:GetTall()-g.ScreenScale(6),Color(0,0,200,200),TEXT_ALIGN_RIGHT,TEXT_ALIGN_TOP);
	g.draw.SimpleText("V","OHLogoFont",self:GetWide()-g.ScreenScale(22),g.ScreenScale(8),Color(255,255,255,255),TEXT_ALIGN_RIGHT,TEXT_ALIGN_BOTTOM);
	g.draw.SimpleText(OH.Version,"OHLogoFont",self:GetWide()-g.ScreenScale(8),g.ScreenScale(8),Color(0,0,200,200),TEXT_ALIGN_RIGHT,TEXT_ALIGN_BOTTOM);
end 

function panel:SetCBFunction(func)
	self.CBFunction = func;
end


function panel:Init()
	self.reqw,self.reqh = 0,0;
end 


OH.RegDControl("OHLogo",panel);

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
  _____  _     _ _______ _     _ ______  _______ _______ ______ 
 |     | |_____| |______ |     | |_____]    |    |_____| |_____]
 |_____| |     | ______| |_____| |_____]    |    |     | |_____]
                                                                
*/

local panel = {};

function panel:Init()
	self.PanelKey,self.name,self.desc = "","","";
	self:SetCursor("hand");
end 

function panel:OnMousePressed()
	if !OH.menu[self.PanelKey].Panel then OH.menu[self.PanelKey].create(); end 
	if !OH.menu[self.PanelKey].Panel:IsVisible() then 
		OH.menu[self.PanelKey].Panel:Open();
		if OH.menu[self.PanelKey].update then OH.menu[self.PanelKey]:update(); end
		for name,panel in g.pairs(OH.menu) do
			if type(panel) == "table" and panel.Panel and panel.Panel:IsVisible() then
				if name == self.PanelKey then continue; end
				panel.Panel:Close(); 
			end 
		end
	else
		OH.menu[self.PanelKey].Panel:Close();
	end
end 

function panel:Paint()
	local w,h = self:GetSize();
	skin.DrawAltBG(0,0,w,h,2,Color(0,0,200,200));
	g.draw.SimpleText(self.name,"OHSubTabFont",5,5,Color(255,255,255,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM);
end 

function panel:SetPanel(key)
	self.PanelKey = key;
end 

function panel:SetName(text)
	self.name = text;
end 

function panel:SetDesc(text)
	self:SetToolTip(text); -- temp
	self.desc = text;
end 

OH.RegDControl("OHSubTab",panel);


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
  _____  _     _ _______ _  _  _ _____ _______ _______ _     _ ______   _____  _______  ______ ______ 
 |     | |_____| |______ |  |  |   |      |    |       |_____| |_____] |     | |_____| |_____/ |     \
 |_____| |     | ______| |__|__| __|__    |    |_____  |     | |_____] |_____| |     | |    \_ |_____/
                                                                                                      
*/

local panel = {};

function panel:Init()
	self.reqw,self.reqh = 0,0;
	self.max_X,self.max_y = 0,0;
end 

function panel:Paint()
	local w,h = self:GetSize();
	
	surface.SetDrawColor(255,255,255,255);
	surface.DrawRect(0,0,w,2); // top
	surface.DrawRect(0,h-2,w,2); // bottom
	surface.DrawRect(0,0,2,h); // left
	surface.DrawRect(w-2,0,2,h); // right
	
	surface.SetDrawColor(0,0,0,90);
	surface.DrawRect(2,2,w-4,h-4);
end 


function panel:Think()
	if (!self.sw or !self.sh) or (!OH.compLHB(self.reqw,self.sw) or !OH.compLHB(self.reqh,self.sh)) then 
		self.sw,self.sh = g.Lerp(0.9,self.reqw,(self.sw or self:GetWide())),g.Lerp(0.9,self.reqh,(self.sh or self:GetTall()));
		self:SetSize(self.sw,self.sh);
	else 
		if self.CBFunction then self.CBFunction(); end 
	end
end 

function panel:SetCBFunction(func)
	self.CBFunction = func;
end 

function panel:RequestSize(w,h)
	self.reqw,self.reqh = w,h;
end 


OH.RegDControl("OHSwitchBoard",panel);

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
  _____  _     _ _______ _______ _______ _______  ______  ______  _____   ______ __   __ _______ _______        _______ _______ _______ _______  ______
 |     | |_____| |       |_____|    |    |______ |_____/ |  ____ |     | |_____/   \_/   |______ |______ |      |______ |          |    |______ |_____/
 |_____| |     | |_____  |     |    |    |______ |    \_ |_____| |_____| |    \_    |    ______| |______ |_____ |______ |_____     |    |______ |    \_

*/

local panel = {};

function panel:Init()
	self.Tabs = {};
	self.sizeh = 50;
end 

function panel:Paint()
	local w,h = self:GetSize();

	surface.SetDrawColor(255,255,255,255);
	surface.DrawRect(0,0,w,2); // top
	surface.DrawRect(0,h-2,w,2); // bottom
	surface.DrawRect(0,0,2,h); // left
	surface.DrawRect(w-2,0,2,h); // right
	
	surface.SetDrawColor(15,12,18,213);
	surface.DrawRect(2,2,w-4,h-4);
end 

function panel:Think()
	// Override
end

function panel:AddTab(name,info,ind,pnlkey)
	self.Tabs[name] = OH.CreateDControl("DButton",self);
	self.Tabs[name].DoClick = function()
		for info,data in g.pairs(self:GetParent().SwitchBoard) do 
			local index = data[2];
			OH.menu[pnlkey].Panel[index]:RequestSize(1,1);
			OH.menu[pnlkey].Panel[index]:SetCBFunction(function() OH.menu[pnlkey].Panel[index]:SetVisible(false) end);
		end 
		OH.menu[pnlkey].Panel[ind]:SetVisible(true);
		OH.menu[pnlkey].Panel[ind]:SetCBFunction(nil);
		OH.menu[pnlkey].Panel[ind]:RequestSize(self:GetParent():GetWide()-self:GetWide()-5,self:GetParent():GetTall()-7); 
		print(self:GetParent():GetWide()-self:GetWide()-5);
	end 
	self.Tabs[name]:SetPos(4,self.sizeh*(g.table.Count(self.Tabs)-1)+4);
	self.Tabs[name]:SetSize(self:GetWide()-8,self.sizeh-4);
	self.Tabs[name]:SetText(name);
	self.Tabs[name]:SetTooltip(info);
end

OH.RegDControl("OHCatergorySelecter",panel);

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/*
  _____  _     _ _______  _____  __   _ _______  _____         _______
 |     | |_____| |       |     | | \  | |______ |     | |      |______
 |_____| |     | |_____  |_____| |  \_| ______| |_____| |_____ |______

*/

local panel = {};

function panel:Init()
	self.reqw,self.reqh = 0,0;

	self.Console = OH.CreateDControl("RichText",self);
	self.Console:SetPos(10,2);
	self.Console:SetVerticalScrollbarEnabled(true);

	OH.AddOption("text_field",self,"TextField",1,1,1,1,"");
	self.TextField:SetEnterAllowed(true);
	self.TextField.OnEnter = function()

		local panel,text = self.TextField,self.TextField:GetValue();
		local t = g.string.Explode(" ",text);
		local args={};
		for i=2,#t do args[i-1]=t[i]; end

		OH.cprint(g.Color(255,255,255,255),"] "..t[1]);
		if (OH.cmds[t[1]]) then 
			OH.cmds[t[1]](t[1],args);
		else 
			OH.cprint(g.Color(255,0,0,255),"ERROR: ",g.Color(255,255,255,255),"No such command '"..t[1].."' !");
		end

		g.timer.Simple(0,function()
			panel:RequestFocus();
			panel:OnGetFocus();
		end);

		panel:SetText("");
	end
	self.TextField:RequestFocus();
end

function panel:Paint()
	local w,h = self:GetSize();
	surface.SetDrawColor(0,0,0,255);
	surface.DrawRect(0,0,w,h);
end 

function panel:Think()
	if (!self.sw or !self.sh) or (!OH.compLHB(self.reqw,self.sw) or !OH.compLHB(self.reqh,self.sh)) then 
		self.sw,self.sh = g.Lerp(0.9,self.reqw,(self.sw or self:GetWide())),g.Lerp(0.9,self.reqh,(self.sh or self:GetTall()));
		self:SetSize(self.sw,self.sh);
	else 
		if self.CBFunction then self.CBFunction(); end 
	end
end 

function panel:SetCBFunction(func)
	self.CBFunction = func;
end 

function panel:RequestSize(w,h)
	self.reqw,self.reqh = w,h;
	self.Console:SetPos(2,2)
	self.Console:SetSize(w-4,h-34);
	
	self.TextField:SetPos(75,h-30)
	self.TextField:SetSize((w-75)-25,28);
end

OH.RegDControl("OHConsole",panel,"EditablePanel");

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


/***************************************************************************************************************************************
 .d8888b.   .d88888b.  888b    888  .d8888b. 88888888888 8888888b.  888     888  .d8888b. 88888888888 .d88888b.  8888888b.   .d8888b.  
d88P  Y88b d88P" "Y88b 8888b   888 d88P  Y88b    888     888   Y88b 888     888 d88P  Y88b    888    d88P" "Y88b 888   Y88b d88P  Y88b 
888    888 888     888 88888b  888 Y88b.         888     888    888 888     888 888    888    888    888     888 888    888 Y88b.      
888        888     888 888Y88b 888  "Y888b.      888     888   d88P 888     888 888           888    888     888 888   d88P  "Y888b.   
888        888     888 888 Y88b888     "Y88b.    888     8888888P"  888     888 888           888    888     888 8888888P"      "Y88b. 
888    888 888     888 888  Y88888       "888    888     888 T88b   888     888 888    888    888    888     888 888 T88b         "888 
Y88b  d88P Y88b. .d88P 888   Y8888 Y88b  d88P    888     888  T88b  Y88b. .d88P Y88b  d88P    888    Y88b. .d88P 888  T88b  Y88b  d88P 
 "Y8888P"   "Y88888P"  888    Y888  "Y8888P"     888     888   T88b  "Y88888P"   "Y8888P"     888     "Y88888P"  888   T88b  "Y8888P"  
****************************************************************************************************************************************/


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.g_esp.update()
	if (!OH.menu.g_esp.Panel) then return; end
end

function OH.menu.g_esp.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	// Colour, Text, Targeting

	OH.menu.g_esp.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.g_esp.Panel:SetVisible(false);
	OH.menu.g_esp.Panel.memKey = "g_esp";

	OH.menu.g_esp.Panel["colour_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.g_esp.Panel);
	OH.menu.g_esp.Panel["colour_board"]:SetPos(OH.menu.g_esp.Panel.TabSheet:GetWide()+2,4);
	OH.menu.g_esp.Panel["colour_board"]:SetSize(1,1);
	OH.menu.g_esp.Panel["colour_board"]:SetVisible(false);

	OH.menu.g_esp.Panel["text_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.g_esp.Panel);
	OH.menu.g_esp.Panel["text_board"]:SetPos(OH.menu.g_esp.Panel.TabSheet:GetWide()+2,4);
	OH.menu.g_esp.Panel["text_board"]:SetSize(1,1);
	OH.menu.g_esp.Panel["text_board"]:SetVisible(false);

	OH.menu.g_esp.Panel["entity_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.g_esp.Panel);
	OH.menu.g_esp.Panel["entity_board"]:SetPos(OH.menu.g_esp.Panel.TabSheet:GetWide()+2,4);
	OH.menu.g_esp.Panel["entity_board"]:SetSize(1,1);
	OH.menu.g_esp.Panel["entity_board"]:SetVisible(false);

	OH.menu.g_esp.Panel.SwitchBoard = {};
	OH.menu.g_esp.Panel.SwitchBoard["Colour"] = {"A configuration menu, devoted to colours used by the ESP","colour_board"};
	OH.menu.g_esp.Panel.SwitchBoard["Text"] = {"This is where you configurate text related options, used by the ESP","text_board"};
	OH.menu.g_esp.Panel.SwitchBoard["Targeting"] = {"Change how the ESP targets entities and players","entity_board"};

	for name,data in g.pairs(OH.menu.g_esp.Panel.SwitchBoard) do 
		OH.menu.g_esp.Panel.TabSheet:AddTab(name,data[1],data[2]);
	end


end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.g_wallhack.update()
	if (!OH.menu.g_wallhack.Panel) then return; end
	for _,panel in g.pairs(OH.menu.g_wallhack.Panel["mech_board"].COptions:GetLines()) do panel:SetToolTip("Double click to remove"); end

	OH.menu.g_wallhack.Panel["colour_board"].COptions:Clear();
	OH.menu.g_wallhack.Panel["mech_board"].COptions:Clear();
	OH.menu.g_wallhack.Panel["activation_board"].CBinds:Clear();

	for name,data in g.pairs(OH.Wallhack.tbl_colour) do 
		local col = data.colour.r..","..data.colour.g..","..data.colour.b..","..data.colour.a;
		OH.menu.g_wallhack.Panel["colour_board"].COptions:AddLine(name,data.class,data.mdl,col);
		OH.menu.g_wallhack.Panel["mech_board"].COptions:AddLine(name,data.class,data.mdl,col);
	end

	local usekeys = {};

	for name,data in g.pairs(OH.KeyBind.binds) do 
		if !usekeys[data.BindKey] then usekeys[data.BindKey] = {}; end
		usekeys[data.BindKey][#usekeys[data.BindKey]+1] = name;
	end

	for _,data in g.pairs(OH.KeyBind.keys) do 
		local occ = "";
		if usekeys[data[2]] then
			for int,name in g.pairs(usekeys[data[2]]) do 
				occ = occ .. name;
				if (int != #usekeys[data[2]]) then occ = occ .. ", "; end
			end
		end
		OH.menu.g_wallhack.Panel["activation_board"].CBinds:AddLine(data[1],data[2],occ);
	end

	for _,panel in g.pairs(OH.menu.g_wallhack.Panel["mech_board"].COptions:GetLines()) do panel:SetToolTip("Double click to remove"); end

end 

function OH.menu.g_wallhack.create()
	local max_x,max_y = (g.ScrW()*0.5)-(ScrW()/6)-5,(ScrH()-(g.ScreenScale(60))-g.ScreenScale(108))-7
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.g_wallhack.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.g_wallhack.Panel:SetVisible(false);

	OH.menu.g_wallhack.Panel.SwitchBoard = {};
	OH.menu.g_wallhack.Panel.SwitchBoard["Colour"] = {"A configuration menu, devoted to colours used by the Wallhack","colour_board"};
	OH.menu.g_wallhack.Panel.SwitchBoard["Mechanics"] = {"Change the wallhack Mechanics here","mech_board"};
	OH.menu.g_wallhack.Panel.SwitchBoard["Activation"] = {"Wallhack's Activation methods","activation_board"};

	/*
		Colour Board
	*/

	OH.menu.g_wallhack.Panel["colour_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.g_wallhack.Panel);
	OH.menu.g_wallhack.Panel["colour_board"]:SetPos(OH.menu.g_wallhack.Panel.TabSheet:GetWide()+2,4);
	OH.menu.g_wallhack.Panel["colour_board"]:SetSize(1,1);
	OH.menu.g_wallhack.Panel["colour_board"]:SetVisible(false);

	// Colour field

	OH.menu.g_wallhack.Panel["colour_board"].PColour = OH.CreateDControl("DColorMixer",OH.menu.g_wallhack.Panel["colour_board"]);
	OH.menu.g_wallhack.Panel["colour_board"].PColour:SetPos(2,2);
	OH.menu.g_wallhack.Panel["colour_board"].PColour:SetSize(max_x-8,(max_y*0.50));

	OH.menu.g_wallhack.Panel["colour_board"].PColour.oUpdateColor = OH.menu.g_wallhack.Panel["colour_board"].PColour.UpdateColor;

	OH.menu.g_wallhack.Panel["colour_board"].PColour.UpdateColor = function(panel,color)

		OH.menu.g_wallhack.Panel["colour_board"].PColour.oUpdateColor(panel,color);

		color = panel:GetColor();

		local selected = OH.menu.g_wallhack.Panel["colour_board"].COptions:GetLine(OH.menu.g_wallhack.Panel["colour_board"].COptions.Selected or 1):GetValue(1);

		OH.Wallhack.tbl_colour[selected].colour = panel:GetColor();

		local col = color.r..","..color.g..","..color.b..","..color.a;
		OH.menu.g_wallhack.Panel["colour_board"].COptions:GetLine(OH.menu.g_wallhack.Panel["colour_board"].COptions.Selected or 1):SetValue(4,col);
		
	end

	// Option field 

	OH.menu.g_wallhack.Panel["colour_board"].COptions = OH.CreateDControl("DListView",OH.menu.g_wallhack.Panel["colour_board"]);
	OH.menu.g_wallhack.Panel["colour_board"].COptions:AddColumn("Name");OH.menu.g_wallhack.Panel["colour_board"].COptions:AddColumn("Class");
	OH.menu.g_wallhack.Panel["colour_board"].COptions:AddColumn("Model");OH.menu.g_wallhack.Panel["colour_board"].COptions:AddColumn("Colour");
	OH.menu.g_wallhack.Panel["colour_board"].COptions:SetPos(4,OH.menu.g_wallhack.Panel["colour_board"].PColour:GetTall()+4);
	OH.menu.g_wallhack.Panel["colour_board"].COptions:SetSize(max_x-8,(max_y*0.50));
	OH.menu.g_wallhack.Panel["colour_board"].COptions:SetMultiSelect(false);
	OH.menu.g_wallhack.Panel["colour_board"].COptions.OnRowSelected = function(panel,line) OH.menu.g_wallhack.Panel["colour_board"].COptions.Selected = line; end

	/*
		Mechanics Board
	*/

	OH.menu.g_wallhack.Panel["mech_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.g_wallhack.Panel);
	OH.menu.g_wallhack.Panel["mech_board"]:SetPos(OH.menu.g_wallhack.Panel.TabSheet:GetWide()+2,4);
	OH.menu.g_wallhack.Panel["mech_board"]:SetSize(1,1);
	OH.menu.g_wallhack.Panel["mech_board"]:SetVisible(false);

	OH.menu.g_wallhack.Panel["mech_board"].COptions = OH.CreateDControl("DListView",OH.menu.g_wallhack.Panel["mech_board"]);
	OH.menu.g_wallhack.Panel["mech_board"].COptions:AddColumn("Name");OH.menu.g_wallhack.Panel["mech_board"].COptions:AddColumn("Class");
	OH.menu.g_wallhack.Panel["mech_board"].COptions:AddColumn("Model");OH.menu.g_wallhack.Panel["mech_board"].COptions:AddColumn("Colour");
	OH.menu.g_wallhack.Panel["mech_board"].COptions:SetPos(4,8);
	OH.menu.g_wallhack.Panel["mech_board"].COptions:SetSize((max_x*0.50),max_y-76);
	OH.menu.g_wallhack.Panel["mech_board"].COptions:SetMultiSelect(false);
	OH.menu.g_wallhack.Panel["mech_board"].COptions.DoDoubleClick = function(panel,line) 
		local _line = panel:GetLine(line);
		local name = _line:GetValue(1);

		if (name == "Players" or name == "NPCs" or name == "Bots") then
			g.Derma_Message("Cannot remove default colour groups!");
			return;
		end
		g.Derma_Message("Removed "..name.." successfully!");
		OH.Wallhack.tbl_colour[name] = nil;
		panel:RemoveLine(line);

		for l,p in g.pairs(OH.menu.g_wallhack.Panel["colour_board"].COptions:GetLines()) do if p:GetValue(1) == name then OH.menu.g_wallhack.Panel["colour_board"].COptions:RemoveLine(l) end end
		OH.menu.g_wallhack.Panel["colour_board"].COptions.Selected = nil;
	end

	OH.AddOption("text_field",OH.menu.g_wallhack.Panel["mech_board"],"input_name",2,OH.menu.g_wallhack.Panel["mech_board"].COptions:GetTall()+10,OH.menu.g_wallhack.Panel["mech_board"].COptions:GetWide()-4,20,"Enter a Name");
	OH.AddOption("text_field",OH.menu.g_wallhack.Panel["mech_board"],"input_class",2,OH.menu.g_wallhack.Panel["mech_board"].COptions:GetTall()+30,(OH.menu.g_wallhack.Panel["mech_board"].COptions:GetWide()-4)*0.5,20,"Enter a Class");
	OH.AddOption("text_field",OH.menu.g_wallhack.Panel["mech_board"],"input_model",(OH.menu.g_wallhack.Panel["mech_board"].COptions:GetWide())*0.5,OH.menu.g_wallhack.Panel["mech_board"].COptions:GetTall()+30,(OH.menu.g_wallhack.Panel["mech_board"].COptions:GetWide()-4)*0.5,20,"Enter a Model");
	OH.AddOption("button",OH.menu.g_wallhack.Panel["mech_board"],"input",2,OH.menu.g_wallhack.Panel["mech_board"].COptions:GetTall()+50,OH.menu.g_wallhack.Panel["mech_board"].COptions:GetWide()-4,20,"Add",function() 
		local _mdl,_name,_class = OH.menu.g_wallhack.Panel["mech_board"]["input_model"]:GetText(),OH.menu.g_wallhack.Panel["mech_board"]["input_name"]:GetText(),OH.menu.g_wallhack.Panel["mech_board"]["input_class"]:GetText();

		if ( (_name == "" or _name == "Enter a Name") or (_class == "" or _class == "Enter a Class") ) then 
			g.Derma_Message("Invalid Setup Data!");
			return;
		end

		if (OH.Wallhack.tbl_colour[_name]) then 
			g.Derma_Message("Name already used!");
			return;
		end

		if (_class == "Player" or _class == "NPC" or _class == "Bot") then 
			g.Derma_Message("Class reserved by default colour groups!");
			return;
		end

		_mdl = (_mdl == "Enter a Model" or _mdl == "") and "Any" or _mdl;

		OH.Wallhack.tbl_colour[_name] = {colour=g.Color(0,0,0,255),class=_class,mdl=_mdl};

		OH.menu.g_wallhack.Panel["mech_board"].COptions:AddLine(_name,_class,_mdl,"0,0,0,255");
		OH.menu.g_wallhack.Panel["colour_board"].COptions:AddLine(_name,_class,_mdl,"0,0,0,255");

		g.Derma_Message("Added ".._name.." successfully!");

		OH.menu.g_wallhack.Panel["mech_board"]["input_name"]:SetText("Enter a Name");
		OH.menu.g_wallhack.Panel["mech_board"]["input_class"]:SetText("Enter a Class");
		OH.menu.g_wallhack.Panel["mech_board"]["input_model"]:SetText("Enter a Model");

	end);

	OH.AddOption("slider",OH.menu.g_wallhack.Panel["mech_board"],"show_dist_slider",max_x*0.50+6,15,(max_x*0.50)-12,30,"WallHack Max Target Distance",1500,0,15000,0,"Wallhack","show_distance");

	OH.AddOption("toggle",OH.menu.g_wallhack.Panel["mech_board"],"t_npcs_toggle",max_x*0.50+6,55,0,0,"Target NPCs",OH.Wallhack.t_npcs,"Wallhack","t_npcs");
	OH.AddOption("toggle",OH.menu.g_wallhack.Panel["mech_board"],"t_bots_toggle",max_x*0.50+6,75,0,0,"Target Bots",OH.Wallhack.t_bots,"Wallhack","t_bots");
	OH.AddOption("toggle",OH.menu.g_wallhack.Panel["mech_board"],"t_players_toggle",max_x*0.50+6,95,0,0,"Target Players",OH.Wallhack.t_players,"Wallhack","t_players");
	OH.AddOption("toggle",OH.menu.g_wallhack.Panel["mech_board"],"use_wireframe_toggle",max_x*0.50+6,115,0,0,"Use Wireframe",OH.Wallhack.use_wireframe,"Wallhack","use_wireframe");

	/*
		Targeting board
	*/

	OH.menu.g_wallhack.Panel["activation_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.g_wallhack.Panel);
	OH.menu.g_wallhack.Panel["activation_board"]:SetPos(OH.menu.g_wallhack.Panel.TabSheet:GetWide()+2,4);
	OH.menu.g_wallhack.Panel["activation_board"]:SetSize(1,1)
	OH.menu.g_wallhack.Panel["activation_board"]:SetVisible(false);

	OH.menu.g_wallhack.Panel["activation_board"].CBinds = OH.CreateDControl("DListView",OH.menu.g_wallhack.Panel["activation_board"]);
	OH.menu.g_wallhack.Panel["activation_board"].CBinds:SetPos(6,6);
	OH.menu.g_wallhack.Panel["activation_board"].CBinds:SetSize(max_x-12,max_y-50);
	OH.menu.g_wallhack.Panel["activation_board"].CBinds:SetMultiSelect(false);
	OH.menu.g_wallhack.Panel["activation_board"].CBinds.OnRowSelected = function(panel,line)
		OH.menu.g_wallhack.Panel["activation_board"].Selected = panel:GetLine(line);
		OH.menu.g_wallhack.Panel["activation_board"].bind:SetText("Bind to "..panel:GetLine(line):GetValue(1));
	end

	OH.menu.g_wallhack.Panel["activation_board"].CBinds:AddColumn("Key");OH.menu.g_wallhack.Panel["activation_board"].CBinds:AddColumn("Key Integer");
	OH.menu.g_wallhack.Panel["activation_board"].CBinds:AddColumn("Key is Used by");

	OH.AddOption("button",OH.menu.g_wallhack.Panel["activation_board"],"bind",6,OH.menu.g_wallhack.Panel["activation_board"].CBinds:GetTall()+8,max_x-12,24,"Select a key",function() 
		if (!OH.menu.g_wallhack.Panel["activation_board"].Selected or !g.ValidPanel(OH.menu.g_wallhack.Panel["activation_board"].Selected)) then 
			g.Derma_Message("You must select a key first!");
			return;
		end
		g.Derma_Message("Bound to "..OH.menu.g_wallhack.Panel["activation_board"].Selected:GetValue(1).." ("..OH.menu.g_wallhack.Panel["activation_board"].Selected:GetValue(2)..")!");
		OH.AddKeyBind(OH.menu.g_wallhack.Panel["activation_board"].Selected:GetValue(2),"WallHack",function() OH.Wallhack.enabled = !OH.Wallhack.enabled; end);

		OH.menu.g_wallhack.Panel["activation_board"].CBinds:Clear();

		// TODO: redo this code

		local usekeys = {};

		for name,data in g.pairs(OH.KeyBind.binds) do 
			if !usekeys[data.BindKey] then usekeys[data.BindKey] = {}; end
			usekeys[data.BindKey][#usekeys[data.BindKey]+1] = name;
		end

		for _,data in g.pairs(OH.KeyBind.keys) do 
			local occ = "";
			if usekeys[data[2]] then
				for int,name in g.pairs(usekeys[data[2]]) do 
					occ = occ .. name;
					if (int != #usekeys[data[2]]) then occ = occ .. ", "; end
				end
			end
			OH.menu.g_wallhack.Panel["activation_board"].CBinds:AddLine(data[1],data[2],occ);
		end
	end);

	for name,data in g.pairs(OH.menu.g_wallhack.Panel.SwitchBoard) do 
		OH.menu.g_wallhack.Panel.TabSheet:AddTab(name,data[1],data[2],"g_wallhack");
	end

	OH.menu.g_wallhack.update();
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.g_lasersts.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.g_lasersts.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.g_lasersts.Panel:SetVisible(false);
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.g_lasereyes.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.g_lasereyes.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.g_lasereyes.Panel:SetVisible(false);
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.c_aimbot.update()
	if (!OH.menu.c_aimbot.Panel) then return; end

	OH.menu.c_aimbot.Panel["friend_board"].FList:Clear();
	OH.menu.c_aimbot.Panel["friend_board"].TempFList:Clear();
	OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:Clear();

	for _,e in g.pairs(OH.t_players) do
		if (!OH.Aimbot.CanTarget(e)) then continue; end
		if (OH.IsPlayer(e) and !OH.IsBot(e)) then 
			local t = OH.Aimbot.friend_ids[r["Player"]["SteamID"](e)] and "Friended" or "Not Friended";
			OH.menu.c_aimbot.Panel["friend_board"].FList:AddLine(r["Player"]["GetName"](e),r["Player"]["SteamID"](e),r["Player"]["GetFriendStatus"](e),t); 
		else 
			local t = OH.Aimbot.friends[r["Entity"]["EntIndex"](e)] and "Friended" or "Not Friended";
			local name = OH.IsPlayer(e) and r["Player"]["GetName"](e) or g.tostring(e);
			local typ = (OH.IsNPC(e) and "NPC") or (OH.IsPlayer(e) and "Bot") or "Entity";
			OH.menu.c_aimbot.Panel["friend_board"].TempFList:AddLine(name,r["Entity"]["EntIndex"](e),typ,t); 
		end 
	end

	OH.menu.c_aimbot.Panel["activation_board"].CBinds:Clear();

	local usekeys = {};

	for name,data in g.pairs(OH.KeyBind.binds) do 
		if !usekeys[data.BindKey] then usekeys[data.BindKey] = {}; end
		usekeys[data.BindKey][#usekeys[data.BindKey]+1] = name;
	end

	for _,data in g.pairs(OH.KeyBind.keys) do 
		local occ = "";
		if usekeys[data[2]] then
			for int,name in g.pairs(usekeys[data[2]]) do 
				occ = occ .. name;
				if (int != #usekeys[data[2]]) then occ = occ .. ", "; end
			end
		end
		OH.menu.c_aimbot.Panel["activation_board"].CBinds:AddLine(data[1],data[2],occ);
	end

	for _,panel in g.pairs(OH.menu.c_aimbot.Panel["friend_board"].FList:GetLines()) do 
		panel:SetTooltip("Double Click to toggle friend state");
	end

	for _,panel in g.pairs(OH.menu.c_aimbot.Panel["friend_board"].TempFList:GetLines()) do 
		panel:SetTooltip("Double Click to toggle friend state");
	end

	for _,wep in g.pairs(OH.Aimbot.no_tweps) do
		OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:AddLine(wep);
	end

	OH.menu.c_aimbot.Panel["trace_board"]["class_input"]:SetValue(me:GetActiveWeapon() and me:GetActiveWeapon():GetClass() or "weapon_class");

	for _,panel in g.pairs(OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:GetLines()) do panel:SetToolTip("Double click to remove"); end

end

function OH.menu.c_aimbot.create()
	local max_x,max_y = (g.ScrW()*0.5)-(ScrW()/6)-5,(ScrH()-(g.ScreenScale(60))-g.ScreenScale(108))-7;
	if !g.ValidPanel(OH.menu.Panel) then return; end

	OH.menu.c_aimbot.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.c_aimbot.Panel:SetVisible(false);

	OH.menu.c_aimbot.Panel.SwitchBoard = {};
	OH.menu.c_aimbot.Panel.SwitchBoard["Friends"] = {"Add and remove friends","friend_board"};
	OH.menu.c_aimbot.Panel.SwitchBoard["Activation"] = {"Change how the aimbot 'activates' itself","activation_board"};
	OH.menu.c_aimbot.Panel.SwitchBoard["Targeting"] = {"Aimbot targeting related settings","target_board"};
	OH.menu.c_aimbot.Panel.SwitchBoard["Tracing"] = {"Aimbot tracing related settings","trace_board"};
	OH.menu.c_aimbot.Panel.SwitchBoard["Antisnap"] = {"Make the Aimbot's aim smoother with these settings","antisnap_board"};
	OH.menu.c_aimbot.Panel.SwitchBoard["Utilities"] = {"Configure Aimbot Utilitiess","util_board"};

	for name,data in g.pairs(OH.menu.c_aimbot.Panel.SwitchBoard) do 
		OH.menu.c_aimbot.Panel.TabSheet:AddTab(name,data[1],data[2],"c_aimbot");
	end

	/*
	 	Group board
	*/

	OH.menu.c_aimbot.Panel["friend_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.c_aimbot.Panel);
	OH.menu.c_aimbot.Panel["friend_board"]:SetPos(OH.menu.c_aimbot.Panel.TabSheet:GetWide()+2,4);
	OH.menu.c_aimbot.Panel["friend_board"]:SetSize(1,1)
	OH.menu.c_aimbot.Panel["friend_board"]:SetVisible(false);

	OH.menu.c_aimbot.Panel["friend_board"].TempFList = OH.CreateDControl("DListView",OH.menu.c_aimbot.Panel["friend_board"]);
	OH.menu.c_aimbot.Panel["friend_board"].TempFList:SetPos(4,4);
	OH.menu.c_aimbot.Panel["friend_board"].TempFList:SetSize(max_x-8,(max_y*0.50)-8);
	OH.menu.c_aimbot.Panel["friend_board"].TempFList:AddColumn("Name");OH.menu.c_aimbot.Panel["friend_board"].TempFList:AddColumn("Index");
	OH.menu.c_aimbot.Panel["friend_board"].TempFList:AddColumn("Type");OH.menu.c_aimbot.Panel["friend_board"].TempFList:AddColumn("Friend Status");
	OH.menu.c_aimbot.Panel["friend_board"].TempFList:SetMultiSelect(false);
	OH.menu.c_aimbot.Panel["friend_board"].TempFList.DoDoubleClick = function(panel,line)	
		local p = panel:GetLine(line);
		if (OH.Aimbot.friends[g.tonumber(p:GetValue(2))]) then 
			OH.Aimbot.friends[g.tonumber(p:GetValue(2))] = nil;
			p:SetValue(4,"Not Friended");
		else 
			OH.Aimbot.friends[g.tonumber(g.tonumber(p:GetValue(2)))] = true;
			p:SetValue(4,"Friended");
		end
	end


	OH.menu.c_aimbot.Panel["friend_board"].FList = OH.CreateDControl("DListView",OH.menu.c_aimbot.Panel["friend_board"]);
	OH.menu.c_aimbot.Panel["friend_board"].FList:SetPos(4,4+(max_y*0.50));
	OH.menu.c_aimbot.Panel["friend_board"].FList:SetSize((max_x)-8,(max_y*0.50)-8);
	OH.menu.c_aimbot.Panel["friend_board"].FList:AddColumn("Name");OH.menu.c_aimbot.Panel["friend_board"].FList:AddColumn("Steam ID");
	OH.menu.c_aimbot.Panel["friend_board"].FList:AddColumn("Steam Friend Status");OH.menu.c_aimbot.Panel["friend_board"].FList:AddColumn("Friend Status");
	OH.menu.c_aimbot.Panel["friend_board"].FList.DoDoubleClick = function(panel,line)
		local p = panel:GetLine(line);
		if (OH.Aimbot.friend_ids[p:GetValue(2)]) then 
			OH.Aimbot.friend_ids[p:GetValue(2)] = nil;
			p:SetValue(4,"Not Friended");
		else 
			OH.Aimbot.friend_ids[p:GetValue(2)] = true;
			p:SetValue(4,"Friended");
		end
	end

	/*
	 	Activation board
	*/

	OH.menu.c_aimbot.Panel["activation_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.c_aimbot.Panel);
	OH.menu.c_aimbot.Panel["activation_board"]:SetPos(OH.menu.c_aimbot.Panel.TabSheet:GetWide()+2,4);
	OH.menu.c_aimbot.Panel["activation_board"]:SetSize(1,1)
	OH.menu.c_aimbot.Panel["activation_board"]:SetVisible(false);

	OH.menu.c_aimbot.Panel["activation_board"].CBinds = OH.CreateDControl("DListView",OH.menu.c_aimbot.Panel["activation_board"]);
	OH.menu.c_aimbot.Panel["activation_board"].CBinds:SetPos(6,6);
	OH.menu.c_aimbot.Panel["activation_board"].CBinds:SetSize(max_x-12,max_y-50);
	OH.menu.c_aimbot.Panel["activation_board"].CBinds:SetMultiSelect(false);
	OH.menu.c_aimbot.Panel["activation_board"].CBinds.OnRowSelected = function(panel,line)
		OH.menu.c_aimbot.Panel["activation_board"].Selected = panel:GetLine(line);
		OH.menu.c_aimbot.Panel["activation_board"].bind:SetText("Bind to "..panel:GetLine(line):GetValue(1));
	end

	OH.menu.c_aimbot.Panel["activation_board"].CBinds:AddColumn("Key");OH.menu.c_aimbot.Panel["activation_board"].CBinds:AddColumn("Key Integer");
	OH.menu.c_aimbot.Panel["activation_board"].CBinds:AddColumn("Key is Used by");

	OH.AddOption("button",OH.menu.c_aimbot.Panel["activation_board"],"bind",6,OH.menu.c_aimbot.Panel["activation_board"].CBinds:GetTall()+8,max_x-12,24,"Select a key",function() 
		if (!OH.menu.c_aimbot.Panel["activation_board"].Selected or !g.ValidPanel(OH.menu.c_aimbot.Panel["activation_board"].Selected)) then 
			g.Derma_Message("You must select a key first!");
			return;
		end
		g.Derma_Message("Bound to "..OH.menu.c_aimbot.Panel["activation_board"].Selected:GetValue(1).." ("..OH.menu.c_aimbot.Panel["activation_board"].Selected:GetValue(2)..")!");
		OH.Aimbot.trace_key = OH.menu.c_aimbot.Panel["activation_board"].Selected:GetValue(2);

		OH.menu.c_aimbot.Panel["activation_board"].CBinds:Clear();

		// TODO: redo this code

		local usekeys = {};

		for name,data in g.pairs(OH.KeyBind.binds) do 
			if !usekeys[data.BindKey] then usekeys[data.BindKey] = {}; end
			usekeys[data.BindKey][#usekeys[data.BindKey]+1] = name;
		end

		for _,data in g.pairs(OH.KeyBind.keys) do 
			local occ = "";
			if usekeys[data[2]] then
				for int,name in g.pairs(usekeys[data[2]]) do 
					occ = occ .. name;
					if (int != #usekeys[data[2]]) then occ = occ .. ", "; end
				end
			end
			OH.menu.c_aimbot.Panel["activation_board"].CBinds:AddLine(data[1],data[2],occ);
		end
	end);

	/*
	 	Targeting board
	*/

	local bones = {

	}

	OH.menu.c_aimbot.Panel["target_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.c_aimbot.Panel);
	OH.menu.c_aimbot.Panel["target_board"]:SetPos(OH.menu.c_aimbot.Panel.TabSheet:GetWide()+2,4);
	OH.menu.c_aimbot.Panel["target_board"]:SetSize(1,1)
	OH.menu.c_aimbot.Panel["target_board"]:SetVisible(false);

	OH.menu.c_aimbot.Panel["target_board"].BoneSelecter = OH.CreateDControl("DModelPanel",OH.menu.c_aimbot.Panel["target_board"]);
	OH.menu.c_aimbot.Panel["target_board"].BoneSelecter:SetPos(2,2);
	OH.menu.c_aimbot.Panel["target_board"].BoneSelecter:SetSize(max_x-4,max_y-4);
	OH.menu.c_aimbot.Panel["target_board"].BoneSelecter:SetModel("models/kleiner.mdl");
	OH.menu.c_aimbot.Panel["target_board"].BoneSelecter.LayoutEntity = function(ent) end

	/*
	 	Trace board
	*/

	OH.menu.c_aimbot.Panel["trace_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.c_aimbot.Panel);
	OH.menu.c_aimbot.Panel["trace_board"]:SetPos(OH.menu.c_aimbot.Panel.TabSheet:GetWide()+2,4);
	OH.menu.c_aimbot.Panel["trace_board"]:SetSize(1,1)
	OH.menu.c_aimbot.Panel["trace_board"]:SetVisible(false);

	OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList = OH.CreateDControl("DListView",OH.menu.c_aimbot.Panel["trace_board"]);
	OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:SetSize(max_x*0.50,max_y-60);
	OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:SetPos(2,2);
	OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:AddColumn("No Trace Weapons");
	OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList.DoDoubleClick = function(panel,line)
		local p = panel:GetLine(line);
		panel:RemoveLine(line);
		if (g.table.HasValue(OH.Aimbot.no_tweps,p:GetValue(1))) then
			for k,v in g.pairs(OH.Aimbot.no_tweps) do 
				if (v == p:GetValue(1)) then g.table.remove(OH.Aimbot.no_tweps,k); end
			end
		end
	end

	OH.AddOption("text_field",OH.menu.c_aimbot.Panel["trace_board"],"class_input",2,OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:GetTall()+5,OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:GetWide(),20,me:GetActiveWeapon() and me:GetActiveWeapon():GetClass() or "weapon_class");
	OH.AddOption("button",OH.menu.c_aimbot.Panel["trace_board"],"input_button",2,OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:GetTall()+30,OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:GetWide(),20,"Add",function()

		local wep = OH.menu.c_aimbot.Panel["trace_board"]["class_input"]:GetValue();

		if (wep == "" or wep == nil) then 
			g.Derma_Message("Invalid weapon!");
		elseif (g.table.HasValue(OH.Aimbot.no_tweps,wep)) then
			g.Derma_Message(wep.." is already listed!");
		else 
			OH.Aimbot.no_tweps[#OH.Aimbot.no_tweps+1] = wep;
			OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:AddLine(wep);
			for _,panel in g.pairs(OH.menu.c_aimbot.Panel["trace_board"].NoTWeapsList:GetLines()) do panel:SetToolTip("Double click to remove"); end
		end

	end);

	/*
	 	Anti - Snap board
	*/

	OH.menu.c_aimbot.Panel["antisnap_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.c_aimbot.Panel);
	OH.menu.c_aimbot.Panel["antisnap_board"]:SetPos(OH.menu.c_aimbot.Panel.TabSheet:GetWide()+2,4);
	OH.menu.c_aimbot.Panel["antisnap_board"]:SetSize(1,1)
	OH.menu.c_aimbot.Panel["antisnap_board"]:SetVisible(false);

	/*
	 	Utilties board
	*/

	OH.menu.c_aimbot.Panel["util_board"] = OH.CreateDControl("OHSwitchBoard",OH.menu.c_aimbot.Panel);
	OH.menu.c_aimbot.Panel["util_board"]:SetPos(OH.menu.c_aimbot.Panel.TabSheet:GetWide()+2,4);
	OH.menu.c_aimbot.Panel["util_board"]:SetSize(1,1)
	OH.menu.c_aimbot.Panel["util_board"]:SetVisible(false);
	/*
	Aimbot = { 
		
		target_npcs = true, -- Target NPCs
		target_bots = true, -- Target bots 
		target_ownteam = true, -- Target my team
		target_harmless = true, -- Target harmless *players*
		target_vehicles = false, -- Target play*rs in vehicles 
		target_locking = false, -- Enable target locking
		target_espents = false, -- Target Entities from the ESP
		otrg_traitors = false, -- Only target traitors in TTT
		target_bone = "ValveBiped.Bip01_Head1",

		// Tracing
		los_check = true, -- Check LOS
		voffset = g.Vector(0,0,0), -- Aimbot Vector offset
		aoffset = g.Angle(0,0,0), -- Angle offset

		// Anti-snap
 		antisnap_enabled = false	, -- Anti-snap enabled 
 		antisnap_letoff = 180, -- Anti-snap let-off (slowness)
		antisnap_lb = 0, -- Anti-snap Lower Bound
		antisnap_hb = 360, -- Anti-snap Higher Bound
		antisnap_clhb = false, -- Enabled Higher Bound clamping
		antisnap_cllb = false, -- Enable Lower Bound clamping 

		// Triggerbot
		tb_enabled = false, -- Triggerbot Enabled
		tb_firing = false,
		// Silent Aim
		sa_enabled = true, -- Enabled Silent Aim
		sa_ang = nil, -- Silent Aim Angle
		// vars
		
		tlocked = false, -- Target Locked
		targets = false, -- Targets
		vtargets = {}, -- Visible Targets
		target = false, -- Current Target
		tracing = false, -- Aimbot tracing
		ext_t = false -- Enabled extra traces
	*/

	OH.menu.c_aimbot.update();
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.c_trigbot.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.c_trigbot.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.c_trigbot.Panel:SetVisible(false);
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.c_autorld.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.c_autorld.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.c_autorld.Panel:SetVisible(false);
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.m_theme.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.m_theme.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.m_theme.Panel:SetVisible(false);
end 

function OH.menu.m_settings.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.m_settings.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.m_settings.Panel:SetVisible(false);
end

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.me_detour.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.me_detour.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.me_detour.Panel:SetVisible(false);
end 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.me_logging.create()
	if !g.ValidPanel(OH.menu.Panel) then return; end
	OH.menu.me_logging.Panel = OH.CreateDControl("OHBasePanel",OH.menu.Panel);
	OH.menu.me_logging.Panel:SetVisible(false);
end

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

function OH.menu.close()
	if !OH.menu.Panel then OH.menu.create(); return; end 
	if !OH.menu.Panel:IsVisible() then return; end 
	
	for _,panel in g.pairs(OH.menu.Panel.Tabs) do if panel.TabBG then panel.TabBG:Collapse(); end end

	for k,v in g.pairs(OH.menu.Panel.Tabs) do 
		v:RequestPos(1,g.ScrH()-1);
		v:SetCBFunction(function() 
			v:SetVisible(false);
			local vis_panels = false;
			for _,panel in g.pairs(OH.menu.Panel.Tabs) do 
				if panel:IsVisible() then vis_panels = true; end 
			end 
			OH.menu.Panel:SetVisible(vis_panels);
		end);
	end 

	OH.menu.Panel.Logo:RequestSize(1,150);
	OH.menu.Panel.Logo:SetCBFunction(function() OH.menu.Panel.Logo:SetCBFunction(nil); OH.menu.Panel.Logo:SetVisible(false); end);
end 

local tabs = {
	["Graphics"] = { 
		["ESP"] = {"Extra Sensory Perception","g_esp"},
		["Wallhack"] = {"Ability to see targets through walls","g_wallhack"},
		["Laser Sights"] = {"Lasers from your gun's barrel","g_lasersts"},
		["Laser Eyes"] = {"Lasers from enemy's eyes","g_lasereyes"}
	},
	["Combat"] = {
		["Aimbot"] = {"Aims at the enemy when told to","c_aimbot"},
		["Trigger Bot"] = {"Fires when a target is visible","c_trigbot"},
		["Auto Reload"] = {"Reloads your gun when it needs it","c_autorld"}
	},
	["Menu"] = {
		["Theme"] = {"The menu's theme","m_theme"},
		["Settings"] = {"The menu's settings","m_settings"}

	},
	["Mechanics"] = {
		["Detours"] = {"Block / Unblock functions","me_detour"},
		["Logging"] = {"OubHack's Logs","me_logging"}
	}
}

function OH.menu.open()
	if !OH.menu.Panel then OH.menu.create(); return; end 
	if OH.menu.Panel:IsVisible() then return; end
 	OH.menu.Panel:SetVisible(true);

	local div = ( (g.ScrW()) / table.Count(OH.menu.Panel.Tabs) );
	local i = 0.25;

	for name,data in g.pairs(tabs) do 
		OH.menu.Panel.Tabs[name]:SetVisible(true);
		OH.menu.Panel.Tabs[name]:SetPos(1,g.ScrH()-1);
		OH.menu.Panel.Tabs[name]:SetSize(div*0.5,g.ScreenScale(50));
		OH.menu.Panel.Tabs[name]:RequestPos((i*(div)),g.ScreenScale(10));
		OH.menu.Panel.Tabs[name]:SetCBFunction(function() end);
		i=i+1;
	end 

	OH.menu.Panel.Logo:SetVisible(true);
	OH.menu.Panel.Logo:SetCBFunction(nil);
	OH.menu.Panel.Logo:RequestSize(g.ScreenScale(140),g.ScreenScale(60));
	OH.menu.Panel.Logo:SetSize(1,g.ScreenScale(60));
	OH.menu.Panel.Logo:SetPos(1,g.ScrH()-OH.menu.Panel.Logo:GetTall()-2);

end 

function OH.menu.create()
	gui.EnableScreenClicker(true);
	if OH.menu.Panel then OH.menu.Panel:Remove(); OH.menu.Panel = nil; end 
	OH.menu.Panel = g.vgui.Create("EditablePanel");
	OH.menu.Panel:SetPos(0,0);
	OH.menu.Panel:MakePopup();
	OH.menu.Panel:SetSize(g.ScrW(),g.ScrH());
	OH.menu.Panel.GetSkin = function() return skin; end
	OH.menu.Panel.Paint = function() end; 

	local div = ( (g.ScrW()) / g.table.Count(tabs) );
	local i = 0.25;
	OH.menu.Panel.Tabs = {};
	for name,data in g.pairs(tabs) do 
		OH.menu.Panel.Tabs[name] = OH.CreateDControl("OHTab",OH.menu.Panel);

		OH.menu.Panel.Tabs[name]:SetPos(1,g.ScrH()-1);
		OH.menu.Panel.Tabs[name]:SetSize(div*0.5,g.ScreenScale(50));
		OH.menu.Panel.Tabs[name]:RequestPos((i*(div)),g.ScreenScale(10));

		OH.menu.Panel.Tabs[name]:SetName(name);
		OH.menu.Panel.Tabs[name]:SetTabData(data);
		i=i+1;
	end 
	
	OH.menu.Panel.Logo = OH.CreateDControl("OHLogo",OH.menu.Panel);
	OH.menu.Panel.Logo:RequestSize(g.ScreenScale(140),g.ScreenScale(60))
	OH.menu.Panel.Logo:SetSize(1,g.ScreenScale(60));
	OH.menu.Panel.Logo:SetPos(1,g.ScrH()-OH.menu.Panel.Logo:GetTall()-2);
	--OH.menu.Panel.Logo:Expand();

end                                                                                

function OH.menu.toggle()
	if OH.menu.Console.Panel and OH.menu.Console.Panel:IsVisible() then return; end
	if !OH.menu.Panel then OH.menu.create(); return; end 
	if OH.menu.Panel:IsVisible() then 
		OH.menu.close(); 
		gui.EnableScreenClicker(false);
	else
		OH.menu.open();
		gui.EnableScreenClicker(true);
	end
end 

OH.AddKeyBind(KEY_H,"OHMenuToggle",OH.menu.toggle);

local badhud = {
	["CHudHealth"] = true,
	["CHudAmmo"] = true,
	["CHudChat"] = true,
	["CHudDeathNotice"] = true,
	["CHudSecondaryAmmo"] = true,
	["CHudWeaponSelection"] = true
};

-- 0,270
-- 0.680

OH.AddHook("HUDShouldDraw",function(name)
	if OH.menu.Panel and OH.menu.Panel:IsVisible() and badhud[name] then 
		return false;
	else 
		return GAMEMODE:HUDShouldDraw(name);
	end 	
end);

/*****************************************************************************
 .d8888b.   .d88888b.  888b    888  .d8888b.   .d88888b.  888      8888888888 
d88P  Y88b d88P" "Y88b 8888b   888 d88P  Y88b d88P" "Y88b 888      888        
888    888 888     888 88888b  888 Y88b.      888     888 888      888        
888        888     888 888Y88b 888  "Y888b.   888     888 888      8888888    
888        888     888 888 Y88b888     "Y88b. 888     888 888      888        
888    888 888     888 888  Y88888       "888 888     888 888      888        
Y88b  d88P Y88b. .d88P 888   Y8888 Y88b  d88P Y88b. .d88P 888      888        
 "Y8888P"   "Y88888P"  888    Y888  "Y8888P"   "Y88888P"  88888888 8888888888
******************************************************************************/

function OH.menu.Console.create()
	OH.menu.Console.Panel = OH.CreateDControl("OHConsole");
	OH.menu.Console.Panel:SetVisible(false);
end 

function OH.menu.Console.open()
	OH.menu.Console.Panel:SetPos((g.ScrW()/2)-(g.ScrW()/2)*0.5,1);
	OH.menu.Console.Panel:SetSize(ScrW()/2,1);
	OH.menu.Console.Panel:RequestSize(g.ScrW()/2,250);
	OH.menu.Console.Panel:SetCBFunction(nil);
	OH.menu.Console.Panel:SetVisible(true);
	OH.menu.Console.Panel:MakePopup();
	OH.menu.Console.Panel.TextField:RequestFocus();
end 

function OH.menu.Console.close()
	OH.menu.Console.Panel:SetPos((g.ScrW()/2)-(g.ScrW()/2)*0.5,1);
	OH.menu.Console.Panel:RequestSize(g.ScrW()/2,1);
	OH.menu.Console.Panel:SetCBFunction(function() OH.menu.Console.Panel:SetVisible(false); end);
end 

function OH.menu.Console.toggle()
	if OH.menu.Panel and OH.menu.Panel:IsVisible() then return; end
	if !OH.menu.Console.Panel then OH.menu.Console.create(); OH.menu.Console.open() return; end
	if OH.menu.Console.Panel:IsVisible() then 
		OH.menu.Console.close();
		gui.EnableScreenClicker(false);
	else
		OH.menu.Console.open();
		gui.EnableScreenClicker(true);
	end
end

function OH.cprint(...)
	local arg = {...};
	if !arg[1] then return; end
	if (OH.menu.Console.Panel) then 
		for _,data in g.pairs(arg) do 
			if (g.type(data) == "string") then
				OH.menu.Console.Panel.Console:AppendText(data);
			elseif (g.type(data) == "table") then 
				OH.menu.Console.Panel.Console:InsertColorChange(data.r,data.g,data.b,data.a);
			end
		end
		OH.menu.Console.Panel.Console:AppendText("\n");
	end

end

// Default binds
// key,name,downfunc,upfunc,downfuncthink,upfuncthink
OH.AddKeyBind(KEY_I,"CSpam",function() OH.spam = !OH.spam; end) -- Spam
OH.AddKeyBind(KEY_J,"CNoClipBind",function() OH.CNoClip.enabled = !OH.CNoClip.enabled; end) -- No Clip
OH.AddKeyBind(KEY_K,"WallHack",function() OH.Wallhack.enabled = !OH.Wallhack.enabled; end) -- Wallhack
OH.AddKeyBind(KEY_L,"ESP",function() OH.ESP.enabled = !OH.ESP.enabled; end) -- ESP
OH.AddKeyBind(KEY_P,"TB",function() OH.Aimbot.tb_enabled = !OH.Aimbot.tb_enabled; end) -- ESP
OH.AddKeyBind(KEY_U,"Console",OH.menu.Console.toggle) -- ESP
OH.AddKeyBind(KEY_0,"Hidemode",function() 

	if ( OH.hidemode ) then 

		g.print("OubHack Enabled!");
		OH.hidemode = false;

	else 

		g.print("OubHack Disabled!");
		OH.hidemode = true;

	end

end); -- ESP

local canzoom = false;
//(key,name,downfunc,upfunc,downfuncthink,upfuncthink
OH.AddKeyBind(KEY_LCONTROL,"ZoomActivate",nil,nil,function() canzoom = true; end,function() canzoom = false; end);
OH.AddKeyBind(KEY_EQUAL,"Zoomin",nil,nil,function() if (canzoom) then OH.CNoClip.fov=OH.CNoClip.fov-1; end end);
OH.AddKeyBind(KEY_MINUS,"Zoomout",nil,nil,function() if (canzoom) then OH.CNoClip.fov=OH.CNoClip.fov+1; end end);

OH.AddCmd("print",function(cmd,args)
	local tex="";
	for _,t in g.pairs(args) do tex=tex..t; end
	OH.cprint(g.Color(0,255,0,255),"You said : "..tex);
end);

OH.AddCmd("run",function(cmd,args)

	local tex = "";

	for _,t in g.pairs(args) do tex = tex .. t .. " "; end

	tex = tex:sub( 1, tex:len() - 1 );

	local res, err = g.pcall( g.RunString, tex );

	if ( !res ) then OH.cprint( "Generated Errors : " .. err ); end

end);

OH.AddCmd("save_config",function(cmd,args)
	c_name = args[1];

	for name,tbl in g.pairs(OH) do // Go through the main table, sorting data we want to save, and stuff we don't want saved
		if (goodkeys[name]) then 
			for key,var in g.pairs(tbl) do 
				if (badvalues[key]) then continue; end
				if (g.type(var) == "Angle" or g.type(var) == "Vector") then 
					writereg("OubHack/Configs/"..c_name.."/"..name,key,('('..g.type(var):upper()..')')..g.tostring(var));
				elseif (g.type(var) == "number") then 
					writereg("OubHack/Configs/"..c_name.."/"..name,key,g.tonumber(var));
				elseif (g.type(var) == "table") then 
					for subkey,sub in g.pairs(var) do 
						if (g.type(sub) == "string") then
							writereg("OubHack/Configs/"..c_name.."/"..name.."/"..key,g.tostring(subkey),g.tostring(sub));
						elseif (g.type(sub) == "table") then
							for subsubkey,subsubval in g.pairs(sub) do 
								if (g.type(subsubval) == "string") then 
									writereg("OubHack/Configs/"..c_name.."/"..name.."/"..key.."/"..subkey,subsubkey,g.tostring(subsubval));
								elseif (g.type(subsubval) == "table") then 
									writereg("OubHack/Configs/"..c_name.."/"..name.."/"..key.."/"..subkey,subsubkey,("(COLOR)")..(subsubval.r.." "..subsubval.g.." "..subsubval.b.." "..subsubval.a));
								end
							end
						end
					end
				elseif (g.type(var) == "strirg") then 
					writereg("OubHack/Configs/"..c_name.."/"..name,key,g.tostring(var));
				elseif (g.type(var) == "boolean") then 
					writereg("OubHack/Configs/"..c_name.."/"..name,key,var);
				end

			end
		end
	end

	OH.cprint(g.Color(0,255,0,255),"Saved "..c_name.." successfully!");

end);

OH.AddCmd("load_config",function(cmd,args)

	c_name = args[1];

	if (!c_name) then
		OH.cprint(g.Color(255,0,0,255),"ERROR: ",g.Color(255,255,255,255),"Specify a config!");
		return; 
	end

	if (!getconfs()[c_name]) then 
		OH.cprint(g.Color(255,0,0,255),"ERROR: ",g.Color(255,255,255,255),"No such config '"..c_name.."' !");
		return;
	end

	for _,d in g.pairs(OH) do 
		if (!goodkeys[d]) then continue; end
		for key,data in g.pairs(d) do
			OH[d][key] = def[d][key];
			PrintTable(OH[d][key]);
		end
	end	

	for name,tbl in g.pairs(getconf(c_name)) do
		if (goodkeys[name]) then 
			for key,var in g.pairs(tbl) do
				if (g.type(var) == "string") then 
					if (var:sub(1,7)=="(ANGLE)") then OH[name][key]=OH.SAToA(var:sub(8,var:len())); continue; end
					if (var:sub(1,7)=="(COLOR)") then OH[name][key]=OH.SCToC(var:sub(8,var:len())); continue; end
					if (var:sub(1,8)=="(VECTOR)") then OH[name][key]=OH.SVToV(var:sub(9,var:len())); continue; end
					if (var == "False" or var == "True") then OH[name][key]=g.tobool(var:lower()); continue; end
					OH[name][key]=var;
				elseif (g.type(var) == "number") then
					OH[name][key]=var;
				else 
					for subkey,sub in g.pairs(var) do 
						if (g.type(sub) == "string") then
							OH[name][key][subkey]=sub;
						elseif (g.type(sub) == "table") then
							for subsubkey,subsubval in g.pairs(sub) do 
								OH[name][key][subkey] = OH[name][key][subkey] or {};
								if (g.type(subsubval) == "string" && subsubval:sub(1,7)=="(COLOR)") then 
									OH[name][key][subkey][subsubkey]=OH.SCToC(subsubval:sub(8,subsubval:len()));
								elseif (g.type(subsubval) == "string") then 
									OH[name][key][subkey][subsubkey]=subsubval;
								end
							end
						end
					end
				end
			end
		end 
	end

	OH.cprint(g.Color(0,255,0,255),"Loaded "..c_name.." successfully!");

end);

OH.AddCmd("get_configs",function(cmd,args)

end);

OH.AddCmd("get_traitors",function(cmd,args)

	local i = 0;

	if ( _G.KARMA ) then 

		for _, ent in pairs( ents.GetAll() ) do 

			if ( ent:IsWeapon() ) then 

				if ( ent.CanBuy && table.HasValue( ent.CanBuy, ROLE_TRAITOR ) ) then 

					OH.cprint(g.Color(0,255,0,255),tostring( r["Entity"]["GetOwner"]( ent ) ));
					i = i + 1;

				end

			end

		end

	else 

		OH.cprint(g.Color(255,0,0,255), "Game isn't TTT!" );

	end 

	OH.cprint(g.Color(0,255,0,255), i .. " traitors found" );


end);




OH.AddCmd("set_default_config",function(cmd,args)
	if (args[1]) then 
		if (getconfs()[args[1]]) then 
			OH.cprint(g.Color(0,255,0,255),""..c_name.." is now your default config!");
			setdefconf(args[1]);
		else 
			OH.cprint(g.Color(255,0,0,255),"ERROR: ",g.Color(255,255,255,255),"No such config '"..c_name.."' !");
		end
	else 
		OH.cprint(g.Color(255,0,0,255),"ERROR: ",g.Color(255,255,255,255),"Specify a config!");
	end
end);


g.timer.Create( "Spam", 1, 0, function()

	if ( !OH.spam ) then return; end 

	g.RunConsoleCommand("say"," I have " .. me:Ping() .. " ping, " .. me:Health() .. " health and I'm moving at " .. tostring( me:GetVelocity():Length() ) .. " units per second!");

end);

// Load default config from disk

g.timer.Simple(0,function() // Anything that has to be done AFTER GUI is loaded, is done in here.
	if (!OH.menu.Console.Panel) then OH.menu.Console.create(); end
	//if (getconfs()[getdefconf()]) then OH.cmds["load_config"]("load_config",{getdefconf()}); end
end);

print("OubHack "..g.tostring(OH.Version).." Loaded!");
