if not doesDirectoryExist('moonloader/config') then createDirectory('moonloader/config') end
local events = require 'lib.samp.events'
local keys = require 'lib.vkeys'
local state = false
local debugMode = false
local settings = {
max_distance = 85,
field_of_search = 3,
show_circle = true,
through_walls = false,
key_activation = 0x4A,
miss_ratio = 50
}
function convertSettingsToString(settings_table)
local output = ''
for k, v in pairs(settings_table) do
output = output .. k .. '=' .. tostring(v) .. ','
end
return output:sub(0, -2)
end
function convertStringToSettings(str)
local output = {}
for par in str:gmatch('[^,]+') do
local field, value = par:match('(.+)=(.+)')
if value == 'true' then value = true
elseif value == 'false' then value = false
else value = tonumber(value) end
output[field] = value
end
return output
end
function saveSettings(str)
local file = io.open('moonloader/config/hui.ini', 'w')
file:write(str)
file:close()
end
function loadSettings()
local file = io.open('moonloader/config/hui.ini', 'r')
settings = convertStringToSettings(file:read())
file:close()
end
function debugSay(msg)
if debugMode then sampAddChatMessage('[SHOT] ' .. msg, -1) end
end
if not doesFileExist('moonloader/config/hui.ini') then saveSettings( convertSettingsToString(settings) ) end
loadSettings()
local cx = representIntAsFloat(readMemory(0xB6EC10, 4, false))
local cy = representIntAsFloat(readMemory(0xB6EC14, 4, false))
local w, h = getScreenResolution()
local xc, yc = w * cy, h * cx
function getpx()
return ((w / 2) / getCameraFov()) * settings.field_of_search
end
function canPedBeShot(ped)
local ax, ay, az = convertScreenCoordsToWorld3D(xc, yc, 0) -- getCharCoordinates(1)
local bx, by, bz = getCharCoordinates(ped)
return not select(1, processLineOfSight(ax, ay, az, bx, by, bz + 0.7, true, false, false, true, false, true, false, false))
end
function getcond(ped)
if settings.through_walls or isKeyDown(keys.VK_E) then return true
else return canPedBeShot(ped) end
end
function getDistanceFromPed(ped)
local ax, ay, az = getCharCoordinates(1)
local bx, by, bz = getCharCoordinates(ped)
return math.sqrt( (ax - bx) ^ 2 + (ay - by) ^ 2 + (az - bz) ^ 2 )
end
function getClosestPlayerFromCrosshair()
local R1, target = getCharPlayerIsTargeting(0)
local R2, player = sampGetPlayerIdByCharHandle(target)
if R2 then return player, target end
local minDist = getpx()
local closestId, closestPed = -1, -1
for i = 0, 999 do
local res, ped = sampGetCharHandleBySampPlayerId(i)
if res then
if getDistanceFromPed(ped) < settings.max_distance then
local xi, yi = convert3DCoordsToScreen(getCharCoordinates(ped))
local dist = math.sqrt( (xi - xc) ^ 2 + (yi - yc) ^ 2 )
if dist < minDist then
minDist = dist
closestId, closestPed = i, ped
end
end
end
end
return closestId, closestPed
end
function rand() return math.random(-50, 50) / 100 end
function getDamage(weap)
local damage = {
[22] = 8.25,
[23] = 13.2,
[24] = 46.200000762939,
[25] = 30,
[26] = 30,
[27] = 30,
[28] = 6.6,
[29] = 8.25,
[30] = 9.9,
[31] = 9.9000005722046,
[32] = 6.6,
[33] = 25,
[38] = 46.2
}
return (damage[weap] or 0) + math.random(1e9)/1e15
end
local shotindex = 0
function events.onSendBulletSync(data)
math.randomseed(os.clock())
if not state then return end
local weap = getCurrentCharWeapon(1)
if not getDamage(weap) then return end
local id, ped = getClosestPlayerFromCrosshair()
if id == -1 then return debugSay('В зоне FOV не было найдено игроков') end
local vmes = sampGetPlayerNickname(id) .. ' > ' .. math.floor(getDistanceFromPed(ped)) .. 'm > ' ..
math.floor(getCharSpeed(1) * 3) .. ' vs ' .. math.floor(getCharSpeed(ped) * 3) .. ' > '
if data.targetType == 1 then return debugSay(vmes .. 'Попадание без помощи аима') end
if math.random(1, 100) < settings.miss_ratio and not isKeyDown(keys.VK_E) then return debugSay(vmes .. 'Промах (вероятность промаха)') end
if not getcond(ped) then return debugSay(vmes .. 'Выстрел отменен (игрок за текстурами)') end
debugSay(vmes .. 'OK')
data.targetType = 1
local px, py, pz = getCharCoordinates( ped )
data.targetId = id
data.target = { x = px + rand(), y = py + rand(), z = pz + rand() }
data.center = { x = rand(), y = rand(), z = rand() }
lua_thread.create(function ()
wait(1)
sampSendGiveDamage(id, getDamage(weap), weap, 3)
end)
end
function showmenu()
local output = ' \t \n' ..
'Статус:\t' .. (state and '{FFFFFF}ON' or '{FFFFFF}OFF') .. '\n' ..
'Стрельба сквозь текстуры:\t' .. (settings.through_walls and '{1e00ff}ON' or '{FFFFFF}OFF') .. '\n' ..
'FOV:\t{1e00ff}' .. settings.field_of_search .. '{FFFFFF} градусов\n' ..
'Показывать FOV:\t' .. (settings.show_circle and '{FFFFFF}ON' or '{FFFFFF}OFF') .. '\n' ..
'Кнопка активации:\t{1e00ff}' .. keys.id_to_name(settings.key_activation) .. '\n' ..
'Лимит дистанции до куда аим работает:\t{1e00ff}' .. settings.max_distance .. '{FFFFFF} метров\n' ..
'Вероятность промаха:\t{1e00ff}' .. settings.miss_ratio .. '{FFFFFF} %\n' ..
'Информация о выстрелах:\t' .. (debugMode and '{FFFFFF}ON' or '{FFFFFF}OFF') .. '\n' ..
'Показать справку'
sampShowDialog(900, '{FF0000}Aim | Настройки', output, 'Выбрать', 'Закрыть', 5)
saveSettings( convertSettingsToString(settings) )
end
local faqtext = 'Данный аим имитирует выстрел по ближайшему к прицелу игроку.\n' ..
'Таким образом, достаточно просто стрелять хотя бы в ту сторону, где находится игрок.\n' ..
'Открыть меню настроек аима - /aim\nВключить/выключить аим - J (по умолчанию)\n\n' ..
'Подробная информация по всем настройкам:\n' ..
'Стрельба сквозь текстуры - позволяет стрелять в игроков сквозь текстуры. Есть и зажимной вариант (на клавишу "E")\n' ..
'FOV - зона вокруг прицела, в пределах которой будет производиться поиск игроков\n' ..
'Показывать FOV - отображает круг вокруг прицела, соответствующий FOV\n' ..
'Кнопка активации - настраивает кнопку для быстрого включения/выключения аима\n' ..
'Лимит дистанции - максимальное расстояние до игрока, в пределах которого работает аим\n' ..
'Вероятность промахов - Имитация промахов для предотвращения определения аима\n' ..
'Информация о выстрелах - показывает дистанцию, скорость и другие параметры, также можно командой /aimdebug\n' ..
'Все настройки сохраняются при перезаходе.\n' ..
'Стрельбу сквозь текстуры включать на свой страх и риск, можно в крайних случаях использовать зажимной вариант.'
function main()
while not isSampAvailable() do wait(0) end
sampRegisterChatCommand('aim', function ()
showmenu()
end)
sampRegisterChatCommand('aimdebug', function ()
debugMode = not debugMode
end)
local PI = 3.14159
while true do
wait(0)
if state and settings.show_circle and isKeyDown(2) and isCharOnFoot(1) and getDamage(getCurrentCharWeapon(1)) then
local px = getpx()
local step = px / 1e4
for i = 0, 6.28, step do
if
i > PI * 1.875 or i < PI * 0.125 or
i > PI * 0.875 and i < PI * 1.125 or
i > PI * 0.375 and i < PI * 0.625 or
i > PI * 1.375 and i < PI * 1.625
then
renderDrawBox(xc + math.cos(i) * px, yc + math.sin(i) * px, 3, 3, 0xFFD00000)
end
end
end
local res1, but1, list1 = sampHasDialogRespond(900)
if res1 and but1 == 1 then
if list1 == 0 then state = not state; showmenu() end
if list1 == 1 then settings.through_walls = not settings.through_walls; showmenu() end
if list1 == 2 then sampShowDialog(901, "{FF0000}Введите FOV", '', "ОК", "Закрыть", 1) end
if list1 == 3 then settings.show_circle = not settings.show_circle; showmenu() end
if list1 == 4 then sampShowDialog(902, "{FF0000}Введите кнопку активации", '', "ОК", "Закрыть", 1) end
if list1 == 5 then sampShowDialog(903, "{FF0000}Введите лимит дистанции", '', "ОК", "Закрыть", 1) end
if list1 == 6 then sampShowDialog(904, "{FF0000}Введите вероятность промаха", '', "ОК", "Закрыть", 1) end
if list1 == 7 then debugMode = not debugMode; showmenu() end
if list1 == 8 then sampShowDialog(905, "{FF0000}Aim | Справка", faqtext, "ОК") end
end
local res2, but2, list2, input2 = sampHasDialogRespond(901)
if res2 and but2 == 1 then
input2 = tonumber(input2)
if not input2 or input2 < 0 or input2 > 100 then
sampAddChatMessage('Введено неверное значение.', 0xAFAFAF)
else
settings.field_of_search = input2
end
showmenu()
end
if res2 and but2 == 0 then showmenu() end
local res3, but3, list3, input3 = sampHasDialogRespond(902)
if res3 and but3 == 1 then
local k = keys.name_to_id(input3)
if not k then
sampAddChatMessage('Введено некорректное название клавиши.', 0xAFAFAF)
else
settings.key_activation = k
end
showmenu()
end
if res3 and but3 == 0 then showmenu() end
local res4, but4, list4, input4 = sampHasDialogRespond(903)
if res4 and but4 == 1 then
input4 = tonumber(input4)
if not input4 or input4 < 0 or input4 > 1000 then
sampAddChatMessage('Введено неверное значение.', 0xAFAFAF)
else
settings.max_distance = input4
end
showmenu()
end
if res4 and but4 == 0 then showmenu() end
local res5, but5, list5, input5 = sampHasDialogRespond(904)
if res5 and but5 == 1 then
input5 = tonumber(input5)
if not input5 or input5 < 0 or input5 > 100 then
sampAddChatMessage('Введено неверное значение.', 0xAFAFAF)
else
settings.miss_ratio = input5
end
showmenu()
end
if res5 and but5 == 0 then showmenu() end
local res6, but6, list6, input6 = sampHasDialogRespond(905)
if res6 then
showmenu()
end
if wasKeyPressed(settings.key_activation) and not (sampIsChatInputActive() or sampIsDialogActive()) then
state = not state
printStringNow(state and 'ON' or 'OFF', 500)
end
end
end