SA:MP Lua Evolve Умный бот на рыбалку + Автопродажа [Evolve RP]

lafro

Новичок
Автор темы
1
0
Версия SA-MP
  1. 0.3.7 (R1)
Представляю своего бота для рыбалки на Evolve RP. Скрипт не просто кликает по координатам, а читает диалоги, обходит серверные баги и может безопасно работать часами.
FISHERMAN MASTER 2000 GAME BOY RETRO STATION PRO MAX 8K ULTRA HD

🎣 Основной функционал:
Авто-ловля и копка:
Безошибочное прохождение мини-игры (текстдравы). Выбор наживки прямо в меню.
Интеллектуальная скупка: Автоматический запуск продажи в PayDay. Бот сам обходит баги сервера с весом (граммы/кг), не зависает на пустых слотах и моментально пропускает предметы, которые нельзя продать.


🛡 Безопасность и Имитация (Humanizer):
Защита от админов:
Остановка работы при проверках в /pm, слапе или телепорте (запоминает координаты).
Имитация игрока: Случайные микро-шаги (Анти-АФК), система случайных "перекуров" и авто-еда при голоде.
Связь со смартфоном: Управление ботом через Telegram (команды /status, /stop, /screen). При опасности бот делает скриншот и кидает его вам в Discord или ТГ.


⚙️ Управление и Требования:
Меню:
Клавиша Insert или команда /fishmenu (Mimgui интерфейс).
Ручная продажа: Команда /autosell.
Установка: Перекинуть файл lafro_fishbot.lua в папку moonloader.
Требования: MoonLoader 0.26.5+, библиотеки mimgui, samp.events, requests, vkeys, lfs, ffi.


📲 Как настроить уведомления (Telegram / Discord): Чтобы уведомления и скриншоты приходили лично вам, откройте файл lafro_fishbot.lua через любой текстовый редактор (например, Блокнот или Notepad++) и в самом начале кода (около 120-й строки) замените пустые значения в кавычках на свои:
Lua:
local webhookUrl = "ВАШ_ВЕБХУК" — вставьте сюда ссылку на Webhook вашего Discord-канала.
local tgToken = "ВАШ_ТОКЕН" — вставьте токен вашего бота (создается через @BotFather в ТГ).
local tgChatId = "ВАШ_ID" — ваш личный ID в Telegram (можно узнать через бота @getmyid_bot).

Делал этого бота чисто под свои нужды, чтобы не париться с фармом. Код не претендует на идеальность: тайминги и клики настраивал под свой монитор и пинг. Если у вас где-то промахивается или тупит — не ругайтесь.
MAIN:
script_name("Fisherman Master PRO")
script_author("l4fr0")

local sampev = require('lib.samp.events')
local vkeys = require('vkeys')
local requests = require('requests')
local imgui = require('mimgui')
local encoding = require('encoding')
local lfs = require('lfs')
local ffi = require('ffi')

encoding.default = 'CP1251'
local u8 = encoding.UTF8

-- Идеальная функция для скрытого Discord
ffi.cdef([[
   int ShellExecuteA(void* hwnd, const char* lpOperation, const char* lpFile, const char* lpParameters, const char* lpDirectory, int nShowCmd);
]])

-- ================= КАСТОМНЫЙ ДИЗАЙН ИНТЕРФЕЙСА =================
imgui.OnInitialize(function()
   local style = imgui.GetStyle()
   local colors = style.Colors
   style.WindowRounding = 8.0; style.FrameRounding = 5.0; style.PopupRounding = 5.0; style.ScrollbarRounding = 5.0; style.GrabRounding = 5.0
   style.WindowPadding = imgui.ImVec2(12, 12); style.ItemSpacing = imgui.ImVec2(8, 8)
   colors[imgui.Col.WindowBg]           = imgui.ImVec4(0.08, 0.08, 0.10, 1.00)
   colors[imgui.Col.TitleBg]            = imgui.ImVec4(0.12, 0.12, 0.14, 1.00)
   colors[imgui.Col.TitleBgActive]      = imgui.ImVec4(0.35, 0.15, 0.55, 1.00)
   colors[imgui.Col.FrameBg]            = imgui.ImVec4(0.15, 0.15, 0.18, 1.00)
   colors[imgui.Col.FrameBgHovered]     = imgui.ImVec4(0.35, 0.15, 0.55, 0.50)
   colors[imgui.Col.FrameBgActive]      = imgui.ImVec4(0.40, 0.20, 0.60, 1.00)
   colors[imgui.Col.CheckMark]          = imgui.ImVec4(0.75, 0.40, 0.95, 1.00)
   colors[imgui.Col.Button]             = imgui.ImVec4(0.35, 0.15, 0.55, 1.00)
   colors[imgui.Col.ButtonHovered]      = imgui.ImVec4(0.45, 0.20, 0.70, 1.00)
   colors[imgui.Col.ButtonActive]       = imgui.ImVec4(0.55, 0.25, 0.80, 1.00)
   colors[imgui.Col.Header]             = imgui.ImVec4(0.35, 0.15, 0.55, 0.60)
   colors[imgui.Col.HeaderHovered]      = imgui.ImVec4(0.45, 0.20, 0.70, 0.80)
   colors[imgui.Col.HeaderActive]       = imgui.ImVec4(0.55, 0.25, 0.80, 1.00)
   colors[imgui.Col.Text]               = imgui.ImVec4(0.90, 0.90, 0.95, 1.00)
end)

-- ================= НАСТРОЙКИ СТАТУСОВ =================
local winState = imgui.new.bool(false)
local state = imgui.new.bool(false)
local wormsFarm = imgui.new.bool(false)
local slapperProtect = imgui.new.bool(true)
local pmProtect = imgui.new.bool(true)
local antiAfk = imgui.new.bool(false)
local autoEat = imgui.new.bool(true)
local enableSmoke = imgui.new.bool(false)
local isOnBreak = false
local enableAutoQuit = imgui.new.bool(false)
local autoQuitTime = imgui.new.int(60)
local quitTargetTime = 0

local selectedBait = imgui.new.int(0)
local baits = {u8"Наживка 1", u8"Наживка 2", u8"Наживка 3", u8"Наживка 4"}
local baits_ptr = imgui.new['const char*'][#baits](baits)

local webhookUrl = ""
local enableTelegram = imgui.new.bool(true)
local tgToken = ""
local tgChatId = ""
local lastTgUpdateId = 0

-- ОРИГИНАЛЬНЫЕ ПЕРЕМЕННЫЕ РЫБАЛКИ
local delay = 50
local startX, startY, startZ = 0.0, 0.0, 0.0
local fishCount = 0
local wormsCount = 0

-- Настройки Авто-Продажи
local autoSellPayday = imgui.new.bool(true)
local runSellCheckbox = imgui.new.bool(false)
local autoSellDelay = imgui.new.int(800)
local autoSellActive = false
local currentSellIndex = 1
local amountToSell = 0
local sellItemsList = {}

-- БРОНЕБОЙНАЯ СИСТЕМА ЗАЩИТЫ ОТ ПРОМАХОВ И ДВОЙНЫХ КЛИКОВ
local targetDialogAction = nil
local dialogActionTimer = 0
local dialogSequence = 0
local errorDebounceTime = 0

local pendingAltPress = false
local lastAltPress = 0
local autoSellAttempts = 0
local dialogClosedTimer = nil

local taskQueue = {}
local function enqueueTask(func) table.insert(taskQueue, func) end

local cmdStartFish = false
local cmdStartWorms = false
local cmdStartAutoSell = false
local cmdTestDiscord = false
local cmdTestTelegram = false

local sellItemsConfig = {
   imgui.new.bool(false), imgui.new.bool(false), imgui.new.bool(false), imgui.new.bool(false),
   imgui.new.bool(true),  imgui.new.bool(false), imgui.new.bool(true),  imgui.new.bool(false),
   imgui.new.bool(true),  imgui.new.bool(false), imgui.new.bool(false), imgui.new.bool(true),
   imgui.new.bool(true),  imgui.new.bool(true),  imgui.new.bool(false), imgui.new.bool(false)
}

-- ИДЕАЛЬНЫЙ ПОИСКОВИК
local matchKeywords = {
   "Окунь", "Форель", "Горбуша", "Сом",
   "Палтус", "Осётр", "Желтопёрый", "Блюфин",
   "Золотая", "Сломанная", "Кости", "Мусор",
   "Ящик", "Жемчуг", "Маленькие", "Большие"
}

local itemLabels = {
   "1. Окунь", "2. Форель", "3. Горбуша", "4. Сом",
   "5. Палтус", "6. Осётр", "7. Желтопёрый тунец", "8. Тунец Блюфин",
   "9. Золотая рыбка", "10. Сломанная удочка", "11. Кости рыбы", "12. Мусор",
   "13. Ящик старых инструментов", "14. Жемчуг", "15. Маленькие металл. детали", "16. Большие металл. детали"
}

function msg(v) return sampAddChatMessage('{D5C5DB}<= FishMaster => :{C987E6} '..v, -1) end
function drawDesc(text) imgui.TextColored(imgui.ImVec4(0.60, 0.60, 0.65, 1.0), text) end

function sendTelegramMessage(text)
   if enableTelegram[0] and tgToken ~= "" and tgChatId ~= "" then
       lua_thread.create(function()
           local safeText = u8(text):gsub('"', '\\"'):gsub('\n', '\\n')
           pcall(function() requests.post(string.format("https://api.telegram.org/bot%s/sendMessage", tgToken), {headers = { ['Content-Type'] = 'application/json; charset=utf-8' }, data = string.format('{"chat_id": "%s", "text": "%s", "parse_mode": "Markdown"}', tgChatId, safeText)}) end)
       end)
   end
end

function sendDiscordPhoto(filePath, messageText)
   if webhookUrl ~= "" then
       lua_thread.create(function()
           local params = string.format('-F "payload_json={\\"content\\": \\"%s\\"}" -F "file=@\\"%s\\"" "%s"', messageText, filePath, webhookUrl)
           pcall(function() ffi.C.ShellExecuteA(nil, "open", "curl.exe", params, nil, 0) end)
       end)
   end
end

function sendDiscordWebhook(text)
   if webhookUrl ~= "" then
       lua_thread.create(function()
           pcall(function() requests.post(webhookUrl, {headers = { ['Content-Type'] = 'application/json; charset=utf-8' }, data = string.format('{"content": "%s"}', u8(text))}) end)
       end)
   end
end

function triggerAlarm(reason)
   state[0] = false; wormsFarm[0] = false; msg("{FF0000}[!] ВНИМАНИЕ! " .. reason)
   lua_thread.create(function()
       setVirtualKeyDown(vkeys.VK_F8, true); wait(50); setVirtualKeyDown(vkeys.VK_F8, false); wait(1500)
       local screensPath = os.getenv("USERPROFILE") .. "\\Documents\\GTA San Andreas User Files\\Evolve\\screens\\"
       local latestFile = nil; local latestTime = -1
       pcall(function()
           for file in lfs.dir(screensPath) do
               if file:lower():match("%.jpg$") or file:lower():match("%.png$") then
                   local fullPath = screensPath .. file
                   local modTime = lfs.attributes(fullPath, "modification") or 0
                   if modTime >= latestTime then latestTime = modTime; latestFile = fullPath end
               end
           end
       end)
       if latestFile then sendDiscordPhoto(latestFile, "[!] ТРЕВОГА! " .. reason) else sendDiscordWebhook("[!] ТРЕВОГА! " .. reason) end
   end)
   sendTelegramMessage("[!] ТРЕВОГА! " .. reason)
end

function startAutoSellProcess()
   if autoSellActive then return end
   sellItemsList = {}
   for i, st in ipairs(sellItemsConfig) do if st[0] then table.insert(sellItemsList, i - 1) end end
  
   if #sellItemsList > 0 then
       autoSellActive = true
       runSellCheckbox[0] = true
       currentSellIndex = 1
       amountToSell = 0
       autoSellAttempts = 0
       targetDialogAction = nil
       lastAltPress = os.clock()
       msg("[*] Интеллектуальная авто-продажа запущена...")
       pendingAltPress = true
   else
       runSellCheckbox[0] = false
       msg("{FF0000}[ERROR] Авто-продажа отменена: не выбрано ни одного предмета.")
   end
end

-- ЕДИНЫЙ ЦЕНТР ОБРАБОТКИ ОШИБОК (Двигает список вперед)
local function handleSellError(reasonText)
   if os.clock() - errorDebounceTime < 1.5 then return end
   errorDebounceTime = os.clock()
  
   msg("[*] Пропуск: " .. reasonText)
   currentSellIndex = currentSellIndex + 1
   amountToSell = 0
   targetDialogAction = nil
  
   if sampIsDialogActive() then
       sampCloseCurrentDialogWithButton(0)
   end
  
   if currentSellIndex <= #sellItemsList then
       pendingAltPress = true
   else
       autoSellActive = false
       runSellCheckbox[0] = false
       msg("[OK] Авто-продажа завершена (остальные предметы закончились)!")
   end
end

function sendKey()
   setGameKeyState(16, 8)
   wait(delay)
   setGameKeyState(16, 0)
end

-- ================= ОТРИСОВКА ИНТЕРФЕЙСОВ =================
imgui.OnFrame(function() return winState[0] or state[0] or wormsFarm[0] end, function(player)
   if winState[0] then
       imgui.SetNextWindowPos(imgui.ImVec2(500, 300), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
       imgui.SetNextWindowSize(imgui.ImVec2(500, 850), imgui.Cond.FirstUseEver)
       imgui.Begin(u8"Fisherman Master PRO | Evolve RP", winState)
      
       if imgui.Checkbox(u8"Запустить РЫБАЛКУ", state) then if state[0] then cmdStartFish = true end end
       imgui.SameLine(220)
       if imgui.Checkbox(u8"Запустить ЧЕРВЕЙ", wormsFarm) then if wormsFarm[0] then cmdStartWorms = true end end

       imgui.Separator()
       if imgui.CollapsingHeader(u8"Отдел: Авто-Продажа (PayDay)", imgui.TreeNodeFlags.DefaultOpen) then
           imgui.Checkbox(u8"Включить перехват PayDay (Авто-старт)", autoSellPayday)
          
           if imgui.Checkbox(u8"Скупки", runSellCheckbox) then
               if runSellCheckbox[0] then cmdStartAutoSell = true else autoSellActive = false; msg("[OK] Авто-продажа остановлена.") end
           end
          
           imgui.SliderInt(u8"Задержка кликов (мс)", autoSellDelay, 100, 2000)
          
           imgui.TextColored(imgui.ImVec4(1.0, 0.8, 0.2, 1.0), u8"Выберите предметы для автоматической продажи:")
           imgui.Columns(2, "sell_columns", false)
           for i = 1, #itemLabels do
               imgui.Checkbox(u8(itemLabels[i]), sellItemsConfig[i])
               if i == 8 then imgui.NextColumn() end
           end
           imgui.Columns(1)
       end

       if imgui.CollapsingHeader(u8"Отдел: Защита от Администрации") then
           imgui.Checkbox(u8"Остановка при Слапе / Телепорте", slapperProtect)
           imgui.Checkbox(u8"Остановка при проверке в /pm", pmProtect)
           if imgui.Button(u8"Тестовое сообщение в Discord", imgui.ImVec2(-1, 25)) then cmdTestDiscord = true end
       end

       if imgui.CollapsingHeader(u8"Отдел: Telegram Уведомления") then
           imgui.Checkbox(u8"Включить Telegram-уведомления", enableTelegram)
           if imgui.Button(u8"Тест сообщения в Telegram", imgui.ImVec2(-1, 25)) then cmdTestTelegram = true end
       end

       if imgui.CollapsingHeader(u8"Отдел: Имитация человека") then
           imgui.Checkbox(u8"Анти-АФК (Медленный шаг)", antiAfk)
           imgui.Checkbox(u8"Авто-питание при голоде", autoEat)
           imgui.Checkbox(u8"Система Перекуров", enableSmoke)
       end

       if imgui.CollapsingHeader(u8"Отдел: Авто-выход") then
           if imgui.Checkbox(u8"Включить выход по таймеру (/q)", enableAutoQuit) then if enableAutoQuit[0] then quitTargetTime = os.time() + (autoQuitTime[0] * 60) end end
           if imgui.SliderInt(u8"Минут до выхода", autoQuitTime, 1, 300) then if enableAutoQuit[0] then quitTargetTime = os.time() + (autoQuitTime[0] * 60) end end
       end
      
       imgui.Separator()
       imgui.Combo(u8"Выбор наживки", selectedBait, baits_ptr, #baits)
       imgui.End()
   end

   if state[0] or wormsFarm[0] then
       local resX, resY = getScreenResolution()
       imgui.SetNextWindowPos(imgui.ImVec2(resX - 200, resY - 140), imgui.Cond.Always)
       imgui.PushStyleColor(imgui.Col.WindowBg, imgui.ImVec4(0.1, 0.1, 0.1, 0.6))
       imgui.PushStyleColor(imgui.Col.Border, imgui.ImVec4(0, 0, 0, 0))
       imgui.Begin("##HUD", nil, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoMove + imgui.WindowFlags.AlwaysAutoResize)
       imgui.Text(u8"FishMaster HUD")
       imgui.Separator()
       if isOnBreak then imgui.TextColored(imgui.ImVec4(1.0, 1.0, 0.0, 1.0), u8"Статус: ПЕРЕКУР")
       elseif state[0] then imgui.TextColored(imgui.ImVec4(0.0, 1.0, 0.0, 1.0), u8"Статус: ЛОВИТ РЫБУ")
       elseif wormsFarm[0] then imgui.TextColored(imgui.ImVec4(0.0, 1.0, 0.0, 1.0), u8"Статус: КОПАЕТ ЧЕРВЕЙ") end
       imgui.Text(u8"Рыбы поймано: " .. fishCount)
       imgui.Text(u8"Червей выкопано: " .. wormsCount)
       imgui.End()
       imgui.PopStyleColor(2)
   end
end)

-- ================= ОСНОВНЫЕ ПОТОКИ =================
function main()
   while not isSampAvailable() do wait(0) end
   msg('Скрипт загружен. Клавиша Insert - меню.')
  
   sampRegisterChatCommand('fishmenu', function() winState[0] = not winState[0] end)
   sampRegisterChatCommand('autosell', function() cmdStartAutoSell = true end)

   lua_thread.create(function()
       while true do wait(0) if #taskQueue > 0 then local func = table.remove(taskQueue, 1); pcall(func) end end
   end)

   lua_thread.create(function()
       while true do wait(0) if wasKeyPressed(vkeys.VK_INSERT) and not sampIsChatInputActive() and not isSampfuncsConsoleActive() then winState[0] = not winState[0] end end
   end)

   lua_thread.create(function()
       local tgUpdateFile = getWorkingDirectory() .. "\\tg_updates.json"
       while true do
           wait(3000)
           if enableTelegram[0] and tgToken ~= "" then
               local url = string.format("https://api.telegram.org/bot%s/getUpdates?offset=%d", tgToken, lastTgUpdateId + 1)
               pcall(function()
                   downloadUrlToFile(url, tgUpdateFile, function(id, status)
                       if status == 6 then
                           local f = io.open(tgUpdateFile, "r")
                           if f then
                               local text = f:read("*a"); f:close(); pcall(os.remove, tgUpdateFile)
                               if text then
                                   for updateId, msgText in text:gmatch('"update_id":(%d+).-"text":"([^"]+)"') do
                                       local currentId = tonumber(updateId)
                                       if currentId > lastTgUpdateId then
                                           lastTgUpdateId = currentId; msgText = msgText:match("^%s*(.-)%s*$")
                                           if msgText == "/start" then sendTelegramMessage("[*] Fisherman Master PRO\n\nПривет! Бот успешно подключен.")
                                           elseif msgText == "/status" then sendTelegramMessage(string.format("[*] Статус бота:\n• Рыбы поймано: %d\n• Червей выкопано: %d", fishCount, wormsCount))
                                           elseif msgText == "/stop" then state[0] = false; wormsFarm[0] = false; sendTelegramMessage("[!] Бот остановлен!")
                                           elseif msgText == "/screen" then
                                               sendTelegramMessage("[*] Запрос получен! Делаю скриншот...")
                                               lua_thread.create(function()
                                                   setVirtualKeyDown(vkeys.VK_F8, true); wait(50); setVirtualKeyDown(vkeys.VK_F8, false); wait(1500)
                                                   local screensPath = os.getenv("USERPROFILE") .. "\\Documents\\GTA San Andreas User Files\\Evolve\\screens\\"
                                                   local latestFile = nil; local latestTime = -1
                                                   pcall(function() for file in lfs.dir(screensPath) do if file:lower():match("%.jpg$") or file:lower():match("%.png$") then local attr = lfs.attributes(screensPath .. file); if attr and attr.modification >= latestTime then latestTime = attr.modification; latestFile = screensPath .. file end end end end)
                                                   if latestFile then sendDiscordPhoto(latestFile, "Скриншот запрошен из Telegram:"); sendTelegramMessage("[OK] Отправлен в Discord!") else sendTelegramMessage("[ERROR] Не удалось найти скрин.") end
                                               end)
                                           end
                                       end
                                   end
                               end
                           end
                       end
                   end)
               end)
           end
       end
   end)

   -- ГЛАВНЫЙ БЕЗОПАСНЫЙ ПОТОК
   while true do
       wait(0)
      
       -- СИНХРОНИЗИРОВАННОЕ НАЖАТИЕ ALT
       if pendingAltPress then
           pendingAltPress = false
           targetDialogAction = nil
           lua_thread.create(function()
               wait(500)
               if sampIsDialogActive() then sampCloseCurrentDialogWithButton(0); wait(300) end
               setVirtualKeyDown(vkeys.VK_LMENU, true)
               wait(150)
               setVirtualKeyDown(vkeys.VK_LMENU, false)
               lastAltPress = os.clock()
           end)
       end

       -- СИНХРОНИЗИРОВАННЫЙ ОТВЕТ НА ДИАЛОГ
       if targetDialogAction and os.clock() >= dialogActionTimer then
           local action = targetDialogAction
           targetDialogAction = nil
           if dialogSequence == action.seq and sampIsDialogActive() and sampGetCurrentDialogId() == action.id then
               if action.actionType == "close" then
                   sampCloseCurrentDialogWithButton(action.button)
               else
                   sampSendDialogResponse(action.id, action.button, action.list, action.input)
               end
           end
       end
      
       if cmdStartFish then cmdStartFish = false; if isCharDead(PLAYER_PED) then state[0] = false; msg("{FF0000}Ошибка: Вы не заспавнены!") else startX, startY, startZ = getCharCoordinates(PLAYER_PED); sampSendChat('/fish') end end
       if cmdStartWorms then cmdStartWorms = false; sampSendChat('/mfish') end
       if cmdStartAutoSell then cmdStartAutoSell = false; startAutoSellProcess() end
       if cmdTestDiscord then cmdTestDiscord = false; sendDiscordWebhook("[TEST] Тест связи: Discord работает!"); msg("Тестовое сообщение отправлено в Discord.") end
       if cmdTestTelegram then cmdTestTelegram = false; sendTelegramMessage("[TEST] Тест связи: Telegram работает!"); msg("Тестовое сообщение отправлено в Telegram.") end

       if autoSellActive then
           if not sampIsDialogActive() and amountToSell == 0 and not pendingAltPress and not targetDialogAction then
               if not dialogClosedTimer then
                   dialogClosedTimer = os.clock()
               elseif os.clock() - dialogClosedTimer > 1.5 then
                   if os.clock() - lastAltPress > 4.0 then
                       if autoSellAttempts >= 3 then
                           autoSellActive = false; runSellCheckbox[0] = false; msg("{FF0000}[ERROR] Скупщик не отвечает. Авто-продажа остановлена.")
                       else
                           autoSellAttempts = autoSellAttempts + 1; msg("[*] Меню пропало. Пытаюсь открыть снова..."); pendingAltPress = true
                       end
                   end
               end
           else
               dialogClosedTimer = nil
           end
       else
           dialogClosedTimer = nil
           autoSellAttempts = 0
           targetDialogAction = nil
       end

       if enableAutoQuit[0] and quitTargetTime > 0 and (state[0] or wormsFarm[0]) then
           if os.time() >= quitTargetTime then sampSendChat("/q"); os.exit() end
       end

       if state[0] then
           if slapperProtect[0] and not isOnBreak then
               if not isCharDead(PLAYER_PED) then
                   local curX, curY, curZ = getCharCoordinates(PLAYER_PED)
                   if math.sqrt((curX - startX)^2 + (curY - startY)^2 + (curZ - startZ)^2) > 3.5 then triggerAlarm("Подозрение на ТП/Слап!") end
               end
           end

           if minigameTd1 and minigameTd2 and sampTextdrawIsExists(minigameTd1) and sampTextdrawIsExists(minigameTd2) then
               local tx1, ty1 = sampTextdrawGetPos(minigameTd1)
               local tx2, ty2 = sampTextdrawGetPos(minigameTd2)
              
               if (ty1 - ty2) >= 0 then
                   sendKey()
               elseif (ty1 - ty2) < -0.5 then
                   setGameKeyState(16, 0)
                   delay = 400
               end
           else
               minigameTd1, minigameTd2 = nil, nil
               for id = 0, 2304 do
                   if sampTextdrawIsExists(id) then
                       local _, _, sizX, sizY = sampTextdrawGetBoxEnabledColorAndSize(id)
                       local model = sampTextdrawGetModelRotationZoomVehColor(id)
                       local _, outlinecolor = sampTextdrawGetOutlineColor(id)
                       if model == 19630 and sizX == 21 and sizY == 12 then minigameTd1 = id end
                       if outlinecolor == 4278190080 and sizX == 6 and sizY == 11 then minigameTd2 = id end
                       if minigameTd1 and minigameTd2 then break end
                   end
               end
           end
       end
   end
end

lua_thread.create(function()
   while true do
       wait(1000)
       if antiAfk[0] and (state[0] or wormsFarm[0]) and not isOnBreak then
           local waitTime = math.random(180, 360)
           for i = 1, waitTime do wait(1000); if not antiAfk[0] then break end end
           if antiAfk[0] then
               local keys = {vkeys.VK_W, vkeys.VK_A, vkeys.VK_S, vkeys.VK_D}
               local randKey = keys[math.random(1, 4)]
               setVirtualKeyDown(vkeys.VK_LMENU, true); wait(math.random(30, 80)); setVirtualKeyDown(randKey, true)
               wait(math.random(300, 600)); setVirtualKeyDown(randKey, false); wait(math.random(20, 50)); setVirtualKeyDown(vkeys.VK_LMENU, false)
           end
       end
   end
end)

lua_thread.create(function()
   while true do
       wait(1000)
       if enableSmoke[0] and (state[0] or wormsFarm[0]) and not isOnBreak then
           local nextBreak = math.random(2400, 3600)
           for i = 1, nextBreak do wait(1000); if not enableSmoke[0] or (not state[0] and not wormsFarm[0]) then break end end
           if enableSmoke[0] and (state[0] or wormsFarm[0]) then
               isOnBreak = true; wait(math.random(120000, 240000)); isOnBreak = false
               if state[0] then sampSendChat('/fish') end; if wormsFarm[0] then sampSendChat('/mfish') end
           end
       end
   end
end)

function sampev.onShowTextDraw(id, data)
   if not data or not data.text then return end
   if state[0] and not isOnBreak and data.text:match("SPACE") then
       lua_thread.create(function() delay = 50; sendKey() end)
   end
end

function sampev.onServerMessage(color, text)
   if not text then return end
   text = tostring(text)

   if pmProtect[0] and (text:find("Ответ в /b") or text:find("Вы тут")) then
       if state[0] or wormsFarm[0] then triggerAlarm("Проверка админом!") end
   end

   if autoSellPayday[0] and (text:find("PayDay") or text:find("Банковский чек") or text:find("Ежечасная выдача") or text:find("Оплата мобильной связи")) then
       cmdStartAutoSell = true
   end
  
   local cleanText = text:gsub("{%x%x%x%x%x%x}", ""):gsub("\r", "")
  
   -- БРОНЕБОЙНЫЙ ПЕРЕХВАТ ОШИБОК ИЗ ЧАТА (Ровно то, что выдает сервер)
   local isFailMsg = cleanText:find("У Вас нет такого предмета") or
                     cleanText:find("Вы указали неверное количество") or
                     cleanText:find("У Вас недостаточно такого предмета") or
                     cleanText:find("Необходимо минимум") or
                     cleanText:find("Данный предмет больше нельзя продать")

   if autoSellActive and isFailMsg then
       handleSellError("отказ сервера: " .. cleanText)
   end

   if state[0] then
       if text:find("Вы поймали .+") or text:find("Вам не удалось поймать") then
           if text:find("Вы поймали") then fishCount = fishCount + 1 end
           if not isOnBreak then lua_thread.create(function() wait(math.random(3500, 5500)); sampSendChat('/fish') end) end
       end
       if autoEat[0] and text:find("проголодал") then
           lua_thread.create(function() wait(2500); sampSendChat('/eat ' .. math.random(1, 3)) end)
       end
   end

   if wormsFarm[0] then
       if text:find("Вы выкопали") or text:find("Вам не удалось") or text:find("Пожалуйста, подождите") then
           if text:find("Вы выкопали") then wormsCount = wormsCount + 1 end
           if not isOnBreak then lua_thread.create(function() wait(math.random(3800, 4500)); sampSendChat('/mfish') end) end
       end
   end
end

function sampev.onShowDialog(id, style, title, button1, button2, text)
   if not title or not text then return end
   title = tostring(title)
   text = tostring(text)
  
   dialogSequence = dialogSequence + 1
   local currentSeq = dialogSequence
  
   local cleanTitle = title:gsub("{%x%x%x%x%x%x}", "")

   if state[0] and not isOnBreak then
       if cleanTitle:find("Удочка") then lua_thread.create(function() sampSendDialogResponse(id, 1, 0, '') end); return false end
       if cleanTitle:find("Наживка") and cleanTitle:find("Рыбалка") then lua_thread.create(function() sampSendDialogResponse(id, 1, selectedBait[0], '') end); return false end
   end
   if wormsFarm[0] and not isOnBreak then
       if cleanTitle:find("Меню | Рыбалка") or text:find("Накопать червей") then
           lua_thread.create(function() wait(150); sampSendDialogResponse(id, 1, 2, '') end)
           return false
       end
   end

   if autoSellActive then
      
       if style == 0 then
           local cleanTextForFail = text:gsub("{%x%x%x%x%x%x}", ""):gsub("\r", "")
           local isFailMsg = cleanTextForFail:find("У Вас нет такого предмета") or
                             cleanTextForFail:find("Вы указали неверное количество") or
                             cleanTextForFail:find("У Вас недостаточно такого предмета") or
                             cleanTextForFail:find("Необходимо минимум") or
                             cleanTextForFail:find("Данный предмет больше нельзя продать")
                            
           if isFailMsg then
               targetDialogAction = { id = id, button = 1, list = 0, input = "", seq = currentSeq, actionType = "close" }
               dialogActionTimer = os.clock() + 0.2
               handleSellError("ошибка в окне")
               return false
           end
       end

       if cleanTitle:find("Магазин") or cleanTitle:find("Рыбалка") or text:find("Продажа") or text:find("Окунь") then
           autoSellAttempts = 0
           lastAltPress = os.clock()
       end

       if cleanTitle:find("Магазин | Рыбалка") and text:find("Продажа предметов") and not text:find("Окунь") then
           local lines = {}
           for str in string.gmatch(text .. "\n", "(.-)\n") do
               local cleanStr = str:gsub("{%x%x%x%x%x%x}", ""):gsub("\r", "")
               table.insert(lines, cleanStr)
           end
          
           local lineIndex = 0
           local skipHeader = (style == 5)
          
           for _, line in ipairs(lines) do
               if skipHeader then skipHeader = false else
                   if line:find("Продажа предметов") then
                       targetDialogAction = { id = id, button = 1, list = lineIndex, input = "", seq = currentSeq, actionType = "respond" }
                       dialogActionTimer = os.clock() + (autoSellDelay[0] / 1000.0)
                       return
                   end
                   lineIndex = lineIndex + 1
               end
           end
       end
      
       -- СИСТЕМА СЛЕПОГО КЛИКА (Жмем без проверок цифр и ждем реакции сервера!)
       if cleanTitle:find("Магазин | Рыбалка") and text:find("Окунь") then
           local lines = {}
           for str in string.gmatch(text .. "\n", "(.-)\n") do
               local cleanStr = str:gsub("{%x%x%x%x%x%x}", ""):gsub("\r", "")
               table.insert(lines, cleanStr)
           end
          
           local dataLines = {}
           local skipHeader = (style == 5)
           for _, line in ipairs(lines) do
               if skipHeader then skipHeader = false else table.insert(dataLines, line) end
           end
          
           local nextItemFound = false
          
           while currentSellIndex <= #sellItemsList do
               local itemIndex = sellItemsList[currentSellIndex]
               local targetName = matchKeywords[itemIndex + 1]
               local listIndexToClick = -1
              
               for idx, line in ipairs(dataLines) do
                   if line:find(targetName) then
                       listIndexToClick = idx - 1
                       nextItemFound = true
                       break
                   end
               end
              
               if nextItemFound then
                   -- МЫ ПРОСТО КЛИКАЕМ! Если рыбы нет - сервер отпишет в чат и бот сам перейдет дальше.
                   targetDialogAction = { id = id, button = 1, list = listIndexToClick, input = "", seq = currentSeq, actionType = "respond" }
                   dialogActionTimer = os.clock() + (autoSellDelay[0] / 1000.0)
                   break
               else
                   currentSellIndex = currentSellIndex + 1
               end
           end
          
           if not nextItemFound then
               autoSellActive = false
               runSellCheckbox[0] = false
               targetDialogAction = { id = id, button = 0, list = 0, input = "", seq = currentSeq, actionType = "close" }
               dialogActionTimer = os.clock() + (autoSellDelay[0] / 1000.0)
               msg("[OK] Авто-продажа успешно завершена!")
           end
       end
      
       -- ПАРСИНГ ОКНА ВВОДА (Сюда дойдет, только если сервер разрешил продажу)
       if (style == 1 or style == 3) and autoSellActive then
           local cleanText = text:gsub("{%x%x%x%x%x%x}", ""):gsub("\r", "")
          
           local trueMax = cleanText:match("Вы можете продать:%s*(%d+)") or
                           cleanText:match("В инвентаре:%s*(%d+)") or
                           cleanText:match("Доступно:?%s*(%d+)") or
                           cleanText:match("В наличии:?%s*(%d+)")
          
           local inputAmount = 1
           if trueMax and tonumber(trueMax) > 0 then
               inputAmount = tonumber(trueMax)
           end
          
           targetDialogAction = { id = id, button = 1, list = 0, input = tostring(inputAmount), seq = currentSeq, actionType = "respond" }
           dialogActionTimer = os.clock() + (autoSellDelay[0] / 1000.0)
           amountToSell = 0
       end
   end
end
 

Вложения

  • lafro_fishbot.lua
    30.8 KB · Просмотры: 5
Последнее редактирование: