From 34569ce5dffd70020ff9f95ccfb10da4ca5e9ed9 Mon Sep 17 00:00:00 2001 From: rubin Date: Thu, 9 Feb 2023 00:02:00 +0300 Subject: [PATCH] fixed crashes --- mafia-tools.lua | 3525 ++++++++++++++++++++++++----------------------- 1 file changed, 1776 insertions(+), 1749 deletions(-) diff --git a/mafia-tools.lua b/mafia-tools.lua index addda1d..5dc95e6 100644 --- a/mafia-tools.lua +++ b/mafia-tools.lua @@ -1,1749 +1,1776 @@ -script_name('mafia-tools') -script_author("Serhiy_Rubin") -script_version("07.02.2023.1") - -sampev = require 'samp.events' -inicfg = require "inicfg" -dlstatus = require("moonloader").download_status -vkeys = require "vkeys" -live = 0 - -function main() - if not isSampLoaded() or not isSampfuncsLoaded() then return end - while not isSampAvailable() do wait(0) end - lua_thread.create(script_update.main) - repeat wait(0) until sampGetCurrentServerName() ~= "SA-MP" - repeat wait(0) until sampGetCurrentServerName():find("Samp%-Rp.Ru") or sampGetCurrentServerName():find("SRP") - local server = getSampRpServerName() - if server == "" then - thisScript():unload() - end - config.init() - lua_thread.create(timer_2min.loop) - lua_thread.create(ammo_timer.loop) - lua_thread.create(request.loop) - lua_thread.create(menu.loop) - lua_thread.create(mafia_checker.loop) - lua_thread.create(antiflood.loop) - lua_thread.create(invite_helper.loop) - lua_thread.create(get_guns.loop) - while true do - wait(0) - live = os.time() - end -end - --->> MENU DIALOG -menu = {} -menu.dialog = {} -menu.data = {} -menu.ffixcar_log = {} -menu.update = function() - - -->> Список блокировщика - local blacklist = {} - for k,v in pairs(config.data.list) do - blacklist[#blacklist+1] = { - title = k, - click = function(button, list, input , outs) - if button == 1 then - config.data.list[k] = nil - config.save(config.data) - addChatMessage(string.format("Вы удалили %s из списка!", k)) - end - menu.show = { true, "main" } - end - } - end - - -->> Обновление инфы от сервера - local players = getNicknamesOnline() - local count = 0 - local members = {} - for sender, sender_data in pairs(menu.data) do - count = count + 1 - members[#members+1] = { - title = string.format("%s\t", (players[sender] ~= nil and sender.."["..players[sender].."]" or sender)), - click = function(button, list, input, outs) - if button == 1 then - menu.show = { - true, - "members_user", - { - { - title = (config.data.list[sender] ~= nil and "Убрать из списка" or "Добавить в список"), - click = function(button, list, input , outs) - if button == 1 then - if config.data.list[sender] == nil then - config.data.list[sender] = true - addChatMessage(string.format("Вы добавли %s в список!", sender)) - else - config.data.list[sender] = nil - addChatMessage(string.format("Вы удалили %s из списка!", sender)) - end - config.save(config.data) - end - menu.show = { true, "members" } - end - }, - { - title = "{"..config.data.font.color1.."}".."Тайминги от пользователя:", - click = function(button, list, input , outs) - menu.show = { true, "members" } - end - }, - { - title = "{"..config.data.font.color1.."}"..">{FFFFFF} LS: "..sender_data["ls"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), - click = function(button, list, input , outs) - menu.show = { true, "members" } - end - }, - { - title = "{"..config.data.font.color1.."}"..">{FFFFFF} SF: "..sender_data["sf"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), - click = function(button, list, input , outs) - menu.show = { true, "members" } - end - }, - { - title = "{"..config.data.font.color1.."}"..">{FFFFFF} LV: "..sender_data["lv"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), - click = function(button, list, input , outs) - menu.show = { true, "members" } - end - }, - { - title = "{"..config.data.font.color1.."}"..">{FFFFFF} MHCARS: "..sender_data["mhcars"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), - click = function(button, list, input , outs) - menu.show = { true, "members" } - end - }, - } - } - else - menu.show = { true, "main" } - end - end - } - end - - -->> Список слов для открытия склада - local warelock_text = {} - warelock_text[#warelock_text+1] = { - title = ">> Добавить строку", - click = function(button, list, input, outs) - if button == 1 then - menu.show = { true, "edit", function(button, list, input, outs) - if button == 1 then - if #input > 0 then - local arr = split(input, " ") - if arr[1] ~= nil then - config.data.get_guns.warelock_text[#config.data.get_guns.warelock_text+1] = arr[1] - config.save(config.data) - end - end - end - menu.show = { true, "warelock_auto" } - end, "", "Введите слово для открытия склада!"} - else - menu.show = { true, "main" } - end - end - } - for i = 1, #config.data.get_guns.warelock_text do - warelock_text[#warelock_text+1] = { - title = config.data.get_guns.warelock_text[i], - click = function(button, list, input, outs) - if button == 1 then - table.remove(config.data.get_guns.warelock_text, i) - config.save(config.data) - menu.show = { true, "warelock_auto" } - else - menu.show = { true, "main" } - end - end - } - end - - menu.dialog = { - ["main"] = { - settings = {title = "mafia-tools" ,style = 4 ,btn1 = "Выбрать" ,btn2 = "Закрыть" ,forward = "{ffffff}" ,backwards = "\n" ,score = false}, - { - { -->> Синхронизация таймингов - title = "{"..config.data.font.color1.."}".."Синхронизация таймингов\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Комната - title = "{"..config.data.font.color1.."}"..">{ffffff} Комната\t"..config.data.room, - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "edit", function(button, list, input, outs) - if button == 1 then - if #input > 0 then - config.data.room = input - config.save(config.data) - end - end - menu.show = { true, "main" } - end, config.data.room, "Введите название комнаты!"} - end - }, - { -->> Участники - title = "{"..config.data.font.color1.."}"..">{ffffff} Участники комнаты\t"..count, - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "members" } - end - }, - { -->> Список блокировщика - title = "{"..config.data.font.color1.."}"..">{ffffff} Список блокировщика\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - if #blacklist > 0 then - menu.show = { true, "members_user", blacklist } - else - menu.show = { true, "main" } - end - end - }, - { -->> Использовать список как - title = "{"..config.data.font.color1.."}"..">{ffffff} Использовать список как:\t"..(config.data.list_block and "Черный список" or "Белый список"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.list_block = not config.data.list_block - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Разделитель - title = " \t ", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Настройки отображения - title = "{"..config.data.font.color1.."}".."Настройки отображения\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Рендер - title = "{"..config.data.font.color1.."}"..">{ffffff} Показать на экране\t"..(config.data.timer_hud.main and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.timer_hud.main = not config.data.timer_hud.main - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Показывать таймер mhcars - title = "{"..config.data.font.color1.."}"..">{ffffff} Показывать таймер mhcars\t"..(config.data.timer_hud.mhcars and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.timer_hud.mhcars = not config.data.timer_hud.mhcars - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Показывать таймер ffixcar - title = "{"..config.data.font.color1.."}"..">{ffffff} Показывать таймер ffixcar\t"..(config.data.timer_hud.ffixcar and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.timer_hud.ffixcar = not config.data.timer_hud.ffixcar - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Логи ffixcar - title = "{"..config.data.font.color1.."}"..">{ffffff} Логи /ffixcar\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - wait(100) - menu.show = { true, "ffixcar_log" } - end - }, - { -->> Смена позиции - title = "{"..config.data.font.color1.."}"..">{ffffff} Сменить позицию\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.timer_hud.main = true - ammo_timer.setpos = true - menu.show = { true, "main" } - end - }, - { -->> Разделитель - title = " \t ", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Mafia Checker - title = "{"..config.data.font.color1.."}".."Счетчик мафий на сервере и в стриме\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Рендер Mafia Checker - title = "{"..config.data.font.color1.."}"..">{ffffff} Показать на экране\t"..(config.data.mafia_checker.main and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.mafia_checker.main = not config.data.mafia_checker.main - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Позиция Mafia Checker - title = "{"..config.data.font.color1.."}"..">{ffffff} Сменить позицию\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.mafia_checker.main = true - mafia_checker.setpos = true - menu.show = { true, "main" } - end - }, - { -->> Разделитель - title = " \t ", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Invite Helper - title = "{"..config.data.font.color1.."}".."Инвайт хелпер\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Минимальный лвл - title = "{"..config.data.font.color1.."}"..">{ffffff} Минимальный уровень\t"..config.data.invite_helper.lvl, - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "edit", function(button, list, input, outs) - if button == 1 then - if #input > 0 and input:find("(%d+)") then - config.data.invite_helper.lvl = tonumber(input:match("(%d+)")) - config.save(config.data) - end - end - menu.show = { true, "main" } - end, config.data.invite_helper.lvl, "Введите минимальный уровень для инвайта!"} - end - }, - { -->> Авто ранг вкл выкл - title = "{"..config.data.font.color1.."}"..">{ffffff} Устанавливать ранг автоматически\t"..(config.data.invite_helper.auto_rank and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.invite_helper.auto_rank = not config.data.invite_helper.auto_rank - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Ранг по умолчанию - title = "{"..config.data.font.color1.."}"..">{ffffff} Установить ранг\t"..config.data.invite_helper.rank, - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "edit", function(button, list, input, outs) - if button == 1 then - if #input > 0 and input:find("(%d+)") then - config.data.invite_helper.rank = tonumber(input:match("(%d+)")) - config.save(config.data) - end - end - menu.show = { true, "main" } - end, config.data.invite_helper.rank, "Введите какой ранг давать после инвайта!"} - end - }, - { -->> Сообщение в чат после инвайта - title = "{"..config.data.font.color1.."}"..">{ffffff} Сообщение в рацию\t"..config.data.invite_helper.message, - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "edit", function(button, list, input, outs) - if button == 1 then - config.data.invite_helper.message = input - config.save(config.data) - end - menu.show = { true, "main" } - end, config.data.invite_helper.message, "{name} - Заменится на никнейм игрока которого приняли\nЧтобы не отправлять сообщение оставьте поле пустым!"} - end - }, - { -->> Клавиша инвайта - title = "{"..config.data.font.color1.."}"..">{ffffff} Инвайт по кнопке\tПрицел + "..config.data.invite_helper.key:gsub("VK_", ""), - click = function(button, list, input , outs) - if button ~= 1 then return end - wait(100) - local key = "" - repeat - wait(0) - if not sampIsDialogActive() then - sampShowDialog(222, "Смена активации", "Нажмите на любую клавишу", "Выбрать", "Закрыть", 0) - end - for k, v in pairs(vkeys) do - if wasKeyPressed(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" then - key = k - end - end - until key ~= "" - config.data.invite_helper.key = key - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Разделитель - title = " \t ", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Склад - title = "{"..config.data.font.color1.."}".."Склад\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "main" } - end - }, - { -->> Открывать склад по запросу в рацию - title = "{"..config.data.font.color1.."}"..">{ffffff} Открывать склад по запросу\t"..(config.data.get_guns.warelock_auto and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.get_guns.warelock_auto = not config.data.get_guns.warelock_auto - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Брать оружие сразу как откроют склад - title = "{"..config.data.font.color1.."}"..">{ffffff} Брать оружие сразу как откроют склад\t"..(config.data.get_guns.auto_get_guns and "вкл" or "выкл"), - click = function(button, list, input , outs) - if button ~= 1 then return end - config.data.get_guns.auto_get_guns = not config.data.get_guns.auto_get_guns - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Клавиша взятия ганов - title = "{"..config.data.font.color1.."}"..">{ffffff} Брать оружие по кнопке\t"..config.data.get_guns.key:gsub("VK_", ""), - click = function(button, list, input , outs) - if button ~= 1 then return end - wait(100) - local key = "" - repeat - wait(0) - if not sampIsDialogActive() then - sampShowDialog(222, "Смена активации", "Нажмите на любую клавишу", "Выбрать", "Закрыть", 0) - end - for k, v in pairs(vkeys) do - if wasKeyPressed(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" then - key = k - end - end - until key ~= "" - config.data.get_guns.key = key - config.save(config.data) - menu.show = { true, "main" } - end - }, - { -->> Список слов для запросов - title = "{"..config.data.font.color1.."}"..">{ffffff} Список запросов на открытие склада\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "warelock_auto" } - end - }, - { -->> Список оружия - title = "{"..config.data.font.color1.."}"..">{ffffff} Список оружия\t", - click = function(button, list, input , outs) - if button ~= 1 then return end - menu.show = { true, "get_guns" } - end - }, - } - }, - ["edit"] = { - settings = {title = "mafia-tools" ,style = 1 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, - { - text = menu.show[5], - { - click = function(button, list, input, outs) - menu.show[3](button, list, input, outs) - end - } - } - }, - ["members"] = { - settings = {title = "mafia-tools" ,style = 4 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, - members - }, - ["members_user"] = { - settings = {title = "mafia-tools" ,style = 2 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, - menu.show[3] - }, - ["ffixcar_log"] = { - settings = {title = "mafia-tools" ,style = 0 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = false}, - { - text = menu.ffixcar_log, - { - click = function(button, list, input, outs) - menu.show = { true, "main" } - end - } - } - }, - ["get_guns"] = { - settings = {title = "mafia-tools" ,style = 4 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, - { - { -->> Desert Eagle - title = "Desert Eagle\t"..config.data.get_guns.list[1][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[1][2] = config.data.get_guns.list[1][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> Shotgun - title = "Shotgun\t"..config.data.get_guns.list[2][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[2][2] = config.data.get_guns.list[2][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> SMG - title = "SMG\t"..config.data.get_guns.list[3][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[3][2] = config.data.get_guns.list[3][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> AK47 - title = "AK47\t"..config.data.get_guns.list[4][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[4][2] = config.data.get_guns.list[4][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> M4A1 - title = "M4A1\t"..config.data.get_guns.list[5][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[5][2] = config.data.get_guns.list[5][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> Rifle - title = "Rifle\t"..config.data.get_guns.list[6][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[6][2] = config.data.get_guns.list[6][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> Броня - title = "Броня\t"..config.data.get_guns.list[7][2], - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - config.data.get_guns.list[7][2] = config.data.get_guns.list[7][2] + 1 - config.save(config.data) - menu.show[1] = true - end - }, - { -->> Сброс - title = "Сброс\t", - click = function(button, list, input, outs) - if button ~= 1 then - menu.show = { true, "main" } - return - end - for i = 1, #config.data.get_guns.list do - config.data.get_guns.list[i][2] = 0 - end - config.save(config.data) - menu.show[1] = true - end - }, - } - }, - ["warelock_auto"] = { - settings = {title = "mafia-tools" ,style = 2 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = false}, - warelock_text - }, - } -end -menu.show = { false, "main" } -menu.put = "" -af_chat = 0 -menu.loop = function() - sampRegisterChatCommand('maf', function(param) - if #param > 0 then - if os.time() - af_chat < 60 then - addChatMessage("Не чаще чем раз в минуту!") - else - request.send[#request.send + 1] = { - key = "messages", - text = AnsiToUtf8(param) - } - request.wait = 0 - af_chat = os.time() - end - else - menu.show = { true, "main" } - end - end) - while true do - wait(0) - if menu.show[1] then - menu.show[1] = false - menu.update() - if menu.dialog[menu.show[2]] ~= nil then - wait(100) - start_dialog(menu.dialog[menu.show[2]], menu.show[4]) - end - end - end -end - --->> GET GUNS -get_guns = {} -get_guns.warehouse = false -get_guns.isCanOpen = false -get_guns.onServerMessage = function(color, message) - if message == "{FFFFFF} Вы можете использовать {00AB06}/getgun [ID игрока]{FFFFFF}, чтобы выдать оружие другим членам организации" then - if get_guns.getgun then - return true, false - end - end - if message == " Вы не на складе оружия своей организации / у вас нет доступа!" or message == " Склад закрыт" then - if get_guns.getgun then - get_guns.getgun = false - end - end - if message:find("^ Склад .+ %{C42100%}закрыт") or message == " Склад закрыт" then - get_guns.warehouse = false - if not get_guns.check_warehouse then - get_guns.check_warehouse = true - get_guns.check_warehouse_time = os.time() - return true, false - end - end - if message:find("^ Склад .+ %{00AB06%}открыт") or message == " Склад открыт" then - get_guns.warehouse = true - if not get_guns.check_warehouse then - get_guns.check_warehouse = true - get_guns.check_warehouse_time = os.time() - return true, false - end - end - if message == " Вам недоступна эта функция" then - if not get_guns.check_warehouse then - get_guns.check_warehouse = true - get_guns.check_warehouse_time = os.time() - return true, false - end - end - if message:find("^ %d+/%d+ Матов | %d+/%d+ Аптечек") and os.time() - get_guns.check_warehouse_time < 2 then - return true, false - end - if message:find("^ .+%[%d+%]: (.+)") then - get_guns.messages[#get_guns.messages+1] = message:match("^ .+%[%d+%]: (.+)") - end - if config.data.get_guns.auto_get_guns and get_guns.enter_textdraw and message:find("^ .+ открыл%(а%) склад с оружием$") and not message:find(getLocalPlayerNickname()) then - get_guns.start_get() - end - if message == " Броня уже 100%" and get_guns.getgun then - antiflood.send[#antiflood.send+1] = "/getgun" - end -end -get_guns.enter_textdrawId = -1 -get_guns.enter_textdraw = false -get_guns.onShowTextDraw = function(id, textdraw) - if textdraw.text:find("VEHICLE_ENTER_EXIT") then - get_guns.enter_textdrawId = id - get_guns.enter_textdraw = true - end -end -get_guns.onTextDrawHide = function(id) - if id == get_guns.enter_textdrawId then - get_guns.enter_textdrawId = -1 - get_guns.enter_textdraw = false - end -end -get_guns.onShowDialog = function(id, style, title, button1, button2, text) - if title == "Статистика персонажа" then - local frac, rank = text:match("Организация\t(.+).Ранг\tКонсильере.%[(.+)%]") - rank = rank:gsub("Лидер", "10") - rank = tonumber(rank) - config.data.stats.rank = rank - config.data.stats.frac = frac - config.save(config.data) - if not get_guns.check_stats then - get_guns.check_stats = true - get_guns.antiflood = os.time() - 28 - return true, false - end - end - if title == "Склад оружия" then - if get_guns.getgun then - if #get_guns.list > 0 then - sampSendDialogResponse(id,1,get_guns.list[1],"") - table.remove(get_guns.list, 1) - else - get_guns.getgun = false - end - return true, false - end - end -end -get_guns.weapon = {} -get_guns.onSendWeaponsUpdate = function(playerTarget, actorTarget, weapons) -- ганы при использовании - for i = 1, #weapons do - get_guns.weapon[weapons[i]["slot"]] = weapons[i]["ammo"] - if weapons[i]["ammo"] == 0 then - table.remove(get_guns.weapon, weapons[i]["slot"]) - end - end -end -get_guns.onResetPlayerWeapons = function() - get_guns.weapon = {} -end -get_guns.loop = function() - get_guns.antiflood = 0 - get_guns.check_stats = false - get_guns.check_warehouse = false - get_guns.check_warehouse_time = 0 - get_guns.warehouse = false - get_guns.getgun = false - get_guns.list = {} - get_guns.messages = {} - get_guns.warelock_send = {} - while true do - wait(0) - if not get_guns.check_stats then - if sampIsLocalPlayerSpawned() and os.time() - get_guns.antiflood > 30 then - get_guns.antiflood = os.time() - antiflood.send[#antiflood.send+1] = "/stats" - end - elseif not get_guns.check_warehouse then - if sampIsLocalPlayerSpawned() and os.time() - get_guns.antiflood > 30 then - get_guns.antiflood = os.time() - antiflood.send[#antiflood.send+1] = "/warehouse" - end - end - if get_guns.enter_textdraw and isKeyCanBePressed() and wasKeyPressed(vkeys[config.data.get_guns.key]) and not get_guns.getgun then - get_guns.start_get() - else - if wasKeyPressed(vkeys[config.data.get_guns.key]) and get_guns.getgun then - addChatMessage("Выполняется взятие ганов") - end - end - if #get_guns.messages > 0 then - if config.data.get_guns.warelock_auto and not get_guns.warehouse and config.data.stats.rank >= 8 then - local result = false - local text = split(get_guns.messages[1], " ") - for i = 1, #config.data.get_guns.warelock_text do - for p = 1, #text do - if text[p] == config.data.get_guns.warelock_text[i] then - result = true - end - end - end - if result then - local rand = math.random(1, 5) - get_guns.warelock_send = { - { os.time() + rand, false }, - { os.time() + config.data.get_guns.warelock_time + rand, true } - } - end - end - table.remove(get_guns.messages, 1) - end - if #get_guns.warelock_send > 0 then - if get_guns.warelock_send[1][1] < os.time() then - if get_guns.warelock_send[1][2] == get_guns.warehouse then - antiflood.send[#antiflood.send+1] = "/warelock" - end - table.remove(get_guns.warelock_send, 1) - end - end - end -end -get_guns.start_get = function() - get_guns.list = {} - for i = 1, #config.data.get_guns.list do - if config.data.get_guns.list[i][2] > 0 then - if get_guns.weapon[config.data.get_guns.list[i][3]] == nil or get_guns.weapon[config.data.get_guns.list[i][3]] < (config.data.get_guns.list[i][4] * config.data.get_guns.list[i][2]) then - for n = 1, config.data.get_guns.list[i][2] do - get_guns.list[#get_guns.list+1] = i - 1 - end - end - end - end - if #get_guns.list > 0 then - get_guns.getgun = true - antiflood.send[#antiflood.send+1] = "/getgun" - else - addChatMessage("У Вас достаточно оружия!") - end -end - - --->> INVITE HELPER -invite_helper = {} -invite_helper.data = {} -invite_helper.onServerMessage = function(color, message) - if message:find("^ Вы приняли .+ в ") then - local name = message:match("^ Вы приняли (.+) в ") - if invite_helper.data[name] ~= nil then - antiflood.send[#antiflood.send+1] = invite_helper.data[name] - invite_helper.data[name] = nil - else - if config.data.invite_helper.auto_rank then - local result, id = getPlayerIdByPlayerName(name) - if result then - antiflood.send[#antiflood.send+1] = "/giverank "..id.." "..config.data.invite_helper.rank - end - end - end - if #config.data.invite_helper.message > 0 then - name = name:gsub("_", " ") - antiflood.send[#antiflood.send+1] = string.format("/r %s", config.data.invite_helper.message:gsub("{name}", name)) - end - end -end -invite_helper.onSendCommand = function(cmd) - if cmd:lower():find("%/invite %d+") then - local id, rank = cmd:lower():match("%/invite (%d+)"), config.data.invite_helper.rank - if cmd:lower():find("%/invite (%d+) (%d+)") then - id, rank = cmd:lower():match("%/invite (%d+) (%d+)") - end - local id = tonumber(id) - local result, name = getNickNameByPlayerId(id) - if result then - local score = sampGetPlayerScore(id) - if score >= config.data.invite_helper.lvl then - invite_helper.data[name] = "/giverank "..id.." "..rank - else - addChatMessage(string.format("У игрока %s[%d] всего %d уровень. Нужен %d уровень!", name, id, score, config.data.invite_helper.lvl)) - return true, false - end - end - end -end -invite_helper.loop = function() - while true do - wait(0) - local result, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) - if result then - local result, id = sampGetPlayerIdByCharHandle(ped) - if result and wasKeyPressed(vkeys[config.data.invite_helper.key]) then - antiflood.send[#antiflood.send+1] = "/invite "..id - end - end - end -end - --->> ANTIFLOOD -antiflood = {} -antiflood.clock = 0 -antiflood.set = function() - antiflood.clock = os.clock() * 1000 -end -antiflood.get = function() - return (os.clock() * 1000 - antiflood.clock) -end -antiflood.send = {} -antiflood.loop = function() - while true do - wait(0) - if antiflood.get() > 1300 then - if #antiflood.send > 0 then - sampSendChat(antiflood.send[1]) - table.remove(antiflood.send, 1) - antiflood.set() - end - end - end -end - --->> MAFIA CHECKER -mafia_checker = {} -mafia_checker.loop = function() - mafia_checker.skin = { - [118] = 2868839942, - [117] = 2868839942, - [169] = 2868839942, - [120] = 2868839942, - [186] = 2868839942, - [123] = 2868839942, - [272] = 2864232118, - [112] = 2864232118, - [125] = 2864232118, - [214] = 2864232118, - [111] = 2864232118, - [126] = 2864232118, - [124] = 2868164608, - [223] = 2868164608, - [113] = 2868164608, - [91] = 2868164608, - [127] = 2868164608 - } - while true do - wait(0) - if config.data.mafia_checker.main then - if mafia_checker.setpos then - sampSetCursorMode(3) - local x, y = getCursorPos() - config.data.mafia_checker.x = x - config.data.mafia_checker.y = y - if isKeyJustPressed(1) then - sampSetCursorMode(0) - config.save(config.data) - mafia_checker.setpos = false - end - end - local players = { - [2868164608] = { "lcn", 0, 0 }, - [2868839942] = { "yakuza", 0, 0 }, - [2864232118] = { "rm", 0, 0 }, - } - for i = 0, sampGetMaxPlayerId(false) do - if sampIsPlayerConnected(i) then - local color = sampGetPlayerColor(i) - if players[color] ~= nil then - players[color][2] = players[color][2] + 1 - end - local result, handle = sampGetCharHandleBySampPlayerId(i) - if result then - local model = getCharModel(handle) - if mafia_checker.skin[model] ~= nil then - players[mafia_checker.skin[model]][3] = players[mafia_checker.skin[model]][3] + 1 - end - end - end - end - local text = string.format("{ba9307}LCN:{ffffff} %d (%d)\n{b81a24}Yakuza:{ffffff} %d (%d)\n{999696}RM:{ffffff} %d (%d)\n", players[2868164608][2], players[2868164608][3], players[2868839942][2], players[2868839942][3], players[2864232118][2], players[2864232118][3]) - renderFontDrawText(font,text,config.data.mafia_checker.x,config.data.mafia_checker.y,-1) - end - end -end - --->> MSK TIME -msk_time = {} -msk_time.update = 0 -msk_time.time = 0 -msk_time.get = function() - if msk_time.update == 0 then - return os.time() - end - return msk_time.time + (os.time() - msk_time.update) -end - --->> REQUEST -request = {} -request.chat = {} -request.send = {} -request.base = {} -request.loop = function() - request.wait = 0 - while true do - wait(0) - if os.time() - request.wait >= 5 then - request.wait = os.time() - local request_table = { - sender = getLocalPlayerNickname(), - server = getServerAddress(), - room = config.data.room, - send = request.send, - rand = os.clock() - } - request.send = {} - local url = string.format("http://mafia.deadpoo.net/%s", urlencode(encodeJson(request_table))) - local result, text = pcall(openURL, url, os.tmpname(), true) - if result then - local result = pcall(request.handler, text) - if not result then - addChatMessage(text) - addChatMessage("Сервер 'mafia-tools' не отвечает!") - break - end - end - end - end -end -request.handler = function(text) - local info = decodeJson(text) - if info["time"] ~= nil then - msk_time.update = os.time() - msk_time.time = info["time"] - end - if info["result"] == "ok" then - menu.data = info["data"] - local new_data = { - ls = { time = 0, text = "00:00:00" }, - sf = { time = 0, text = "00:00:00" }, - lv = { time = 0, text = "00:00:00" }, - mhcars = { time = 0, text = "00:00:00" }, - ffixcar = { time = 0, text = "00:00:00" }, - } - for sender, sender_data in pairs(info["data"]) do - if isPlayerInList(sender) then - for key, v in pairs(sender_data) do - if new_data[key] ~= nil then - if new_data[key]["time"] < v["time"] then - new_data[key]["time"] = v["time"] - new_data[key]["text"] = v["text"] - end - end - end - end - end - ammo_timer.data = new_data - local text = "" - for i = 1, #info["ffixcar_log"] do - local data = info["ffixcar_log"][i] - if isPlayerInList(data["sender"]) then - text = string.format("%s[%s] %s\n", text, os.date("%X", data["time"]), data["text"]) - end - end - menu.ffixcar_log = text - for sender, sender_data in pairs(info["chat"]) do - if isPlayerInList(sender) then - local key = string.format("%d%s", sender_data.time, sender_data.text) - if request.chat[key] == nil then - request.chat[key] = true - local dev = "" - if sender == "Serhiy_Rubin" or sender == "Rafael_Moreno" then - dev = "[Разработчик] " - end - if msk_time.get() - sender_data.time < 15 then - local text = string.format("%s%s: %s", dev, sender, sender_data.text) - addChatMessage(text) - end - end - end - end - end - return true -end - --->> AMMO TIMER -ammo_timer = {} -ammo_timer.last_ammo = "" -ammo_timer.onServerMessage = function(color, message) - if message:find("^ Следующее ограбление будет доступно в (%d+:%d+:%d+)") then - if ammo_timer.last_ammo ~= "" then - request.send[#request.send + 1] = { - key = ammo_timer.last_ammo, - text = message:match("^ Следующее ограбление будет доступно в (%d+:%d+:%d+)") - } - request.wait = 0 - end - end - if message:find("^ Задание будет доступно через: ") then - local p1, p2, p3 = string.match(message, "Задание будет доступно через: (%d+):(%d+):(%d+)") - if(p3 == nil)then - p1, p2 = string.match(message, "Задание будет доступно через: (%d+):(%d+)") - end - if(p1 ~= nil and p2 ~= nil)then - local mhTimer = 0 - if(p3 ~= nil)then - mhTimer = tonumber(p1) * 3600 - mhTimer = mhTimer + (tonumber(p2) * 60) - mhTimer = mhTimer + tonumber(p3) - else - mhTimer = mhTimer + (tonumber(p1) * 60) - mhTimer = mhTimer + tonumber(p2) - end - request.send[#request.send + 1] = { - key = "mhcars", - second = mhTimer - } - request.wait = 0 - end - end --> by Richard_Holmes - if message:find(".+ заказал спавн транспорта через %d+ секунд%. С банка фракции снято %d+ вирт$") then - request.send[#request.send + 1] = { - key = "ffixcar", - text = message:match(" (%g+_%g+ заказал спавн транспорта через %d+ секунд%. С банка фракции снято %d+ вирт)$") - } - request.wait = 0 - end -end -ammo_timer.data = { - ls = { time = 0, text = "00:00:00" }, - sf = { time = 0, text = "00:00:00" }, - lv = { time = 0, text = "00:00:00" }, - mhcars = { time = 0, text = "00:00:00" }, - ffixcar = { time = 0, text = "00:00:00" }, -} -ammo_timer.loop = function() - font = renderCreateFont(config.data.font.name,config.data.font.size,config.data.font.flag) - local getText = function(key) - if config.data.timer_hud[key] ~= nil and not config.data.timer_hud[key] then - return "" - end - if ammo_timer.data[key]["time"] == 0 then - return string.format("{%s}%s:{%s} %s\n", config.data.font.color1, key:upper(), config.data.font.color2, ammo_timer.data[key]["text"]) - else - local min = math.floor((msk_time.get() - ammo_timer.data[key]["time"]) / 60) - return string.format("{%s}%s:{%s} %s (%d min)\n", config.data.font.color1, key:upper(), config.data.font.color2, ammo_timer.data[key]["text"], min) - end - end - while true do - wait(0) - if config.data.timer_hud.main then - if ammo_timer.setpos then - sampSetCursorMode(3) - local x, y = getCursorPos() - config.data.timer_hud.x = x - config.data.timer_hud.y = y - if isKeyJustPressed(1) then - sampSetCursorMode(0) - config.save(config.data) - ammo_timer.setpos = false - end - end - local text = string.format("%s%s%s%s%s", getText("ls"), getText("sf"), getText("lv"), getText("mhcars"), getText("ffixcar")) - renderFontDrawText(font,text,config.data.timer_hud.x,config.data.timer_hud.y,-1) - end - end -end - --->> 2 MIN TIMER -timer_2min = {} -timer_2min.onServerMessage = function(color, message) - if message:find("Война за бизнес .+ продлена на 2 минуты") then - local now = os.time() - config.data.time_2min - if now < 300 and (os.time() - config.data.time_2min) > 120 then - addChatMessage("2 мин длилось на "..((os.time() - config.data.time_2min) - 120).." секунд больше") - end - config.data.time_2min = os.time() - config.save(config.data) - end -end -timer_2min.loop = function() - while true do - wait(0) - for a = 0, 2304 do - if sampTextdrawIsExists(a) then - local x, y = sampTextdrawGetPos(a) - if math.ceil(x) == 87 and math.ceil(y) == 256 then - local time = 120 - (os.time() - config.data.time_2min) - local text = string.format("%02d:%02d", math.floor(time / 60), time % 60) - if time < 120 and time >= 0 and sampTextdrawGetString(a) ~= text then - sampTextdrawSetString(a,text) - end - end - end - end - end -end - --->> CONFIG -config = {} -config.data = {} -local x1, y1 = convertGameScreenCoordsToWindowScreenCoords(14, 310) -local x2, y2 = convertGameScreenCoordsToWindowScreenCoords(40, 410) -config.default = { - font = { - name = "Segoe UI", - size = 10, - flag = 13, - color1 = "fffd8f", - color2 = "ffffff" - }, - time_2min = 0, - room = "all", - list = {}, -->> Список - list_block = true, -->> Использовать как Черный или Белый список - timer_hud = { - main = false, - mhcars = false, - ffixcar = false, - x = x1, - y = y1 - }, - mafia_checker = { - main = false, - x = x2, - y = y2 - }, - invite_helper = { - lvl = 7, - auto_rank = true, - rank = 7, - key = "VK_I", - message = "Добро пожаловать, {name}!" - }, - get_guns = { - list = { - { "Desert Eagle", 0, 2, 14 }, - { "Shotgun", 0, 3, 10 }, - { "SMG", 0, 4, 60 }, - { "AK47", 0, 5, 60 }, - { "M4A1", 0, 5, 100 }, - { "Rifle", 0, 6, 10 }, - { "Броня", 0, 777, 10 } - }, - key = "VK_G", - auto_get_guns = false, - warelock_auto = false, - warelock_text = { - "sklad", - "склад" - }, - warelock_time = 10 - }, - stats = { - frac = "", - rank = 0 - }, - war = { - armoff = true, - armoff_id = { 0, 1, 4 } - } -} -config.directory = string.format("%s\\moonloader\\config\\%s\\", getGameDirectory(), thisScript().name) -config.init = function() - if not doesDirectoryExist("moonloader\\config") then - createDirectory("moonloader\\config") - end - if not doesDirectoryExist(config.directory) then - createDirectory(config.directory) - end - config.address = string.format("%s\\%s-%s.json", config.directory, getSampRpServerName(), getLocalPlayerNickname()) - if not doesFileExist(config.address) then - config.save(config.default) - end - config.read() - for k,v in pairs(config.default) do - if config.data[k] == nil then - config.data[k] = v - end - end - config.save(config.data) -end -config.save = function(data) - local file, error = io.open(config.address, "w") - if file == nil then - addChatMessage(error) - end - file:write(encodeJson(data)) - file:flush() - io.close(file) -end -config.read = function() - local readJson = function() - local file, error = io.open(config.address, "r") - if file then - config.data = decodeJson(file:read("*a")) - io.close(file) - if config.data == nil then - addChatMessage("Ошибка чтения конфига! Сбрасываю конфиг!") - config.save(config.default) - end - end - end - local result = pcall(readJson) - if not result then - addChatMessage("Ошибка чтения конфига! Сбрасываю конфиг!") - config.save(config.default) - end - if config.data == nil then - config.error = true - addChatMessage("Ошибка чтения конфига! Пробую ещё раз прочесть") - config.read() - else - if config.error then - addChatMessage("Конфиг был успешно загружен!") - config.error = false - end - end -end - -events = {} -events.handler = function(handler, param) - for i = 1, #handler do - local result, pack = handler[i](table.unpack(param)) - if result then - return pack - end - end -end -events.onServerMessage = { - get_guns.onServerMessage -} -events.onSendCommand = { - invite_helper.onSendCommand -} -events.onShowDialog = { - get_guns.onShowDialog -} - --->> EVENTS -function sampev.onServerMessage(color, message) - if os.time() - live < 3 then - timer_2min.onServerMessage(color, message) - ammo_timer.onServerMessage(color, message) - invite_helper.onServerMessage(color, message) - local result = events.handler(events.onServerMessage, { color, message }) - if result ~= nil then - return result - end - end -end -function sampev.onSendPickedUpPickup(id) - local X, Y, Z = getCharCoordinates(PLAYER_PED) - local ammo = { - ["ls"] = {x = 1366.6401367188, y = -1279.4899902344, z = 13.546875}, - ["sf"] = {x = -2626.4050292969, y = 210.6088104248, z = 4.6033186912537}, - ["lv"] = {x = 2158.3286132813, y = 943.17541503906, z = 10.371940612793} - } - for k, v in pairs(ammo) do - local distance = getDistanceBetweenCoords3d(X, Y, Z, v.x, v.y, v.z) - if distance <= 5 then - ammo_timer.last_ammo = k - end - end --> by Benya -end -function sampev.onSendCommand(cmd) - antiflood.set() - local result = events.handler(events.onSendCommand, { cmd }) - if result ~= nil then - return result - end -end -function sampev.onSendChat(message) - antiflood.set() -end -function sampev.onShowDialog(id, style, title, button1, button2, text) - local result = events.handler(events.onShowDialog, { id, style, title, button1, button2, text }) - if result ~= nil then - return result - end -end -function sampev.onShowTextDraw(id, data) - get_guns.onShowTextDraw(id, data) -end -function sampev.onTextDrawHide(id) - get_guns.onTextDrawHide(id) -end -function sampev.onSendWeaponsUpdate(playerTarget, actorTarget, weapons) - get_guns.onSendWeaponsUpdate(playerTarget, actorTarget, weapons) -end -function sampev.onResetPlayerWeapons() - get_guns.onResetPlayerWeapons() -end --->> NEW FUNCTION -function getLocalPlayerNickname() - return sampGetPlayerNickname(select(2, sampGetPlayerIdByCharHandle(PLAYER_PED))) -end -function getServerAddress() - local ip, port = sampGetCurrentServerAddress() - return string.format("%s:%s", ip, port) -end -function getSampRpServerName() - local result = "" - local server = sampGetCurrentServerName():gsub("|", "") - local server_find = { "02", "Two", "Revo", "Legacy", "Classic" } - for i = 1, #server_find do - if server:find(server_find[i]) then - result = server_find[i] - end - end - return result -end -function convertTableToString(table) - local result = "" - for i = 1, #table do - result = string.format("%s%s\n", result, table[i]) - end - return result -end -function start_dialog(_menu, put) -- module by trefa & modify (put & list in []) - function _dialog(_menu, id, outs, put) - sampShowDialog(id, _menu.settings.title, tbl_split(_menu.settings.style, _menu, _menu.settings.forward ,_menu.settings.backwards ,_menu.settings.score), _menu.settings.btn1, (_menu.settings.btn2 ~= nil and _menu.settings.btn2 or _), _menu.settings.style) - repeat - wait(0) - if put ~= nil and sampIsDialogActive() then - sampSetCurrentDialogEditboxText(put) - put = nil - end - local result, button, list, input = sampHasDialogRespond(id) - if result then - local out, outs = _menu[((_menu.settings.style == 0 or _menu.settings.style == 1 or _menu.settings.style == 3) and 1 or ((list + 1) > #_menu[1] and 2 or 1))][((_menu.settings.style == 0 or _menu.settings.style == 1 or _menu.settings.style == 3) and 1 or ((list + 1) > #_menu[1] and (list - #_menu[1]) + 1 or list + 1))].click(button, list, input, outs) - if type(out) == "table" then - return _dialog(out, id - 1, outs, put) - elseif type(out) == "boolean" then - if not out then - return out - end - return _dialog(_menu, id, outs, put) - end - end - until result or menu.show[1] - end - - function tbl_split(style, tbl, forward ,backwards ,score) - if style == 2 or style == 4 or style == 5 then - text = (style == 5 and tbl[1].text.."\n" or "") - for i, val in ipairs(tbl[1]) do - text = text..""..forward..""..(score and "["..(i-1).."] " or "")..""..val.title..""..backwards - end - if tbl[2] ~= nil then - for _, val in ipairs(tbl[2]) do - text = text..""..forward..""..val.title..""..backwards - end - end - return text - end - return tbl[1].text - end - - return _dialog(_menu, 1337, outs, put) -end -function getNicknamesOnline() - local result = {} - for i = 0, sampGetMaxPlayerId(false) do - if sampIsPlayerConnected(i) or select(2, sampGetPlayerIdByCharHandle(PLAYER_PED)) == i then - result[sampGetPlayerNickname(i)] = i - end - end - return result -end -function urlencode(str) - str = string.gsub (str, "([^0-9a-zA-Z !'()*._~-])", -- locale independent - function (c) return string.format ("%%%02X", string.byte(c)) end) - return str -end -function getNickNameByPlayerId(id) - local result = false - local nick = "" - if sampIsPlayerConnected(id) then - nick = sampGetPlayerNickname(id) - result = true - end - return result, nick -end -function getPlayerIdByPlayerName(name) - local result = false - local id = -1 - for i = 0, sampGetMaxPlayerId(false) do - if sampIsPlayerConnected(i) then - if sampGetPlayerNickname(i) == name then - result = true - id = i - break - end - end - end - return result, id -end -function isPlayerInList(sender) - local result = false - if config.data.list_block then - if config.data.list[sender] == nil then - result = true - end - else - if config.data.list[sender] ~= nil then - result = true - end - end - return result -end -function isKeyCanBePressed() - if sampIsDialogActive() or sampIsChatInputActive() or sampIsCursorActive() or isSampfuncsConsoleActive() then - return false - end - return true -end -function split(str, delim, plain) - local tokens, pos, plain = {}, 1, not (plain == false) --[[ delimiter is plain text by default ]] - repeat - local npos, epos = string.find(str, delim, pos, plain) - table.insert(tokens, string.sub(str, pos, npos and npos - 1)) - pos = epos and epos + 1 - until not pos - return tokens -end - --->> UPDATE MODULE -function openURL(url, fpath, message_off) - local text = "" - local file_download = false - local download_final = false - - - if doesFileExist(fpath) then - os.remove(fpath) - end - - downloadUrlToFile(url, fpath, function(id, status, p1, p2) - if status == dlstatus.STATUS_ENDDOWNLOADDATA then - file_download = true - end - if status == dlstatus.STATUSEX_ENDDOWNLOAD then - download_final = true - end - end - ) - - repeat - wait(1000) - until download_final or file_download - - if file_download then - local f = io.open(fpath, "r") - if f then - text = f:read("*a") - io.close(f) - end - os.remove(fpath) - end - - if (text:find("Not found") and not text:find('"Not found"')) or text == "" then - text = "" - if not message_off then - addChatMessage("Не удалось скачать обновление по ссылке:") - addChatMessage(url) - end - end - - return text -end - -function addChatMessage(text) - local tag = string.format("{667dff}[%s]{FFFFFF} ", thisScript().name) - sampAddChatMessage(tag..text, 0xFFFFFFFF) -end - -script_update = { - version_url = "http://git.deadpoo.net/rubin/mafia-tools/raw/branch/master/version", - script_url = "http://git.deadpoo.net/rubin/mafia-tools/raw/branch/master/mafia-tools.lua", - changelog_url = "http://git.deadpoo.net/rubin/mafia-tools/raw/branch/master/changelog", - address_ini = string.format("rubin-mods-updates\\%s.ini", thisScript().name), - main = function() - if not doesDirectoryExist("moonloader\\config\\rubin-mods-updates") then - createDirectory("moonloader\\config\\rubin-mods-updates") - end - local ini = inicfg.load({ - settings = { - check_update = true, - auto_update = true, - server_version = "" - } - }, script_update.address_ini) - ini.settings.version_url = script_update.version_url - ini.settings.script_url = script_update.script_url - ini.settings.changelog_url = script_update.changelog_url - ini.settings.version = thisScript().version - ini.settings.script_name = thisScript().name - local command = (thisScript().name:gsub(" ", "").."-update"):lower() - sampRegisterChatCommand(command, script_update.command) - if ini.settings.check_update or ini.settings.auto_update then - local fpath = os.tmpname() - local result, text = pcall(openURL, script_update.version_url, fpath) - if result then - ini.settings.server_version = text - if text ~= "" and text ~= thisScript().version then - addChatMessage( string.format("Вышла новая версия '%s'. Текущая: '%s'", text, thisScript().version) ) - if ini.settings.auto_update then - addChatMessage( string.format("Автообновление скрипта включено. Процесс запущен!") ) - script_update.command() - else - addChatMessage( string.format("Автообновление скрипта выключено. Обновить самому: /%s", command) ) - end - end - end - end - inicfg.save(ini, script_update.address_ini) - script_update.menu.init() - end, - command = function() - lua_thread.create(function() - local fpath = os.tmpname() - local result, text = pcall(openURL, script_update.version_url, fpath) - if result then - if text ~= "" and text ~= thisScript().version then - addChatMessage( string.format("Вышла новая версия '%s'. Текущая: '%s'", text, thisScript().version) ) - local fpath = os.tmpname() - local result, text = pcall(openURL, script_update.script_url, fpath) - if result and text ~= "" and text:find(thisScript().name:gsub("%-", "%%-")) then - local file, error = io.open(thisScript().path, "w") - if file ~= nil then - file:write(text) - file:flush() - io.close(file) - addChatMessage("Обновление завершено, скрипт перезагружен!") - wait(500) - thisScript():reload() - end - end - else - addChatMessage("У Вас установлена последняя версия!") - end - end - end) - end, - menu = { - dialog = {}, - ini = {}, - init = function() - if not sampIsChatCommandDefined("rubin-mods") then - sampAddChatMessage("{667dff}[RUBIN MODS]{FFFFFF} Управление обновлениями скриптов: /rubin-mods", 0xFFFFFFFF) - sampRegisterChatCommand("rubin-mods",script_update.menu.show) - while true do - wait(0) - local result, button, list, input = sampHasDialogRespond(2160) - if result and button == 1 then - if script_update.menu.ini[list+1] ~= nil and script_update.menu.dialog[list+1] ~= nil then - script_update.menu.dialog[list+1](script_update.menu.ini[list+1]) - end - end - local result, button, list, input = sampHasDialogRespond(2162) - if result then - if button == 1 then - if script_update.menu2.text[list+1] ~= nil and script_update.menu2.dialog[list+1] ~= nil then - script_update.menu2.dialog[list+1]() - end - else - script_update.menu.show() - end - end - local result, button, list, input = sampHasDialogRespond(2161) - if result then - script_update.menu2.show(script_update.menu2.data) - end - end - end - end, - show = function() - script_update.menu.dialog = {} - script_update.menu.ini = {} - local text = "" - if doesDirectoryExist("moonloader\\config\\rubin-mods-updates") then - local FileHandle, FileName = findFirstFile("moonloader\\config\\rubin-mods-updates\\*") - while FileName ~= nil do - if FileName ~= nil and FileName ~= ".." and FileName ~= "." and FileName:find("%.ini") then - local address = string.format("moonloader\\config\\rubin-mods-updates\\%s", FileName) - if doesFileExist(address) then - local ini = inicfg.load({}, address) - script_update.menu.ini[#script_update.menu.ini+1] = address - text = string.format("%s%s\n", text, string.format("%s\t%s%s", ini.settings.script_name, (ini.settings.version == ini.settings.server_version and "{59fc30}" or "{ff0000}"),ini.settings.version)) - script_update.menu.dialog[#script_update.menu.dialog+1] = function(data) - script_update.menu2.show(data) - end - end - end - FileName = findNextFile(FileHandle) - end - findClose(FileHandle) - else - text = "Не найдена директория:\t\n moonloader\\config\\rubin-mods-updates\t" - end - sampShowDialog(2160,"Обновление скриптов: Rubin Mods","Скрипт\tВерсия\n"..text,"Выбрать","Закрыть",5) - end - }, - menu2 = { - data = {}, - text = {}, - dialog = {}, - show = function(data) - script_update.menu2.data = data - script_update.menu2.text = {} - script_update.menu2.dialog = {} - if doesFileExist(data) then - local ini = inicfg.load({}, data) - script_update.menu2.text[#script_update.menu2.text+1] = string.format("Автообновление %s", (ini.settings.auto_update and "{59fc30}ON" or "{ff0000}OFF")) - script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() - ini.settings.auto_update = not ini.settings.auto_update - inicfg.save(ini, data) - script_update.menu2.show(data) - end - if not ini.settings.auto_update then - script_update.menu2.text[#script_update.menu2.text+1] = string.format("Проверять обновления %s", (ini.settings.check_update and "{59fc30}ON" or "{ff0000}OFF")) - script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() - ini.settings.check_update = not ini.settings.check_update - inicfg.save(ini, data) - script_update.menu2.show(data) - end - end - script_update.menu2.text[#script_update.menu2.text+1] = string.format("Последние изменения") - script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() - script_update.changelog(ini.settings.changelog_url, ini.settings.script_name) - end - script_update.menu2.text[#script_update.menu2.text+1] = string.format("Удалить из списка") - script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() - os.remove(data) - script_update.menu.show() - end - local text = "" - for i = 1, #script_update.menu2.text do - text = text..script_update.menu2.text[i].."\n" - end - sampShowDialog(2162,"Настройки обновления для "..ini.settings.script_name,text,"Выбрать","Назад",2) - end - end - }, - changelog = function(url, name) - local fpath = os.tmpname() - local result, text = pcall(openURL, url, fpath) - if result then - sampShowDialog(2161,"Changelog - "..name,text,"Выбрать","Назад",4) - end - end -} - --->> SCRIPT UTF-8 --->> utf8(table path, incoming variables encoding, outcoming variables encoding) --->> table path example { "sampev", "onShowDialog" } --->> encoding options nil | AnsiToUtf8 | Utf8ToAnsi -_utf8 = load([=[return function(utf8_func, in_encoding, out_encoding); if encoding == nil then; encoding = require("encoding"); encoding.default = "CP1251"; u8 = encoding.UTF8; end; if type(utf8_func) ~= "table" then; return false; end; if AnsiToUtf8 == nil or Utf8ToAnsi == nil then; AnsiToUtf8 = function(text); return u8(text); end; Utf8ToAnsi = function(text); return u8:decode(text); end; end; if _UTF8_FUNCTION_SAVE == nil then; _UTF8_FUNCTION_SAVE = {}; end; local change_var = "_G"; for s = 1, #utf8_func do; change_var = string.format('%s["%s"]', change_var, utf8_func[s]); end; if _UTF8_FUNCTION_SAVE[change_var] == nil then; _UTF8_FUNCTION = function(...); local pack = table.pack(...); readTable = function(t, enc); for k, v in next, t do; if type(v) == 'table' then; readTable(v, enc); else; if enc ~= nil and (enc == "AnsiToUtf8" or enc == "Utf8ToAnsi") then; if type(k) == "string" then; k = _G[enc](k); end; if type(v) == "string" then; t[k] = _G[enc](v); end; end; end; end; return t; end; return table.unpack(readTable({_UTF8_FUNCTION_SAVE[change_var](table.unpack(readTable(pack, in_encoding)))}, out_encoding)); end; local text = string.format("_UTF8_FUNCTION_SAVE['%s'] = %s; %s = _UTF8_FUNCTION;", change_var, change_var, change_var); load(text)(); _UTF8_FUNCTION = nil; end; return true; end]=]) -function utf8(...) - pcall(_utf8(), ...) -end - -utf8({ "sampShowDialog" }, "Utf8ToAnsi") -utf8({ "sampSendChat" }, "Utf8ToAnsi") -utf8({ "sampAddChatMessage" }, "Utf8ToAnsi") -utf8({ "print" }, "Utf8ToAnsi") -utf8({ "renderGetFontDrawTextLength" }, "Utf8ToAnsi") -utf8({ "renderFontDrawText" }, "Utf8ToAnsi") -utf8({ "sampSetCurrentDialogEditboxText" }, "Utf8ToAnsi") -utf8({ "sampHasDialogRespond" }, nil, "AnsiToUtf8") -utf8({ "sampev", "onServerMessage" }, "AnsiToUtf8", "Utf8ToAnsi") -utf8({ "sampev", "onShowDialog" }, "AnsiToUtf8", "Utf8ToAnsi") \ No newline at end of file +script_name('mafia-tools') +script_author("Serhiy_Rubin") +script_version("05.02.2023.2") + +sampev = require 'samp.events' +inicfg = require "inicfg" +dlstatus = require("moonloader").download_status +vkeys = require "vkeys" +live = 0 + +function main() + if not isSampLoaded() or not isSampfuncsLoaded() then return end + while not isSampAvailable() do wait(0) end + lua_thread.create(script_update.main) + repeat wait(0) until sampGetCurrentServerName() ~= "SA-MP" + repeat wait(0) until sampGetCurrentServerName():find("Samp%-Rp.Ru") or sampGetCurrentServerName():find("SRP") + local server = getSampRpServerName() + if server == "" then + thisScript():unload() + end + config.init() + lua_thread.create(timer_2min.loop) + lua_thread.create(ammo_timer.loop) + lua_thread.create(request.loop) + lua_thread.create(menu.loop) + lua_thread.create(mafia_checker.loop) + lua_thread.create(antiflood.loop) + lua_thread.create(invite_helper.loop) + lua_thread.create(get_guns.loop) + while true do + wait(0) + live = os.time() + msg.loop() + end +end + +-->> MENU DIALOG +menu = {} +menu.dialog = {} +menu.data = {} +menu.ffixcar_log = {} +menu.update = function() + + -->> Список блокировщика + local blacklist = {} + for k,v in pairs(config.data.list) do + blacklist[#blacklist+1] = { + title = k, + click = function(button, list, input , outs) + if button == 1 then + config.data.list[k] = nil + config.save(config.data) + addChatMessage(string.format("Вы удалили %s из списка!", k)) + end + menu.show = { true, "main" } + end + } + end + + -->> Обновление инфы от сервера + local players = getNicknamesOnline() + local count = 0 + local members = {} + for sender, sender_data in pairs(menu.data) do + count = count + 1 + members[#members+1] = { + title = string.format("%s\t", (players[sender] ~= nil and sender.."["..players[sender].."]" or sender)), + click = function(button, list, input, outs) + if button == 1 then + menu.show = { + true, + "members_user", + { + { + title = (config.data.list[sender] ~= nil and "Убрать из списка" or "Добавить в список"), + click = function(button, list, input , outs) + if button == 1 then + if config.data.list[sender] == nil then + config.data.list[sender] = true + addChatMessage(string.format("Вы добавли %s в список!", sender)) + else + config.data.list[sender] = nil + addChatMessage(string.format("Вы удалили %s из списка!", sender)) + end + config.save(config.data) + end + menu.show = { true, "members" } + end + }, + { + title = "{"..config.data.font.color1.."}".."Тайминги от пользователя:", + click = function(button, list, input , outs) + menu.show = { true, "members" } + end + }, + { + title = "{"..config.data.font.color1.."}"..">{FFFFFF} LS: "..sender_data["ls"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), + click = function(button, list, input , outs) + menu.show = { true, "members" } + end + }, + { + title = "{"..config.data.font.color1.."}"..">{FFFFFF} SF: "..sender_data["sf"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), + click = function(button, list, input , outs) + menu.show = { true, "members" } + end + }, + { + title = "{"..config.data.font.color1.."}"..">{FFFFFF} LV: "..sender_data["lv"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), + click = function(button, list, input , outs) + menu.show = { true, "members" } + end + }, + { + title = "{"..config.data.font.color1.."}"..">{FFFFFF} MHCARS: "..sender_data["mhcars"]["text"].." "..(sender_data["mhcars"]["time"] > 0 and math.floor(msk_time.get() - sender_data["mhcars"]["time"]).." sec" or ""), + click = function(button, list, input , outs) + menu.show = { true, "members" } + end + }, + } + } + else + menu.show = { true, "main" } + end + end + } + end + + -->> Список слов для открытия склада + local warelock_text = {} + warelock_text[#warelock_text+1] = { + title = ">> Добавить строку", + click = function(button, list, input, outs) + if button == 1 then + menu.show = { true, "edit", function(button, list, input, outs) + if button == 1 then + if #input > 0 then + local arr = split(input, " ") + if arr[1] ~= nil then + config.data.get_guns.warelock_text[#config.data.get_guns.warelock_text+1] = arr[1] + config.save(config.data) + end + end + end + menu.show = { true, "warelock_auto" } + end, "", "Введите слово для открытия склада!"} + else + menu.show = { true, "main" } + end + end + } + for i = 1, #config.data.get_guns.warelock_text do + warelock_text[#warelock_text+1] = { + title = config.data.get_guns.warelock_text[i], + click = function(button, list, input, outs) + if button == 1 then + table.remove(config.data.get_guns.warelock_text, i) + config.save(config.data) + menu.show = { true, "warelock_auto" } + else + menu.show = { true, "main" } + end + end + } + end + + menu.dialog = { + ["main"] = { + settings = {title = "mafia-tools" ,style = 4 ,btn1 = "Выбрать" ,btn2 = "Закрыть" ,forward = "{ffffff}" ,backwards = "\n" ,score = false}, + { + { -->> Синхронизация таймингов + title = "{"..config.data.font.color1.."}".."Синхронизация таймингов\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Комната + title = "{"..config.data.font.color1.."}"..">{ffffff} Комната\t"..config.data.room, + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "edit", function(button, list, input, outs) + if button == 1 then + if #input > 0 then + config.data.room = input + config.save(config.data) + end + end + menu.show = { true, "main" } + end, config.data.room, "Введите название комнаты!"} + end + }, + { -->> Участники + title = "{"..config.data.font.color1.."}"..">{ffffff} Участники комнаты\t"..count, + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "members" } + end + }, + { -->> Список блокировщика + title = "{"..config.data.font.color1.."}"..">{ffffff} Список блокировщика\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + if #blacklist > 0 then + menu.show = { true, "members_user", blacklist } + else + menu.show = { true, "main" } + end + end + }, + { -->> Использовать список как + title = "{"..config.data.font.color1.."}"..">{ffffff} Использовать список как:\t"..(config.data.list_block and "Черный список" or "Белый список"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.list_block = not config.data.list_block + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Разделитель + title = " \t ", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Настройки отображения + title = "{"..config.data.font.color1.."}".."Настройки отображения\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Рендер + title = "{"..config.data.font.color1.."}"..">{ffffff} Показать на экране\t"..(config.data.timer_hud.main and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.timer_hud.main = not config.data.timer_hud.main + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Показывать таймер mhcars + title = "{"..config.data.font.color1.."}"..">{ffffff} Показывать таймер mhcars\t"..(config.data.timer_hud.mhcars and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.timer_hud.mhcars = not config.data.timer_hud.mhcars + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Показывать таймер ffixcar + title = "{"..config.data.font.color1.."}"..">{ffffff} Показывать таймер ffixcar\t"..(config.data.timer_hud.ffixcar and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.timer_hud.ffixcar = not config.data.timer_hud.ffixcar + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Логи ffixcar + title = "{"..config.data.font.color1.."}"..">{ffffff} Логи /ffixcar\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + wait(100) + menu.show = { true, "ffixcar_log" } + end + }, + { -->> Смена позиции + title = "{"..config.data.font.color1.."}"..">{ffffff} Сменить позицию\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.timer_hud.main = true + ammo_timer.setpos = true + menu.show = { true, "main" } + end + }, + { -->> Разделитель + title = " \t ", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Mafia Checker + title = "{"..config.data.font.color1.."}".."Счетчик мафий на сервере и в стриме\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Рендер Mafia Checker + title = "{"..config.data.font.color1.."}"..">{ffffff} Показать на экране\t"..(config.data.mafia_checker.main and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.mafia_checker.main = not config.data.mafia_checker.main + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Позиция Mafia Checker + title = "{"..config.data.font.color1.."}"..">{ffffff} Сменить позицию\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.mafia_checker.main = true + mafia_checker.setpos = true + menu.show = { true, "main" } + end + }, + { -->> Разделитель + title = " \t ", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Invite Helper + title = "{"..config.data.font.color1.."}".."Инвайт хелпер\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Минимальный лвл + title = "{"..config.data.font.color1.."}"..">{ffffff} Минимальный уровень\t"..config.data.invite_helper.lvl, + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "edit", function(button, list, input, outs) + if button == 1 then + if #input > 0 and input:find("(%d+)") then + config.data.invite_helper.lvl = tonumber(input:match("(%d+)")) + config.save(config.data) + end + end + menu.show = { true, "main" } + end, config.data.invite_helper.lvl, "Введите минимальный уровень для инвайта!"} + end + }, + { -->> Авто ранг вкл выкл + title = "{"..config.data.font.color1.."}"..">{ffffff} Устанавливать ранг автоматически\t"..(config.data.invite_helper.auto_rank and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.invite_helper.auto_rank = not config.data.invite_helper.auto_rank + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Ранг по умолчанию + title = "{"..config.data.font.color1.."}"..">{ffffff} Установить ранг\t"..config.data.invite_helper.rank, + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "edit", function(button, list, input, outs) + if button == 1 then + if #input > 0 and input:find("(%d+)") then + config.data.invite_helper.rank = tonumber(input:match("(%d+)")) + config.save(config.data) + end + end + menu.show = { true, "main" } + end, config.data.invite_helper.rank, "Введите какой ранг давать после инвайта!"} + end + }, + { -->> Сообщение в чат после инвайта + title = "{"..config.data.font.color1.."}"..">{ffffff} Сообщение в рацию\t"..config.data.invite_helper.message, + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "edit", function(button, list, input, outs) + if button == 1 then + config.data.invite_helper.message = input + config.save(config.data) + end + menu.show = { true, "main" } + end, config.data.invite_helper.message, "{name} - Заменится на никнейм игрока которого приняли\nЧтобы не отправлять сообщение оставьте поле пустым!"} + end + }, + { -->> Клавиша инвайта + title = "{"..config.data.font.color1.."}"..">{ffffff} Инвайт по кнопке\tПрицел + "..config.data.invite_helper.key:gsub("VK_", ""), + click = function(button, list, input , outs) + if button ~= 1 then return end + wait(100) + local key = "" + repeat + wait(0) + if not sampIsDialogActive() then + sampShowDialog(222, "Смена активации", "Нажмите на любую клавишу", "Выбрать", "Закрыть", 0) + end + for k, v in pairs(vkeys) do + if wasKeyPressed(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" then + key = k + end + end + until key ~= "" + config.data.invite_helper.key = key + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Разделитель + title = " \t ", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Склад + title = "{"..config.data.font.color1.."}".."Склад\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "main" } + end + }, + { -->> Открывать склад по запросу в рацию + title = "{"..config.data.font.color1.."}"..">{ffffff} Открывать склад по запросу\t"..(config.data.get_guns.warelock_auto and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.get_guns.warelock_auto = not config.data.get_guns.warelock_auto + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Брать оружие сразу как откроют склад + title = "{"..config.data.font.color1.."}"..">{ffffff} Брать оружие сразу как откроют склад\t"..(config.data.get_guns.auto_get_guns and "вкл" or "выкл"), + click = function(button, list, input , outs) + if button ~= 1 then return end + config.data.get_guns.auto_get_guns = not config.data.get_guns.auto_get_guns + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Клавиша взятия ганов + title = "{"..config.data.font.color1.."}"..">{ffffff} Брать оружие по кнопке\t"..config.data.get_guns.key:gsub("VK_", ""), + click = function(button, list, input , outs) + if button ~= 1 then return end + wait(100) + local key = "" + repeat + wait(0) + if not sampIsDialogActive() then + sampShowDialog(222, "Смена активации", "Нажмите на любую клавишу", "Выбрать", "Закрыть", 0) + end + for k, v in pairs(vkeys) do + if wasKeyPressed(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" then + key = k + end + end + until key ~= "" + config.data.get_guns.key = key + config.save(config.data) + menu.show = { true, "main" } + end + }, + { -->> Список слов для запросов + title = "{"..config.data.font.color1.."}"..">{ffffff} Список запросов на открытие склада\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "warelock_auto" } + end + }, + { -->> Список оружия + title = "{"..config.data.font.color1.."}"..">{ffffff} Список оружия\t", + click = function(button, list, input , outs) + if button ~= 1 then return end + menu.show = { true, "get_guns" } + end + }, + } + }, + ["edit"] = { + settings = {title = "mafia-tools" ,style = 1 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, + { + text = menu.show[5], + { + click = function(button, list, input, outs) + menu.show[3](button, list, input, outs) + end + } + } + }, + ["members"] = { + settings = {title = "mafia-tools" ,style = 4 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, + members + }, + ["members_user"] = { + settings = {title = "mafia-tools" ,style = 2 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, + menu.show[3] + }, + ["ffixcar_log"] = { + settings = {title = "mafia-tools" ,style = 0 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = false}, + { + text = menu.ffixcar_log, + { + click = function(button, list, input, outs) + menu.show = { true, "main" } + end + } + } + }, + ["get_guns"] = { + settings = {title = "mafia-tools" ,style = 4 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = true}, + { + { -->> Desert Eagle + title = "Desert Eagle\t"..config.data.get_guns.list[1][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[1][2] = config.data.get_guns.list[1][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> Shotgun + title = "Shotgun\t"..config.data.get_guns.list[2][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[2][2] = config.data.get_guns.list[2][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> SMG + title = "SMG\t"..config.data.get_guns.list[3][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[3][2] = config.data.get_guns.list[3][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> AK47 + title = "AK47\t"..config.data.get_guns.list[4][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[4][2] = config.data.get_guns.list[4][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> M4A1 + title = "M4A1\t"..config.data.get_guns.list[5][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[5][2] = config.data.get_guns.list[5][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> Rifle + title = "Rifle\t"..config.data.get_guns.list[6][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[6][2] = config.data.get_guns.list[6][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> Броня + title = "Броня\t"..config.data.get_guns.list[7][2], + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + config.data.get_guns.list[7][2] = config.data.get_guns.list[7][2] + 1 + config.save(config.data) + menu.show[1] = true + end + }, + { -->> Сброс + title = "Сброс\t", + click = function(button, list, input, outs) + if button ~= 1 then + menu.show = { true, "main" } + return + end + for i = 1, #config.data.get_guns.list do + config.data.get_guns.list[i][2] = 0 + end + config.save(config.data) + menu.show[1] = true + end + }, + } + }, + ["warelock_auto"] = { + settings = {title = "mafia-tools" ,style = 2 ,btn1 = "Выбрать" ,btn2 = "Назад" ,forward = "{ffffff}" ,backwards = "\n" ,score = false}, + warelock_text + }, + } +end +menu.show = { false, "main" } +menu.put = "" +af_chat = 0 +menu.loop = function() + sampRegisterChatCommand('maf', function(param) + if #param > 0 then + if os.time() - af_chat < 60 then + addChatMessage("Не чаще чем раз в минуту!") + else + request.send[#request.send + 1] = { + key = "messages", + text = AnsiToUtf8(param) + } + request.wait = 0 + af_chat = os.time() + end + else + menu.show = { true, "main" } + end + end) + while true do + wait(0) + if menu.show[1] then + menu.show[1] = false + menu.update() + if menu.dialog[menu.show[2]] ~= nil then + wait(100) + start_dialog(menu.dialog[menu.show[2]], menu.show[4]) + end + end + end +end + +-->> GET GUNS +get_guns = {} +get_guns.warehouse = false +get_guns.isCanOpen = false +get_guns.onServerMessage = function(color, message) + if message == "{FFFFFF} Вы можете использовать {00AB06}/getgun [ID игрока]{FFFFFF}, чтобы выдать оружие другим членам организации" then + if get_guns.getgun then + return false + end + end + if message == " Вы не на складе оружия своей организации / у вас нет доступа!" or message == " Склад закрыт" then + if get_guns.getgun then + get_guns.getgun = false + end + end + if message:find("^ Склад .+ %{C42100%}закрыт") or message == " Склад закрыт" then + get_guns.warehouse = false + if not get_guns.check_warehouse then + get_guns.check_warehouse = true + get_guns.check_warehouse_time = os.time() + return false + end + end + if message:find("^ Склад .+ %{00AB06%}открыт") or message == " Склад открыт" then + get_guns.warehouse = true + if not get_guns.check_warehouse then + get_guns.check_warehouse = true + get_guns.check_warehouse_time = os.time() + return false + end + end + if message == " Вам недоступна эта функция" then + if not get_guns.check_warehouse then + get_guns.check_warehouse = true + get_guns.check_warehouse_time = os.time() + return false + end + end + if message:find("^ %d+/%d+ Матов | %d+/%d+ Аптечек") and os.time() - get_guns.check_warehouse_time < 2 then + return false + end + if message:find("^ .+%[%d+%]: (.+)") then + get_guns.messages[#get_guns.messages+1] = message:match("^ .+%[%d+%]: (.+)") + end + if config.data.get_guns.auto_get_guns and get_guns.enter_textdraw and message:find("^ .+ открыл%(а%) склад с оружием$") and not message:find(getLocalPlayerNickname()) then + get_guns.start_get() + end + if message == " Броня уже 100%" and get_guns.getgun then + antiflood.send[#antiflood.send+1] = "/getgun" + end +end +get_guns.enter_textdrawId = -1 +get_guns.enter_textdraw = false +get_guns.onShowTextDraw = function(id, textdraw) + if textdraw.text:find("VEHICLE_ENTER_EXIT") then + get_guns.enter_textdrawId = id + get_guns.enter_textdraw = true + end +end +get_guns.onTextDrawHide = function(id) + if id == get_guns.enter_textdrawId then + get_guns.enter_textdrawId = -1 + get_guns.enter_textdraw = false + end +end +get_guns.onShowDialog = function(id, style, title, button1, button2, text) + if title == "Статистика персонажа" then + local frac, rank = text:match("Организация\t(.+).Ранг\t.+%[(.+)%]") + if rank ~= nil then + rank = rank:gsub("Лидер", "10") + rank = tonumber(rank) + config.data.stats.rank = rank + config.data.stats.frac = frac + config.save(config.data) + end + if not get_guns.check_stats then + get_guns.check_stats = true + get_guns.antiflood = os.time() - 28 + return false + end + end + if title == "Склад оружия" then + if get_guns.getgun then + if #get_guns.list > 0 then + sampSendDialogResponse(id,1,get_guns.list[1],"") + table.remove(get_guns.list, 1) + else + get_guns.getgun = false + end + return false + end + end +end +get_guns.weapon = {} -- >> onSendPacket +get_guns.onResetPlayerWeapons = function() + get_guns.weapon = {} +end +get_guns.loop = function() + get_guns.antiflood = 0 + get_guns.check_stats = false + get_guns.check_warehouse = false + get_guns.check_warehouse_time = 0 + get_guns.warehouse = false + get_guns.getgun = false + get_guns.list = {} + get_guns.messages = {} + get_guns.warelock_send = {} + while true do + wait(0) + if not get_guns.check_stats then + if sampIsLocalPlayerSpawned() and os.time() - get_guns.antiflood > 30 then + get_guns.antiflood = os.time() + antiflood.send[#antiflood.send+1] = "/stats" + end + elseif not get_guns.check_warehouse then + if sampIsLocalPlayerSpawned() and os.time() - get_guns.antiflood > 30 then + get_guns.antiflood = os.time() + antiflood.send[#antiflood.send+1] = "/warehouse" + end + end + if get_guns.enter_textdraw and isKeyCanBePressed() and wasKeyPressed(vkeys[config.data.get_guns.key]) and not get_guns.getgun then + get_guns.start_get() + else + if wasKeyPressed(vkeys[config.data.get_guns.key]) and get_guns.getgun then + msg.add("Выполняется взятие ганов") + end + end + if #get_guns.messages > 0 then + if config.data.get_guns.warelock_auto and not get_guns.warehouse and config.data.stats.rank >= 8 then + local result = false + local text = split(get_guns.messages[1], " ") + for i = 1, #config.data.get_guns.warelock_text do + for p = 1, #text do + if text[p] == config.data.get_guns.warelock_text[i] then + result = true + end + end + end + if result then + local rand = math.random(1, 5) + get_guns.warelock_send = { + { os.time() + rand, false }, + { os.time() + config.data.get_guns.warelock_time + rand, true } + } + end + end + table.remove(get_guns.messages, 1) + end + if #get_guns.warelock_send > 0 then + if get_guns.warelock_send[1][1] < os.time() then + if get_guns.warelock_send[1][2] == get_guns.warehouse then + antiflood.send[#antiflood.send+1] = "/warelock" + end + table.remove(get_guns.warelock_send, 1) + end + end + end +end +get_guns.start_get = function() + get_guns.list = {} + for i = 1, #config.data.get_guns.list do + if config.data.get_guns.list[i][2] > 0 then + if get_guns.weapon[config.data.get_guns.list[i][3]] == nil or get_guns.weapon[config.data.get_guns.list[i][3]] < (config.data.get_guns.list[i][4] * config.data.get_guns.list[i][2]) then + for n = 1, config.data.get_guns.list[i][2] do + get_guns.list[#get_guns.list+1] = i - 1 + end + end + end + end + if #get_guns.list > 0 then + get_guns.getgun = true + antiflood.send[#antiflood.send+1] = "/getgun" + else + msg.add("У Вас достаточно оружия!") + end +end + +-->> INVITE HELPER +invite_helper = {} +invite_helper.data = {} +invite_helper.onServerMessage = function(color, message) + if message:find("^ Вы приняли .+ в ") then + local name = message:match("^ Вы приняли (.+) в ") + if invite_helper.data[name] ~= nil then + antiflood.send[#antiflood.send+1] = invite_helper.data[name] + invite_helper.data[name] = nil + else + if config.data.invite_helper.auto_rank then + local result, id = getPlayerIdByPlayerName(name) + if result then + antiflood.send[#antiflood.send+1] = "/giverank "..id.." "..config.data.invite_helper.rank + end + end + end + if #config.data.invite_helper.message > 0 then + name = name:gsub("_", " ") + antiflood.send[#antiflood.send+1] = string.format("/r %s", config.data.invite_helper.message:gsub("{name}", name)) + end + end +end +invite_helper.onSendCommand = function(cmd) + if cmd:find("%/invite %d+") then + local id, rank = cmd:match("%/invite (%d+)"), config.data.invite_helper.rank + if cmd:find("%/invite (%d+) (%d+)") then + id, rank = cmd:match("%/invite (%d+) (%d+)") + end + id = tonumber(id) + local result, name = getNickNameByPlayerId(id) + if result then + if ScoresAndPings[id] ~= nil then + local score = ScoresAndPings[id].score + if score >= config.data.invite_helper.lvl then + invite_helper.data[name] = "/giverank "..id.." "..rank + else + msg.add(string.format("У игрока %s[%d] всего %d уровень. Нужен %d уровень!", name, id, score, config.data.invite_helper.lvl)) + return false + end + end + end + end +end +invite_helper.loop = function() + while true do + wait(0) + local result, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) + if result then + local result, id = sampGetPlayerIdByCharHandle(ped) + if result and wasKeyPressed(vkeys[config.data.invite_helper.key]) then + antiflood.send[#antiflood.send+1] = "/invite "..id + end + end + end +end + +-->> ANTIFLOOD +antiflood = {} +antiflood.clock = 0 +antiflood.set = function() + antiflood.clock = os.clock() * 1000 +end +antiflood.get = function() + return (os.clock() * 1000 - antiflood.clock) +end +antiflood.send = {} +antiflood.loop = function() + while true do + wait(0) + if antiflood.get() > 1300 then + if #antiflood.send > 0 then + sampSendChat(antiflood.send[1]) + table.remove(antiflood.send, 1) + antiflood.set() + end + end + end +end + +-->> MAFIA CHECKER +mafia_checker = {} +mafia_checker.loop = function() + mafia_checker.skin = { + [118] = 2868839942, + [117] = 2868839942, + [169] = 2868839942, + [120] = 2868839942, + [186] = 2868839942, + [123] = 2868839942, + [272] = 2864232118, + [112] = 2864232118, + [125] = 2864232118, + [214] = 2864232118, + [111] = 2864232118, + [126] = 2864232118, + [124] = 2868164608, + [223] = 2868164608, + [113] = 2868164608, + [91] = 2868164608, + [127] = 2868164608 + } + while true do + wait(0) + if config.data.mafia_checker.main then + if mafia_checker.setpos then + sampSetCursorMode(3) + local x, y = getCursorPos() + config.data.mafia_checker.x = x + config.data.mafia_checker.y = y + if isKeyJustPressed(1) then + sampSetCursorMode(0) + config.save(config.data) + mafia_checker.setpos = false + end + end + local players = { + [2868164608] = { "lcn", 0, 0 }, + [2868839942] = { "yakuza", 0, 0 }, + [2864232118] = { "rm", 0, 0 }, + } + for i = 0, sampGetMaxPlayerId(false) do + if sampIsPlayerConnected(i) then + local color = sampGetPlayerColor(i) + if players[color] ~= nil then + players[color][2] = players[color][2] + 1 + end + local result, handle = sampGetCharHandleBySampPlayerId(i) + if result then + local model = getCharModel(handle) + if mafia_checker.skin[model] ~= nil then + players[mafia_checker.skin[model]][3] = players[mafia_checker.skin[model]][3] + 1 + end + end + end + end + local text = string.format("{ba9307}LCN:{ffffff} %d (%d)\n{b81a24}Yakuza:{ffffff} %d (%d)\n{999696}RM:{ffffff} %d (%d)\n", players[2868164608][2], players[2868164608][3], players[2868839942][2], players[2868839942][3], players[2864232118][2], players[2864232118][3]) + renderFontDrawText(font,text,config.data.mafia_checker.x,config.data.mafia_checker.y,-1) + end + end +end + +-->> MSK TIME +msk_time = {} +msk_time.update = 0 +msk_time.time = 0 +msk_time.get = function() + if msk_time.update == 0 then + return os.time() + end + return msk_time.time + (os.time() - msk_time.update) +end + +-->> REQUEST +request = {} +request.chat = {} +request.send = {} +request.base = {} +request.loop = function() + request.wait = 0 + while true do + wait(0) + if os.time() - request.wait >= 5 then + request.wait = os.time() + local request_table = { + sender = getLocalPlayerNickname(), + server = getServerAddress(), + room = config.data.room, + send = request.send, + rand = os.clock() + } + request.send = {} + local url = string.format("http://mafia.deadpoo.net/%s", urlencode(encodeJson(request_table))) + local result, text = pcall(openURL, url, os.tmpname(), true) + if result then + local result = pcall(request.handler, text) + if not result then + addChatMessage(text) + addChatMessage("Сервер 'mafia-tools' не отвечает!") + break + end + end + end + end +end +request.handler = function(text) + local info = decodeJson(text) + if info["time"] ~= nil then + msk_time.update = os.time() + msk_time.time = info["time"] + end + if info["result"] == "ok" then + menu.data = info["data"] + local new_data = { + ls = { time = 0, text = "00:00:00" }, + sf = { time = 0, text = "00:00:00" }, + lv = { time = 0, text = "00:00:00" }, + mhcars = { time = 0, text = "00:00:00" }, + ffixcar = { time = 0, text = "00:00:00" }, + } + for sender, sender_data in pairs(info["data"]) do + if isPlayerInList(sender) then + for key, v in pairs(sender_data) do + if new_data[key] ~= nil then + if new_data[key]["time"] < v["time"] then + new_data[key]["time"] = v["time"] + new_data[key]["text"] = v["text"] + end + end + end + end + end + ammo_timer.data = new_data + local text = "" + for i = 1, #info["ffixcar_log"] do + local data = info["ffixcar_log"][i] + if isPlayerInList(data["sender"]) then + text = string.format("%s[%s] %s\n", text, os.date("%X", data["time"]), data["text"]) + end + end + menu.ffixcar_log = text + for sender, sender_data in pairs(info["chat"]) do + if isPlayerInList(sender) then + local key = string.format("%d%s", sender_data.time, sender_data.text) + if request.chat[key] == nil then + request.chat[key] = true + local dev = "" + if sender == "Serhiy_Rubin" or sender == "Rafael_Moreno" then + dev = "[Разработчик] " + end + if msk_time.get() - sender_data.time < 15 then + local text = string.format("%s%s: %s", dev, sender, sender_data.text) + addChatMessage(text) + end + end + end + end + end + return true +end + +-->> AMMO TIMER +ammo_timer = {} +ammo_timer.last_ammo = "" +ammo_timer.onServerMessage = function(color, message) + if message:find("^ Следующее ограбление будет доступно в (%d+:%d+:%d+)") then + if ammo_timer.last_ammo ~= "" then + request.send[#request.send + 1] = { + key = ammo_timer.last_ammo, + text = message:match("^ Следующее ограбление будет доступно в (%d+:%d+:%d+)") + } + request.wait = 0 + end + end + if message:find("^ Задание будет доступно через: ") then + local p1, p2, p3 = string.match(message, "Задание будет доступно через: (%d+):(%d+):(%d+)") + if(p3 == nil)then + p1, p2 = string.match(message, "Задание будет доступно через: (%d+):(%d+)") + end + if(p1 ~= nil and p2 ~= nil)then + local mhTimer = 0 + if(p3 ~= nil)then + mhTimer = tonumber(p1) * 3600 + mhTimer = mhTimer + (tonumber(p2) * 60) + mhTimer = mhTimer + tonumber(p3) + else + mhTimer = mhTimer + (tonumber(p1) * 60) + mhTimer = mhTimer + tonumber(p2) + end + request.send[#request.send + 1] = { + key = "mhcars", + second = mhTimer + } + request.wait = 0 + end + end --> by Richard_Holmes + if message:find(".+ заказал спавн транспорта через %d+ секунд%. С банка фракции снято %d+ вирт$") then + request.send[#request.send + 1] = { + key = "ffixcar", + text = message:match(" (%g+_%g+ заказал спавн транспорта через %d+ секунд%. С банка фракции снято %d+ вирт)$") + } + request.wait = 0 + end +end +ammo_timer.data = { + ls = { time = 0, text = "00:00:00" }, + sf = { time = 0, text = "00:00:00" }, + lv = { time = 0, text = "00:00:00" }, + mhcars = { time = 0, text = "00:00:00" }, + ffixcar = { time = 0, text = "00:00:00" }, +} +ammo_timer.loop = function() + font = renderCreateFont(config.data.font.name,config.data.font.size,config.data.font.flag) + local getText = function(key) + if config.data.timer_hud[key] ~= nil and not config.data.timer_hud[key] then + return "" + end + if ammo_timer.data[key]["time"] == 0 then + return string.format("{%s}%s:{%s} %s\n", config.data.font.color1, key:upper(), config.data.font.color2, ammo_timer.data[key]["text"]) + else + local min = math.floor((msk_time.get() - ammo_timer.data[key]["time"]) / 60) + return string.format("{%s}%s:{%s} %s (%d min)\n", config.data.font.color1, key:upper(), config.data.font.color2, ammo_timer.data[key]["text"], min) + end + end + while true do + wait(0) + if config.data.timer_hud.main then + if ammo_timer.setpos then + sampSetCursorMode(3) + local x, y = getCursorPos() + config.data.timer_hud.x = x + config.data.timer_hud.y = y + if isKeyJustPressed(1) then + sampSetCursorMode(0) + config.save(config.data) + ammo_timer.setpos = false + end + end + local text = string.format("%s%s%s%s%s", getText("ls"), getText("sf"), getText("lv"), getText("mhcars"), getText("ffixcar")) + renderFontDrawText(font,text,config.data.timer_hud.x,config.data.timer_hud.y,-1) + end + end +end + +-->> 2 MIN TIMER +timer_2min = {} +timer_2min.onServerMessage = function(color, message) + if message:find("Война за бизнес .+ продлена на 2 минуты") then + local now = os.time() - config.data.time_2min + if now < 300 and (os.time() - config.data.time_2min) > 120 then + addChatMessage("2 мин длилось на "..((os.time() - config.data.time_2min) - 120).." секунд больше") + end + config.data.time_2min = os.time() + config.save(config.data) + end +end +timer_2min.loop = function() + while true do + wait(0) + for a = 0, 2304 do + if sampTextdrawIsExists(a) then + local x, y = sampTextdrawGetPos(a) + if math.ceil(x) == 87 and math.ceil(y) == 256 then + local time = 120 - (os.time() - config.data.time_2min) + local text = string.format("%02d:%02d", math.floor(time / 60), time % 60) + if time < 120 and time >= 0 and sampTextdrawGetString(a) ~= text then + sampTextdrawSetString(a,text) + end + end + end + end + end +end + +-->> CONFIG +config = {} +config.data = {} +local x1, y1 = convertGameScreenCoordsToWindowScreenCoords(14, 310) +local x2, y2 = convertGameScreenCoordsToWindowScreenCoords(40, 410) +config.default = { + font = { + name = "Segoe UI", + size = 10, + flag = 13, + color1 = "fffd8f", + color2 = "ffffff" + }, + time_2min = 0, + room = "all", + list = {}, -->> Список + list_block = true, -->> Использовать как Черный или Белый список + timer_hud = { + main = false, + mhcars = false, + ffixcar = false, + x = x1, + y = y1 + }, + mafia_checker = { + main = false, + x = x2, + y = y2 + }, + invite_helper = { + lvl = 7, + auto_rank = true, + rank = 7, + key = "VK_I", + message = "Добро пожаловать, {name}!" + }, + get_guns = { + list = { + { "Desert Eagle", 0, 2, 14 }, + { "Shotgun", 0, 3, 10 }, + { "SMG", 0, 4, 60 }, + { "AK47", 0, 5, 60 }, + { "M4A1", 0, 5, 100 }, + { "Rifle", 0, 6, 10 }, + { "Броня", 0, 777, 10 } + }, + key = "VK_G", + auto_get_guns = false, + warelock_auto = false, + warelock_text = { + "sklad", + "склад" + }, + warelock_time = 10 + }, + stats = { + frac = "", + rank = 0 + }, + war = { + armoff = true, + armoff_id = { 0, 1, 4 } + } +} +config.directory = string.format("%s\\moonloader\\config\\%s\\", getGameDirectory(), thisScript().name) +config.init = function() + if not doesDirectoryExist("moonloader\\config") then + createDirectory("moonloader\\config") + end + if not doesDirectoryExist(config.directory) then + createDirectory(config.directory) + end + config.address = string.format("%s\\%s-%s.json", config.directory, getSampRpServerName(), getLocalPlayerNickname()) + if not doesFileExist(config.address) then + config.save(config.default) + end + config.read() + for k,v in pairs(config.default) do + if config.data[k] == nil then + config.data[k] = v + end + end + config.save(config.data) +end +config.save = function(data) + local file, error = io.open(config.address, "w") + if file == nil then + addChatMessage(error) + end + file:write(encodeJson(data)) + file:flush() + io.close(file) +end +config.read = function() + local readJson = function() + local file, error = io.open(config.address, "r") + if file then + config.data = decodeJson(file:read("*a")) + io.close(file) + if config.data == nil then + addChatMessage("Ошибка чтения конфига! Сбрасываю конфиг!") + config.save(config.default) + end + end + end + local result = pcall(readJson) + if not result then + addChatMessage("Ошибка чтения конфига! Сбрасываю конфиг!") + config.save(config.default) + end + if config.data == nil then + config.error = true + addChatMessage("Ошибка чтения конфига! Пробую ещё раз прочесть") + config.read() + else + if config.error then + addChatMessage("Конфиг был успешно загружен!") + config.error = false + end + end +end + +-->> EVENTS +function processEvent(func, args) + if args == nil then + args = {} + end + local kk = table.pack(func(table.unpack(args))) + if kk.n > 0 then + return kk + end +end -- by QRLK (edith.lua) +function sampev.onServerMessage(color, message) + if os.time() - live < 3 then + timer_2min.onServerMessage(color, message) + ammo_timer.onServerMessage(color, message) + invite_helper.onServerMessage(color, message) + local res = processEvent(get_guns.onServerMessage, table.pack(color, message)) + if res then + return table.unpack(res) + end + end +end +function sampev.onSendPickedUpPickup(id) + local X, Y, Z = getCharCoordinates(PLAYER_PED) + local ammo = { + ["ls"] = {x = 1366.6401367188, y = -1279.4899902344, z = 13.546875}, + ["sf"] = {x = -2626.4050292969, y = 210.6088104248, z = 4.6033186912537}, + ["lv"] = {x = 2158.3286132813, y = 943.17541503906, z = 10.371940612793} + } + for k, v in pairs(ammo) do + local distance = getDistanceBetweenCoords3d(X, Y, Z, v.x, v.y, v.z) + if distance <= 5 then + ammo_timer.last_ammo = k + end + end --> by Benya +end +ScoresAndPings = {} +function sampev.onUpdateScoresAndPings(data) + ScoresAndPings = data +end +function sampev.onSendCommand(cmd) + antiflood.set() + local res = processEvent(invite_helper.onSendCommand, table.pack(cmd)) + if res then + return table.unpack(res) + end +end +function sampev.onSendChat(message) + antiflood.set() + local score = sampGetPlayerScore(tonumber(message)) + addChatMessage(score) +end +function sampev.onShowDialog(id, style, title, button1, button2, text) + local res = processEvent(get_guns.onShowDialog, table.pack(id, style, title, button1, button2, text)) + if res then + return table.unpack(res) + end +end +function sampev.onShowTextDraw(id, data) + get_guns.onShowTextDraw(id, data) +end +function sampev.onTextDrawHide(id) + get_guns.onTextDrawHide(id) +end +function onSendPacket(id, bs) + if id == 204 then + raknetBitStreamIgnoreBits(bs,40) + local count = raknetBitStreamGetNumberOfUnreadBits(bs) / 32 + for i = 1, count do + local slot = raknetBitStreamReadInt8(bs) + local weapon = raknetBitStreamReadInt8(bs) + local ammo = raknetBitStreamReadInt16(bs) + if get_guns.weapon ~= nil then + get_guns.weapon[slot] = ammo + if ammo == 0 then + table.remove(get_guns.weapon, slot) + end + end + end + end +end +function sampev.onResetPlayerWeapons() + get_guns.onResetPlayerWeapons() +end +-->> NEW FUNCTION +function getLocalPlayerNickname() + return sampGetPlayerNickname(select(2, sampGetPlayerIdByCharHandle(PLAYER_PED))) +end +function getServerAddress() + local ip, port = sampGetCurrentServerAddress() + return string.format("%s:%s", ip, port) +end +function getSampRpServerName() + local result = "" + local server = sampGetCurrentServerName():gsub("|", "") + local server_find = { "02", "Two", "Revo", "Legacy", "Classic" } + for i = 1, #server_find do + if server:find(server_find[i]) then + result = server_find[i] + end + end + return result +end +function convertTableToString(table) + local result = "" + for i = 1, #table do + result = string.format("%s%s\n", result, table[i]) + end + return result +end +function start_dialog(_menu, put) -- module by trefa & modify (put & list in []) + function _dialog(_menu, id, outs, put) + sampShowDialog(id, _menu.settings.title, tbl_split(_menu.settings.style, _menu, _menu.settings.forward ,_menu.settings.backwards ,_menu.settings.score), _menu.settings.btn1, (_menu.settings.btn2 ~= nil and _menu.settings.btn2 or _), _menu.settings.style) + repeat + wait(0) + if put ~= nil and sampIsDialogActive() then + sampSetCurrentDialogEditboxText(put) + put = nil + end + local result, button, list, input = sampHasDialogRespond(id) + if result then + local out, outs = _menu[((_menu.settings.style == 0 or _menu.settings.style == 1 or _menu.settings.style == 3) and 1 or ((list + 1) > #_menu[1] and 2 or 1))][((_menu.settings.style == 0 or _menu.settings.style == 1 or _menu.settings.style == 3) and 1 or ((list + 1) > #_menu[1] and (list - #_menu[1]) + 1 or list + 1))].click(button, list, input, outs) + if type(out) == "table" then + return _dialog(out, id - 1, outs, put) + elseif type(out) == "boolean" then + if not out then + return out + end + return _dialog(_menu, id, outs, put) + end + end + until result or menu.show[1] + end + + function tbl_split(style, tbl, forward ,backwards ,score) + if style == 2 or style == 4 or style == 5 then + text = (style == 5 and tbl[1].text.."\n" or "") + for i, val in ipairs(tbl[1]) do + text = text..""..forward..""..(score and "["..(i-1).."] " or "")..""..val.title..""..backwards + end + if tbl[2] ~= nil then + for _, val in ipairs(tbl[2]) do + text = text..""..forward..""..val.title..""..backwards + end + end + return text + end + return tbl[1].text + end + + return _dialog(_menu, 1337, outs, put) +end +function getNicknamesOnline() + local result = {} + for i = 0, sampGetMaxPlayerId(false) do + if sampIsPlayerConnected(i) or select(2, sampGetPlayerIdByCharHandle(PLAYER_PED)) == i then + result[sampGetPlayerNickname(i)] = i + end + end + return result +end +function urlencode(str) + str = string.gsub (str, "([^0-9a-zA-Z !'()*._~-])", -- locale independent + function (c) return string.format ("%%%02X", string.byte(c)) end) + return str +end +function getNickNameByPlayerId(id) + local result = false + local nick = "" + if sampIsPlayerConnected(id) then + nick = sampGetPlayerNickname(id) + result = true + end + return result, nick +end +function getPlayerIdByPlayerName(name) + local result = false + local id = -1 + for i = 0, sampGetMaxPlayerId(false) do + if sampIsPlayerConnected(i) then + if sampGetPlayerNickname(i) == name then + result = true + id = i + break + end + end + end + return result, id +end +function isPlayerInList(sender) + local result = false + if config.data.list_block then + if config.data.list[sender] == nil then + result = true + end + else + if config.data.list[sender] ~= nil then + result = true + end + end + return result +end +function isKeyCanBePressed() + if sampIsDialogActive() or sampIsChatInputActive() or sampIsCursorActive() or isSampfuncsConsoleActive() then + return false + end + return true +end +function split(str, delim, plain) + local tokens, pos, plain = {}, 1, not (plain == false) --[[ delimiter is plain text by default ]] + repeat + local npos, epos = string.find(str, delim, pos, plain) + table.insert(tokens, string.sub(str, pos, npos and npos - 1)) + pos = epos and epos + 1 + until not pos + return tokens +end +function sendRpcCommand(text) + local bs = raknetNewBitStream() + raknetBitStreamWriteInt32(bs, #text) + raknetBitStreamWriteString(bs,text) + raknetSendRpc(50,bs) + raknetDeleteBitStream(bs) +end + +-->> UPDATE MODULE +function openURL(url, fpath, message_off) + local text = "" + local file_download = false + local download_final = false + + + if doesFileExist(fpath) then + os.remove(fpath) + end + + downloadUrlToFile(url, fpath, function(id, status, p1, p2) + if status == dlstatus.STATUS_ENDDOWNLOADDATA then + file_download = true + end + if status == dlstatus.STATUSEX_ENDDOWNLOAD then + download_final = true + end + end + ) + + repeat + wait(1000) + until download_final or file_download + + if file_download then + local f = io.open(fpath, "r") + if f then + text = f:read("*a") + io.close(f) + end + os.remove(fpath) + end + + if (text:find("Not found") and not text:find('"Not found"')) or text == "" then + text = "" + if not message_off then + addChatMessage("Не удалось скачать обновление по ссылке:") + addChatMessage(url) + end + end + + return text +end + +function addChatMessage(text) + local tag = string.format("{667dff}[%s]{FFFFFF} ", thisScript().name) + sampAddChatMessage(tag..text, 0xFFFFFFFF) +end + +-->> Chat Message HOOK (Для addChatMessage вне хука samp events) +msg = {} +msg.list = {} +msg.add = function(arg) + msg.list[#msg.list+1] = arg +end +msg.loop = function() + if #msg.list > 0 then + addChatMessage(msg.list[1]) + table.remove(msg.list, 1) + end +end + +script_update = { + version_url = "http://git.deadpoo.net/rubin/mafia-tools/raw/branch/master/version", + script_url = "http://git.deadpoo.net/rubin/mafia-tools/raw/branch/master/mafia-tools.lua", + changelog_url = "http://git.deadpoo.net/rubin/mafia-tools/raw/branch/master/changelog", + address_ini = string.format("rubin-mods-updates\\%s.ini", thisScript().name), + main = function() + if not doesDirectoryExist("moonloader\\config\\rubin-mods-updates") then + createDirectory("moonloader\\config\\rubin-mods-updates") + end + local ini = inicfg.load({ + settings = { + check_update = true, + auto_update = true, + server_version = "" + } + }, script_update.address_ini) + ini.settings.version_url = script_update.version_url + ini.settings.script_url = script_update.script_url + ini.settings.changelog_url = script_update.changelog_url + ini.settings.version = thisScript().version + ini.settings.script_name = thisScript().name + local command = (thisScript().name:gsub(" ", "").."-update"):lower() + sampRegisterChatCommand(command, script_update.command) + if ini.settings.check_update or ini.settings.auto_update then + local fpath = os.tmpname() + local result, text = pcall(openURL, script_update.version_url, fpath) + if result then + ini.settings.server_version = text + if text ~= "" and text ~= thisScript().version then + addChatMessage( string.format("Вышла новая версия '%s'. Текущая: '%s'", text, thisScript().version) ) + if ini.settings.auto_update then + addChatMessage( string.format("Автообновление скрипта включено. Процесс запущен!") ) + script_update.command() + else + addChatMessage( string.format("Автообновление скрипта выключено. Обновить самому: /%s", command) ) + end + end + end + end + inicfg.save(ini, script_update.address_ini) + script_update.menu.init() + end, + command = function() + lua_thread.create(function() + local fpath = os.tmpname() + local result, text = pcall(openURL, script_update.version_url, fpath) + if result then + if text ~= "" and text ~= thisScript().version then + addChatMessage( string.format("Вышла новая версия '%s'. Текущая: '%s'", text, thisScript().version) ) + local fpath = os.tmpname() + local result, text = pcall(openURL, script_update.script_url, fpath) + if result and text ~= "" and text:find(thisScript().name:gsub("%-", "%%-")) then + local file, error = io.open(thisScript().path, "w") + if file ~= nil then + file:write(text) + file:flush() + io.close(file) + addChatMessage("Обновление завершено, скрипт перезагружен!") + wait(500) + thisScript():reload() + end + end + else + addChatMessage("У Вас установлена последняя версия!") + end + end + end) + end, + menu = { + dialog = {}, + ini = {}, + init = function() + if not sampIsChatCommandDefined("rubin-mods") then + sampAddChatMessage("{667dff}[RUBIN MODS]{FFFFFF} Управление обновлениями скриптов: /rubin-mods", 0xFFFFFFFF) + sampRegisterChatCommand("rubin-mods",script_update.menu.show) + while true do + wait(0) + local result, button, list, input = sampHasDialogRespond(2160) + if result and button == 1 then + if script_update.menu.ini[list+1] ~= nil and script_update.menu.dialog[list+1] ~= nil then + script_update.menu.dialog[list+1](script_update.menu.ini[list+1]) + end + end + local result, button, list, input = sampHasDialogRespond(2162) + if result then + if button == 1 then + if script_update.menu2.text[list+1] ~= nil and script_update.menu2.dialog[list+1] ~= nil then + script_update.menu2.dialog[list+1]() + end + else + script_update.menu.show() + end + end + local result, button, list, input = sampHasDialogRespond(2161) + if result then + script_update.menu2.show(script_update.menu2.data) + end + end + end + end, + show = function() + script_update.menu.dialog = {} + script_update.menu.ini = {} + local text = "" + if doesDirectoryExist("moonloader\\config\\rubin-mods-updates") then + local FileHandle, FileName = findFirstFile("moonloader\\config\\rubin-mods-updates\\*") + while FileName ~= nil do + if FileName ~= nil and FileName ~= ".." and FileName ~= "." and FileName:find("%.ini") then + local address = string.format("moonloader\\config\\rubin-mods-updates\\%s", FileName) + if doesFileExist(address) then + local ini = inicfg.load({}, address) + script_update.menu.ini[#script_update.menu.ini+1] = address + text = string.format("%s%s\n", text, string.format("%s\t%s%s", ini.settings.script_name, (ini.settings.version == ini.settings.server_version and "{59fc30}" or "{ff0000}"),ini.settings.version)) + script_update.menu.dialog[#script_update.menu.dialog+1] = function(data) + script_update.menu2.show(data) + end + end + end + FileName = findNextFile(FileHandle) + end + findClose(FileHandle) + else + text = "Не найдена директория:\t\n moonloader\\config\\rubin-mods-updates\t" + end + sampShowDialog(2160,"Обновление скриптов: Rubin Mods","Скрипт\tВерсия\n"..text,"Выбрать","Закрыть",5) + end + }, + menu2 = { + data = {}, + text = {}, + dialog = {}, + show = function(data) + script_update.menu2.data = data + script_update.menu2.text = {} + script_update.menu2.dialog = {} + if doesFileExist(data) then + local ini = inicfg.load({}, data) + script_update.menu2.text[#script_update.menu2.text+1] = string.format("Автообновление %s", (ini.settings.auto_update and "{59fc30}ON" or "{ff0000}OFF")) + script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() + ini.settings.auto_update = not ini.settings.auto_update + inicfg.save(ini, data) + script_update.menu2.show(data) + end + if not ini.settings.auto_update then + script_update.menu2.text[#script_update.menu2.text+1] = string.format("Проверять обновления %s", (ini.settings.check_update and "{59fc30}ON" or "{ff0000}OFF")) + script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() + ini.settings.check_update = not ini.settings.check_update + inicfg.save(ini, data) + script_update.menu2.show(data) + end + end + script_update.menu2.text[#script_update.menu2.text+1] = string.format("Последние изменения") + script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() + script_update.changelog(ini.settings.changelog_url, ini.settings.script_name) + end + script_update.menu2.text[#script_update.menu2.text+1] = string.format("Удалить из списка") + script_update.menu2.dialog[#script_update.menu2.dialog+1] = function() + os.remove(data) + script_update.menu.show() + end + local text = "" + for i = 1, #script_update.menu2.text do + text = text..script_update.menu2.text[i].."\n" + end + sampShowDialog(2162,"Настройки обновления для "..ini.settings.script_name,text,"Выбрать","Назад",2) + end + end + }, + changelog = function(url, name) + local fpath = os.tmpname() + local result, text = pcall(openURL, url, fpath) + if result then + sampShowDialog(2161,"Changelog - "..name,text,"Выбрать","Назад",4) + end + end +} + +-->> SCRIPT UTF-8 +-->> utf8(table path, incoming variables encoding, outcoming variables encoding) +-->> table path example { "sampev", "onShowDialog" } +-->> encoding options nil | AnsiToUtf8 | Utf8ToAnsi +_utf8 = load([=[return function(utf8_func, in_encoding, out_encoding); if encoding == nil then; encoding = require("encoding"); encoding.default = "CP1251"; u8 = encoding.UTF8; end; if type(utf8_func) ~= "table" then; return false; end; if AnsiToUtf8 == nil or Utf8ToAnsi == nil then; AnsiToUtf8 = function(text); return u8(text); end; Utf8ToAnsi = function(text); return u8:decode(text); end; end; if _UTF8_FUNCTION_SAVE == nil then; _UTF8_FUNCTION_SAVE = {}; end; local change_var = "_G"; for s = 1, #utf8_func do; change_var = string.format('%s["%s"]', change_var, utf8_func[s]); end; if _UTF8_FUNCTION_SAVE[change_var] == nil then; _UTF8_FUNCTION = function(...); local pack = table.pack(...); readTable = function(t, enc); for k, v in next, t do; if type(v) == 'table' then; readTable(v, enc); else; if enc ~= nil and (enc == "AnsiToUtf8" or enc == "Utf8ToAnsi") then; if type(k) == "string" then; k = _G[enc](k); end; if type(v) == "string" then; t[k] = _G[enc](v); end; end; end; end; return t; end; return table.unpack(readTable({_UTF8_FUNCTION_SAVE[change_var](table.unpack(readTable(pack, in_encoding)))}, out_encoding)); end; local text = string.format("_UTF8_FUNCTION_SAVE['%s'] = %s; %s = _UTF8_FUNCTION;", change_var, change_var, change_var); load(text)(); _UTF8_FUNCTION = nil; end; return true; end]=]) +function utf8(...) + pcall(_utf8(), ...) +end + +utf8({ "sampShowDialog" }, "Utf8ToAnsi") +utf8({ "sampSendChat" }, "Utf8ToAnsi") +utf8({ "sampAddChatMessage" }, "Utf8ToAnsi") +utf8({ "print" }, "Utf8ToAnsi") +utf8({ "renderGetFontDrawTextLength" }, "Utf8ToAnsi") +utf8({ "renderFontDrawText" }, "Utf8ToAnsi") +utf8({ "sampSetCurrentDialogEditboxText" }, "Utf8ToAnsi") +utf8({ "sampHasDialogRespond" }, nil, "AnsiToUtf8") +utf8({ "sampev", "onServerMessage" }, "AnsiToUtf8", "Utf8ToAnsi") +utf8({ "sampev", "onShowDialog" }, "AnsiToUtf8", "Utf8ToAnsi") +utf8({ "sampev", "onSendCommand" }, "AnsiToUtf8", "Utf8ToAnsi") \ No newline at end of file