Исходник Как сделать скрипт «Быстрый звонок Arizona-RP(G)»

Vintik

Мечтатель
Автор темы
Проверенный
1,464
914
Всем привет! Меня зовут Vintik.

Сегодня я буду рассказывать, как делать скрипт «Быстрый звонок Arizona-RP(G)». Суть далеко не в исходнике, а, скорее, для новичков, которые хотят познакомиться с синтаксисом этого языка программирования и параллельно научиться создавать реальные скрипты (не в одну строчку).

Начать стоит с самого начального кода (можно назвать "шапкой"), с которым мы будем в дальнейшем работать. Кодировку скрипта не забудьте указать – Windows 1251.
Lua:
require 'lib.moonloader' -- подключение стандартных библиотек
require 'sampfuncs' -- для работы с SAMP функциями
local sampev = require 'lib.samp.events' -- модуль SAMP.Lua

function main()
    if not isSampLoaded() and not isSampfuncsLoaded() then return end -- если самп не загружен – выгружаем скрипт
    while not isSampAvailable() do wait(0) end -- ждём, пока пройдёт меню загрузки

end
Модуль SAMP.Events необходим для того, чтобы работать с коллбэками, что мы будем делать позже. Да, кстати, в LUA "--" комментирует всё после этих двух символов (это никак не влияет на программу, просто пометки для разработчика). После каждого обновления кода, чтобы не перезаходить в игру, просто нажмите Ctrl + R, если у вас установлен перезапускатель скриптов (если нет – добавлю его в конец статьи, сразу скачайте и закиньте в папку moonloader).

Первым делом стоит "зарегистрировать" команду /call (то есть сделать так, чтобы при вводе такой команды скрипт реагировал и делал какие-то действия).
Lua:
require 'lib.moonloader' -- подключение стандартных библиотек
require 'sampfuncs' -- для работы с SAMP функциями
local sampev = require 'lib.samp.events' -- модуль SAMP.Lua

function main()
    if not isSampLoaded() and not isSampfuncsLoaded() then return end -- если самп не загружен – выгружаем скрипт
    while not isSampAvailable() do wait(0) end -- ждём, пока пройдёт меню загрузки
    sampRegisterChatCommand('call', phone) -- "регистрация" команды. первым аргументом функции является сама команда (без /), вторым – функция, которая вызывается при её написании
end

function phone(arg) -- вот и сама функция, которая будет вызывать тогда, когда мы пишем /call
    sampAddChatMessage(arg, -1) -- для теста будем писать в чат аргумент этой функции (то, что после /call)
    -- например при вводе: /call hello world
    -- в чат выведет: hello world
end
Работает? Тогда удаляем написание сообщения в чат. Теперь давайте не отклоняться от нашей темы. При вводе /call первым делом надо достать телефон, написав команду в чат "/phone". После этого в открывшемся диалоге выбрать первый (или любой другой) телефон.
Для начала надо узнать title (заголовок) диалога, который открывается. Для этого в конец кода добавим такой кусок:
Lua:
function sampev.onShowDialog(dialogId, style, title, button1, button2, text) -- вот и модуль SAMP.Events. эта функция будет вызываться тогда, когда откроется диалог
    sampAddChatMessage(title, -1) -- отправляем в чат заголовок диалога. -1 – это цвет строки, в данном случае (-1) это белый
end
Теперь, чтобы скопировать строку из чата (от руки переписывать строку НЕ НАДО, потому что она разноцветная – сейчас поймете), заходим в "Мои документы", "GTA San Andreas User Files", "SAMP", "chatlog". Листаем в конец и находим эту строку, вот она:
{BFBBBA}{FFFFFF}Телефоны | {ae433d}Телефоны
Видите {...}? Это так задаётся цвет в строке, теперь понятно, что от руки никто бы не переписал заголовок диалогу (который мы вывели в чат). Теперь кидаю вам обновленный код:
Lua:
require 'lib.moonloader' -- подключение стандартных библиотек
require 'sampfuncs' -- для работы с SAMP функциями
local sampev = require 'lib.samp.events' -- модуль SAMP.Lua

function main()
    if not isSampLoaded() and not isSampfuncsLoaded() then return end -- если самп не загружен – выгружаем скрипт
    while not isSampAvailable() do wait(0) end -- ждём, пока пройдёт меню загрузки
    sampRegisterChatCommand('call', phone) -- "регистрация" команды. первым аргументом функции является сама команда (без /), вторым – функция, которая вызывается при её написании
end

function phone(arg) -- вот и сама функция, которая будет вызывать тогда, когда мы пишем /call
    sampSendChat('/phone') -- пишем в чат
end

function sampev.onShowDialog(dialogId, style, title, button1, button2, text) -- вот и модуль SAMP.Events. эта функция будет вызываться тогда, когда откроется диалог
    if title == '{BFBBBA}{FFFFFF}Телефоны | {ae433d}Телефоны' then -- если у диалога такой заголовок (то бишь это нужный нам диалог)
        sampSendDialogResponse(dialogId, 1, 0, nil) -- закрываем диалог первой (левой) кнопкой с выбранным 1 пунктом (нумерация пунктов с нуля, поэтому типо "нулевой")
        return false -- запрещаем диалогу визуально показываться на экран (иначе он останется открытым).
    end
end
Вроде работает, скажите Вы. Но нет! Он закрывать диалог должен только в случае, если его вызвал скрипт, вдруг Вы хотите воспользоваться телефоном самостоятельно и выбрать другой мобильный аппарат? Надо сделать проверку.
Перед main() добавляем:
Lua:
local phoneDialog = false -- глобальная переменная (работает во всех функциях). true - если след. диалог вызван скриптом
После sampSendChat('/phone') добавляем:
Lua:
phoneDialog = true -- говорим, что следующий диалог вызван скриптом
И перед return false тоже добавляем:

Lua:
phoneDialog = false -- говорим, что след. диалог будет вызван не скриптом.
Теперь можете проверить. Если пишите /phone – диалог остаётся, если пишите /call – сразу выбирается первый телефон. То что надо!

Начинается самое важное и моё нелюбимое: работа с текстдравами. Придётся. Нужно узнать ID текстдрава, который является значком "Позвонить". Для этого в конец кода добавляем:
Lua:
function sampev.onSendClickTextDraw(id) -- когда мы кликаем по текстдраву
  sampAddChatMessage(id, -1) -- выписываем его id в чат
end
Теперь перезагружаем скрипт и пишем в чат /call, затем нажимаем на значок позвонить – в чат добавляется цифра "2098", и это ID нужного нам текстдрава. Отлично! Теперь нужно реализовать нажатие на этот текстдрав (извините за тавтологию, это слово никак не заменить) с помощью скрипта.
Первым делом удалим "отладочный" код, который я написал последним, затем после local phoneDialog = false добавим:

Lua:
local callTextdraw = false
А после phoneDialog = false добавим:
Lua:
callTextdraw = true
Ну и в конец кода добавляем:
Lua:
function sampev.onShowTextDraw(id, data) -- когда появляется любой текстдрав
    if id == 2098 and callTextdraw then -- если он вызван нашим скриптом и если это нужный нам текстдрав
        callTextdraw = false
        sampSendClickTextdraw(id) -- говорим, что мы кликнули по текстдраву
        numberTextdraw = true
    end
end
Теперь когда мы открываем тф через /call – автоматически называется значок "Набрать номер" (ранее я его назвал "Позвонить").
Lua:
require 'lib.moonloader' -- подключение стандартных библиотек
require 'sampfuncs' -- для работы с SAMP функциями
local sampev = require 'lib.samp.events' -- модуль SAMP.Lua

local phoneDialog = false -- глобальная переменная (работает во всех функциях). true - если след. диалог вызван скриптом
local callTextdraw = false

function main()
    if not isSampLoaded() and not isSampfuncsLoaded() then return end -- если самп не загружен – выгружаем скрипт
    while not isSampAvailable() do wait(0) end -- ждём, пока пройдёт меню загрузки
    sampRegisterChatCommand('call', phone) -- "регистрация" команды. первым аргументом функции является сама команда (без /), вторым – функция, которая вызывается при её написании
end

function phone(arg) -- вот и сама функция, которая будет вызывать тогда, когда мы пишем /call
    sampSendChat('/phone') -- пишем в чат
    phoneDialog = true -- говорим, что следующий диалог вызван скриптом
end

function sampev.onShowDialog(dialogId, style, title, button1, button2, text) -- вот и модуль SAMP.Events. эта функция будет вызываться тогда, когда откроется диалог
    if title == '{BFBBBA}{FFFFFF}Телефоны | {ae433d}Телефоны' and phoneDialog then -- если у диалога такой заголовок (то бишь это нужный нам диалог)
        -- добавляем проверку phoneDialog == true (можно просто phoneDialog)
        sampSendDialogResponse(dialogId, 1, 0, nil) -- закрываем диалог первой (левой) кнопкой с выбранным 1 пунктом (нумерация пунктов с нуля, поэтому типо "нулевой")
        phoneDialog = false -- говорим, что след. диалог будет вызван не скриптом.
        callTextdraw = true
        return false -- запрещаем диалогу визуально показываться на экран (иначе он останется открытым).
    end
end

function sampev.onShowTextDraw(id, data) -- когда появляется любой текстдрав
    if id == 2098 and callTextdraw then -- если он вызван нашим скриптом и если это нужный нам текстдрав
        callTextdraw = false
        sampSendClickTextdraw(id) -- говорим, что мы кликнули по текстдраву
    end
end

Чтобы вы не терялись, буду регулярно скидывать полный код.

Далее задача немного усложняется. Надо вернуться к тому, что уже написали, и добавить кое-что: нам надо проверить, является ли аргумент команды /call неотрицательным числом (чтобы быть номером телефона). Для этого будем проходиться по всем элементам аргумента, проверяя, являются ли она числами, и затем записывать в массив.
И так, после local callTextdraw = false добавляем:
Lua:
local number = {} -- создаем массив цифр номера телефона, который набираем
То есть, если номер, например, 1234598, то массив такой:
{ 1, 2, 3, 4, 5, 9, 8 }
Надеюсь, усвоили.
Теперь заменяем функцию phone на вот эту (все объяснил в комментариях к строкам):
Lua:
function phone(arg) -- вот и сама функция, которая будет вызывать тогда, когда мы пишем /call
    number = {} -- обнуление номера
    local isNumber = true
    for i = 1, string.len(arg) do -- проходимся по всем символам строки
        local c = tonumber(string.sub(arg, i, i)) -- берем i-тый элемент строки, преобразуем его в число
        if type(c) ~= 'number' then -- если преобразовать в число не получилось (не число, короче)
            isNumber = false -- говорим, что не число
            break -- заканчиваем проверку
        end
        number[#number + 1] = c -- в конец массива добавляем новую (следующую) цифру. и так до конца нашего аргумента
    end
    if isNumber and #number ~= 0 then -- если аргумент – число
        sampSendChat('/phone') -- пишем в чат
        phoneDialog = true -- говорим, что следующий диалог вызван скриптом
    else -- если не число
        sampAddChatMessage('Чтобы совершить быстрый звонок, введите /call [номер]', 0x4287f5) -- говорим юзеру как ввести команду
    end
end
Теперь опять в конец добавляем код:
Lua:
function sampev.onSendClickTextDraw(id) -- когда мы кликаем по текстдраву
  sampAddChatMessage('id = ' .. id, -1) -- выписываем его id в чат
end
По очереди кликаем на циферки от 0 до 9 и записываем в массив соответствующие ID-шники текстдравов. И вот я это сделал:
Lua:
local textdrawlist = { 2111, 2103, 2104, 2102, 2106, 2107, 2105, 2109, 2110, 2108, 2096 } -- ид текстдравов цифер от "0" до "9" и "Позвонить"
В конец списка (массива) я добавил ID текстдрава "Позвонить" (его id 2096).

Разумеется, я опять по аналогии после объявленных глоб. переменных сделал:
Lua:
local numberTextdraw = false
Если переменная - false, то при виде текстдравов циферок ничего не происходит. Если true - начинается набор номера из массива number.
Lua:
function sampev.onShowTextDraw(id, data) -- когда появляется любой текстдрав
    if id == 2098 and callTextdraw then -- если он вызван нашим скриптом и если это нужный нам текстдрав
        callTextdraw = false
        sampSendClickTextdraw(id) -- говорим, что мы кликнули по текстдраву
        numberTextdraw = true
    end
    -- работаем уже с набором номера:
    local textdrawlist = { 2111, 2103, 2104, 2102, 2106, 2107, 2105, 2109, 2110, 2108, 2096 } -- ид текстдравов цифер от "0" до "9" и "Позвонить"
    local isNumeralsExist = true
    for i = 1, 11 do -- проходимся по всем текстдравам
        if not sampTextdrawIsExists(textdrawlist[i]) then -- если не существует текстдрава с какой-то цифрой (или кнопкой "Позвонить")
            isNumeralsExist = false -- говорим, что нету всех цифер на экране
            break -- заканчиваем проверку
        end
    end
    if isNumeralsExist and numberTextdraw then -- если все цифры есть на экране
        numberTextdraw = false
        for i = 1, #number do -- вписываем номер телефона
            local b = number[i] + 1 -- текущая цифра; +1 потому, что textdrawlist начинается с ID текстрава нуля, а массив начинается с элемента 1
            sampSendClickTextdraw(textdrawlist[b])
        end
        sampSendClickTextdraw(2096) -- нажимаем позвонить
    end
end

Заключение:
Я постарался доступно и пошагово объяснить, как надо делать такой скрипт. Надеюсь, что все поняли все (ну или почти все). Я обязательно буду стараться отвечать на вопросы, которые вы можете задать в этой теме.
Вот исходный код скрипта:
Lua:
script_name('Fast call Arizona RP')
script_author('Vintik')
require 'lib.moonloader' -- подключение стандартных библиотек
require 'sampfuncs' -- для работы с SAMP функциями
local sampev = require 'lib.samp.events' -- модуль SAMP.Lua

local phoneDialog = false -- глобальная переменная (работает во всех функциях). true - если след. диалог вызван скриптом
local callTextdraw = false
local numberTextdraw = false
local number = {} -- создаем массив цифр номера телефона, который набираем

function main()
    if not isSampLoaded() and not isSampfuncsLoaded() then return end -- если самп не загружен – выгружаем скрипт
    while not isSampAvailable() do wait(0) end -- ждём, пока пройдёт меню загрузки
    sampRegisterChatCommand('call', phone) -- "регистрация" команды. первым аргументом функции является сама команда (без /), вторым – функция, которая вызывается при её написании
end

function phone(arg) -- вот и сама функция, которая будет вызывать тогда, когда мы пишем /call
    number = {} -- обнуление номера
    local isNumber = true
    for i = 1, string.len(arg) do -- проходимся по всем символам строки
        local c = tonumber(string.sub(arg, i, i)) -- берем i-тый элемент строки, преобразуем его в число
        if type(c) ~= 'number' then -- если преобразовать в число не получилось (не число, короче)
            isNumber = false -- говорим, что не число
            break -- заканчиваем проверку
        end
        number[#number + 1] = c -- в конец массива добавляем новую (следующую) цифру. и так до конца нашего аргумента
    end
    if isNumber and #number ~= 0 then -- если аргумент – число
        sampSendChat('/phone') -- пишем в чат
        phoneDialog = true -- говорим, что следующий диалог вызван скриптом
    else -- если не число
        sampAddChatMessage('Чтобы совершить быстрый звонок, введите /call [номер]', 0x4287f5) -- говорим юзеру как ввести команду
    end
end

function sampev.onShowDialog(dialogId, style, title, button1, button2, text) -- вот и модуль SAMP.Events. эта функция будет вызываться тогда, когда откроется диалог
    if title == '{BFBBBA}{FFFFFF}Телефоны | {ae433d}Телефоны' and phoneDialog then -- если у диалога такой заголовок (то бишь это нужный нам диалог)
        -- добавляем проверку phoneDialog == true (можно просто phoneDialog)
        sampSendDialogResponse(dialogId, 1, 0, nil) -- закрываем диалог первой (левой) кнопкой с выбранным 1 пунктом (нумерация пунктов с нуля, поэтому типо "нулевой")
        phoneDialog = false -- говорим, что след. диалог будет вызван не скриптом.
        callTextdraw = true
        return false -- запрещаем диалогу визуально показываться на экран (иначе он останется открытым).
    end
end

function sampev.onShowTextDraw(id, data) -- когда появляется любой текстдрав
    if id == 2098 and callTextdraw then -- если он вызван нашим скриптом и если это нужный нам текстдрав
        callTextdraw = false
        sampSendClickTextdraw(id) -- говорим, что мы кликнули по текстдраву
        numberTextdraw = true
    end
    -- работаем уже с набором номера:
    local textdrawlist = { 2111, 2103, 2104, 2102, 2106, 2107, 2105, 2109, 2110, 2108, 2096 } -- ид текстдравов цифер от "0" до "9" и "Позвонить"
    local isNumeralsExist = true
    for i = 1, 11 do -- проходимся по всем текстдравам
        if not sampTextdrawIsExists(textdrawlist[i]) then -- если не существует текстдрава с какой-то цифрой (или кнопкой "Позвонить")
            isNumeralsExist = false -- говорим, что нету всех цифер на экране
            break -- заканчиваем проверку
        end
    end
    if isNumeralsExist and numberTextdraw then -- если все цифры есть на экране
        numberTextdraw = false
        for i = 1, #number do -- вписываем номер телефона
            local b = number[i] + 1 -- текущая цифра; +1 потому, что textdrawlist начинается с ID текстрава нуля, а массив начинается с элемента 1
            sampSendClickTextdraw(textdrawlist[b])
        end
        sampSendClickTextdraw(2096) -- нажимаем позвонить
    end
end

Естественно, я даю право на свободное использование этого кода в своих скриптах, но с указанием авторства. На БХ вроде бы нету таких же скриптов с открытым кодом (а не .luac). Ну а кому нужен лишь скрипт – будет прикреплён к сообщению. Так же прикрепляю тот скрипт, который упоминал в теме – "перезагружатор скриптов на Ctrl + R", автором которого является @FYP

Все, всем пока! Спасибо, что прочитали эту статью.
P. S. У меня в коде никогда не было так много комментов

 

Вложения

  • reload_all.lua
    458 байт · Просмотры: 41
  • auto_phone.lua
    3.8 KB · Просмотры: 108

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Всефорумный модератор
2,634
2,482
Ищи идшники текстдравов по местоположению / содержимому
 

Vintik

Мечтатель
Автор темы
Проверенный
1,464
914
  • Нравится
Реакции: SXN7R

tRue:#

Известный
68
17
При вызове команды " /call [Номер] " вызывает лишь справочник (информация), открытый телефон вызвова номера. Скрипт разве не должен сразу звонить на номер?
 

Вложения

  • Screenshot_4.png
    Screenshot_4.png
    157.7 KB · Просмотры: 373

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Друг
8,768
11,210
При вызове команды " /call [Номер] " вызывает лишь справочник (информация), открытый телефон вызвова номера. Скрипт разве не должен сразу звонить на номер?
поменяй id текстдравов в скрипте под нужные
 
  • Нравится
Реакции: tRue:#

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Друг
8,768
11,210
  • Нравится
Реакции: SXN7R

Tema05

Известный
1,441
401
Ты не вчёл что у тебя не может быть телефона. Также ты не учёл возможность звонить если телефон уже окрыт, что открыт набор номера, что введён другой номер, открыто приложение вк койнов. Я и не говорю о выборе телефона для работы и поддержки всех 5 телефонов.
 

Vintik

Мечтатель
Автор темы
Проверенный
1,464
914
Ты не вчёл что у тебя не может быть телефона. Также ты не учёл возможность звонить если телефон уже окрыт, что открыт набор номера, что введён другой номер, открыто приложение вк койнов. Я и не говорю о выборе телефона для работы и поддержки всех 5 телефонов.
Не учел. Но это такие мелочи...
Поддержка пяти телефонов - сделаю, это 1 минута дела
 

AnWu

Guardian of Order
Всефорумный модератор
4,687
5,167
Убрал тег гайд с этого чудища
 
  • Нравится
Реакции: Tema05