Данная тема посвящена нюансам и особенностям разработки Lua скриптов для MoonLoader.
Список вопросов:
Начало разработки.
Взаимодействие с игроками.
Работа с переменными.
Работа с командами.
Начало разработки.
Каждый Lua скрипт при запуске создает поток «main» который и является основным местом работы со скриптом.
Сразу обговорим — скрипт «жив» пока «жив» поток main(), поэтому если мы хотим продолжать работать со скриптом после запуска — будем держать поток активным:
function main() -- Объявляем поток main()
wait(-1) -- Устанавливаем бесконечное ожидание
end -- закрываем функцию
Запускаем скрипт — работает!
Что ж, поставим себе цель — при запуске выводить сообщение «Привет мир» в чат.
Что нам для этого нужно?
Заходим на WIKI (Раздел «Функции» moonloader`a) и ищем функции чата — Поиск -> «Chat». Видим функцию sampAddChatMessage(message, color) — то что надо.
Вставляем:
function main()
sampAddChatMessage("Привет мир!", 0xFFFFFFFF) -- Выводим сообщение в чат
wait(-1) -- Устанавливаем бесконечное ожидание
end
Запускаем скрипт — ошибка?
(error) test.lua: opcode '0AF8' call caused an unhandled exception
Бежим на WIKI (Опять раздел «Функции» moonloader`a) и в поиск вводим наш опкод «0AF8».
Находим нашу функцию sampAddChatMessage()
Что это значит? Дело в том что нельзя вызывать функции для работы с SA:MP пока сам SA:MP не готов. Что делать? Добавим перед выводом сообщения такой код:
if not isSampfuncsLoaded() or not isSampLoaded() then -- Если SF или SA:MP не загружены
return -- Завершаем работу скрипта
end
while not isSampAvailable() do -- Ждём пока функция isSampAvailable() вернет true
wait(0) -- Устанавливаем минимальное ожидание, что бы наша игра не зависла
-- значение 0 говорит что мы ждём следующий кадр (Frame)
end
Теперь наш скрипт будет ждать пока самп полностью не загрузится и продолжит выполнение кода.
Что такое wait() и с чем его едят?
Wait позволяет ставить
поток
в режим ожидания на указанное количество мили-секунд (ms)
Wait нельзя в CallBack-функциях, это приведет к ошибке, а в последствии и смерти, скрипта.
Почему мы ставим 0? Потому-что это минимальная задержка.
Подведем краткий итог кода:
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then
return
end
while not isSampAvailable() do
wait(0)
end
sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
wait(-1)
end
Теперь при входе в игру / перезапуске скрипта в чат будет выводиться сообщение «Привет мир».
К списку вопросов
Взаимодействие с игроками
Перейдем к примерам посложнее — попробуем получить ник, ид и счет игрока в которого мы прицелились.
Цель поставили, какие нам нужны средства?
Опять бежим к WIKI, всё в тот же раздел функций и ищем функции связанные с целями, Поиск -> Target.
Смотрим в списке есть getCharPlayerIsTargeting(ped).
Она возвращает 2 значения — result, ped.
Первое значение — возвращает результат проверки на целится ли указанный Ped в кого-либо.
Второе — если указанный Ped целится — возвращает саму цель.
Как нам это использовать? Всё просто, уберем бесконечное ожидание и будем проверять значение result.
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then
return
end
while not isSampAvailable() do
wait(0)
end
sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
while true do -- Создаем бесконечный цикл, вместо бесконечного ожидания
wait(0) -- Опять таки чтобы наша игра не зависла, ждем след кадр
local result, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) -- Каждый кадр получаем данные функции, PLAYER_HANDLE - возвращает ваш Handle
if result then -- Если result вернет true
print("True!") -- Выведем сообщение в лог / консоль
end
end
end
Что мы можем с этим делать? Теперь если мы целимся в кого-либо, мы увидим сообщения в moonloader.log об этом. Мы получили Ped игрока в которого мы целимся. Давайте используем эту информацию.
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then
return
end
while not isSampAvailable() do
wait(0)
end
sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
while true do
wait(0)
local result, ped = getCharPlayerIsTargeting(playerPed)
if result then
local result2, id = sampGetPlayerIdByCharHandle(ped) -- Попробуем получить ID игрока по его Ped
if result2 then -- Если получилось
local nickname = sampGetPlayerNickname(id) -- Запишем его ник
local score = sampGetPlayerScore(id) -- и счет
sampAddChatMessage(string.format("%s[%d] имеет счет %d", nickname, id, score), -1) -- И выведем это в чат
end
end
end
end
К списку вопросов
Работа с переменными
Что у нас получилось? Мы будем получать кучу сообщений в чат о игрока по пока целимся в кого-либо, но как убрать этот флуд?
Давайте создадим переменную перед main(), например targeting, и присвоим ей значение false.
И задействуем её в коде
local targeting = false -- Создаем булевую переменную
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then
return
end
while not isSampAvailable() do
wait(0)
end
sampAddChatMessage("Привет мир!", 0xFFFFFFFF)
while true do
wait(0)
local result, ped = getCharPlayerIsTargeting(playerPed)
if result and not targeting then -- Если мы целимся, но ранее ни в кого не целились
local result2, id = sampGetPlayerIdByCharHandle(ped)
if result2 then
local nickname = sampGetPlayerNickname(id)
local score = sampGetPlayerScore(id)
sampAddChatMessage(string.format("%s[%d] имеет счет %d", nickname, id, score), -1)
targeting = true -- запишем что мы целимся в кого либо и наше условие выше станет ложным
end
elseif not result and targeting then -- Если условие обратное - скажем скрипту что мы не целимся
targeting = false
end
end
end
Отлично, теперь если мы целимся в игрока — получаем одно сообщение, меняем цель или заново целимся в того же игрока — снова получим о нём информацию.
К списку вопросов
Работа с командами.
Уже лучше, давайте теперь работаем с командами.
Уберем лишний код и оставим следующее:
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then
return
end
while not isSampAvailable() do
wait(0)
end
while true do
wait(0)
end
end
Как добавить команду? Давайте опять порыщем на WIKI, Поиск -> Command
Нашли sampRegisterChatCommand(command, callback)? Отлично, можно уже приступать.
Зарегистрируем нашу команду, например «toster»:
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then
return
end
while not isSampAvailable() do
wait(0)
end
sampRegisterChatCommand("toster", tosterCallBack) -- Регистрируем ДО бесконечного цикла.
-- Первый параметр - команда, без слэша.
-- Второй - функция-callback которая будет вызваться если будет введена команда.
wait(-1) -- Уберем бесконечный цикл, он тут вовсе не нужен, но нам же нужно чтобы скрипт работал
end
function tosterCallBack(params)
sampAddChatMessage("Дзынь!", -1)
end
Теперь при вводе команды «/toster» мы увидим в чате сообщение. Успех? Но как например вывести свой текст в чат? Легко!
sampAddChatMessage(params, -1)
Теперь мы выводим весь текст после команды «/toster» в чат. Например: /toster Привет жалкий мирок!
Помните я говорил что нельзя использовать wait() внутри callback-функций, это всё еще так, но есть тут одна хитрость!
function tosterCallBack()
sampAddChatMessage("Дзынь!", -1)
lua_thread.create(function() -- Создаем новый поток
wait(5000) -- Ждём 5 секунд
sampAddChatMessage("Тоже дзынь, но на 5 секунд позже!", -1) -- Выводим текст в чат
end) -- Тут наш поток умирает :(
end
К списку вопросов
На сегодня всё, теперь вы чертовы волшебники, поняв как всё работает, можно приступать к изучению примеров Lua скриптов!
Тема будет дополняться по мере изучения популярных вопросов по Lua скриптингу.
Я понимаю что вы невъебенные мастера луа скриптинга, но это тема не для вас
Что такое скриптинг?
От слова script – сценарий, то есть последовательность каких-либо действий. А скриптинг – процесс создания этой последовательности. Для GTA это значит: писать миссии либо более простые вещи (например, давать игроку новые возможности). Тех, кто пишет скрипты, называют скриптерами. Основа любого скрипта – это опкоды (операционные коды), а они сами базируются на переменных, в которые записываются нужные для правильной работы скрипта значения (цифровые, то есть числа целые 1, 2, -1, -2… либо дробные, обязательно с точкой 1.2, -2.3; или аналоговые, то есть люди, авто, объекты). Могут иметь вид 0@, 1@, 2@…33@ или $0, $1, $2… или $»текст на латинице без пробелов и кавычек». Разница между @ и $ такая: первые переменные действуют лишь в рамках одного скрипта (или потока), а вторые можно спокойно использовать на всём протяжении main.scm (наглядный пример: $PLAYER_CHAR).
Как записать значение в переменную?
2@ = 0 // в переменную 2@ записан нуль
00BF: $1 = current_time_hours, $2 = current_time_minutes // в переменные $1, $2 записано текущее игровое время (часы, минуты соответственно).
009A: 2@ = create_actor_pedtype 4 model #MALE01 at 0.0 0.0 0.0 // в переменную 2@ записан актёр
00A5: 0@ = create_car #PONY at 0.0 0.0 0.0 // в переменную 0@ записана машина
Переменную, в которую записывают актёра или авто, принято называть именем. Т.е. в примерах выше 2@ – имя актёра, 0@ – имя транспорта.
Как открыть main.scm?
Самая удобная программа – Sanny Builder. Свежую версию можно найти на sannybuilder.com, и там же на форуме задать интересующий вопрос. Полезные советы: 1) если курсор стоит на модели (она отличается символом # в начале), то в нижней панели слева появляется ID; 2) в современном SB есть много ключевых слов, набрав которые и поставив точку, можно получить список доступных действий, например: Actor, Car, Model; 3) нажатие Сtrl+Alt+1 вызовет Редактор координат, где при запущенной игре будет отображаться текущее положение игрока, а также его можно использовать как телепорт; 4) нажатие Сtrl+Alt+2 вызовет список опкодов; 5) если компиляция скрипта выдала ошибку, не спеши кликать ОК, если не знаешь причину бага, а нажми для начала Помощь; 6) при первом запуске программы нажми F10 или зайди в Сервис > Настройки и выбери себе язык и обязательно укажи папку GTA SA.
Как писать миссии?
Подробная справка прилагается к SB. Вызвать можно нажатием F12 или Справка > Помощь.
Как припарковать транспорт и поставить пикап?
Проще через IPL, но некоторым не нравится, что там иногда угол поворота машины бывает не тот, который нужен. И главное: для этих опкодов модель загружать не нужно.
09E2: 0@ = parked_car_generator_w_numberplate #BF400 -1 -1 0 alarm 0 door_lock 0 0 10000 plate «HOMEP_69» at X Y Z angle 0.0 // или…
014B: 0@ = init_parked_car_generator #BF400 -1 -1 1 alarm 0 door_lock 0 0 10000 at X Y Z angle 0.0 // 0@ – имя автогенератора, #BF400 – модель авто (можно писать ID, т.е. в данном случае 581), 2 цифры далее – цвет, X Y Z – координаты, 0.0 – угол; plate – номерной знак (в кавычках, не больше 8 латинских символов)
014C: set_parked_car_generator 0@ cars_to_generate_to 101 // это включает генератор, если вместо 101 написать 0, машина появляться не будет
Для пикапа:
0213: $0 = create_pickup #INFO type 3 at X Y Z // обычный пикап-значок
032B: $0 = create_weapon_pickup #teargas type 15 ammo 15 at X Y Z // оружие
$0 – имя пикапа, #INFO и #teargas – модель (оружие или значок, можно ID); type – тип (3 – одноразовый, 15 – многоразовый); ammo – количество боеприпасов; X Y Z – координаты
Как изменить оружие банд и число гангстеров в определённом районе?
0237: set_gang 0 weapons_to 23 32 1 // 0 – ID банды (0 == Ballas, 1 == Grove Street Families, 2 == Los Santos Vagos, 3 == San Fierro Rifa, 4 == Da Nang Boys, 5 == Mafia, 6 == Mountain Cloud Triad, 7 == Varrio Los Aztecas); 23 32 1 – это оружие (0 – кулaки, 1 – кастет, 2 – клюшка для гольфа, 3 – дубинка для копов, 4 – ножик, 5 – бита, 6 – лопата, 7 – кий, 8 – кaтaнa, 9 – пила, с 10 до 14 – дилдо и цветы, 15 – трость, 16 – гранаты, 17 – слезоточивый газ, 18 – мoлoтoвы, 22 – пистолет, 23 – с глушаком, 24 – Desert Eagle, 25 – дробоган, 26 – обрез, 27 – мощный дробоган, 28 – Mac 10, 29 – MP5, 30 – AK47, 31 – M4, 32 – Tec9, 33 – винтовка, 34 – снайперка, 35 – РПУ, 36 – ракетница с самонаводкой, 37 – огнемёт, 38 – старый добрый Mиниган, 41 – баллончик с краской, 42 – огнетушитель)
076C: set_zone ‘SUN1’ gang 1 density_to 30 // SUN1 – имя района (см. в Справке SB: Документация по SCM > GTA SA > Типы зон); 1 – знакомый ID; 30 – плотность (в процентах от населения этого района)
Какие есть особые опкоды?
015D: set_gamespeed 0.0 // скорость игры (1.0 – обычная; этот опкод используется в режиме Bullet Time)
01EB: set_traffic_density_multiplier_to 0.0 // отключает движение на дорогах
0110: clear_player $PLAYER_CHAR wanted_level // очистить уровень розыска
01F7: set_player $PLAYER_CHAR ignored_by_cops 1 // копы игнорируют
02AB: set_actor $PLAYER_ACTOR immunities BP 1 FP 1 EP 1 CP 1 MP 1 // установить иммунитет
0330: set_player $PLAYER_CHAR infinite_run 1 // бесконечный спринт
0331: set_player $PLAYER_CHAR fast_reload 1 // быстрая перезарядка оружия (не у всех видов)
0335: enable_free_respray 1 // халявные перекраски
03BF: set_player $PLAYER_CHAR ignored_by_everyone 1 // все игнорируют
03DE: set_pedestrians_density_multiplier_to 0.0 // отключает людской поток на улицах
055D: make_player $PLAYER_CHAR fireproof 1 // огнеупорность
0572: enable_taxi_nitros 1 // все такси с азотоускорением
0629: change_integer_stat 181 to 4 // можно свободно гулять по SA без звёзд розыска
0631: put_actor 0@ in_group $PLAYER_GROUP // актёр будет следовать за игроком
0632: release_group $PLAYER_GROUP // отпустить актёров из группы
06C8: enable_riot 1 // включает бунт (только в LS)
06D0: enable_emergency_traffic 0 // отключает спецслужбы
07A7: put_jetpack_on_actor $PLAYER_ACTOR // джетпак
0879: enable_gang_wars 1 // включает войну за территории
08C6: set_actor $PLAYER_ACTOR stay_on_bike 1 // игрок не падает с байка
08FD: enable_heat_visuals 1 // включение (0 – выключение) эффекта «жарка» при высокой температуре окружающей среды
09C7: change_player $PLAYER_CHAR model_to #MODEL // замена своей модели (сначала надо загрузить новую)
09E6: set_burglary_houses_accessible 1 // доступ в жилые дома
09E9: car 3@ add_single_nitro // одноразовый нитроазот
0A24: enable_military_zones_wanted_level 1 // отключение охраны на военных зонах
0A3D: enable_prostitutes_pay_you 1 // шлюхи платят тебе
Как убрать эффект NFS MW в моде Night Crimes?
1) открыть в SB файл data/script/main.scm
2) найти строку create_thread @Noname_9 (Сtrl+F)
3) удалить либо закомментировать (Сtrl+Q), чтобы игра игнорировала поток Noname_9
4) компилировать (F6) и запустить игру (F8)
P.S. Для проверки, тот ли это поток, найди Noname_9, там должно быть написано
02E3: 12@ = car $11883 speed
if
12@ >= 30.0
else_jump @Noname_9
Как изменить количество денег?
0109: player $PLAYER_CHAR money += X // X – положительное или отрицательное целое число, в зависимости от которого денег прибавят или отнимут
Как сделать, чтобы актёр или автомобиль шёл по определённому пути?
05D6: clear_scmpath
05D7: add_point_to_scmpath X Y Z // X Y Z – координаты добавляемой точки в маршруте
05D8: AS_assign_scmpath to_actor $PLAYER_ACTOR flags 4 0 // для актёра: 4 – скорость (до 7)
06BB: set_actor -1 drive_car 1@ speed 10.0 along_SCM_path // для машины: 10.0 – скорость
Как выбрать случайного пешехода?
:Noname
wait 0
if and
06FF: any_ped_near_actor $PLAYER_ACTOR in_range 20.0 // радиус
Player.Defined($PLAYER_CHAR)
else_jump @Noname
0AB5: store_actor $PLAYER_ACTOR closest_vehicle_to -1 closest_ped_to 1@
if
not 1@ == -1
else_jump @Noname
Как сделать чтобы банды не приставали?
0746: set_acquaintance 1 of_actors_pedtype 7 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 8 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 9 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 10 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 11 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 12 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 13 to_actors_pedtype 0
0746: set_acquaintance 1 of_actors_pedtype 14 to_actors_pedtype
Как сделать актёра другом или врагом?
077A: set_actor $Actor acquaintance 4 to_actors_pedtype 0 // acquaintance бывают такие: 1 – уважение, 2 – симпатия, 3 – неприязнь, 4 – вражда
Что такое CLEO?
Библиотека CLEO шагнула в новое измерение, и перед нами четвертая версия этого проекта. Теперь библиотека CLEO поддерживает игры GTA III и GTA VC, что это открывает новые возможности для разработчиков скриптов на данных платформах.
Возможности
• Новые опкоды
CLEO 4 имеет в наличии 100 полезных опкодов, которые позволяют работать с внешними файлами, изменять данные в памяти игры, вызывать игровые функции со своими параметрами, а также многое другое. В четвертой версии появились новые опкоды для работы со звуками, форматирования текста, была добавлена возможность выводить на экран тексты без использования внешних текстовых файлов (.gxt, .fxt). Чтобы оценить новые достижения и использовать их в ваших скриптах, установите последнюю версию библиотеки CLEO 4.
• Плагины
CLEO-плагины — это обычные DLL-файлы, но имеющие расширение .CLEO. При запуске библиотека CLEO ищет в папке <игра>CLEO файлы с данным расширением и пытается загрузить их. В случае удачной загрузки плагин начинает работать и выполнять те функции, для которых он написан.
CLEO 4 позволяет создавать новые опкоды, используя исходные коды CLEO SDK. В стартовом комплекте библиотеки можно найти три примера таких плагинов:
• IniFiles.cleo — работа с INI файлами;
• FileSystemOperations.cleo — работа с файлами и папками.
• IntOperations.cleo — битовые операции над целыми
Процедура установки плагина очень проста: просто скопируйте файл в папку <игра>CLEO. Чтобы прекратить пользование плагином — удалите файл или измените его расширение. Список доступных плагинов можно найти на этой странице.
• Добавление скриптов
Начиная с CLEO 3, в игру можно добавлять новые скрипты, написанные в редакторе Sanny Builder, без необходимости начала новой игры. Все, что требуется для добавления такого скрипта в игру — это поместить его в папку <игра>CLEO. После запуска новой или сохраненной игры скрипт начнет работу. Для удаления скрипта из игры — удалите соответствующий файл.
CLEO 4 разрабатывалась для трех версий exe: 1.0 us, 1.0 eu и 1.01 eu. Таким образом, существует 8 разных exe, с которыми совместима библиотека:
Оригинальное имя
Описание
Версия игры
Размер
gta_sa.exe
оригинальный 1.0 us
1.0
14 405 632 байт
gta_sa.exe
публичный no-dvd 1.0 us
1.0
14 383 616 байт
gta_sa_compact.exe
listener’s exe
1.0
5 189 632 байт
gta_sa.exe
оригинальный 1.01 eu
1.01
14 405 632 байт
gta_sa.exe
публичный no-dvd 1.01 eu
1.01
15 806 464 байт
gta_sa.exe
версия от 1С
1.01
15 806 464 байт
gta_sa.exe
оригинальный 1.0 eu
1.0
неизвестно
gta_sa.exe
публичный no-dvd 1.0 eu
1.0
14 386 176 байт
Установка
СLEO 4 распространяется в виде автоматического инсталлятора. Для установки библиотеки запустите инсталлятор и следуйте его инструкциям.
CLEO 4 использует 3 файла в работе: vorbisFile.dll, vorbishooked.dll, cleo.asi.
CLEO 4 для San Andreas для проигрывания звуковых файлов требует установленной библиотеки BASS.dll версии 2.4, которую можно скачать с официального сайта Un4seen Developments Ltd. Устанавливается BASS.dll очень просто — нужно просто скопировать файл bass.dll в корневую директорию игры GTA San Andreas.
Распространение библиотеки CLEO
Если вы написали скрипт, использующий библиотеку CLEO и (или) ее плагины, вы можете также распространять вместе с ним необходимые файлы. Вы можете указать ссылку на данную страницу, чтобы пояснить, как необходимо пользоваться библиотекой и сопутствующими файлами.
Что-же нужно знать? С чего начать? Многие задаются этим вопросом.
Материала на форуме и за пределами — валом.
Нужно уверенно знать:
1. Основы скриптинга — синтаксис языка и операторы.
Начинается все с переменной, вспомните математику. В основном весь код это переменные и то что мы с ними вытворяем. Что делаем с переменными? Мы их присваиваем, сравниваем, умножаем и т.д., посмотрите тут.
Можем задать условие: если одна переменная больше другой, то третью переменную делим на два. Работу с циклами, массивами и многими другими вещами Вам предстоит понимать.
В обязательном порядке Вам нужно ознакомиться с работой функций, потому что в павне без функций нечего делать.
2. Автовызываемые функции — встроенные функции, которые вызываются самим сервером, когда происходит какое-то определенное событие.
Автовызываемые функции — это функции, которые вызываются самим сервером, когда происходит какое-то определенное событие. О каких событиях идет речь? Все просто. Событие: игрок вошел в игру => сервер вызвал функцию коннекта игрока. Что нам это дает? Мы можем сделать так, что-бы при вызове этой функции — в чат выводилось сообщение о входе игрока на сервер. Все наверное замечали такую штуку. Аналогично можно при выходе игрока и так далее. Автовызываемых функций куча — соотвестственно возможностей столько-же.
3. Функции скриптинга — встроенные функции, для написания игровых режимов и сценариев в SA-MP.
Список функций. Функции существуют для написания сценариев. Добавление машин, смена погоды и времени, управление игроком, ботом, машиной, объектом. Эти функции не вызываются сервером. Мы их уже засовываем в автозывываемые функции, или в функции, которые создадим сами.
Приведу пример. Событие: игрок вошел в игру => вызывается функция коннекта игрока => в функции коннекта мы будем менять время входящему игроку функцией смены времени.
4. Общие ресурсы скриптинга — ID’ы, модели, типы, номера — машин, интерьеров, взрывов, скинов
Списки ресурсов. Полезная вещь, в примеру нам нужно поменять цвет машины. Список цветов вы найдете по ссылке. Или дать оружие игроку = список оружия есть.
Как начать писать скрипты:
Мы уже знаем основы скриптинга, функции, нам нужна практика.
Необходимо полазить на форуме в поиске уроков по написанию простеньких скриптов.
К примеру «Работа Дальнобойщиком». Взять и прочитать весь код, разобрать как он работает.
Разберетесь? Думаю да. Теперь что-то измените в нем и проверьте, получилось ли?
Возьмите следующий урок и т.д., пока не надоест, а когда надоест — еще поработайте.
Когда начнете писать свой скрипт — сначала нужно составить в голове алгоритм работы кода.
Что куда идет и что выполняется, если сложно в голове сложить — нарисуйте блоками на бумажке.
Проведите линии между блоками, дабы не запутаться.
Набирайте код, проверяйте на ошибки.
Если что-то не получается или не знаете как сделать — не нужно бежать к друзьями и просить о помощи, а нужно самому разобраться в ситуации.
Поискать на форуме, в частности в этом разделе. Когда сам что-то ищешь и находишь — лучше откладывается в памяти.
Уроков по основам скриптинга на павне не так уж много, и не такие они ёмкие.
Почитайте о таком языке как PHP и других подобных, они похожи между собой, да и знания не помешают.
Кому хоть чем то помог,поставьте +
Введение.
Для начала надо знать:
1. Pawn — язык программирования. Приспособлен для создание модов и скриптов в SA-MP.
2. Чтобы использовать данный язык, нужна программа Pawno.
Неплохо знать английский язык, т.к. именно на нём записаны все функции и калбеки.
Оглавление:
Урок 1. Начало.
Урок 2. Паблики.
Урок 3. Функции.
Урок 4. Переменные.
Урок 5. Проверки.
Урок 6. Создание новых пабликов.
Урок 7. Таймер.
Урок 8. Циклы.
Урок 9. #define.
Урок 10. enum.
Дополнение 1. Работа с dcmd.
Дополнение 2. Работа с strtok.
Урок 1. Начало.
Если вы делаете мод, то сначала стоит записать данные строки:
#include <a_samp>//Включение в мод все функций и калбеков sa-mp. main(){}
a_samp.inc — это файл, содержащий в себе все функции и паблики sa-mp.
Урок 2. Паблики.
Паблики (public), иногда их называют калбеки (callbacks).
Callback, переводится как «функция, вызываемая автоматически».
Это процедуы, которые определяют, что будет
выполняться при данном действии, будь то игрока написал что то в чате,
или запустился мод. Каждый калбек имеет определённое название и определённые параметры.
Пример паблика:
public OnPlayerDeath(playerid,killerid,reason)//Строка определяет, что это за паблик, его параметры. {//Начало действия. }//Конец действия
Данный паблик паблик отвечает за то, что будет, когда игрок сдохнет.
playerid — ИД того, кто погиб
killerid — ИД того, кто убил игрока
reason — причина (в смысле, каким оружием)
public OnPlayerDeath(playerid,killerid,reason) //Игрок умер. { //здесь описывается то, что будет, если игрок умер }
В конце каждого паблика должен стоять return.
Если паблик находится в моде, то вводим return 1;
Если паблик находится в скрипте, то вводим return 0;
Если установить return 1; в скрипте, то выйдет такая ситуация:
паблик в скрипте работать не будет!
Исключение: OnPlayerText.
Основные паблики.
OnGameModeInit() — события, когда загружается мод
OnGameModeExit() — события, когда выгружается мод
OnPlayerConnect(playerid) — события, когда игрок подключается к серверу
OnPlayerDisconnect(playerid,reason) — события, когда игроку отключается от сервера. reason — причина отключения.
OnPlayerDeath(playerid, killerid, reason) — события, когда игрок погибает. reason — причина гибели.
OnPlayerRequestClass(playerid, classid) — события, когда игрок выбирает скина. classid — какой скин выбран на данный
момент.
OnPlayerCommandText(playerid,cmdtext[]) — события, когда игрок ввёл команду. cmdtext — команда, используется в strcmp.
OnPlayerPickUpPickup(playerid, pickupid) — события, когда игрок поднял пикап. pickupid — ID пикапа
OnPlayerText(playerid,text[]) — события, когда игрок ввёл текст в чат.
Типы return-ов. Если return1; — текст игрока отображается в чате,
если return 0; — текст игрока не отображается в чате.
OnPlayerSpawn(playerid) — события, когда игрок отправился на спавн.
OnFilterScriptInit() — события, когда скрипт загружается на сервер
OnFilterScriptExit() — события, когда скрипт выгружается из памяти сервера
Практика.
public OnPlayerDeath(playerid,killerid,reason)//Игрок умер. { //некий код return 1;//т.к. стоит в моде }
Урок 3. Функции.
Функции — они и в Африке функции. Каждая функция, как и паблик,
имеет определённые параметры. Синтаксис нативной функции:
GivePlayerMoney(playerid,money);
Данная функция даёт игроку playerid деньги money.
Может быть функция с одним параметром, например:
GetPlayerMoney(playerid);
Данная функция определяет число денег у игрока playerid. Cама по себе бесполезна,
используется для других фукнций.
Основные функции.
SetPlayerHealth(playerid,health); — установить игроку playerid здоровье health
SetPlayerArmour(playerid,armour); — установить игроку playerid уровень брони armour
GivePlayerMoney(playerid,money); — дать игроку playerid деньги money
ResetPlayerMoney(playerid); — все деньги игроку обнуляются
ResetPlayerWeapons(playerid); — игрок лишается всего оружие
GivePlayerWeapon(playerid,weaponid,var1); — игроку playerid даётся оружие weaponid с патронами var1
CreatePickup(model,type,Float:X,Float:Y,Float:Z); — создаёт пикап (разбросанное оружие) с ид model, с типом пикапа type
и с координатами X,Y,Z
Если пикап будет перерождаться, то ставим type 2. Если создаётся только один раз — type 3.
AddStaticPickup(model,type,Float:X,Float:Y,Float:Z); — создаётся пикап model с типом type и координатами X,Y,Z
CreateVehicle(modelid, Float:x, Float:y,Float:z, Float:angle, color1, color2, respawn_delay); — создаётся автомобиль modelid,
x,y,z — координаты, angle — угол поворота, color1, color2 — цвета, respawn_delay — время в секундах, через которое
автомобиль будет респавниться после того, как оно было покинуто водителем.
AddStaticVehicle(modelid, Float:spawn_x, Float:spawn_y,Float:spawn_z, Float:angle, color1, color2); — создаётся автомобиль
modelid,
spawn_x, spawn_y, spawn_z — координаты, angle — угол поворота, color1, color2 — цвета авто. Используется только в
OnGameModeInit().
SendClientMessage(playerid, 0xDEEE20FF, «Hello.»); — отправляет текст в чат игроку playerid с определённом цветом, и с
текстом
«Hello.»
SendClientMessageToAll(0xDEEE20FF, «Hello.»); — аналогично, только тот же текст отправляется всем игрокам в общий чат.
И теперь практика!
public OnPlayerDeath(playerid,killerid,reason)//Игрок умер. { //Начало действия паблика GivePlayerMoney(killerid,GetPlayerMoney(playerid));//Игроку killerid (тот кто убил) даются все деньги playerid (тот, кто умер). //Конец действия }
Урок 4. Переменные.
Строго говоря это адреса памяти, имеющие определённое значение.
Говоря проще, это некое слово, имеющие числовое значение
Существуют несколько видов переменных:
1. серверные переменные,
2. переменные игроков,
3. текстовые переменные.
1. Серверные переменные.
Так будем называть общие переменные.
new server_players=0;
Создана перменная server_players со значением 0.
Присвоение значения:
server_players=5;
Переменной server_players присвоено значение 5.
Функция прибавление к значению опред. числа:
server_players+=5;
Функция отнятия из значения опред. числа:
server_players-=5;
+1 к значению:
server_players++;
-1 к значению:
server_players--;
К переменной можно присвоить значение функции.
server_players=GetPlayerMoney(playerid);//переменной server_players присвоено значение денег игрока playerid
Также к переменной можно присвоить ИД, например, транспорта.
new vehicle;//Создаётся переменная.
vehicle=CreateVehicle(522, 1683, 785,0, 0, 6, 9,-1);//Переменной ‘vehicle’ присвоено значение ИД транспорта.
DestroyVehicle(vehicle);//Транспорт уничтожается.
Практика.
public OnPlayerDeath(playerid,killerid,reason)//Паблик {//Начало выполнения server_players++;//+ 1 к значению server_players }//Конец выполнения
2. Переменные игроков.
Переменная, которая приклепляется к каждому игроку на сервере.
new player[MAX_PLAYERS]=0;
Создана переменная player со значением 0.
На данном этапе каждый игрок имеет значение 0.
player[playerid]=5;
Переменной player одного игрока playerid присваивается значение 5.
Также с данной переменной совершаются все действия серверной переменной.
Практика.
new kills[MAX_PLAYERS]=0;//Создана переменная kills. Для всех игроков установлено значение 0. new deaths[MAX_PLAYERS]=0;//Создана переменная deaths. Для всех игроков установлено значение 0. public OnPlayerDeath(playerid,killerid,reason)//Паблик { kills[killerid]++;//+1 к значению kills у игрока killerid deaths[playerid]++;//+1 к значению deaths у игрока playerid }
3. Текстовые переменные.
Текстовые переменные — переменные, значением которых может быть только текст.
new string[256];//cоздана переменная string
Такая переменная в основном используется для создания форматированного текста.
format(string,256," Ваши деньги: %d",GetPlayerMoney(playerid));
%d — некое числовое значение
%s — некое текстовое значение
Переменной string присвоено текстовое значение, указанное в кавычках.
Есть ещё переменная, используемая для имени:
new name[MAX_PLAYER_NAME];
Cоздана переменная name.
Практика.
GetPlayerName(playerid,name,256);//Получено имя игрока format(string,256," Ваше имя: %s",name);//Форматирование текста SendClientMessage(playerid,0xAAFF00,string);//Отправлено сообщение
Урок 5. Проверки.
Проверка — функция, проверящая, выполняется ли данная функция. Если выполняется функция,
то и выполняется определённый код.
if(некая_функция) { // код, который должен выполняться, при выполнение некая_функция }
В качестве проверки может использоваться:
1. сравнению переменных, либо значений функций,
2. выполняеться ли некая функция.
1. Сравнение переменных.
if(GetPlayerMoney(playerid) >= money) { выполнение_кода; }
В данной проверка произведено сравнение:
ЕСЛИ деньги_игрока >= (больше или равно) money
ТО выполнение_кода
Есть разных виды сравнений:
!= — не равно
>= — больше или равно
<= — меньше или равно
> — больше
< — меньше
== — равно
Практика.
new kills[MAX_PLAYERS]=0;//Создана переменная kills. Для всех игроков установлено значение 0. new string[256]; public OnPlayerDeath(playerid,killerid,reason)//Паблик { kills[killerid]++;//+1 к значению kills у игрока killerid if(kills[killerid] == 10)//Если значение kills игрока killerid равно 10 {//Начало выполнения кода SendClientMessage(playerid,0x000FFF,"Вы убили уже 10 раз, вы получили бонус $10000.");//Сообщение GivePlayerMoney(playerid,10000);//Выдаются деньги }//Конец выполнения кода }
2. Выполнение определённой фукнции.
Проверяет, выполняеться ли данная функция.
if(IsPlayerConnected(playerid)) { }
Выполняется проверка, подключён ли игрок к серверу.
Практика.
public OnPlayerCommandText(playerid,cmdtext[])//Паблик { if(strcmp(cmdtext,"/testmessage",true)==0)//Проверка, выполнена ли данная комманда. {//Начало выполнения кода SendClientMessage(playerid,0xAFF00000,"Команда выполнена."); return 1;//Здесь тоже нужен return. }//Конец выполнения кода return 1; }
Конечно, есть функия, использующаяся при невыполнениии проверки.
Называется else. Используется так.
public OnPlayerCommandText(playerid,cmdtext[]) { if(strcmp(cmdtext,"/testmessage",true)==0) { if(IsPlayerAdmin(playerid))//Являеться ли игрок ркон-админом. { SendClientMessage(playerid,0xAFF00000,"Команда выполнена.");//Если да, то выполняеться данная функция. } else SendClientMessage(playerid,0xAFF00000,"Вы не являетесь ркон админом.");//Если нет, то выполняется другая функция.. return 1; } return 1; }
Урок 6. Создание новых пабликов.
Новый паблик создаётся так:
forward SetPlayerMoney(playerid,money);
Создаётся он для того, чтобы вызвать некоторые функции одновременно.
Например, функция установки денег.
forward SetPlayerMoney(playerid,money);//Создан паблик public SetPlayerMoney(playerid,money) { ResetPlayerMoney(playerid);//Все деньги у игрока отбираются. GivePlayerMoney(playerid,money);//Игрок получат деньги. }
Урок 7. Таймер.
Таймер — функция, вызвающая определённый паблик в определённое время.
Функция может вызваться единожды, либо повторяться через
заданные промежутки времени.
Для того, чтобы повесить таймер на определённый паблик,
создаётся такая фукнция.
SetTimer("NewPublic",1000,1);
В 1 секунде — 1000 миллисекунд.
1000 — заданный промежуток времени в миллисекундах, после которого паблик запускается заново.
1 — тип таймер. Если установлено 1, то таймер перезапускается бесконечное кол-во раз. Если 0, то таймер вызывает
паблик только первый раз.
Примечание: не стоит ставить значение таймера < 100, это может вызвать нагрузку на процессор.
Пример использования:
public OnGameModeInit() { SetTimer("AllMessage",120000,1);//Cоздан таймер, поставленный на паблик NewPublic. //Таймер запускается каждые 2 минуты } forward AllMessage(); public AllMessage() { SendClientMessageToAll(0xAFDAFD00," >> Серверу требуются модераторы."); //Cообщение. Отправляется всем игрокам каждые 2 минуты.
Урок 8. Циклы.
Цикл — функция, которая перебирает все значения определённой
переменной, в указанных рамках.
Код цикла:
for(new i=0;i<50;i++)//Цикл {//Начало действия цикла GivePlayerMoney(i,1000);//Даются деньги GameTextForPlayer(i,"~r~bonus!",1000,1);//Сообщение //Перебираюся все значения i, выходит, что функция выполняется для всех игроков с ID < 50 //Конец действия цикла }
Примечание: не стоит ставить ограничение цикла на MAX_PLAYERS (500). Это вызывает большую
нагрузку на процессор.
Пример использования цикла.
public OnGameModeInit() { SetTimer("TTimer",120000,1);//Создаётся таймер. } forward TTimer();//Создаётся паблик. public TTimer() { for(new i=0;i<50;i++)//Цикл, просматриваются все значения i до 50. { SendClientMessage(i,0xAFAFAF," >> Серверу требуются модераторы.");//Всем игрокам с ID < 50 отправляется сообщение. } }
Урок 9. #define.
Данная функция используется довольно редко. Позволяет на одно слово «поставить» другое.
#define COLOR_ZEL 0x00FF00AA
Слово COLOR_ZEL теперь понимается компилятором как определённый код цвета.
Урок 10. enum
enum — это вещь, позволяющая создавать большее количество адресов одной переменной.
Пример:
enum PVar { PHealth, PArmour }
Здесь у адреса PVar создаются подразделы PHealth, PArmour.
new PlayerVar[MAX_PLAYERS][PVar];
Теперь игрок может на одну переменную игрока ставить несколько адресов.
Под PVar подразумевается PHealth, либо PArmour.
Разумеется, enum можно юзать и в общей (серверной) переменной.
enum SVar//Создан адрес SVar с подразделами Players и AllPlayers { Players, AllPlayers } new PlayerServer[SVar];
Пример использования.
enum Var1//Создан адрес Var1 с подразделами PBank, PKills и PDeaths. { PBank, PKills, PDeaths } new PlayerVar[MAX_PLAYERS][Var1];//Создана переменная с данными адресами public OnPlayerDeath(playerid,killerid,reason) { PlayerVar[playerid][PDeaths]+=1;//К адресу PDeaths переменной игрока ставиться +1 PlayerVar[killerid][PKills]+=1;//К адресу PKills переменной игрока ставиться +1 }
Дополнение 1. Работа с dcmd.
dcmd — командный процессор, с помощью которого можно более просто (обходя strtok) создавать команды с переменными.
Вообще сама функция dcmd создаётся при помощи define. Код:
#define dcmd(%1,%2,%3) if (!strcmp((%3)[1], #%1, true, (%2)) && ((((%3)[(%2) + 1] == '') && (dcmd_%1(playerid, ""))) || (((%3)[(%2) + 1] == ' ') && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1
Перед созданием самой команды надо обозначить её в OnPlayerCommandText(playerid,cmdtext[])
public OnPlayerCommandText(playerid,cmdtext[]) { dcmd(healplayer,10,cmdtext); return 1; }
healplayer — название команды, 10 — кол-во символов в команде.
Сама команда создаётся так:
dcmd_healplayer(playerid,params[])//Создана команда healplayer { new player1;//создана переменная player1 = strval(params[0]);//к player1 присваивается числовое значение params[0] if(IsPlayerConnected(player1))//Проверка, подключён ли игрок к серверу { if(IsPlayerAdmin(playerid))//Проверка, является ли игрок, вводивший команду, rcon-админом { SetPlayerHealth(player1,100);//ХП того игрока становиться 100 } } }
Дополнение 2. Работа с strtok.
strtok — функция, аналогичная dcmd. Позволяет создать команды с переменными.
Сама функция strtok .
strtok(const string[], &index) { new length = strlen(string); while ((index < length) && (string[index] <= ' ')) { index++; } new offset = index; new result[20]; while ((index < length) && (string[index] > ' ') && ((index - offset) < (sizeof(result) - 1))) { result[index - offset] = string[index]; index++; } result[index - offset] = EOS; return result; }
Переходим к паблику OnPlayerCommandText. Сначала пишем там код:
new cmd[256],idx; cmd = strtok(cmdtext,idx);
Создаём саму команду:
if(strcmp(cmd,"/healplayer",true)==0)//Проверка на введёную команду { new tmp[256];//Создаём 1 переменную tmp[256]. Обязательна для strtok new splayer;//Создаём общую переменную //Далее код переменной в команде. splayer можно заменить любой другой подходящей переменной tmp = strtok(cmdtext,idx); if(!strlen(tmp)) { SendClientMessage(playerid,0xFFFFF00,"Юзайте: /healplayer [playerid]"); } splayer = strval(tmp); if(IsPlayerConnected(splayer))//На сервере ли игрок? { if(IsPlayerAdmin(playerid))//Являетесь ли вы rcon-админом? { SetPlayerHealth(splayer,100);//Игроку даётся 100 хп. } else SendClientMessage(playerid,0xFFFFF00,"Вы не являетесь RCON-админом!");//Иначе мисага } else SendClientMessage(playerid,0xFFFFF00,"Игрок не находится на сервере.");//Иначе мисага return 1; }
Всё, команда создана.
Вот и весь Урок.
Автор: Не извесен.
Сообщение отредактировал Romzes: 19 марта 2020 — 16:31
Причина редактирования: фикс
- Регистрация
- 8 Дек 2021
- Сообщения
- 358
- Лучшие ответы
- 4
- Репутация
- 94
- Адрес
-
Российской империи
-
#1
Всем привет! Сегодня я расскажу как создать свой скрипт АХК для Samp. Тоесть его задача выполнять быстрые задачи нажав кнопку.
Я буду использовать программу AutoHotkeyScript(AHK).
Первым делом скачаем саму программу на её оффициальном сайте.
После скачивания, создаем файл на рабочем столе.
Кликаем ПКМ по файлику и нажимаем «Edit Script».
У нас открывается файл, в ней будут символы но нам они не нужны, мы их просто удаляем.
И начинаем писать код скрипта, я буду писать для Полиции Лос-Сантоса.
PHP:
NumPad0::
SendMessage, 0x50,, 0x4190419,, A
NumPad0:: — Это клавиша на которой после нажатия будет производиться сам АХК.
SendMessage, 0x50,, 0x4190419,, A — Нужное системное сообщение, без него АХК работать не будет.
Код:
NumPad0::
SendMessage, 0x50,, 0x4190419,, A
SendInput, {F6}/do Удостоверение лежит в правом кармане.{Enter}
Sleep 750
SendInput, {F6}/me достал в открытом виде удостоверение и показал{Enter}
Sleep 750
SendInput, {F6}/do Удостоверение показано.{Enter}
Sleep 750
SendInput, {F6}/me засунул обратно удостоверение в карман{Enter}
Return
SendInput, {F6} — Это команда сама открывает чат с помощью клавиши F6.
{Enter} в конце команды — Это значит что сообщение само будет отправлятся.
Sleep — Это задержка сообщения, НЕ рекомендую ставить меньше 350 потому что может сработать анти-флуд.
Return — Возвращает функцию.
Вот и всё, сейчас я вам показал как сделать простейшую АХК команду. Если возникнут вопросы писать в данной теме.
Ресурсы являются ключевой частью MTA. Ресурс — это папка или zip-архив, содержащий набор файлов, а также meta-файл, который описывает серверу как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе — он может быть запущен и остановлен, при этом несколько ресурсов могут быть запущены одновременно.
Все, связанное со скриптингом, находится в ресурсах. Назначение ресурса и определяет, является ли он модом, картой или чем-либо еще. MTA поставляется с ресурсами, которые вы можете выборочно использовать в своих модах, например, maplimits, позволяющий удерживать игроков в рамках указанных границ карты, или deathpickups, создающий пикапы с оружием.
Tip: Первым шагом в изучении Lua-скриптинга должен быть выбор Lua-редактора. Это намного упрощает скриптинг. Мы рекомендуем Notepad++ или LuaEdit. Также имеется неофициальный MTA Script Editor (на стадии разработки), который вы можете испытать. |
Создание работающего скрипта
Для начала мы узнаем, как пошагово сделать простой скрипт, который позволит игроку прогуливаться по городу.
Где находятся все скрипты?
Давайте взглянем на файловую структуру скрипта. Зайдите в папку сервера MTA и пройдите по следующему пути:
/server/mods/deathmatch/resources/
Вы увидите множество .zip-архивов, являющихся упакованными пробными скриптами, поставляемыми с MTA DM. Каждый файл — это «ресурс», все они будут распакованы и загружены сервером при его старте. Чтобы создать свой собственный ресурс, просто создайте папку и назовите ее так, как хотите. В нашем случае мы назовем ее «myserver».
Теперь вам нужно зайти в эту папку:
/server/mods/deathmatch/resources/myserver/
Идентификация вашего ресурса
Чтобы сервер мог узнать о содержимом того или иного ресурса, в нем должен быть создан файл meta.xml, перечисляющий его содержимое. Этот файл должен быть расположен в корневой директории ресурса, в нашем случае — это папка «myserver». Просто создайте текстовый файл, назовите его «meta.xml» и откройте с помощью Блокнота (notepad).
В файл meta.xml введите следующий код:
<meta> <info author="YourName" type="gamemode" name="Kontol memek" description="My Mta Sa" /> <script src="script.lua" type="server"/> </meta>
В теге <info /> есть поле «type», которое говорит о том, что данный ресурс — gamemode («мод», игровой режим), а не обычный include или map (карта), о которых мы поговорим чуть позже. Gamemode — то, что вам нужно, чтобы создать независимый сервер.
Тег <script /> оговаривает сценарии (скрипты), которые содержит ресурс, о них мы сейчас и поговорим.
Поле «type» говорит о том, что данный скрипт «script.lua» будет выполняться на стороне сервера.
Создание простого скрипта
Заметьте, что в теге <script /> ‘script.lua’ — файл не находится в какой-либо вложенной директории. Следовательно, мы создадим файл в той же папке, что и meta.xml. Теперь можно скопировать и вставить в script.lua следующий код:
local spawnX, spawnY, spawnZ = 1959.55, -1714.46, 10 function joinHandler() spawnPlayer(source, spawnX, spawnY, spawnZ) fadeCamera(source, true) setCameraTarget(source, source) outputChatBox("Welcome to My Server", source) end addEventHandler("onPlayerJoin", getRootElement(), joinHandler)
Этот скрипт заспавнит вас по координатам (x, y, z), указанным выше, когда вы зайдете на сервер. Обратите внимание, что функция fadeCamera обязательно должна быть, иначе экран будет черным. К тому же, в релизах новее DP2 вам нужно установить цель для камеры (иначе все, что увидит игрок — синее небо).
Переменная source указывает на того, кто вызвал срабатывание события. Так как данный код срабатывает при заходе какого-либо игрока, эта переменная используется для установления того, кто зашел. Так что спавнить будет именно этого игрока, а не всех сразу или кого-нибудь случайно.
Если присмотреться к addEventHandler, вы заметите три вещи: ‘onPlayerJoin’, указывающий на то, когда (почему) произойдет срабатывание; getRootElement(), который показывет благодаря кому/чему может произойти срабатывание (getRootElement() — это все/всё) и joinHandler, который отвечает за функцию, на которую произойдет переключение при срабывании события. Остальные подробности будут изложены позже и на отдельном примере, а теперь давайте просто запустим сервер и попрактикуемся!
Запуск скрипта
Чтобы запустить сервер, просто запустите исполняемый файл (на Windows — .exe) по адресу MTA San Andreas x.x/server, где x.x — номер версии MTA. Сначала будут показаны данные сервера; запомните номер порта (server port), который понадобится вам при подключении. Затем сервер загрузит все ресурсы в папку mods/deathmatch/resources/ и позже будет «ready to accept connections!», то есть готов принимать игроков.
Перед тем, как вы подключитесь к серверу, нужно обязательно запустить мод (gamemode). Введите «start myserver» и нажмите Enter. Сервер запустит мод, который вы только что создали, а также начнет отображать различные ошибки и предупреждения, если таковые будут. Теперь можно запустить клиент MTA DM и подключиться через «Quick Connect», воспользовавшись IP-адресом вашего сервера и номером порта, на который мы ранее обратили ваше внимание. Если все пройдет по плану, через несколько секунд ваш персонаж сможет пройтись по улицам Los Santos’а.
Затем мы добавим в скрипт команду, которую игроки смогут использовать для того, чтобы спавнить рядом с собой транспортное средство. Вы можете это пропустить и взглянуть на статью про более продвинутый скриптинг с использованием Map Manager, которая продолжит это руководство. Еще одним ответвлением данного руководства является Введение в скриптинг GUI: прочитав его, вы узнаете, как рисуется и программируется Graphical User Interface в MTA:DM.
Создание простой команды
Давайте вернемся к содержимому файла script.lua. Как уже было сказано, мы хотим предоставить команду для создания трансортного средства рядом с вашей текущей позицией в игре. Во-первых, нам понадобится создать функцию, которую мы будем вызывать, и обработчик команды, который сделает команду доступной для выбора игроком посредством ввода ее в консоли.
-- создаем функцию, вызываемую обработчиком команды, с аргументами: thePlayer, command, vehicleModel function createVehicleForPlayer(thePlayer, command, vehicleModel) -- создаем транспортное средство и другое end -- создаем обработчик команды addCommandHandler("createvehicle", createVehicleForPlayer)
Заметка: Клик по названию функции в образце кода перенаправит на соответствующую страницу с ее описанием.
Про обработчики команд
Первый аргумент addCommandHandler — имя команды, которая будет доступна игроку, второй аргумент — функция, на которую произойдет переключение, в данном случае — это createVehicleForPlayer.
Если у вас уже есть опыт в скриптинге, вы знаете, что функции вызываются примерно следующим образом:
functionName(argument1, argument2, argument3, ..)
functionName(thePlayer, commandName, argument3, ..)
Присмотревшись ко второму образцу (выше), мы увидим, что argument1 — thePlayer, а argument2 — commandName. thePlayer — тот, кто набрал команду, так что как бы вы ее не вводили, переменная будет содержать игрока, который ее активировал. commandName — команда, которую ввели. Так что при вводе «/greet», этот аргумент будет содержать «greet». Argument 3 — еще что-то, введенное игроком после, об этом вы узнаете чуть позже из данного руководства. Никогда не забывайте, что первые 2 аргумента являются стандартными, но назвать вы их можете по своему усмотрению. То есть важен порядок, а не название.
Мы уже вызывали таким образом функцию addCommandHandler, и так как createVehicleForPlayer — также функция, ее тоже можно так вызвать. Но мы для этого используем обработчик команд, который вызывает ее схожим образом, только внутренне.
Например: Кто-то вводит «createvehicle 468» в игровой консоли, чтобы заспавнить Sanchez, обработчик команд вызывает функцию createVehicleForPlayer, как если бы мы имели в скрипте следующую строку кода:
createVehicleForPlayer(thePlayer,"createvehicle","468") -- thePlayer - элемент типа player игрока, который ввел команду
Как можно заметить, предоставляются несколько параметров: игрок, который вызвал команду, сама команда, которую он ввел, и какой-нибудь текст, который он после нее ввел, в данном случае — «468» в качестве id трансопртного средства, отвчечающего за Sanchez. Первые два параметра одинаковы для всех обработчиков команд, о них вы можете почитать на странице addCommandHandler. Фактически, вам всегда придется определять как минимум эти два параметра, чтобы смочь использовать какие-нибудь другие, идущие после них (например, для обработки текста, введенного после команды, как id модели транспортного средства в нашем случае).
Заметка: Обработчик команды надо добавлять именно ПОСЛЕ функции, на которую он сошлется, иначе она не будет найдена. Порядок имеет значение!
Написание функции
Чтобы заполнить созданную нами функцию, нам следует подумать, что нам предстоит сделать:
- Получить позицию игрока, чтобы знать, где спавнить ТС (мы хотим, чтобы оно появлялось прямо рядом с игроком)
- Вычислить позицию, на которой мы хотим заспавнить ТС (мы же не хотим его появления на голове у игрока)
- Собственно, заспавнить ТС
- Проверить, заспавнилось ли оно успешно, в противном случае — вывести сообщение в чат
Чтобы разрешить все поставленные задчаи, нам понадобится задействовать несколько функций. А чтобы найти нужные нам функции, нужно перейти ко списку серверных функций. Для начала нам понадобится функция, которая получит координаты игрока. Так как все игроки являются элементами, мы сразу выбираем Element functions, где и находим функцию getElementPosition. Кликнув по имени функции из списка, вы получите ее описание. Там можно увидеть синтаксис, что она возвращает и, как правило, пример использования. Синтаксис сообщает какие аргументы мы можем или должны ей передать.
Для getElementPosition синтаксис таков:
float, float, float getElementPosition ( element theElement )
Три float перед именем функции и есть типы значений, которые она возвращает. В данном случае это значит, что функция возвращает три числа с плавающей точкой (x, y и z). Внутри круглых скобок указаны аргументы, которые ей необходимо передать. В данном случае это только элемент, чью позицию вы хотите получить, у нас он представлен игроком.
function createVehicleForPlayer(thePlayer, command, vehicleModel) -- get the position and put it in the x,y,z variables -- (local означает, что переменные существуют только здесь, в этой области, внутри этой функции) local x,y,z = getElementPosition(thePlayer) end
Затем нам надо сделать так, чтобы ТС не спавнилось прямо внутри игрока, поэтому мы прибавим небольшое число к переменной x, что повлечет за собой спавн ТС чуть восточнее самого игрока.
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- получаем позицию игрока x = x + 5 -- прибавляем число 5 к позиции по оси x end
Теперь нам понадобится другая функция, чтобы непосредственно заспавнить транспортное средство. Мы снова ищем ее в списке серверных функций, на этот раз, так как мы говорим о транспорте — в разделе Vehicle functions, где выберем createVehicle. В синтаксисе этой функции указано только одно возвращаемое значение (что встречается наиболее часто) — элемент типа vehicle, представляющий только что созданное ТС. Также мы видим, что часть аргументов заключена в [ ], следовательно, они необязательны.
Внутри нашей функции у нас уже есть все аргументы, которые нужны функции createVehicle: Только что вычисленная позиция в переменных x,y,z и id модели, который мы получили через команду («createvehicle 468»), он доступен внутри функции в качестве переменной vehicleModel.
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- получаем позицию игрока x = x + 5 -- прибавляем число 5 к позиции по оси x -- создаем ТС и сохраняем возвращенный элемент типа vehicle в переменной ''createdVehicle'' local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) end
Этот код, конечно же, можно усовершенствовать различными путями, но как минимум мы добавим проверку на то, было ли ТС успешно создано. Как можно прочитать на странице createVehicle под Returns, функция возвращает false, если ТС создать не получилось. Стало быть, мы проверяем значение переменной createVehicle.
Теперь у нас есть готовый скрипт:
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- получаем позицию игрока x = x + 5 -- прибавляем число 5 к позиции по оси x local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) -- проверяем, является ли возвращаемое значение ''false'' if (createdVehicle == false) then -- если да, то выводим сообщение в чат, но только для игрока, который спавнил ТС. outputChatBox("Failed to create vehicle.",thePlayer) end end addCommandHandler("createvehicle", createVehicleForPlayer)
Как вы уже, наверное, заметили, вашему взору предстала новая функция — outputChatBox. Теперь вы самостоятельно можете изучить содержимое ее страницы-документации. Чтобы узнать больше о продвинутом скриптинге, почитайте про Map Manager.
Что вам следует знать
Вы уже кое-что прочитали о ресурсах, обработчиках команд и поиске функций в документации в первом разделе, но многое еще предстоит узнать. Этот раздел проведет довольно краткий обзор о некоторых из этих вещей, по возможности ссылаясь на соответствующие страницы.
Клиентские и серверные скрипты
Может быть, вы уже заметили эти или схожие термины (сервер/клиент) где-либо на данной вики, наиболее вероятно, вкупе с функциями. MTA не только поддерживает работающие на сервере скрипты, предоставляет команды (типа как мы писали выше) и другие возможности, но также и скрипты, выполняющиеся на клиенте MTA, который игроки используют для подключения к серверу. Причиной этому служит то, что некоторые предоставляемые MTA функции не могут быть серверными (например, GUI — Graphical User Interface, т.е. графический интерфейс пользователя), другие там просто работают лучше, но другим все же лучше быть серверными или попросту не работать на клиентской стороне.
Большинство сделанных вами скриптов (модов, карт), вероятно, будут серверными, как и та, которую мы написали в первом разделе. Если вы столкнетесь с чем-то, что не может быть реализовано на серверной стороне, возможно, вы сможете реализовать это на клиентской. Для написания клиентского скрипта, создайте обычный файл-скрипт (например, названный client.lua) и укажите его в meta.xml так:
<script src="client.lua" type="client" />
Атрибут type по умолчанию установлен на ‘server’, так что надобность указывать его существует только для клиентских скриптов. После этого, клиентский скрипт будет загружаться на компьютеры игроков при заходе. Подробнее о клиентских скриптах.
Более сложные ресурсы
Предыдущий раздел вкратце изложил, как добавлять в ресурс клиентские скрипты, но возможностей на самом деле намного больше. Как написано в самом начале статьи, ресурсы могут быть чем угодно. Их назначение определяется тем, что они делают. Давайте теоретически вообразим некоторые ресурсы, глядя на их файлы-содержимое, meta.xml и подумаем, что они могут делать:
Первый пример — Вспомогательный скрипт
/admin_commands /meta.xml /commands.lua /client.lua
<meta> <info author="Someguy" description="admin commands" /> <script src="commands.lua" /> <script src="client.lua" type="client" /> </meta>
- commands.lua предоставляет некоторые администраторские команды, такие как бан и заглушение игроков или еще что-нибудь, что может быть доступно для администраторов сервера
- client.lua предоставляет GUI, чтобы возможно было с легкостью выполнять вышеуказанные действия
Этот пример может выполняться все время (даже автозапускаться со стартом сервера), так как является полезным на протяжении всего игрового процесса и не конфликтует с ним, если администратор, конечно, сам этого не захочет.
Второй пример — Мод
/counterstrike /meta.xml /counterstrike.lua /buymenu.lua
<meta> <info author="Someguy" description="Counterstrike remake" type="gamemode" /> <script src="counterstrike.lua" /> <script src="buymenu.lua" type="client" /> </meta>
- counterstrike.lua содержит схожие с нижеперечисленными функции:
- Позволить игрокам выбирать свою команду и спавниться
- Обеспечить их оружием, целями и инструкциями (возможно, взятыми из игровой карты, см. ниже)
- Определить правила игры, напр., когда кончается раунд, что происходит при смерти игрока
- .. и, может быть, что-то еще
- buymenu.lua — клиентский скрипт, создающий меню для покупки оружия
Этот образец может быть назван модом, так как не только влияет на игровой процесс, но, по сути, и задает его рамки. Атрибут type говорит о том, что этот пример работает с Map Manager, уже другим ресурсом, написанным QA Team для управлениями модами и подгрузки карт. Очень рекомендуется основывать свои моды на предоставляемом им функционале.
Это также означает, что мод, возможно, не запустится без карты. Моды всегда должны пользоваться общим функционалом настолько широко, насколько это возможно. Образец карты — в следующем примере.
Третий пример — Карта
/cs-airport /meta.xml /airport.map /airport.lua
<meta> <info author="Someguy" description="Counterstrike airport map" type="map" gamemodes="counterstrike" /> <map src="airport.map" /> <script src="airport.lua" /> </meta>
- airport.map — XML-файл, предоставляющий моду информацию о карте, что включает в себя:
- Где игроки должны спавниться, с каким оружием, какие имеются команды
- Какие имеются цели
- Погода, время, ограничение по времени
- Предоставляемый транспорт
- airport.lua может содержать присущий данной карте функционал, что включает в себя:
- Открытие каких-либо дверей, подрыв чего-нибудь при определенных условиях
- Создание или передвижение определенных игровых объектов, или управление теми, что были созданы через .map-файл
- .. все что еще угодно, связанное с картами
Как вы уже заметили, атрибут type поменялся на ‘map’, сообщая Map Manager, что этот ресурс — карта, в то время как атрибут gamemodes говорит, с какими модами эта карта совместима, в данном случае — это мод из примера выше.
Сюрпризом может показаться то, что в ресурс-карту также входит и скрипт. Конечно, это совсем не обязательно для карты, но открывает широкий спектр возможностей для их создателей, позволяя создавать собственный мир с правилами мода, на котором он основывается.
Файл airport.map может выглядеть примерно так:
<map mode="deathmatch" version="1.0"> <terrorists> <spawnpoint posX="2332.23" posY="-12232.33" posZ="4.42223" skins="23-40" /> </terrorists> <counterterrorists> <spawnpoint posX="2334.23443" posY="-12300.233" posZ="10.2344" skins="40-50" /> </counterterrorists> <bomb posX="23342.23" posY="" posZ="" /> <vehicle posX="" posY="" posZ="" model="602" /> <vehicle posX="" posY="" posZ="" model="603" /> </map>
Когда мод запускается с картой, ресурс-карта автоматически запускается mapmanager’ом, и информация, которую он содержит, может быть прочитана ресурсом-модом. При смене карты, текущий ресурс-карта останавливается, а следующий — запускается. Для более детального разъяснения и образцов того, как ресурсы-карты используются основным скриптом, посетите страницу RU/Writing Gamemodes.
События
События — способ MTA сообщать скриптам о происходящем. Например, при смерти игрока, срабатывает событие onPlayerWasted. Чтобы при смерти игрока что-то происходило, вам придется проделать действия, схожие с добавлением обработчика команд, как об этом рассказано в первом разделе.
Этот пример будет выводить сообщение с именем игрока, который умер:
function playerDied(totalAmmo, killer, killerWeapon, bodypart) outputChatBox(getPlayerName(source).." умер!") end addEventHandler("onPlayerWasted",getRootElement(),playerDied)
Вместо того, чтобы сначала вывести список требуемых аргументов, страница документации для событий отображает, какие параметры передаются функции-обработчику, так же, как делает обработчик команд, просто это разнится от события к событию. Другим важным моментом является существующая в функциях-обработчиках переменная source. Ее необязательно добавлять в список параметров функции, но она, тем не менее, существует. Ее значение меняется от события к событию, для событий, связанных с игроком (как в образце выше), это — элемент типа player. В качестве другого образца служит базовый скрипт для респавна игрока в первом разделе, на его примере можно понять, как используется source.
Что делать теперь
Теперь вы знакомы с наиболее базовыми аспектами скриптинга в MTA, а также чуть-чуть с документацией. Главная страница обеспечит вас ссылками на множество различной информации, руководства и указания, которые позволят глубже взглянуть на интересующие вас темы.
Note: Теперь мы рекомендуем вам прочитать руководство по отладке. Умение хорошо отлаживать — абсолютная необходимость при написании скриптов. Мы также рекомендуем вам пользоваться списком предписанных переменных, который поможет вам в выполнении определенных задач, а писать скрипты станет намного легче и быстрее. |
Также смотрите:
- Продвинутый функционал