// AutoAim by RabidToaster if SERVER then return end local AA = {} local _R = debug.getregistry() local concommand = concommand local cvars = cvars local debug = debug local ents = ents local file = file local hook = hook local math = math local spawnmenu = spawnmenu local string = string local surface = surface local table = table local timer = timer local util = util local vgui = vgui local Angle = Angle local CreateClientConVar = CreateClientConVar local CurTime = CurTime local ErrorNoHalt = ErrorNoHalt local FrameTime = FrameTime local GetConVarString = GetConVarString local GetViewEntity = GetViewEntity local include = include local ipairs = ipairs local LocalPlayer = LocalPlayer local pairs = pairs local pcall = pcall local print = print local RunConsoleCommand = RunConsoleCommand local ScrH = ScrH local ScrW = ScrW local tonumber = tonumber local type = type local unpack = unpack local IsValid = IsValid local Vector = Vector do local hooks = {} local created = {} local function CallHook(self, name, args) if !hooks[name] then return end for funcName, _ in pairs(hooks[name]) do local func = self[funcName] if func then local ok, err = pcall(func, self, unpack(args or {})) if !ok then ErrorNoHalt(err .. "\n") elseif err then return err end end end end local function RandomName() local random = "" for i = 1, math.random(4, 10) do local c = math.random(65, 116) if c >= 91 && c <= 96 then c = c + 6 end random = random .. string.char(c) end return random end local function AddHook(self, name, funcName) // If we haven't got a hook for this yet, make one with a random name and store it. // This is so anti-cheats can't detect by hook name, and so we can remove them later. if !created[name] then local random = RandomName() hook.Add(name, random, function(...) return CallHook(self, name, {...}) end) created[name] = random end hooks[name] = hooks[name] or {} hooks[name][funcName] = true end local cvarhooks = {} local function GetCallbackTable(convar) local callbacks = cvars.GetConVarCallbacks(convar) if !callbacks then cvars.AddChangeCallback(convar, function() end) callbacks = cvars.GetConVarCallbacks(convar) end return callbacks end local function AddCVarHook(self, convar, funcName, ...) local hookName = "CVar_" .. convar if !cvarhooks[convar] then local random = RandomName() local callbacks = GetCallbackTable(convar) callbacks[random] = function(...) CallHook(self, hookName, {...}) end cvarhooks[convar] = random end AddHook(self, hookName, funcName) end // Don't let other scripts remove our hooks. local oldRemove = hook.Remove function hook.Remove(name, unique) if created[name] == unique then return end oldRemove(name, unique) end // Removes all hooks, useful if reloading the script. local function RemoveHooks() for hookName, unique in pairs(created) do oldRemove(hookName, unique) end for convar, unique in pairs(cvarhooks) do local callbacks = GetCallbackTable(convar) callbacks[unique] = nil end end // Add copies the script can access. AA.AddHook = AddHook AA.AddCVarHook = AddCVarHook AA.CallHook = CallHook AA.RemoveHooks = RemoveHooks end concommand.Add("aa_reload", function() AA:CallHook("Shutdown") print("Removing hooks...") AA:RemoveHooks() AA = nil local info = debug.getinfo(1, "S") if info && info.short_src then if string.Left(info.short_src, 3) == "lua" then info.short_src = string.sub(info.short_src, 5) end print("Reloading (" .. info.short_src .. ")...") include(info.short_src) else print("Cannot find AutoAim file, reload manually.") end end) print("AutoAim loaded.") // ################################################## // MetaTables // ################################################## local function GetMeta(name) return table.Copy(FindMetaTable(name) or {}) end local AngM = GetMeta("Angle") local CmdM = GetMeta("CUserCmd") local EntM = GetMeta("Entity") local PlyM = GetMeta("Player") local VecM = GetMeta("Vector") // ################################################## // Settings // ################################################## do local settings = {} local function SettingVar(self, name) return (self.SettingPrefix or "") .. string.lower(name) end local function RandomName() local random = "" for i = 1, math.random(4, 10) do local c = math.random(65, 116) if c >= 91 && c <= 96 then c = c + 6 end random = random .. string.char(c) end return random end local function SetSetting(name, _, new) if !settings[name] then return end local info = settings[name] if info.Type == "number" then new = tonumber(new) elseif info.Type == "boolean" then new = (tonumber(new) or 0) > 0 end info.Value = new end local function CreateSetting(self, name, desc, default, misc) local cvar = SettingVar(self, name) local info = {Name = name, Desc = desc, CVar = cvar, Type = type(default), Value = default} for k, v in pairs(misc or {}) do if !info[k] then info[k] = v end end // Convert default from boolean to number. if type(default) == "boolean" then default = default and 1 or 0 end if !settings[cvar] then local tab = cvars.GetConVarCallbacks(cvar) if !tab then cvars.AddChangeCallback(cvar, function() end) tab = cvars.GetConVarCallbacks(cvar) end while true do local name = RandomName() if !tab[name] then tab[name] = SetSetting info.Callback = name break end end end settings[cvar] = info settings[#settings + 1] = info // Create the convar. CreateClientConVar(cvar, default, (info.Save != false), false) SetSetting(cvar, _, GetConVarString(cvar)) end local function GetSetting(self, name) local cvar = SettingVar(self, name) if !settings[cvar] then return end return settings[cvar].Value end local function Shutdown() print("Removing settings callbacks...") for _, info in ipairs(settings) do if info.CVar && info.Callback then local tab = cvars.GetConVarCallbacks(info.CVar) if tab then tab[info.Callback] = nil end end end end local function SettingsList() return table.Copy(settings) end local function BuildMenu(self, panel) for _, info in ipairs(settings) do if info.Show != false then if info.MultiChoice then local m = panel:MultiChoice(info.Desc or info.CVar, info.CVar) for k, v in pairs(info.MultiChoice) do m:AddChoice(k, v) end elseif info.Type == "number" then panel:NumSlider(info.Desc or info.CVar, info.CVar, info.Min or -1, info.Max or -1, info.Places or 0) elseif info.Type == "boolean" then panel:CheckBox(info.Desc or info.CVar, info.CVar) elseif info.Type == "string" then panel:TextEntry(info.Desc or info.CVar, info.CVar) end end end end AA.SettingPrefix = "aa_" AA.CreateSetting = CreateSetting AA.Setting = GetSetting AA.SettingsList = SettingsList AA.BuildMenu = BuildMenu AA.SettingsShutdown = Shutdown AA:AddHook("Shutdown", "SettingsShutdown") end // ################################################## // Targetting - Positions // ################################################## AA.ModelTarget = {} function AA:SetModelTarget(model, targ) self.ModelTarget[model] = targ end function AA:BaseTargetPosition(ent) // The eye attachment is a lot more stable than bones for players. if type(ent) == "Player" then local head = EntM["LookupAttachment"](ent, "eyes") if head then local pos = EntM["GetAttachment"](ent, head) if pos then return pos.Pos - (AngM["Forward"](pos.Ang) * 2) end end end // Check if the model has a special target assigned to it. local special = self.ModelTarget[string.lower(EntM["GetModel"](ent) or "")] if special then // It's a string - look for a bone. if type(special) == "string" then local bone = EntM["LookupBone"](ent, special) if bone then local pos = EntM["GetBonePosition"](ent, bone) if pos then return pos end end // It's a Vector - return a relative position. elseif type(special) == "Vector" then return EntM["LocalToWorld"](ent, special) // It's a function - do something fancy! elseif type(special) == "function" then local pos = pcall(special, ent) if pos then return pos end end end // Try and use the head bone, found on all of the player + human models. local bone = "ValveBiped.Bip01_Head1" local head = EntM["LookupBone"](ent, bone) if head then local pos = EntM["GetBonePosition"](ent, head) if pos then return pos end end // Give up and return the center of the entity. return EntM["LocalToWorld"](ent, EntM["OBBCenter"](ent)) end function AA:TargetPosition(ent) local targetPos = self:BaseTargetPosition(ent) local ply = LocalPlayer() if IsValid(ply) then targetPos = self:CallHook("TargetPrediction", {ply, ent, targetPos}) or targetPos end return targetPos end AA:SetModelTarget("models/crow.mdl", Vector(0, 0, 5)) // Crow. AA:SetModelTarget("models/pigeon.mdl", Vector(0, 0, 5)) // Pigeon. AA:SetModelTarget("models/seagull.mdl", Vector(0, 0, 6)) // Seagull. AA:SetModelTarget("models/combine_scanner.mdl", "Scanner.Body") // Scanner. AA:SetModelTarget("models/hunter.mdl", "MiniStrider.body_joint") // Hunter. AA:SetModelTarget("models/combine_turrets/floor_turret.mdl", "Barrel") // Turret. AA:SetModelTarget("models/dog.mdl", "Dog_Model.Eye") // Dog. AA:SetModelTarget("models/vortigaunt.mdl", "ValveBiped.Head") // Vortigaunt. AA:SetModelTarget("models/antlion.mdl", "Antlion.Body_Bone") // Antlion. AA:SetModelTarget("models/antlion_guard.mdl", "Antlion_Guard.Body") // Antlion guard. AA:SetModelTarget("models/antlion_worker.mdl", "Antlion.Head_Bone") // Antlion worker. AA:SetModelTarget("models/zombie/fast_torso.mdl", "ValveBiped.HC_BodyCube") // Fast zombie torso. AA:SetModelTarget("models/zombie/fast.mdl", "ValveBiped.HC_BodyCube") // Fast zombie. AA:SetModelTarget("models/headcrabclassic.mdl", "HeadcrabClassic.SpineControl") // Normal headcrab. AA:SetModelTarget("models/headcrabblack.mdl", "HCBlack.body") // Poison headcrab. AA:SetModelTarget("models/headcrab.mdl", "HCFast.body") // Fast headcrab. AA:SetModelTarget("models/zombie/poison.mdl", "ValveBiped.Headcrab_Cube1") // Poison zombie. AA:SetModelTarget("models/zombie/classic.mdl", "ValveBiped.HC_Body_Bone") // Zombie. AA:SetModelTarget("models/zombie/classic_torso.mdl", "ValveBiped.HC_Body_Bone") // Zombie torso. AA:SetModelTarget("models/zombie/zombie_soldier.mdl", "ValveBiped.HC_Body_Bone") // Zombine. AA:SetModelTarget("models/combine_strider.mdl", "Combine_Strider.Body_Bone") // Strider. AA:SetModelTarget("models/combine_dropship.mdl", "D_ship.Spine1") // Combine dropship. AA:SetModelTarget("models/combine_helicopter.mdl", "Chopper.Body") // Combine helicopter. AA:SetModelTarget("models/gunship.mdl", "Gunship.Body") // Combine gunship. AA:SetModelTarget("models/lamarr.mdl", "HeadcrabClassic.SpineControl") // Lamarr! AA:SetModelTarget("models/mortarsynth.mdl", "Root Bone") // Mortar synth. AA:SetModelTarget("models/synth.mdl", "Bip02 Spine1") // Synth. AA:SetModelTarget("models/vortigaunt_slave.mdl", "ValveBiped.Head") // Vortigaunt slave. // ################################################## // Targetting - General // ################################################## AA.NPCDeathSequences = {} function AA:AddNPCDeathSequence(model, sequence) self.NPCDeathSequences = self.NPCDeathSequences or {} self.NPCDeathSequences[model] = self.NPCDeathSequences[model] or {} if !table.HasValue(self.NPCDeathSequences[model]) then table.insert(self.NPCDeathSequences[model], sequence) end end AA:AddNPCDeathSequence("models/barnacle.mdl", 4) AA:AddNPCDeathSequence("models/barnacle.mdl", 15) AA:AddNPCDeathSequence("models/antlion_guard.mdl", 44) AA:AddNPCDeathSequence("models/hunter.mdl", 124) AA:AddNPCDeathSequence("models/hunter.mdl", 125) AA:AddNPCDeathSequence("models/hunter.mdl", 126) AA:AddNPCDeathSequence("models/hunter.mdl", 127) AA:AddNPCDeathSequence("models/hunter.mdl", 128) AA:CreateSetting("friendlyfire", "Target teammates", false) function AA:IsValidTarget(ent) // We only want players/NPCs. local typename = type(ent) if typename != "NPC" && typename != "Player" then return false end // No invalid entities. if !IsValid(ent) then return false end // Go shoot yourself, emo kid. local ply = LocalPlayer() if ent == ply then return false end if typename == "Player" then if !PlyM["Alive"](ent) then return false end // Dead players FTL. if !self:Setting("friendlyfire") && PlyM["Team"](ent) == PlyM["Team"](ply) then return false end if EntM["GetMoveType"](ent) == MOVETYPE_OBSERVER then return false end // No spectators. if EntM["GetMoveType"](ent) == MOVETYPE_NONE then return false end //if pl["Team"](ent) == 1001 then return false end end if typename == "NPC" then if EntM["GetMoveType"](ent) == MOVETYPE_NONE then return false end // No dead NPCs. // No dying NPCs. local model = string.lower(EntM["GetModel"](ent) or "") if table.HasValue(self.NPCDeathSequences[model] or {}, EntM["GetSequence"](ent)) then return false end end end AA:CreateSetting("predictblocked", "Predict blocked (time)", 0.4, {Min = 0, Max = 1}) function AA:BaseBlocked(target, offset) local ply = LocalPlayer() if !IsValid(ply) then return end // Trace from the players shootpos to the position. local shootPos = PlyM["GetShootPos"](ply) local targetPos = self:TargetPosition(target) if offset then targetPos = targetPos + offset end local trace = util.TraceLine({start = shootPos, endpos = targetPos, filter = {ply, target}, mask = MASK_SHOT}) local wrongAim = self:AngleBetween(PlyM["GetAimVector"](ply), VecM["GetNormal"](targetPos - shootPos)) > 2 // If we hit something, we're "blocked". if trace.Hit && trace.Entity != target then return true, wrongAim end // It is not blocked. return false, wrongAim end function AA:TargetBlocked(target) if !target then target = self:GetTarget() end if !target then return end local blocked, wrongAim = self:BaseBlocked(target) if self:Setting("predictblocked") > 0 && blocked then blocked = self:BaseBlocked(target, EntM["GetVelocity"](target) * self:Setting("predictblocked")) end return blocked, wrongAim end function AA:SetTarget(ent) if self.Target && !ent then self:CallHook("TargetLost") elseif !self.Target && ent then self:CallHook("TargetGained") elseif self.Target && ent && self.Target != ent then self:CallHook("TargetChanged") end self.Target = ent end function AA:GetTarget() if IsValid(self.Target) != false then return self.Target else return false end end AA:CreateSetting("maxangle", "Max angle", 30, {Min = 5, Max = 90}) AA:CreateSetting("targetblocked", "Don't check LOS", false) AA:CreateSetting("holdtarget", "Hold targets", false) function AA:FindTarget() if !self:Enabled() then return end local ply = LocalPlayer() if !IsValid(ply) then return end local maxAng = self:Setting("maxangle") local aimVec, shootPos = PlyM["GetAimVector"](ply), PlyM["GetShootPos"](ply) local targetBlocked = self:Setting("targetblocked") if self:Setting("holdtarget") then local target = self:GetTarget() if target then local targetPos = self:TargetPosition(target) local angle = self:AngleBetween(AngM["Forward"](self:GetView()), VecM["GetNormal"](targetPos - shootPos)) local blocked = self:TargetBlocked(target) if angle <= maxAng && (!blocked || targetBlocked) then return end end end // Filter out targets. local targets = ents.GetAll() for i, ent in pairs(targets) do if self:IsValidTarget(ent) == false then targets[i] = nil end end local closestTarget, lowestAngle = _, maxAng for _, target in pairs(targets) do if targetBlocked || !self:TargetBlocked(target) then local targetPos = self:TargetPosition(target) local angle = self:AngleBetween(AngM["Forward"](self:GetView()), VecM["GetNormal"](targetPos - shootPos)) if angle < lowestAngle then lowestAngle = angle closestTarget = target end end end self:SetTarget(closestTarget) end AA:AddHook("Think", "FindTarget") // ################################################## // Fake view // ################################################## AA.View = Angle(0, 0, 0) function AA:GetView() return self.View * 1 end function AA:KeepView() if !self:Enabled() then return end local ply = LocalPlayer() if !IsValid(ply) then return end self.View = EntM["EyeAngles"](ply) end AA:AddHook("OnToggled", "KeepView") local sensitivity = 0.022 function AA:RotateView(cmd) self.View.p = math.Clamp(self.View.p + (CmdM["GetMouseY"](cmd) * sensitivity), -89, 89) self.View.y = math.NormalizeAngle(self.View.y + (CmdM["GetMouseX"](cmd) * sensitivity * -1)) end AA:CreateSetting("debug", "Debug", false, {Show = false}) function AA:FakeView(ply, origin, angles, FOV) if !self:Enabled() && !self.SetAngleTo then return end if GetViewEntity() != LocalPlayer() then return end if self:Setting("debug") then return end local base = GAMEMODE:CalcView(ply, origin, self.SetAngleTo or self.View, FOV) or {} base.angles = base.angles or (self.AngleTo or self.View) base.angles.r = 0 // No crappy screen tilting in ZS. return base end AA:AddHook("CalcView", "FakeView") function AA:TargetPrediction(ply, target, targetPos) local weap = PlyM["GetActiveWeapon"](ply) if IsValid(weap) then local class = EntM["GetClass"](weap) if class == "weapon_crossbow" then local dist = VecM["Length"](targetPos - PlyM["GetShootPos"](ply)) local time = (dist / 3500) + 0.05 // About crossbow bolt speed. targetPos = targetPos + (EntM["GetVelocity"](target) * time) end local mul = 0.0075 //targetPos = targetPos - (e["GetVelocity"](ply) * mul) end return targetPos end AA:AddHook("TargetPrediction", "TargetPrediction") // ################################################## // Aim // ################################################## function AA:SetAngle(ang) self.SetAngleTo = ang end AA:CreateSetting("smoothspeed", "Smooth aim speed (0 to disable)", 120, {Min = 0, Max = 360}) AA:CreateSetting("snaponfire", "Snap on fire", true) AA:CreateSetting("snapgrace", "Snap on fire grace", 0.5, {Min = 0, Max = 3, Places = 1}) AA.LastAttack = 0 function AA:SetAimAngles(cmd) self:RotateView(cmd) if !self:Enabled() && !self.SetAngleTo then return end local ply = LocalPlayer() if !IsValid(ply) then return end // We're aiming with the view, normally. local targetAim = self:GetView() // If we have a target, aim at them! local target = self:GetTarget() if target then local targetPos = self:TargetPosition(target) targetAim = VecM["Angle"](targetPos - ply:GetShootPos()) end // We're following the view, until we fire. if self:Setting("snaponfire") then local time = CurTime() if PlyM["KeyDown"](ply, IN_ATTACK) || PlyM["KeyDown"](ply, IN_ATTACK2) || self:Setting("autoshoot") != 0 then self.LastAttack = time end if CurTime() - self.LastAttack > self:Setting("snapgrace") then targetAim = self:GetView() end end // We want to change to whatever was SetAngle'd. if self.SetAngleTo then targetAim = self.SetAngleTo end // Smooth aiming. local smooth = self:Setting("smoothspeed") if smooth > 0 then local current = CmdM["GetViewAngles"](cmd) // Approach the target angle. current = self:ApproachAngle(current, targetAim, smooth * FrameTime()) current.r = 0 // If we're just following the view, we don't need to smooth it. if self.RevertingAim then local diff = self:NormalizeAngle(current - self:GetView()) if math.abs(diff.p) < 1 && math.abs(diff.y) < 1 then self.RevertingAim = false end elseif targetAim == self:GetView() then current = targetAim end // Check if the angles are the same... if self.SetAngleTo then local diff = self:NormalizeAngle(current - self.SetAngleTo) if math.abs(diff.p) < 1 && math.abs(diff.y) < 1 then self.SetAngleTo = nil end end aim = current else aim = targetAim self.SetAngleTo = nil end // Set the angles. CmdM["SetViewAngles"](cmd, aim) local sensitivity = 0.22 local diff = aim - CmdM["GetViewAngles"](cmd) CmdM["SetMouseX"](cmd, diff.y / sensitivity) CmdM["SetMouseY"](cmd, diff.p / sensitivity) // Change the players movement to be relative to their view instead of their aim. local move = Vector(CmdM["GetForwardMove"](cmd), CmdM["GetSideMove"](cmd), 0) local norm = VecM["GetNormal"](move) local set = AngM["Forward"](VecM["Angle"](norm) + (aim - self:GetView())) * VecM["Length"](move) CmdM["SetForwardMove"](cmd, set.x) CmdM["SetSideMove"](cmd, set.y) end AA:AddHook("CreateMove", "SetAimAngles") function AA:RevertAim() self.RevertingAim = true end AA:AddHook("TargetLost", "RevertAim") function AA:StopRevertAim() self.RevertingAim = false end AA:AddHook("TargetGained", "RevertAim") // When we turn off the bot, we want our aim to go back to our view. function AA:ViewToAim() if self:Enabled() then return end self:SetAngle(self:GetView()) end AA:AddHook("OnToggled", "ViewToAim") // ################################################## // HUD // ################################################## AA:CreateSetting("crosshair", "Crosshair size (0 to disable)", 18, {Min = 0, Max = 20}) function AA:DrawTarget() if !self:Enabled() then return end local target = self:GetTarget() if !target then return end local size = self:Setting("crosshair") if size <= 0 then return end // Change colour on the block status. local blocked, aimOff = self:TargetBlocked() if blocked then surface.SetDrawColor(255, 0, 0, 255) // Red. elseif aimOff then surface.SetDrawColor(255, 255, 0, 255) // Yellow. else surface.SetDrawColor(0, 255, 0, 255) // Green. end // Get the onscreen coordinates for the target. local pos = self:TargetPosition(target) local screen = VecM["ToScreen"](pos) local x, y = screen.x, screen.y // Work out sizes. local a, b = size / 2, size / 6 // Top left. surface.DrawLine(x - a, y - a, x - b, y - a) surface.DrawLine(x - a, y - a, x - a, y - b) // Bottom right. surface.DrawLine(x + a, y + a, x + b, y + a) surface.DrawLine(x + a, y + a, x + a, y + b) // Top right. surface.DrawLine(x + a, y - a, x + b, y - a) surface.DrawLine(x + a, y - a, x + a, y - b) // Bottom left. surface.DrawLine(x - a, y + a, x - b, y + a) surface.DrawLine(x - a, y + a, x - a, y + b) end AA:AddHook("HUDPaint", "DrawTarget") AA.ScreenMaxAngle = { Length = 0, FOV = 0, MaxAngle = 0 } AA:CreateSetting("draw_maxangle", "Draw Max Angle", true) function AA:DrawMaxAngle() if !self:Enabled() then return end // Check that we want to be drawing this... local show = AA:Setting("draw_maxangle") if !show then return end // We need a player for this to work... local ply = LocalPlayer() if !IsValid(ply) then return end local info = self.ScreenMaxAngle local maxang = AA:Setting("maxangle") local fov = PlyM["GetFOV"](ply) if GetViewEntity() == ply && (maxang != info.MaxAngle || fov != info.FOV) then local view = self:GetView() view.p = view.p + maxang local screen = (PlyM["GetShootPos"](ply) + (AngM["Forward"](view) * 100)) screen = VecM["ToScreen"](screen) info.Length = math.abs((ScrH() / 2) - screen.y) info.MaxAngle = maxang info.FOV = fov end local length = info.Length local cx, cy = ScrW() / 2, ScrH() / 2 for x = -1, 1 do for y = -1, 1 do if x != 0 || y != 0 then local add = VecM["GetNormal"](Vector(x, y, 0)) * length surface.SetDrawColor(0, 0, 0, 255) surface.DrawRect((cx + add.x) - 2, (cy + add.y) - 2, 5, 5) surface.SetDrawColor(255, 255, 255, 255) surface.DrawRect((cx + add.x) - 1, (cy + add.y) - 1, 3, 3) end end end end AA:AddHook("HUDPaint", "DrawMaxAngle") // ################################################## // Auto-shoot // ################################################## AA.AttackDown = false function AA:SetShooting(bool) if self.AttackDown == bool then return end self.AttackDown = bool local pre = {[true] = "+", [false] = "-"} RunConsoleCommand(pre[bool] .. "attack") end AA.NextShot = 0 AA:CreateSetting("autoshoot", "Max auto-shoot distance (0 to disable)", 0, {Min = 0, Max = 16384}) function AA:Shoot() if !self:Enabled() then self:SetShooting(false) return end // Get the maximum distance. local maxDist = self:Setting("autoshoot") if maxDist == 0 then return end // Check we've got something to shoot at... local target = self:GetTarget() if !target then return end // Don't shoot until we can hit, you idiot! local blocked, wrongAim = self:TargetBlocked(target) if blocked || wrongAim then return end // We're gonna need the player object in a second. local ply = LocalPlayer() if !IsValid(ply) then return end // Check we're within our maximum distance. local targetPos = self:TargetPosition(target) local distance = VecM["Length"](targetPos - ply:GetShootPos()) if distance > maxDist && maxDist != -1 then return end // Check if it's time to shoot yet. if CurTime() < self.NextShot then return end // Check we got our weapon. local weap = PlyM["GetActiveWeapon"](ply) if !IsValid(weap) then return end // Shoot! self:SetShooting(true) // If we're semi-auto, we want to stop holding down fire. if self:IsSemiAuto(weap) then timer.Simple(0.05, function() self:SetShooting(false) end) end // Set the next time to shoot. self.NextShot = CurTime() + 0.1 end AA:AddHook("Think", "Shoot") // When we lose our target we stop shooting. function AA:StopShooting() self:SetShooting(false) end AA:AddHook("TargetLost", "StopShooting") // ################################################## // Toggle // ################################################## AA.IsEnabled = false function AA:Enabled() return self.IsEnabled end function AA:SetEnabled(bool) if self.IsEnabled == bool then return end self.IsEnabled = bool local message = {[true] = "ON", [false] = "OFF"} print("AutoAim " .. message[self.IsEnabled]) local e = {[true] = "1", [false] = "0"} RunConsoleCommand("aa_enabled", e[self.IsEnabled]) self:CallHook("OnToggled") end function AA:Toggle() self:SetEnabled(!self:Enabled()) end concommand.Add("aa_toggle", function() AA:Toggle() end) AA:CreateSetting("enabled", "Enabled", false, {Save = false}) function AA:ConVarEnabled(_, old, val) if old == val then return end val = tonumber(val) or 0 self:SetEnabled(val > 0) end AA:AddCVarHook("aa_enabled", "ConVarEnabled") concommand.Add("+aa", function() AA:SetEnabled(true) end) concommand.Add("-aa", function() AA:SetEnabled(false) end) // ################################################## // Menu // ################################################## function AA:OpenMenu() local w, h = ScrW() / 3, ScrH() / 2 local menu = vgui.Create("DFrame") menu:SetTitle("AutoAim") menu:SetSize(w, h) menu:Center() menu:MakePopup() local scroll = vgui.Create("DPanelList", menu) scroll:SetPos(5, 25) scroll:SetSize(w - 10, h - 30) scroll:EnableVerticalScrollbar() local form = vgui.Create("DForm", menu) form:SetName("") form.Paint = function() end scroll:AddItem(form) self:BuildMenu(form) if AA.Menu then AA.Menu:Remove() end AA.Menu = menu end concommand.Add("aa_menu", function() AA:OpenMenu() end) function AA:RegisterMenu() spawnmenu.AddToolMenuOption("Options", "Hacks", "AutoAim", "AutoAim", "", "", function(p) self:BuildMenu(p) end) end AA:AddHook("PopulateToolMenu", "RegisterMenu") // ################################################## // Useful functions // ################################################## function AA:AngleBetween(a, b) return math.deg(math.acos(VecM["Dot"](a, b))) end function AA:NormalizeAngle(ang) return Angle(math.NormalizeAngle(ang.p), math.NormalizeAngle(ang.y), math.NormalizeAngle(ang.r)) end function AA:ApproachAngle(start, target, add) local diff = self:NormalizeAngle(target - start) local vec = Vector(diff.p, diff.y, diff.r) local len = VecM["Length"](vec) vec = VecM["GetNormal"](vec) * math.min(add, len) return start + Angle(vec.x, vec.y, vec.z) end local notAuto = {"weapon_pistol", "weapon_rpg", "weapon_357", "weapon_crossbow"} function AA:IsSemiAuto(weap) if !IsValid(weap) then return end return (weap.Primary && !weap.Primary.Automatic) || table.HasValue(notAuto, EntM["GetClass"](weap)) end