From e45385b2d5dba8818ba7ed0cdbebd65711ad68ac Mon Sep 17 00:00:00 2001 From: rubin Date: Tue, 25 Oct 2022 19:48:53 +0300 Subject: [PATCH] initial commit --- pro100_binder.lua | 725 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 725 insertions(+) create mode 100755 pro100_binder.lua diff --git a/pro100_binder.lua b/pro100_binder.lua new file mode 100755 index 0000000..9411bfa --- /dev/null +++ b/pro100_binder.lua @@ -0,0 +1,725 @@ +script_name('pro100_binder') +script_author("RuBin") +vkeys = require "lib.vkeys" +sampev = require 'lib.samp.events' + +DIALOG_ID = 7761 +DIALOG_ID_NO_LIST = 7762 + +local ffi = require "ffi" +ffi.cdef[[ + void keybd_event(int keycode, int scancode, int flags, int extra); +]] + +function EmulateKey(key, isDown) + if not isDown then + ffi.C.keybd_event(key, 0, 2, 0) + else + ffi.C.keybd_event(key, 0, 0, 0) + end +end + +function sampev.onServerMessage(color, message) + if message:find('SMS: .+Отправитель: .+%[(%d+)%]') then + replace["{id_in_sms}"] = message:match('SMS: .+Отправитель: .+%[(%d+)%]') + end + if message:find('SMS: .+Получатель: .+%[(%d+)%]') then + replace["{id_out_sms}"] = message:match('SMS: .+Получатель: .+%[(%d+)%]') + end +end + +function main() + if not isSampLoaded() or not isSampfuncsLoaded() then return end + while not isSampAvailable() do wait(100) end + + settings_load() + command_show_dialog() + + replace = { + ["{target_id}"] = "0", + ["{target_rp_name}"] = " ", + ["{target_name}"] = " ", + ["{id_in_sms}"] = "0", + ["{id_out_sms}"] = "0" + } + + key_press = {} + key_press_counter = 0 + is_key_press = false + is_block_gamekeys = false + + while true do + wait(0) + while_target_check() + while_key_check() + while_show_dialog() + end +end + +function settings_load() + AdressConfig = string.format("%s\\moonloader\\config ", getGameDirectory()) + AdressJson = string.format("%s\\moonloader\\config\\pro100_binder.json", getGameDirectory()) + + local table_std = { + { cmd = {'/mm'}, enter = true, key = {'VK_M'} } + } + if not doesFileExist(AdressJson) then + local file, error = io.open(AdressJson, "w") + if file ~= nil then + file:write(encodeJson(table_std)) + file:flush() + io.close(file) + else + sampAddChatMessage(error, -1) + end + end + + try( + function() + local file, error = io.open(AdressJson, "r") + if file then + settings = decodeJson(file:read("*a")) + io.close(file) + end + end, + function(e) + sampAddChatMessage("[pro100_binder] Ошибка чтения конфига! Сбрасываю конфиг!", 0xff0000) + local file, error = io.open(AdressJson, "w") + if file ~= nil then + file:write(encodeJson(table_std)) + file:flush() + io.close(file) + end + end + ) + + + if settings ~= nil then + if error_ini ~= nil then + sampAddChatMessage("[pro100_binder] Конфиг был успешно загружен!", 0xff0000) + error_ini = nil + end + for k,v in pairs(table_std) do + if settings[k] == nil then + settings[k] = v + end + for i, s in pairs(v) do + if settings[k][i] == nil then + settings[k][i] = s + end + end + end + settings_save() + else + error_ini = true + sampAddChatMessage("[pro100_binder] Ошибка чтения конфига! Пробую ещё раз прочесть", 0xff0000) + settings_load() + end +end + +function settings_save() + local file, error = io.open(AdressJson, "w") + if file ~= nil then + file:write(encodeJson(settings)) + file:flush() + io.close(file) + else + sampAddChatMessage(error, -1) + end +end + +function try(f, catch_f) + local status, exception = pcall(f) + if not status then + catch_f(exception) + end +end + +function while_target_check() + local result, handle = getCharPlayerIsTargeting(PLAYER_HANDLE) + if result then + local result2, id = sampGetPlayerIdByCharHandle(handle) + if result2 then + local name = sampGetPlayerNickname(id) + replace["{target_id}"] = id + replace["{target_rp_name}"] = name:gsub("_", " ") + replace["{target_name}"] = name + end + end +end + +function while_key_check() + local editDialogActive = false + if sampIsDialogActive() and sampGetCurrentDialogType() == 1 then + editDialogActive = true + end + + if not sampIsScoreboardOpen() and not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not editDialogActive then + if isKeyDown(vkeys["VK_MENU"]) then + if not is_block_gamekeys then + is_block_gamekeys = true + setPlayerDuckButton(PLAYER_HANDLE, false) + setPlayerEnterCarButton(PLAYER_HANDLE, false) + end + else + if is_block_gamekeys then + is_block_gamekeys = false + setPlayerDuckButton(PLAYER_HANDLE, true) + setPlayerEnterCarButton(PLAYER_HANDLE, true) + end + end + + + local isPress = false + local isMenu = false + for k, v in pairs(vkeys) do + if isKeyDown(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" and k ~= "VK_LBUTTON" and k ~= "VK_W" and k ~= "VK_S" and k ~= "VK_A" and k ~= "VK_D" then + isPress = true + if key_press[k] == nil then + if k:find("MENU") then + local enter_press = false + for k,v in pairs(key_press) do + if k:find("MENU") then + enter_press = true + end + end + if not enter_press then + key_press["VK_MENU"] = "VK_MENU" + key_press_counter = key_press_counter + 1 + end + else + key_press[k] = v + key_press_counter = key_press_counter + 1 + end + end + end + end + + if isPress ~= is_key_press and not isPress then + for i = 1, #settings do + local down_counter = 0 + local alt = false + for k = 1, #settings[i].key do + if settings[i].key[k]:find("MENU") then + alt = true + end + if key_press[settings[i].key[k]] ~= nil then + down_counter = down_counter + 1 + end + end + if down_counter == #settings[i].key and key_press_counter == #settings[i].key then + while_send_array(alt, settings[i].enter, settings[i].cmd) + repeat wait(0) until not isKeyDown(vkeys[settings[i].key[#settings[i].key]]) + end + end + key_press = {} + key_press_counter = 0 + end + is_key_press = isPress + end +end + +function check_stop_bind() + if isKeyDown(vkeys["VK_N"]) then + return true + end +end + +function while_send_array(alt, enter, copy) + + local array = {} + local command = 0 + for i = 1, #copy do + array[i] = copy[i] + if array[i]:find("wait (%d+)") then + local ms = array[i]:match("wait (%d+)") + if #("wait "..ms) ~= #array[i] then + command = command + 1 + end + else + command = command + 1 + end + end + + local command_count = 0 + repeat + wait(0) + local text = array[1] + local wait_time = -1 + + if text:find("wait (%d+)") then + local ms = text:match("wait (%d+)") + if #("wait "..ms) == #text then + wait_time = tonumber(ms) + end + end + + if wait_time ~= -1 then + local sleep = os.clock() * 1000 + repeat + wait(0) + until os.clock() * 1000 - sleep > wait_time or check_stop_bind() or not enter + if check_stop_bind() then + break + end + table.remove(array, 1) + else + + for k,v in pairs(replace) do + if text:find(k) then + text = text:gsub(k, v) + end + end + + if alt and enter then + sampSendChat(text) + command_count = command_count + 1 + else + local chattext = sampGetChatInputText() + sampSetChatInputText(text) + sampSetChatInputEnabled(true) + if enter then + repeat + wait(0) + until sampIsChatInputActive() + EmulateKey(13, true) + EmulateKey(13, false) + end + command_count = command_count + 1 + end + repeat + wait(0) + until not sampIsChatInputActive() + if command > 1 then + printStringNow(string.format("BIND COUNT: %s/%s~n~Press N to stop", command_count, command), 1000) + if check_stop_bind() then + break + end + end + table.remove(array, 1) + end + until #array <= 0 +end + +function command_show_dialog() + sampRegisterChatCommand('binder',function() + show_dialog("main") + end) +end + +function show_dialog(param) + if param == "main" then + show_main_dialog() + end +end + +function get_text_keys_array(i) + local key_name = "" + for s = 1, #settings[i].key do + if (settings[i].key[s]:find("MENU") and not key_name:find("ALT")) or not settings[i].key[s]:find("MENU") then + key_name = key_name..settings[i].key[s]:gsub("VK_",""):gsub("MENU", "ALT")..(settings[i].key[s + 1] ~= nil and " + " or "") + end + end + return key_name +end + +function show_main_dialog() + dialogArray = {} + + dialogArray[#dialogArray + 1] = { + text = "Создать бинд\t \t ", + func = function(button, list, input) + if button == 1 then + show_create_dialog() + end + end + } + + for i = 1, #settings do + local key_name = get_text_keys_array(i) + + dialogArray[#dialogArray + 1] = { + text = " ["..i.."] "..key_name.."\t"..(settings[i].cmd[1] ~= nil and settings[i].cmd[1] or "nil").." ["..#settings[i].cmd.."]\t"..(settings[i].enter and "ENTER" or " "), + func = function(button, list, input) + if button == 1 then + show_bind_dialog(i, key_name) + return + end + end + } + end + + local text = "" + for k,v in pairs(dialogArray) do + text = text..v.text.."\n" + end + + sampShowDialog(DIALOG_ID,"PRO100_BINDER",text,"Выбрать","Закрыть",4) +end + +function show_bind_dialog(bind_id, key_name) + if settings[bind_id] == nil then return end + + local reset = function(button, list, input) + if button == 1 then + show_bind_dialog(bind_id, key_name) + else + show_main_dialog() + end + end + + dialogArray = {} + + dialogArray[#dialogArray + 1] = { + text = "Активация: "..key_name, + func = reset + } + + dialogArray[#dialogArray + 1] = { + text = "Авто-отправка: "..(settings[bind_id].enter and "ON" or "OFF"), + func = reset + } + + dialogArray[#dialogArray + 1] = { + text = " ", + func = reset + } + + dialogArray[#dialogArray + 1] = { + text = "[1] Удалить", + func = function(button, list, input) + if button == 1 then + table.remove(settings, bind_id) + settings_save() + end + show_main_dialog() + end + } + + dialogArray[#dialogArray + 1] = { + text = "[2] Редактировать", + func = function(button, list, input) + if button == 1 then + show_create_dialog(bind_id) + end + end + } + + dialogArray[#dialogArray + 1] = { + text = "\nВвод: \n"..get_text_array(settings[bind_id].cmd), + func = reset + } + + local text = "" + for k,v in pairs(dialogArray) do + text = text..v.text.."\n" + end + + sampShowDialog(DIALOG_ID,"PRO100_BINDER",text,"Выбрать","Закрыть",4) +end + +function get_text_keys(keys) + local text_keys = "" + for i = 1, #keys do + if (keys[i]:find("MENU") and not text_keys:find("ALT")) or not keys[i]:find("MENU") then + text_keys = text_keys..keys[i]:gsub("VK_", ""):gsub("MENU", "ALT")..(keys[i+1] ~= nil and " + " or "") + end + end + return text_keys +end + +function get_text_array(array) + local text= "" + for i = 1, #array do + text = text..array[i].."\n" + end + return text +end + +function show_create_dialog(param) + edit_key = param + dialogArray = {} + local keys = {} + + if edit_key ~= nil and settings[edit_key] ~= nil then + keys = settings[edit_key].key + end + + local timer_show_dialog = os.time() + local result, button = false, 0 + local refresh = true + local global_isPress = false + repeat + wait(0) + + local isPress = false + for k, v in pairs(vkeys) do + if isKeyDown(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" and k ~= "VK_LBUTTON" then + isPress = true + + if k:find("MENU") then + local result_search = true + for i = 1, #keys do + if keys[i]:find("MENU") then + result_search = false + end + end + + if result_search then + keys[#keys + 1] = "VK_MENU" + refresh = true + end + else + local result_search = false + for i = 1, #keys do + if keys[i] == k then + result_search = true + end + end + + if not result_search then + keys[#keys + 1] = k + refresh = true + end + end + end + end + + if isPress ~= global_isPress and isPress then + keys = {} + end + global_isPress = isPress + + if os.time() - timer_show_dialog > 0 or refresh then + refresh = false + timer_show_dialog = os.time() + + local text_keys = get_text_keys(keys) + + local text = string.format("{FFFFFF}Нажмите клавишу или сочитание клавиш\nИспользуется: %s", text_keys) + sampShowDialog(DIALOG_ID,"PRO100_BINDER",text,"Далее","Назад",0) + end + + local res, button, list, input = sampHasDialogRespond(DIALOG_ID) + if res then + if button == 1 then + if #keys > 0 then + local array = {} + if edit_key ~= nil and settings[edit_key] ~= nil then + array = settings[edit_key].cmd + end + show_create2_dialog(keys, array) + break + else + show_create_dialog(param) + break + end + else + show_main_dialog() + break + end + end + until result +end + +function show_create2_dialog(keys, array) + dialogArray = {} + dialogArray[#dialogArray + 1] = { + text = "Активация: "..get_text_keys(keys), + func = function(button, list, input) + show_create_dialog(edit_key) + end + } + + dialogArray[#dialogArray + 1] = { + text = " ", + func = function(button, list, input) + show_create_dialog(edit_key) + end + } + + dialogArray[#dialogArray + 1] = { + text = " [1] Добавить строку", + func = function(button, list, input) + if button == 1 then + show_edit("Добавить строку", keys, array) + else + show_create_dialog(edit_key) + end + end + } + + dialogArray[#dialogArray + 1] = { + text = " [2] Добавить задержку (ms)", + func = function(button, list, input) + if button == 1 then + show_edit("Добавить задержку (ms)", keys, array) + else + show_create_dialog(edit_key) + end + end + } + + dialogArray[#dialogArray + 1] = { + text = " [3] Далее", + func = function(button, list, input) + if button == 1 then + show_create3_dialog(keys, array) + else + show_create_dialog(edit_key) + end + end + } + + dialogArray[#dialogArray + 1] = { + text = " [4] Отмена", + func = function(button, list, input) + show_create_dialog(edit_key) + end + } + + dialogArray[#dialogArray + 1] = { + text = " ", + func = function(button, list, input) + show_create_dialog(edit_key) + end + } + + if #array > 0 then + dialogArray[#dialogArray + 1] = { + text = "Список текста (click to del)", + func = function(button, list, input) + show_create_dialog(edit_key) + end + } + end + + for i = 1, #array do + dialogArray[#dialogArray + 1] = { + text = " "..array[i], + func = function(button, list, input) + if button == 1 then + table.remove(array, i) + end + show_create2_dialog(keys, array) + end + } + end + + dialogArray[#dialogArray + 1] = { + text = " ", + func = function(button, list, input) + show_create_dialog(edit_key) + end + } + + local text = "" + for i = 1, #dialogArray do + text = text..dialogArray[i].text.."\n" + end + + sampShowDialog(DIALOG_ID,"PRO100_BINDER",text,"Далее","Отмена",2) +end + +function show_edit(text, keys, array) + dialogArray = {} + + if text == "Добавить строку" then + + text = string.format("%s\nПоддерживаются встроенные переменные!\n\n Таргет - это когда вы прицелились в человека (Зеленый треугольник над головой)\n Тогда скрипт запоминает данные этого игрока и вы можете их использовать!\n\t{target_id} - ID игрока\n\t{target_rp_name} - RP ник игрока\n\t{target_name} - Ник игрока", text) + + local server_name = sampGetCurrentServerName() + if server_name:find("SRP") or server_name:find("Samp%-Rp") then + text = string.format("%s\n\nПоддерживаются переменные для Samp-Rp!\n\t{id_in_sms} - ID игрока с последнего входящего СМС\n\t{id_out_sms} - ID игрока с последнего отправленного Вами СМС", text) + end + + dialogArray[1] = { + text = " [1] Добавить строку", + func = function(button, list, input) + if button == 1 then + if #input > 0 then + array[#array + 1] = input + end + show_create2_dialog(keys, array) + end + show_create2_dialog(keys, array) + end + } + end + + if text == "Добавить задержку (ms)" then + dialogArray[1] = { + text = " [2] Добавить задержку (ms)", + func = function(button, list, input) + if button == 1 then + if input:find("%d+") then + local ms = input:match("(%d+)") + if #ms == #input then + array[#array + 1] = "wait "..input:match("(%d+)") + end + end + end + show_create2_dialog(keys, array) + end + } + end + + sampShowDialog(DIALOG_ID_NO_LIST,"PRO100_BINDER",text,"Отправить","Отмена",1) +end + +function show_create3_dialog(keys, array) + local text_keys = get_text_keys(keys) + local text_command = get_text_array(array) + local text = string.format("{FFFFFF}Активация: %s\nВвод: %s\n\n Отправлять автоматически?\n\n (Иначе вставка в чат)", text_keys, text_command) + + dialogArray = {} + dialogArray[1] = { + text = "", + func = function(button, list, input) + if button == 1 then + show_create4_dialog(keys, array, true) + else + show_create4_dialog(keys, array, false) + end + end + } + + sampShowDialog(DIALOG_ID_NO_LIST,"PRO100_BINDER",text,"Да","Нет",0) +end + +function show_create4_dialog(keys, array, enter) + local text_keys = get_text_keys(keys) + local text_command = get_text_array(array) + + local text = string.format("{FFFFFF}Активация: %s\nВвод: %s\nАвто-отправка: %s\n\n Сохранить?", text_keys, text_command, (enter and "ON" or "OFF")) + + dialogArray = {} + dialogArray[1] = { + text = "", + func = function(button, list, input) + if button == 1 then + if edit_key ~= nil and settings[edit_key] ~= nil then + settings[edit_key] = { cmd = array, enter = enter, key = keys } + else + settings[#settings + 1] = { cmd = array, enter = enter, key = keys } + end + settings_save() + end + show_main_dialog() + end + } + + sampShowDialog(DIALOG_ID_NO_LIST,"PRO100_BINDER",text,"YES","NO",0) +end + + +function while_show_dialog() + local result, button, list, input = sampHasDialogRespond(DIALOG_ID) + if result and dialogArray ~= nil and dialogArray[list + 1] then + dialogArray[list + 1].func(button, list, input) + end + local result, button, list, input = sampHasDialogRespond(DIALOG_ID_NO_LIST) + if result and dialogArray ~= nil and dialogArray[1] then + dialogArray[1].func(button, list, input) + end +end \ No newline at end of file