-- TURBOBOT 386 NTLDR

require("eradicate")
print("*presses the turbo button on your 386 pc*")

local vars = {
	abEnabled = CreateClientConVar("mh_ab_enabled", "1", false, false),
	abFFA = CreateClientConVar("mh_ab_ffa", "0", false, false),
	abNospread = CreateClientConVar("mh_ab_nospread", "0", false, false),
	abPriority = CreateClientConVar("mh_ab_priority", "Closest to crosshair", false, false),
	abFOV = CreateClientConVar("mh_ab_fov", "90", false, false),
	
	espEnabled = CreateClientConVar("mh_esp_enabled", "1", false, false),
	espMode = CreateClientConVar("mh_esp_mode", "Solid Unlit", false, false),
	espNames = CreateClientConVar("mh_esp_names", "0", false, false),
	espWeapons = CreateClientConVar("mh_esp_weps", "0", false, false)
}

-- ##################
-- # ui initializer #
-- ##################
hook.Add("Initialize", "mhgui", function()
	dpanel = vgui.Create("DFrame")
	dpanel:SetPos(64,64)
	dpanel:SetSize(256,512)
	dpanel:SetTitle("")
	dpanel:SetDraggable(true)
	dpanel:ShowCloseButton(true)
	dpanel:SetDeleteOnClose(false)
	dpanel:SetVisible(false)

	local psheet = vgui.Create("DPropertySheet")
	psheet:SetParent(dpanel)
	psheet:SetPos(2,22)
	psheet:SetSize(252,488)

	-- aimbot config

	local abform = vgui.Create("DPanelList", psheet)
	abform:SetPadding(8)
	abform:SetSpacing(4)

	local abtoggle = vgui.Create("DCheckBoxLabel")
	abtoggle:SetText("Enabled")
	abtoggle:SetValue(1)
	abtoggle:SetConVar("mh_ab_enabled")
	abform:AddItem(abtoggle)

	local abffa = vgui.Create("DCheckBoxLabel")
	abffa:SetText("Free-for-all")
	abffa:SetConVar("mh_ab_ffa")
	abform:AddItem(abffa)

	local abspread = vgui.Create("DCheckBoxLabel")
	abspread:SetText("NoSpread (buggy)")
	abspread:SetConVar("mh_ab_nospread")
	abform:AddItem(abspread)

	abform:AddItem((function() local _ = vgui.Create("DLabel") _:SetText("Aiming priority:") _:SetFont("DefaultBold") return _ end)())

	local abmode = vgui.Create("DMultiChoice")
	abmode:AddChoice("Closest to crosshair")
	abmode:AddChoice("Closest to player")
	abmode:ChooseOptionID(1)
	abmode:SetEditable(false)
	abmode:SetConVar("mh_ab_priority")
	abform:AddItem(abmode)
	
	local abfov = vgui.Create("DNumSlider")
	abfov:SetText("Max FOV")
	abfov:SetMin(5)
	abfov:SetMax(360)
	abfov:SetDecimals(0)
	abfov:SetConVar("mh_ab_fov")
	abform:AddItem(abfov)

	-- esp/chams config

	local visform = vgui.Create("DPanelList", psheet)
	visform:SetPadding(8)
	visform:SetSpacing(4)

	local esptoggle = vgui.Create("DCheckBoxLabel")
	esptoggle:SetText("Enabled")
	esptoggle:SetValue(1)
	esptoggle:SetConVar("mh_esp_enabled")
	visform:AddItem(esptoggle)

	local espnames = vgui.Create("DCheckBoxLabel")
	espnames:SetText("Show player names")
	espnames:SetValue(0)
	espnames:SetConVar("mh_esp_names")
	visform:AddItem(espnames)

	local espweps = vgui.Create("DCheckBoxLabel")
	espweps:SetText("Reveal weapons")
	espweps:SetValue(0)
	espweps:SetConVar("mh_esp_weps")
	visform:AddItem(espweps)
	
	visform:AddItem((function() local _ = vgui.Create("DLabel") _:SetText("Cham mode:") _:SetFont("DefaultBold") return _ end)())

	local vismode = vgui.Create("DMultiChoice")
	vismode:AddChoice("Solid Unlit")
	vismode:AddChoice("Wireframe")
	vismode:ChooseOptionID(2)
	vismode:SetEditable(false)
	vismode:SetConVar("mh_esp_mode")
	visform:AddItem(vismode)

	-- sheets

	psheet:AddSheet("Aiming", abform, false, false, false, "Automatic aiming configuration")
	psheet:AddSheet("Vision", visform, false, false, false, "Vision enhancement configuration")
end)

concommand.Add("mh_open", function()
	dpanel:SetVisible(true)
	dpanel:MakePopup()
end)

-- ###############
-- # aimbot core #
-- ###############

function math.dist(ax, ay, bx, by)
	local dx, dy = ax-bx, ay-by
	return math.sqrt(dx*dx+dy*dy)
end

local OrigSVA = _R["CUserCmd"].SetViewAngles

local OtherBones = {
	["models/zombie/classic.mdl"] = "ValveBiped.HC_Body_Bone",
	["models/zombie/fast.mdl"] = "ValveBiped.HC_BodyCube",
	["models/zombie/poison.mdl"] = "ValveBiped.Bip01_Spine4"
}
		
local function IsOpponent(p)
	return LocalPlayer():Team() ~= p:Team() or vars.abFFA:GetBool()
end

local AimModes = {
	-- multichoice setconvar sucks
	["Closest to player"] = function(s,b)
		return s:Distance(b)
	end,
	["Closest to crosshair"] = function(s,b)
		--local bs = b:ToScreen()
		--return math.dist(bs.x, bs.y, ScrW()/2, ScrH()/2)
		--return math.acos(b:DotProduct(s))
		local plang = LocalPlayer():GetAngles()
		local ang = (b-s):Angle()
		local dy = math.abs(math.NormalizeAngle(plang.y - ang.y))
		local dp = math.abs(math.NormalizeAngle(plang.p - ang.p))
		return math.sqrt(dy*dy+dp*dp)
	end
}

local meta = _R["Entity"]
local OrigFireBullets = meta.FireBullets
local spread = Vector(0,0,0)
function meta.FireBullets(ent, bullet)
	spread = bullet.Spread
	return OrigFireBullets(ent, bullet)
end

local function findTarget() 

	local OptimalBone = false
	
	for _, v in pairs(player.GetAll()) do
		if v ~= LocalPlayer() and v:Alive() and IsOpponent(v) then
		
			local ShootPos = LocalPlayer():GetShootPos()
			local BonePos = v:GetBonePosition(v:LookupBone(OtherBones[v:GetModel()] or "ValveBiped.Bip01_Head1"))
			
			local VisTrace = util.TraceLine{start = ShootPos, endpos = BonePos}
			
			if VisTrace.Entity:IsPlayer() then
				local BoneDist = AimModes[vars.abPriority:GetString()](ShootPos, BonePos)
				if not OptimalBone or OptimalBone.dist > BoneDist then
					if BoneDist > vars.abFOV:GetFloat()/2 then break end
					OptimalBone = { player = v, pos = BonePos, dist = BoneDist }
				end
			end
			
		end
	end
	return OptimalBone
	
end

local function AimCore(ucmd)
	
	if ucmd:KeyDown( IN_ATTACK ) and vars.abEnabled:GetBool() then
		local optimal = findTarget()
		if optimal then
			optimal.pos = optimal.pos + optimal.player:GetVelocity() * (1/66) - LocalPlayer():GetVelocity() * (1/66)
			
			local ShootPos = LocalPlayer():GetShootPos()
			local ShootAng = (optimal.pos - ShootPos):Normalize()
			local offset = ShootAng
			
			if vars.abNospread:GetBool() then
				teh.SetPredictionSeed(ucmd)
				offset = Vector(0,0,0)
				teh.GetSpread(offset, ShootAng, Vector(0,0,0)-spread)
			end
				
			OrigSVA(ucmd, offset:Angle())
		end
	end
	
end

hook.Add("CreateMove", "mhab", AimCore)

-- ############
-- # esp core #
-- ############
local ChamParams = { 
	["$basetexture"] = "models/debug/debugwhite", 
	["$model"] = 1, 
	["$ignorez"] = 1
}
	
local mats = {
	["Solid Unlit"]  = CreateMaterial("chamsolid","UnlitGeneric",ChamParams),
	["Wireframe"] = CreateMaterial("chamwire","Wireframe",ChamParams)
}

local function RevealEntity(e, c)

	SetMaterialOverride(mats[vars.espMode:GetString()])
	render.SetColorModulation(c.r/255, c.g/255, c.b/255)
	render.SetBlend(0.75)
	if vars.espMode:GetString() == "Wireframe" then
		render.SetBlend(1)
	end
	e:DrawModel() 
					
	SetMaterialOverride() 
	render.SetColorModulation(1, 1, 1)
	render.SetBlend(1)
	e:DrawModel()
	
end
	
local function ChamCore()

	if vars.espEnabled:GetBool() then
		render.SuppressEngineLighting(true)
		cam.Start3D( EyePos(), EyeAngles() ) 
			
		for k, v in pairs( player.GetAll() ) do
			if v:Alive() and v:GetMoveType() ~= MOVETYPE_OBSERVER and v:GetMoveType() ~= MOVETYPE_NONE then 
				local c = team.GetColor(v:Team())
				RevealEntity(v, c)
			end
		end
		cam.End3D()
		render.SuppressEngineLighting(false)
	end
	
end

hook.Add("RenderScreenspaceEffects", "Chams", ChamCore)

local function ESPCore( )
	
	if vars.espNames:GetBool() then
		for k,v in pairs(player:GetAll()) do
			if v:Alive() and v ~= LocalPlayer() and v:GetMoveType() ~= MOVETYPE_OBSERVER and v:GetMoveType() ~= MOVETYPE_NONE then
				local BonePos = v:GetBonePosition( v:LookupBone("ValveBiped.Bip01_Head1") )
				local HeadScreen = (BonePos+Vector(0,0,8)):ToScreen()
					
				local namecol = (function() if v:IsAdmin() then return Color(255,255,0,255) else return Color(255,255,255,255) end end)() 
				draw.SimpleTextOutlined(string.Left(v:Name(), 16), "DefaultSmall", HeadScreen.x, HeadScreen.y-10, namecol, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, Color(0,0,0,255))
				
				local hp = (function(n) if n < 0 then return 0 else return n end end)(v:Health()) 
				draw.SimpleTextOutlined(hp, "DefaultSmall", HeadScreen.x, HeadScreen.y, Color(255,hp*2.55,hp*2.55,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, Color(0,0,0,255))
			end
		end
	end 
		
	if vars.espWeapons:GetBool() then
		for k,v in pairs(ents.FindByClass("weapon_*")) do
			local sp = v:GetPos():ToScreen()
			draw.SimpleTextOutlined("-", "DefaultSmall", sp.x, sp.y, Color(255,127,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(0,0,0,255))
		end
	end
	
end

hook.Add( "HUDPaint", "ESP", ESPCore )

local GetWeps = _R['Player'].GetWeapons
concommand.Add("mh_weps", function()
	for _, p in pairs(player.GetAll()) do
		if p:Alive()then
			print(p:Name())
			local ws = "-> "
			for _, w in pairs(GetWeps(p)) do
				local wn = w:GetClass()
				ws = ws .. string.sub(wn, string.find(wn, "_")+1) .. " "
			end
			print(ws)
		end
	end
end)