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