Введение в скриптинг: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
("vehicle" changed on "vehicleModel" (typographic error in the english version of article))
 
(15 intermediate revisions by 10 users not shown)
Line 1: Line 1:
Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip архив, содержащий набор файлов, а также мета файл, описывающий серверу, как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, а также могут быть запущены несколько ресурсов одновременно. Всё, что выполняется с помощью сценариев находится в ресурсах, что реализовано в сценариях: игровые режимы, игровые карты или что-либо ещё - все это ресурсы.
Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip-архив, содержащий набор файлов, а также meta-файл, который описывает серверу как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, при этом несколько ресурсов могут быть запущены одновременно.  


==Создание простого сценария==
Все, связанное со скриптингом, находится в ресурсах. Назначение ресурса и определяет, является ли он модом, картой или чем-либо еще. MTA поставляется с ресурсами, которые вы можете выборочно использовать в своих модах, например, maplimits, позволяющий удерживать игроков в рамках указанных границ карты, или deathpickups, создающий пикапы с оружием.
Для начала давайте сделаем так, чтобы по команде игрока "createvehicle" рядом с игроком создавалась машина.
{{tip|Первым шагом в изучении Lua-скриптинга должен быть выбор Lua-редактора. Это намного упрощает скриптинг. Мы рекомендуем [http://notepad-plus.sourceforge.net/uk/site.htm Notepad++] или [http://luaedit.sourceforge.net/ LuaEdit]. Также имеется неофициальный [[RU/MTASE|MTA Script Editor]] (на стадии разработки), который вы можете испытать.}}


===Подготовка===
==Создание работающего скрипта==
Как описывалось выше, ресурс является папкой или zip архивом, поэтому для начала мы должны создать папку. Название папки является названием ресурса. Это название используется для запуска или прекращения выполнения ресурса и для обращения к ресурсу в сценариях. В нашем примере, папку необходимо назвать ''commands''.
Для начала мы узнаем, как пошагово сделать простой скрипт, который позволит игроку прогуливаться по городу.
===Где находятся все скрипты?===
Давайте взглянем на файловую структуру скрипта. Зайдите в папку сервера MTA и пройдите по следующему пути:


Каждому ресурсу необходим файл ''meta.xml''. В нашем случае, мы хотим создать сценарий, который обеспечит пользователю выполнение нескольких простых команд, поэтому нам необходимо сообщить серверу о необходимости загрузки файла сценария, в нашем случае таким файлом сценария пусть будет ''script.lua''.
/server/mods/deathmatch/resources/
Содержимое файла ''meta.xml'':
 
Вы увидите множество .zip-архивов, являющихся упакованными пробными скриптами, поставляемыми с MTA DM. Каждый файл - это "ресурс", все они будут распакованы и загружены сервером при его старте. Чтобы создать свой собственный ресурс, просто создайте папку и назовите ее так, как хотите. В нашем случае мы назовем ее "myserver".
 
Теперь вам нужно зайти в эту папку:
 
/server/mods/deathmatch/resources/myserver/
 
===Идентификация вашего ресурса===
Чтобы сервер мог узнать о содержимом того или иного ресурса, в нем должен быть создан файл ''meta.xml'', перечисляющий его содержимое. Этот файл должен быть расположен в корневой директории ресурса, в нашем случае - это папка "myserver". Просто создайте текстовый файл, назовите его "meta.xml" и откройте с помощью Блокнота (notepad).
 
В файл ''meta.xml'' введите следующий код:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<meta>
<meta>
  <info author="YourName" description="A few simple commands" />
    <info author="YourName" type="gamemode" name="Kontol memek" description="My Mta Sa" />
  <script src="script.lua" />
    <script src="script.lua" type="server"/>
</meta>
</meta>
</syntaxhighlight>
</syntaxhighlight>
В теге ''<info />'' есть поле "type", которое говорит о том, что данный ресурс - ''gamemode'' ("мод", игровой режим), а не обычный include или ''map'' (карта), о которых мы поговорим чуть позже. Gamemode - то, что вам нужно, чтобы создать независимый сервер.


Теперь нам необходимо создать файл ''script.lua'', о котором упоминалось выше, в той же самой директории, где расположен файл ''meta.xml''. В результате содержимое папки ''commands'' должно быть таким:
Тег ''<script />'' оговаривает сценарии (скрипты), которые содержит ресурс, о них мы сейчас и поговорим.
Поле "type" говорит о том, что данный скрипт "script.lua" будет выполняться на стороне сервера.


<syntaxhighlight lang="xml">
===Создание простого скрипта===
/commands/meta.xml
Заметьте, что в теге ''<script /> 'script.lua' - файл не находится в какой-либо вложенной директории. Следовательно, мы создадим файл в той же папке, что и meta.xml. Теперь можно скопировать и вставить в script.lua следующий код:
/commands/script.lua
<syntaxhighlight lang="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)
</syntaxhighlight>
</syntaxhighlight>
Этот скрипт заспавнит вас по координатам (x, y, z), указанным выше, когда вы зайдете на сервер. Обратите внимание, что функция ''fadeCamera'' обязательно должна быть, иначе экран будет черным. К тому же, в релизах новее DP2 вам нужно установить цель для камеры (иначе все, что увидит игрок - синее небо).
Переменная '''source''' указывает на того, кто вызвал срабатывание события. Так как данный код срабатывает при заходе какого-либо игрока, эта переменная используется для установления того, кто зашел. Так что спавнить будет именно этого игрока, а не всех сразу или кого-нибудь случайно.


===Написание сценария===
Если присмотреться к [[addEventHandler]], вы заметите три вещи: 'onPlayerJoin', указывающий на то, когда (почему) произойдет срабатывание; getRootElement(), который показывет благодаря кому/чему может произойти срабатывание (getRootElement() - это все/всё) и joinHandler, который отвечает за функцию, на которую произойдет переключение при срабывании события. Остальные подробности будут изложены позже и на отдельном примере, а теперь давайте просто запустим сервер и попрактикуемся!
Начнем с содержимого файла ''script.lua''. Как описывалось выше, нам необходимо обеспечить команду, которая будет создавать машину рядом с игроком. Для начала нам необходимо создать функцию, которую мы будем вызывать, и обработчик команды, который позволит игроку вводить и выполнять команду в окне консоли.
 
===Запуск скрипта===
Чтобы запустить сервер, просто запустите исполняемый файл (на 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'а.
 
Затем мы добавим в скрипт команду, которую игроки смогут использовать для того, чтобы спавнить рядом с собой транспортное средство. Вы можете это пропустить и взглянуть на статью про более продвинутый скриптинг с использованием [[RU/Map manager|Map Manager]], которая продолжит это руководство. Еще одним ответвлением данного руководства является [[Введение в скриптинг GUI]]: прочитав его, вы узнаете, как рисуется и программируется Graphical User Interface в MTA:DM.
 
==Создание простой команды==
Давайте вернемся к содержимому файла ''script.lua''. Как уже было сказано, мы хотим предоставить команду для создания трансортного средства рядом с вашей текущей позицией в игре. Во-первых, нам понадобится создать функцию, которую мы будем вызывать, и обработчик команды, который сделает команду доступной для выбора игроком посредством ввода ее в консоли.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
-- создание функции, вызываемой обработчиком команды, с аргументами: thePlayer, command, vehicleModel
-- создаем функцию, вызываемую обработчиком команды, с аргументами: thePlayer, command, vehicleModel
function createVehicleForPlayer(thePlayer, command, vehicleModel)
function createVehicleForPlayer(thePlayer, command, vehicleModel)
   -- код сценария для создания машины
   -- создаем транспортное средство и другое
end
end


-- создание обработчика команды
-- создаем обработчик команды
addCommandHandler("createvehicle", createVehicleForPlayer)
addCommandHandler("createvehicle", createVehicleForPlayer)
</syntaxhighlight>
</syntaxhighlight>
''Обратите внимание: Имена функций в коде примеров являются ссылками на wiki-статьи, описывающие функции в документации.''
''Заметка: Клик по названию функции в образце кода перенаправит на соответствующую страницу с ее описанием.''


====О обработчиках команд====
====Про обработчики команд====
Первым аргументом [[addCommandHandler]] название команды, введенной игроком, второй аргумент - функция, которая будет вызвана, в нашем случае это ''createVehicleForPlayer''.
Первый аргумент [[addCommandHandler]] - имя команды, которая будет доступна игроку, второй аргумент - функция, на которую произойдет переключение, в данном случае - это ''createVehicleForPlayer''.


Если вы уже знакомы с написанием сценариев, то вам наверняка приходилось вызывать функции следующего вида:
Если у вас уже есть опыт в скриптинге, вы знаете, что функции вызываются примерно следующим образом:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
functionName(argument1, argument2, argument3, ..)
functionName(argument1, argument2, argument3, ..)
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="lua">
functionName(thePlayer, commandName, argument3, ..)
</syntaxhighlight>
Присмотревшись ко второму образцу (выше), мы увидим, что argument1 - thePlayer, а argument2 - commandName. thePlayer - тот, кто набрал команду, так что как бы вы ее не вводили, переменная будет содержать игрока, который ее активировал. commandName - команда, которую ввели. Так что при вводе "/greet", этот аргумент будет содержать "greet". Argument 3 - еще что-то, введенное игроком после, об этом вы узнаете чуть позже из данного руководства. Никогда не забывайте, что первые 2 аргумента являются стандартными, но назвать вы их можете по своему усмотрению. То есть важен порядок, а не название.


Таким способом мы вызываем функцию [[addCommandHandler]], а затем функцию ''createVehicleForPlayer''. Она, конечно же, может быть вызвана этим же способом отдельно. Но для нее мы используем обработчик команды, который вызывает ее в пожожей манере, но только внутри.
Мы уже вызывали таким образом функцию [[addCommandHandler]], и так как ''createVehicleForPlayer'' - также функция, ее тоже можно так вызвать. Но мы для этого используем обработчик команд, который вызывает ее схожим образом, только внутренне.


Например: Какой-нибудь игрок в процессе игры введет в окно консоли команду "createvehicle 468" для создания машины Sanchez, обработчик команды вызовет функцию createVehicleForPlayer , так же, как '''если бы''' у нас в коде сценария была строка:
Например: Кто-то вводит "createvehicle 468" в игровой консоли, чтобы заспавнить Sanchez, обработчик команд вызывает функцию createVehicleForPlayer, как '''если бы''' мы имели в скрипте следующую строку кода:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
createVehiceForPlayer(thePlayer,"createvehicle","468") -- thePlayer это игрок, который ввел команду
createVehicleForPlayer(thePlayer,"createvehicle","468") -- thePlayer - элемент типа player игрока, который ввел команду
</syntaxhighlight>
</syntaxhighlight>
Эта функция имеет несколько параметров: параметр, отвечающий за игрока, который ввел команду, параметр, имеющий в качестве значения введенную команду и параметр, содержащий текст, который следовал после команды, в нашем случае это "468" - идентификатор машины Sanchez. Первые два параметра такие же, как и у остальных обработчиков команд, о которых вы можете прочитать информацию на странице [[addEventHandler]]. Поэтому, вы всегда должны определить, по крайней мере, эти два параметра для использования чего-либо после них (например, для обработки текста, введенного после команды, как в нашем примере - идентификатора модели машины).
Как можно заметить, предоставляются несколько параметров: игрок, который вызвал команду, сама команда, которую он ввел, и какой-нибудь текст, который он после нее ввел, в данном случае - "468" в качестве id трансопртного средства, отвчечающего за Sanchez. Первые два параметра одинаковы для всех обработчиков команд, о них вы можете почитать на странице [[addCommandHandler]]. Фактически, вам всегда придется определять как минимум эти два параметра, чтобы смочь использовать какие-нибудь другие, идущие после них (например, для обработки текста, введенного после команды, как id модели транспортного средства в нашем случае).


''Обратите внимание: Вы можете добавить обработчик команды только ПОСЛЕ того, как вы определили функцию обработчика, иначе она не будет найдена. Порядок размещения функций имеет значение.''
''Заметка: Обработчик команды надо добавлять именно ПОСЛЕ функции, на которую он сошлется, иначе она не будет найдена. Порядок имеет значение!''


====Написание функции====
====Написание функции====
Для того, чтобы написать код созданной функции, нам необходимо продумать детали того, что мы хотим сделать:
Чтобы заполнить созданную нами функцию, нам следует подумать, что нам предстоит сделать:
* Получить позицию игроков для того, чтобы знать куда поместить новую машину (допустим, что мы хотим, чтобы она появилась справа от игрока)
* Получить позицию игрока, чтобы знать, где спавнить ТС (мы хотим, чтобы оно появлялось прямо рядом с игроком)
* Вычислить позицию того места, куда необходимо поместить машину (это необходимо для того, чтобы она не появилась на месте игрока)
* Вычислить позицию, на которой мы хотим заспавнить ТС (мы же не хотим его появления на голове у игрока)
* Создать машину
* Собственно, заспавнить ТС
* Проверить успешность создания машины или вывести сообщение
* Проверить, заспавнилось ли оно успешно, в противном случае - вывести сообщение в чат


Для того, чтобы выполнить поставленные задачи, мы должны использовать несколько функций. Чтобы найти подходящую для решения задачи функцию, мы должны посмотреть страницу [[Scripting Functions|Список функций серверного приложения]]. Сначала нам необходима функция для получения позиции игроков. Так как игроки относятся к [[RU/Element|'''элементам''']] (основным классам, описывающим игровые сущности или, проще говоря, игровые объекты), то мы сначала переходим к странице [[Server_Scripting_Functions#Element_functions|'''Element functions''']], где и находим функцию [[getElementPosition]]. Щелкнув по названию функции в списке, мы получаем описание функции. Тут же мы можем посмотреть синтаксис, возвращаемое значение и даже пример ее использования. Синтаксис показывает нам, какие аргументы необходимо передать функции.
Чтобы разрешить все поставленные задчаи, нам понадобится задействовать несколько функций. А чтобы найти нужные нам функции, нужно перейти ко [[RU/Server_Scripting_Functions|списку серверных функций]]. Для начала нам понадобится функция, которая получит координаты игрока. Так как все игроки являются элементами, мы сразу выбираем '''Element functions''', где и находим функцию [[getElementPosition]]. Кликнув по имени функции из списка, вы получите ее описание. Там можно увидеть синтаксис, что она возвращает и, как правило, пример использования. Синтаксис сообщает какие аргументы мы можем или должны ей передать.


функция [[getElementPosition]], имеет следующий синтаксис:
Для [[getElementPosition]] синтаксис таков:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
float, float, float getElementPosition ( element theElement )
float, float, float getElementPosition ( element theElement )
</syntaxhighlight>
</syntaxhighlight>


Три ''float'' перед названием функции - это тип возвращаемого значения. В этом случае, подобное означает, что функция возвращает три числа с плавающей точкой. В круглых скобках, вы можете увидеть аргументы, которые необходимо передать функции. В нашем случае имеется только аргумент типа ''element'', содержащий объект, чью позицию мы хотим получить (в нашем примере это игрок).
Три ''float'' перед именем функции и есть типы значений, которые она возвращает. В данном случае это значит, что функция возвращает три числа с плавающей точкой (x, y и z). Внутри круглых скобок указаны аргументы, которые ей необходимо передать. В данном случае это только элемент, чью позицию вы хотите получить, у нас он представлен игроком.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function createVehicleForPlayer(thePlayer, command, vehicleModel)
function createVehicleForPlayer(thePlayer, command, vehicleModel)
-- получить позицию и поместить ее в переменные x,y,z
-- get the position and put it in the x,y,z variables
-- (local обозначает локальный контекст: переменные существуют только в текущей области действия. В данном случае - в пределах текущей функции)
-- (local означает, что переменные существуют только здесь, в этой области, внутри этой функции)
local x,y,z = getElementPosition(thePlayer)
local x,y,z = getElementPosition(thePlayer)
end
end
</syntaxhighlight>
</syntaxhighlight>


Далее мы хотим гарантировать то, что машина не создастся прямо на игроке, поэтому мы добавляем небольшое значение переменной ''x'', что дает на возможность создать машину правее от игрока.
Затем нам надо сделать так, чтобы ТС не спавнилось прямо внутри игрока, поэтому мы прибавим небольшое число к переменной ''x'', что повлечет за собой спавн ТС чуть восточнее самого игрока.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function createVehicleForPlayer(thePlayer, command, vehicleModel)
function createVehicleForPlayer(thePlayer, command, vehicleModel)
local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
local x,y,z = getElementPosition(thePlayer) -- получаем позицию игрока
x = x + 5 -- добавить 5 единиц к позиции по оси x
x = x + 5 -- прибавляем число 5 к позиции по оси x
end
end
</syntaxhighlight>
</syntaxhighlight>


Теперь нам необходима другая функция, а именно функция для создания машины. Мы снова начинаем ее поиск в [[Scripting Functions|списке функций серверного приложения]], в этот раз - так как речь идет о машинах - то ищем функцию в разделе [[Scripting_Functions#Vehicle_functions|'''Vehicle functions''']], в котором мы выбираем  [[createVehicle]]. В синтаксисе этой функции, нам необходимо только возвращаемое значение (которое является единственным), типа ''vehicle'', относящееся к ''element''. Это возвращаемое значение указывает на машину, которая только что создана. Также, вы вероятно обратили внимание на то, что некоторые аргументы заключены в квадратные скобки [ ], которые означают, что этот аргумент функции необязателен.
Теперь нам понадобится другая функция, чтобы непосредственно заспавнить транспортное средство. Мы снова ищем ее в [[RU/Server Scripting Functions|списке серверных функций]], на этот раз, так как мы говорим о транспорте - в разделе '''Vehicle functions''', где выберем [[createVehicle]]. В синтаксисе этой функции указано только одно возвращаемое значение (что встречается наиболее часто) - элемент типа vehicle, представляющий только что созданное ТС. Также мы видим, что часть аргументов заключена в [ ], следовательно, они необязательны.


Теперь у нас имеются все аргументы, необходимые для выполнения команды [[createVehicle]] внутри нашей функции: мы вычислили позицию по переменным ''x,y,z'' и знаем идентификатор модели, которую мы хотим создать с помощью команды ("createvehicle 468") и мы имеем доступ к функции через переменную ''vehicleModel''.
Внутри нашей функции у нас уже есть все аргументы, которые нужны функции [[createVehicle]]: Только что вычисленная позиция в переменных ''x,y,z'' и id модели, который мы получили через команду ("createvehicle 468"), он доступен внутри функции в качестве переменной ''vehicleModel''.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function createVehicleForPlayer(thePlayer, command, vehicleModel)
function createVehicleForPlayer(thePlayer, command, vehicleModel)
local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
local x,y,z = getElementPosition(thePlayer) -- получаем позицию игрока
x = x + 5 -- добавить 5 единиц измерения к координате x позиции игрока
x = x + 5 -- прибавляем число 5 к позиции по оси x
-- создать машину и сохранить возвращенный элемент vehicle в переменной ''createdVehicle''
-- создаем ТС и сохраняем возвращенный элемент типа vehicle в переменной ''createdVehicle''
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
end
end
</syntaxhighlight>
</syntaxhighlight>


Конечно, этот код может быть улучшен многими способами. По крайней мере, нам необходимо добавить проверку на успешное создание машины. На странице [[createVehicle]] мы можем прочитать в разделе '''Returns''' о том, что функция возвращает ''false'' в том случае, если неполучилось создать машину. Поэтому, нам достаточно проверить значение переменной ''createVehicle''.
Этот код, конечно же, можно усовершенствовать различными путями, но как минимум мы добавим проверку на то, было ли ТС успешно создано. Как можно прочитать на странице [[createVehicle]] под '''Returns''', функция возвращает ''false'', если ТС создать не получилось. Стало быть, мы проверяем значение переменной ''createVehicle''.


Теперь у нас имеется полность завершенный сценарий:
Теперь у нас есть готовый скрипт:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function createVehicleForPlayer(thePlayer, command, vehicleModel)
function createVehicleForPlayer(thePlayer, command, vehicleModel)
local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
local x,y,z = getElementPosition(thePlayer) -- получаем позицию игрока
x = x + 5 -- добавить 5 единиц измерения к координате x позиции игрока
x = x + 5 -- прибавляем число 5 к позиции по оси x
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
-- проверка на возврат значения ''false''
-- проверяем, является ли возвращаемое значение ''false''
if (createdVehicle == false) then
if (createdVehicle == false) then
-- если возвращено ''false'', то необходимо вывести сообщение пользователю в окно чата, но только тому игроку, который создавал машину.
-- если да, то выводим сообщение в чат, но только для игрока, который спавнил ТС.
outputChatBox("Failed to create vehicle.",thePlayer)
outputChatBox("Failed to create vehicle.",thePlayer)
end
end
Line 118: Line 156:
</syntaxhighlight>
</syntaxhighlight>


Как вы можете увидеть, в последнем примере кода появилась еще одна функция [[outputChatBox]]. О ней вы можете самостоятельно узнать, посмотрев соответствующую страницу с документацией по этой функции.
Как вы уже, наверное, заметили, вашему взору предстала новая функция - [[outputChatBox]]. Теперь вы самостоятельно можете изучить содержимое ее страницы-документации. Чтобы узнать больше о продвинутом скриптинге, почитайте про [[RU/Map manager|Map Manager]].
 
==Что вы узнали==
Теперь вам уже немного известны файлы ресурсов, обработчики команд и принципы поиска функций в документации, но необходимо знать больше. Следующий раздел проведет краткий обзор по некоторым ресурсам, сопровождая при необходимости изложение материала ссылками на соответствующие страницы.


===Сценарии клиентской и серверной стороны===
==Что вам следует знать==
Вы возможно уже видели эти или похожие термины (сервер/клиент) на этом wiki-сайте. MTA поддерживает не только сценарии, выполняющиеся на сервере и обеспечивающие выполнение команд(похожих на ту, что была описаны выше) и другие возможности, но и также сценарии, выполняющиеся клиентским приложением MTA, которое игроки используют для соединения с игровым сервером. Причиной этому является тот факт, что некоторые возможности MTA обеспечиваются приложением клиентской стороны (например, графический пользовательский интерфейс). Другие возможности MTA работают лучше на стороне сервера или принципиально не могут быть реализованы на клиентской стороне и поэтому выполняются на стороне сервера.
Вы уже кое-что прочитали о ресурсах, обработчиках команд и поиске функций в документации в первом разделе, но многое еще предстоит узнать. Этот раздел проведет довольно краткий обзор о некоторых из этих вещей, по возможности ссылаясь на соответствующие страницы.
===Клиентские и серверные скрипты===
Может быть, вы уже заметили эти или схожие термины (сервер/клиент) где-либо на данной вики, наиболее вероятно, вкупе с функциями. MTA не только поддерживает работающие на сервере скрипты, предоставляет команды (типа как мы писали выше) и другие возможности, но также и скрипты, выполняющиеся на клиенте MTA, который игроки используют для подключения к серверу. Причиной этому служит то, что некоторые предоставляемые MTA функции не могут быть серверными (например, GUI - Graphical User Interface, т.е. графический интерфейс пользователя), другие там просто работают лучше, но другим все же лучше быть серверными или попросту не работать на клиентской стороне.


Многие сценарии, которые вы будете писать (игровые режимы, карты) вероятно будут выполняться на стороне сервера, подобно тому, который был написан выше. Если вам необходимо выполнить что-либо, что нельзя выполнить на стороне сервера, вы вероятно сможете это выполнить на стороне клиента. Например, для сценария клиентской стороны, вы должны создать обычный файл сценария (например, с названием ''client.lua'') и определить его в файле meta.xml, следующим образом:
Большинство сделанных вами скриптов (модов, карт), вероятно, будут серверными, как и та, которую мы написали в первом разделе. Если вы столкнетесь с чем-то, что не может быть реализовано на серверной стороне, возможно, вы сможете реализовать это на клиентской. Для написания клиентского скрипта, создайте обычный файл-скрипт (например, названный ''client.lua'') и укажите его в meta.xml так:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<script src="client.lua" type="client" />
<script src="client.lua" type="client" />
</syntaxhighlight>
</syntaxhighlight>
Атрибут ''type'' по умолчанию имеет значение 'server', поэтому вам необходимо определять его значение для сценариев клиентской стороны. После того, как вы выполнили это, сценарий клиентской стороны будет скачиваться на компьютер игрока при его соединении с сервером. Об этом вы можете также прочитать в статье [[Client side scripts|Сценарии клиентской стороны]].
Атрибут ''type'' по умолчанию установлен на 'server', так что надобность указывать его существует только для клиентских скриптов. После этого, клиентский скрипт будет загружаться на компьютеры игроков при заходе. Подробнее о [[RU/Client side scripts|клиентских скриптах]].


===Более сложные ресурсы===
===Более сложные ресурсы===
Предыдущий раздел кратко показал, как надо добавлять сценарии клиентской стороны в ресурсы, но на самом деле все обстоит немного сложнее. Как упоминалось в самом начале этой страницы, ресурсы могут быть чем угодно. Их цель - определить то, для чего они нужны. Далее приведены наиболее часто используемые ресурсы. Рассмотрим их содержимое, содержимое файла ''meta.xml'' и то, для чего они предназначены:
Предыдущий раздел вкратце изложил, как добавлять в ресурс клиентские скрипты, но возможностей на самом деле намного больше. Как написано в самом начале статьи, ресурсы могут быть чем угодно. Их назначение определяется тем, что они делают. Давайте теоретически вообразим некоторые ресурсы, глядя на их файлы-содержимое, ''meta.xml'' и подумаем, что они могут делать:


====Пример 1: Вспомогательный сценарий====
====Первый пример - Вспомогательный скрипт====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/admin_commands
/admin_commands
Line 150: Line 187:
</syntaxhighlight>
</syntaxhighlight>


* Файл ''commands.lua'' обеспечивает выполнение некоторых команд администратора, например, назначение наказаний провинившимся игрокам, или что-либо другое, что может быть полезным для администрирования сервера
* ''commands.lua'' предоставляет некоторые администраторские команды, такие как бан и заглушение игроков или еще что-нибудь, что может быть доступно для администраторов сервера
* Файл ''client.lua'' обеспечивает графический пользовательский интерфейс для легкого выполнения описанных действий
* ''client.lua'' предоставляет GUI, чтобы возможно было с легкостью выполнять вышеуказанные действия


Этот пример ресурса может быть в состоянии выполнения всё время (даже может запускаться автоматически при начале работы сервера), так как он может использоваться в течении всего игрового процесса и изменять игровой процесс, в случае если администратор решит выполнить какое-либо действие.
Этот пример может выполняться все время (даже автозапускаться со стартом сервера), так как является полезным на протяжении всего игрового процесса и не конфликтует с ним, если администратор, конечно, сам этого не захочет.


====Пример 2: Игровой режим ====
====Второй пример - Мод====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/counterstrike
/counterstrike
Line 170: Line 207:
</syntaxhighlight>
</syntaxhighlight>


* Файл ''counterstrike.lua'' содержит следующие возможности:
* ''counterstrike.lua'' содержит схожие с нижеперечисленными функции:
** Позволяет игрокам выбирать команду, за которую они хотят играть и присоединяться к команде
** Позволить игрокам выбирать свою команду и спавниться
** Обеспечивает игрокам возможность выбора оружия, цели игры и команды (информация подобного характера может также содержаться в файле игровой карты - об этом будет сказано ниже)
** Обеспечить их оружием, целями и инструкциями (возможно, взятыми из игровой карты, см. ниже)
** Определяет правила игры,например, момент наступления конца раунда, какие действия должны произойти после гибели персонажа игрока.
** Определить правила игры, напр., когда кончается раунд, что происходит при смерти игрока
** .. и возможно что-либо ещё
** .. и, может быть, что-то еще
* Файл ''buymenu.lua'' - сценарий клиентской стороны для создания меню покупки оружия.
* ''buymenu.lua'' - клиентский скрипт, создающий меню для покупки оружия


Этот пример может быть отнесен к игровому режиму потому как он не только связан с процессом игры, но и фактически определяет правила игры. Атрибут ''type'' показывает, что этот пример работает в [[Map manager]], хотя и существует другой ресурс, написанный QA Team для управления игровыми режимами и загрузки игровых карт. Его рекомендуется использовать, потому как ваш игровой решим будет основан на принципах, поддерживаемых им.
Этот образец может быть назван модом, так как не только влияет на игровой процесс, но, по сути, и задает его рамки. Атрибут ''type'' говорит о том, что этот пример работает с [[RU/Map manager|Map Manager]], уже другим ресурсом, написанным QA Team для управлениями модами и подгрузки карт. Очень рекомендуется основывать свои моды на предоставляемом им функционале.


Это также означает, что игровой режим вероятно не сможет быть запущен без игровой карты. Игровые режимы должны всегда стремиться настолько использовать общие принципы, насколько это возможно. Далее приведен пример игровой карты.
Это также означает, что мод, возможно, не запустится без карты. Моды всегда должны пользоваться общим функционалом настолько широко, насколько это возможно. Образец карты - в следующем примере.


====Пример 3: Игровая карта====
====Третий пример - Карта====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/cs-airport
/cs-airport
Line 196: Line 233:
</syntaxhighlight>
</syntaxhighlight>


* Файл ''airport.map'' в XML файле, обеспечивает информацию о игровой карте игровому режиму, которая может включать:
* ''airport.map'' - XML-файл, предоставляющий моду информацию о карте, что включает в себя:
** Места, где на карте должны появляться игроки, с каким оружием, какие команды имеются
** Где игроки должны спавниться, с каким оружием, какие имеются команды
** Какие цели имеются
** Какие имеются цели
** Погода, время, ограничение времени
** Погода, время, ограничение по времени
** Возможные машины
** Предоставляемый транспорт
* файл ''airport.lua'' может содержать возможности характерные для конкретной игровой карты, которые в свою очередь могуть включать:
* ''airport.lua'' может содержать присущий данной карте функционал, что включает в себя:
** Реализацию действий, которые могут произойти после открытия двери, ворот и т.п., взрыва чего-либо.
** Открытие каких-либо дверей, подрыв чего-нибудь при определенных условиях
** Создание и перемещение некоторых игровых объектов, или управление объектами, создаваемыми в файле .map
** Создание или передвижение определенных игровых объектов, или управление теми, что были созданы через .map-файл
** .. что-либо ещё, что может относиться к конкретной карте
** .. все что еще угодно, связанное с картами


Как вы можете увидеть, значение атрибута ''type'' изменено на 'map', это говорит [[Map manager]] о том, что этот ресурс является игровой картой, а атрибут ''gamemodes'' говорит о том, к каким игровым режимам относится эта игровая карта. В примере игровая карта относится к игровому режиму, описанному в примере выше.
Как вы уже заметили, атрибут ''type'' поменялся на 'map', сообщая [[RU/Map manager|Map Manager]], что этот ресурс - карта, в то время как атрибут ''gamemodes'' говорит, с какими модами эта карта совместима, в данном случае - это мод из примера выше.
Для ресурса "игровая карта" может быть написан отдельный сценарий. Конечно, это не является необходимым для всех игровых карт, но в то же время открывает создателям игровых карт широкие возможности для создания своих собственных правил игры в игровом режиме, для которого они создают карту.
Сюрпризом может показаться то, что в ресурс-карту также входит и скрипт. Конечно, это совсем не обязательно для карты, но открывает широкий спектр возможностей для их создателей, позволяя создавать собственный мир с правилами мода, на котором он основывается.


Файл ''airport.map'' может иметь следующий вид:
Файл ''airport.map'' может выглядеть примерно так:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<map mode="deathmatch" version="1.0">
<map mode="deathmatch" version="1.0">
Line 226: Line 263:
</syntaxhighlight>
</syntaxhighlight>


Когда игровой режим запущен с игровой картой, mapmanager автоматически запускает ресурсы игровой карты и информация, которую они содержат может быть считана ресурсом игрового режима. При изменении игровой карты, выполнение ресурса текущей игровой карты останавливается и запускается выполнение ресурса следующей игровой карты.
Когда мод запускается с картой, ресурс-карта автоматически запускается mapmanager'ом, и информация, которую он содержит, может быть прочитана ресурсом-модом. При смене карты, текущий ресурс-карта останавливается, а следующий - запускается. Для более детального разъяснения и образцов того, как ресурсы-карты используются основным скриптом, посетите страницу [[RU/Writing Gamemodes]].


===События===
===События===
События являются механизмом MTA сообщать сценариям о том, что произошло. Например, при смерти персонажа игрока, срабатывает событие [[onPlayerWasted]]. В нем выполняются какие-либо действия, которые необходимо выполнить при смерти персонажа игрока, вы можете подготовить что-то подобное для добавления обработчика команды, как показано в [[#Написание_сценария|разделе "Написание сценария"]].
События - способ MTA сообщать скриптам о происходящем. Например, при смерти игрока, срабатывает событие [[onPlayerWasted]]. Чтобы при смерти игрока что-то происходило, вам придется проделать действия, схожие с добавлением обработчика команд, как об этом рассказано в [[#Создание простого скрипта|первом разделе]].


В этом примере выводится сообщение, содержащее имя игрока, персонаж которого погиб:
Этот пример будет выводить сообщение с именем игрока, который умер:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function playerDied(totalAmmo, killer, killerWeapon, bodypart)
function playerDied(totalAmmo, killer, killerWeapon, bodypart)
outputChatBox(getClientName(source).." died!")
outputChatBox(getPlayerName(source).." умер!")
end
end
addEventHandler("onPlayerWasted",getRootElement(),playerDied)
addEventHandler("onPlayerWasted",getRootElement(),playerDied)
</syntaxhighlight>
</syntaxhighlight>


Вместо отображения необходимых параметров, на страницах документации, посвященных событиям, показано какие параметры передаются в функцию-обработчик, подобно тому как сделано в [[#О_обработчиках_команд|обработчике команды]], только с тем отличием, что используется не команда, а событие. Другим немаловажным аспектом является переменная ''source'', которая имеется в обработчике функций. Она не добавляется в список параметров функции, но тем не менее используется. Она принимает различные значения в зависимости от события. Для событий, относящихся к игроку (как в в примере выше) она принимает значение типа ''player'', которое относится к ''элементам'' (''element'').
Вместо того, чтобы сначала вывести список требуемых аргументов, страница документации для событий отображает, какие параметры передаются функции-обработчику, так же, как делает [[#Про обработчики команд|обработчик команд]], просто это разнится от события к событию. Другим важным моментом является существующая в функциях-обработчиках переменная ''source''. Ее необязательно добавлять в список параметров функции, но она, тем не менее, существует. Ее значение меняется от события к событию, для событий, связанных с игроком (как в образце выше), это - элемент типа player. В качестве другого образца служит базовый скрипт для респавна игрока в первом разделе, на его примере можно понять, как используется ''source''.
 
==Заключение==
Теперь вы знаете основные аспекты, использующиеся при написании сценариев в MTA, а также ознакомились с частью документации. [[RU/Main Page|Главная страница]] содержит ссылки на более подробную информацию, учебники и справочники, которые при желании позволят вам более глубже узнать многие вещи о MTA.


==Что делать теперь==
Теперь вы знакомы с наиболее базовыми аспектами скриптинга в MTA, а также чуть-чуть с документацией. [[Главная страница]] обеспечит вас ссылками на множество различной информации, руководства и указания, которые позволят глубже взглянуть на интересующие вас темы.
{{note|Теперь мы рекомендуем вам прочитать руководство по [[RU/Debugging|отладке]]. Умение хорошо отлаживать - абсолютная необходимость при написании скриптов. Мы также рекомендуем вам пользоваться [[RU/Predefined variables list|списком предписанных переменных]], который поможет вам в выполнении определенных задач, а писать скрипты станет намного легче и быстрее.}}
'''Также смотрите:'''
* [[Advanced Topics|Продвинутый функционал]]
[[en:Scripting Introduction]]
[[en:Scripting Introduction]]
[[es:Introducción a la Programación]]
[[it:Introduzione allo scripting]]
[[it:Introduzione allo scripting]]
[[pt-br:Introdução ao Scripting]]
[[nl:Scripting_introductie]]

Latest revision as of 17:12, 19 May 2019

Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip-архив, содержащий набор файлов, а также meta-файл, который описывает серверу как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, при этом несколько ресурсов могут быть запущены одновременно.

Все, связанное со скриптингом, находится в ресурсах. Назначение ресурса и определяет, является ли он модом, картой или чем-либо еще. MTA поставляется с ресурсами, которые вы можете выборочно использовать в своих модах, например, maplimits, позволяющий удерживать игроков в рамках указанных границ карты, или deathpickups, создающий пикапы с оружием.

[[{{{image}}}|link=|]] 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, а также чуть-чуть с документацией. Главная страница обеспечит вас ссылками на множество различной информации, руководства и указания, которые позволят глубже взглянуть на интересующие вас темы.

[[{{{image}}}|link=|]] Note: Теперь мы рекомендуем вам прочитать руководство по отладке. Умение хорошо отлаживать - абсолютная необходимость при написании скриптов. Мы также рекомендуем вам пользоваться списком предписанных переменных, который поможет вам в выполнении определенных задач, а писать скрипты станет намного легче и быстрее.

Также смотрите: