-- Maximum number of "snaps" before a player is given a warning. snaps_needed = 3 -- Max ping to check for aimbotters with. max_ping = 300 -- Maximum number of warnings before an action is taken on a player. warnings_needed = 3 -- Action can be kick, ban, or nil. -- After a players warnings go above the limit, the player can be kicked or banned -- which is determined here. If action is nil, then only players are notified and -- no action is taken. default_action = "ban" -- Should the server log when a person snaps and their total warnings? -- If this is true, it will log to AimbotWarnings.log logwarnings = true -- How long a person should be banned for if a players warnings go above the limit -- and the default action is ban. -- 0 is infinite. default_ban_time = 0 -- Should the player be notified that they have been suspected of aimbotting. notify_player = true -- Should admins be notified that a player has been suspected of aimbotting. notify_admins = true -- Should the server be notified that a player has been suspected of aimbotting. notify_server = true -- The maximum angle allowed for the player to be considered snapping. -- This is to weed out the player moving the mouse quickly and sporadically. -- Lowering this angle weeds out more accidents, but will not catch the snaps -- of bots from angles larger than this. 25 degrees seems to be the default -- maximum that a bot will snap. snap_max_angle = 25 -- The minimum angle allowed for the player to be considered snapping. -- This is to weed out normal movement of the mouse. -- Increasing this angle weeds out more accidents, but will not catch the snaps -- of bots that were in close proximity to the player. 20 degrees seems to weed -- out almost all non-botters. snap_min_angle = 20 -- The maximum angle allowed for the sudden stop of the snap. -- This is to weed out normal movement of the mouse. -- Decreasing this angle weeds out more accidents of the player suddenly stopping -- movement of the mouse, but will catch fewer snaps if the botter, or the target -- being botted is moving. 0.1 degrees seems to weed out most non-botters except -- for the occasional lag that happens. snap_stop_angle = 0.1 camera_table = {} watch_table = {} snap_table = {} warning_table = {} ------------------------------------------------- -- Called when a player has been suspected of aimbotting. -- This is called before the player has been tallied for snapping. -- The return value determines if the player should be tallied. -- Returning true tallies the player, returning false doesn't. function OnAimbotDetection(player) return true end function GetRequiredVersion() return 10057 end function OnScriptLoad(process) profile_path = getprofilepath() log_file = profile_path .. "\\logs\\AimbotWarnings.log" end function OnScriptUnload() end function OnNewGame(map) end function OnGameEnd(mode) end function OnServerChat(player, mode, msg) return 1 end function OnServerCommand(player, cmdline) return 1 end function OnTeamDecision(team) return team end function OnPlayerJoin(player, team) snap_table[player] = 0 warning_table[player] = 0 end function OnPlayerLeave(player, team) camera_table[player] = nil watch_table[player] = nil snap_table[player] = nil warning_table[player] = nil end function OnPlayerKill(killer, victim, mode) camera_table[victim] = nil watch_table[victim] = nil end function OnKillMultiplier(player, multiplier) end function OnPlayerSpawn(player, object) end function OnPlayerSpawnEnd(player, object) end function OnTeamChange(relevant, player, team, change) return 1 end function OnClientUpdate(player, object) local m_player = getplayer(player) if m_player == nil then return end local object = readdword(m_player, 0x34) local m_object = getobject(object) if m_object == nil then return end local camera_x = readfloat(m_object, 0x230) local camera_y = readfloat(m_object, 0x234) local camera_z = readfloat(m_object, 0x238) if camera_table[player] == nil then camera_table[player] = {camera_x, camera_y, camera_z} return end local last_camera_x = camera_table[player][1] local last_camera_y = camera_table[player][2] local last_camera_z = camera_table[player][3] camera_table[player] = {camera_x, camera_y, camera_z} if last_camera_x == 0 and last_camera_y == 0 and last_camera_z == 0 then return end local movement = math.sqrt( (camera_x - last_camera_x) ^ 2 + (camera_y - last_camera_y) ^ 2 + (camera_z - last_camera_z) ^ 2) local angle = math.acos((2 - movement ^ 2) / 2) angle = angle * 180 / math.pi if watch_table[player] ~= nil then watch_table[player] = nil if angle < snap_stop_angle then for i = 0, 15 do if IsLookingAt(player, i) then if OnAimbotDetection(player) then TallyPlayer(player) break end return end end end return end if angle > snap_min_angle and angle < snap_max_angle then watch_table[player] = true end end function OnObjectInteraction(player, object, tag_type, tag_name) return 1 end function OnWeaponReload(player, weapon) return 1 end function OnVehicleEntry(relevant, player, vehicle, tag_name, seat) return 1 end function OnVehicleEject(player, forced) return 1 end function OnDamageLookup(receiver, causer, tag_data, tag_name) end function OnWeaponAssignment(player, object, count, tag_name) return 0 end function OnObjectCreation(object, owner, tag_name) end function TallyPlayer(player) local player_ping = getping(player) if player_ping <= max_ping then if getplayer(player) == nil then return end if snap_table[player] == nil then snap_table[player] = 0 end snap_table[player] = snap_table[player] + 1 if snap_table[player] >= snaps_needed then snap_table[player] = 0 if warning_table[player] == nil then warning_table[player] = 0 end warning_table[player] = warning_table[player] + 1 if warning_table[player] >= warnings_needed then if default_action == "kick" then svcmd("sv_kick " .. resolveplayer(player)) if notify_player then privatesay(player, "You have been kicked for aimbotting.") end if notify_admins then for i = 0, 15 do if i ~= player then privatesay(i, getname(player) .. " has been kicked for aimbotting.") end end end if notify_server then for i = 0, 15 do if i ~= player then if not notify_admins and not isadmin(player) then privatesay(i, getname(player) .. " has been kicked for aimbotting.") end end end end return elseif default_action == "ban" then svcmd("sv_ban " .. resolveplayer(player) .. " " .. default_ban_time) if notify_player then privatesay(player, "You have been banned for aimbotting.") end if notify_admins then for i = 0, 15 do if i ~= player then privatesay(i, getname(player) .. " has been banned for aimbotting.") end end end if notify_server then for i = 0, 15 do if i ~= player then if not notify_admins and not isadmin(player) then privatesay(i, getname(player) .. " has been banned for aimbotting.") end end end end return end end if notify_player then privatesay(player, "You have been suspected of aimbotting. This is warning number " .. warning_table[player] .. ".") if default_action == "kick" then privatesay(player, "You have " .. (warnings_needed - warning_table[player]) .. " more warnings before you are kicked.") elseif default_action == "ban" then privatesay(player, "You have " .. (warnings_needed - warning_table[player]) .. " more warnings before you are banned.") end end if notify_admins then for i = 0, 15 do if i ~= player then privatesay(i, getname(player) .. " has been suspected of aimbotting. This is warning number " .. warning_table[player] .. ".") end end end if notify_server then for i = 0, 15 do if i ~= player then if not notify_admins and not isadmin(player) then privatesay(i, getname(player) .. " has been suspected of aimbotting. This is warning number " .. warning_table[player] .. ".") end end end end if logwarnings then local hash = gethash(player) local ping = getping(player) local name = getname(player) local line = "%s (%s) has snapped. (ping: %s)" line = string.format(line, name, hash, ping) WriteLog(log_file, line) end end end end function WriteLog(filename, value) local file = io.open(filename, "a") if file then local timestamp = os.date("!%m/%d/%Y %H:%M:%S") local line = string.format("%s\t%s\n", timestamp, tostring(value)) file:write(line) file:close() end end function getping(player) local m_player = getplayer(player) if not m_player then return nil end local ping = readword(m_player, 0xDC) return ping end function IsLookingAt(player1, player2) local m_player1 = getplayer(player1) local m_player2 = getplayer(player2) if m_player1 == nil or m_player2 == nil then return end local object1 = readdword(m_player1, 0x34) local object2 = readdword(m_player2, 0x34) local m_object1 = getobject(object1) local m_object2 = getobject(object2) if m_object1 == nil or m_object2 == nil then return end local camera_x = readfloat(m_object1, 0x230) local camera_y = readfloat(m_object1, 0x234) local camera_z = readfloat(m_object1, 0x238) local location1_x = readfloat(m_object1, 0x5C) local location1_y = readfloat(m_object1, 0x60) local location1_z = readfloat(m_object1, 0x64) local location2_x = readfloat(m_object2, 0x5C) local location2_y = readfloat(m_object2, 0x60) local location2_z = readfloat(m_object2, 0x64) local state1 = readbyte(m_object1, 0x2A7) local state2 = readbyte(m_object2, 0x2A7) if state1 == 2 then location1_z = location1_z + 0.6 elseif state1 == 3 then location1_z = location1_z + 0.3 else return end if state2 == 2 then location2_z = location2_z + 0.6 elseif state2 == 3 then location2_z = location2_z + 0.3 else return end local radius = math.sqrt( (location2_x - location1_x) ^ 2 + (location2_y - location1_y) ^ 2 + (location2_z - location1_z) ^ 2) local local_x = location2_x - location1_x local local_y = location2_y - location1_y local local_z = location2_z - location1_z local point_x = 1 / radius * local_x local point_y = 1 / radius * local_y local point_z = 1 / radius * local_z if math.round(camera_x, 1) == math.round(point_x, 1) and math.round(camera_y, 1) == math.round(point_y, 1) and math.round(camera_z, 1) == math.round(point_z, 1) then return true end return false end function math.round(number, place) local mult = 10 ^ (place or 0) return math.floor(number * mult + 0.5) / mult end