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

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
mNo edit summary
(Полный пересмотр перевода аналогичной статьи с англ. языка)
Line 1: Line 1:
Ресурсы - ключевая часть MTA. Ресурс - папка или zip архив, который содержит набор файлов, также мета файл, который рассказывает серверу как нужно загружать ресурс и из каких файлов он состоит. Это как программа в операционной системе - может быть запущен и остановлен, а также могут работать несколько ресурсов одновременно. Всё содержымое скрипта находится в ресурсе
Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip архив, содержащий набор файлов, а также мета файл, описывающий серверу, как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, а также могут быть запущены несколько ресурсов одновременно. Всё, что выполняется с помощью сценариев находится в ресурсах, что реализовано в сценариях: игровые режимы, игровые карты или что-либо ещё - все это ресурсы.
 
==Создание простого сценария==
Для начала давайте сделаем так, чтобы по команде игрока "createvehicle" рядом с игроком создавалась машина.


==Создаем простейший скрипт==
Для начала давайте сделаем команду "createvehicle" которая будет создавать машину рядом с игроком.
===Подготовка===
===Подготовка===
Как написано выше, скрипт содержится в папке или архиве, делаем папку с названием "createvehicle". Имя папки должно соответствовать имени скрипта, это используется для запуска или остановки скрипта.
Как описывалось выше, ресурс является папкой или zip архивом, поэтому для начала мы должны создать папку. Название папки является названием ресурса. Это название используется для запуска или прекращения выполнения ресурса и для обращения к ресурсу в сценариях. В нашем примере, папку необходимо назвать ''commands''.  
 
Каждому скрипту нужен "meta.xml" файл. В этом файле хранятся данные о авторе скрипта, описание и путь к скрипту. В нашем случае мы будем делать скрипт который будет делать машину возле игрока.


Каждому ресурсу необходим файл ''meta.xml''. В нашем случае, мы хотим создать сценарий, который обеспечит пользователю выполнение нескольких простых команд, поэтому нам необходимо сообщить серверу о необходимости загрузки файла сценария, в нашем случае таким файлом сценария пусть будет ''script.lua''.
Содержимое файла ''meta.xml'':
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<meta>
<meta>
Line 15: Line 16:
</syntaxhighlight>
</syntaxhighlight>


"script.lua" - это имя файла самого скрипта в той же самой директории что и "meta.xml" (ОБЯЗАТЕЛЬНО!)
Теперь нам необходимо создать файл ''script.lua'', о котором упоминалось выше, в той же самой директории, где расположен файл ''meta.xml''. В результате содержимое папки ''commands'' должно быть таким:
Сейчас нам надо создать "script.lua" файл, после чего у нас в папке будут два файла:


<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/createvehicle/meta.xml
/commands/meta.xml
/createvehicle/script.lua
/commands/script.lua
</syntaxhighlight>
</syntaxhighlight>


===Пишем скрипт===
===Написание сценария===
Давайте начнем с содержимого файла ''script.lua''. Как было написано выше, мы хотим сделать команду, которая будет создавать машину рядом с игроком. Firstly we need to create a function we want to call and a command handler that creates the command the player will be able to enter in the console.
Начнем с содержимого файла ''script.lua''. Как описывалось выше, нам необходимо обеспечить команду, которая будет создавать машину рядом с игроком. Для начала нам необходимо создать функцию, которую мы будем вызывать, и обработчик команды, который позволит игроку вводить и выполнять команду в окне консоли.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
-- create the function the command handler calls, with the arguments: thePlayer, command, vehicle
-- создание функции, вызываемой обработчиком команды, с аргументами: thePlayer, command, vehicle
function createVehicleForPlayer(thePlayer, command, vehicle)
function createVehicleForPlayer(thePlayer, command, vehicle)
   -- create a vehicle and stuff
   -- код сценария для создания машины
end
end


-- create a command handler
-- создание обработчика команды
addCommandHandler("createvehicle", createVehicleForPlayer)
addCommandHandler("createvehicle", createVehicleForPlayer)
</syntaxhighlight>
</syntaxhighlight>
''Note: Function names are clickable in code examples on the wiki and linked to the functions' documentation.''
''Обратите внимание: Имена функций в коде примеров являются ссылками на wiki-статьи, описывающие функции в документации.''


====About command handlers====
====О обработчиках команд====
The first argument of [[addCommandHandler]] is the name of the command the player will be able to enter, the second argument is the function this will call, in this case ''createVehicleForPlayer''.
Первым аргументом [[addCommandHandler]] название команды, введенной игроком, второй аргумент - функция, которая будет вызвана, в нашем случае это ''createVehicleForPlayer''.


If you have already experience in scripting, you will know that you call a function like this:
Если вы уже знакомы с написанием сценариев, то вам наверняка приходилось вызывать функции следующего вида:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
functionName(argument1, argument2, argument3, ..)
functionName(argument1, argument2, argument3, ..)
</syntaxhighlight>
</syntaxhighlight>


We called the [[addCommandHandler]] function this way already and since ''createVehicleForPlayer'' is a function too, it can be called that way as well. But we are using a command handler for that, which calls it in a similiar manner, internally.
Таким способом мы вызываем функцию [[addCommandHandler]], а затем функцию ''createVehicleForPlayer''. Она, конечно же, может быть вызвана этим же способом отдельно. Но для нее мы используем обработчик команды, который вызывает ее в пожожей манере, но только внутри.


For example: Someone types "createvehicle 468" ingame in the console to spawn a Sanchez, the command handler calls the createVehicleForPlayer function, as '''if''' we would have this line of code in the script:
Например: Какой-нибудь игрок в процессе игры введет в окно консоли команду "createvehicle 468" для создания машины Sanchez, обработчик команды вызовет функцию createVehicleForPlayer , так же, как '''если бы''' у нас в коде сценария была строка:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
createVehiceForPlayer(thePlayer,"createvehicle","468") -- thePlayer is the player element of the player who entered the command
createVehiceForPlayer(thePlayer,"createvehicle","468") -- thePlayer это игрок, который ввел команду
</syntaxhighlight>
</syntaxhighlight>
As we can see, it provides several parameters: the player who called the command, the command he entered and whatever text he had after that, in this case "468" as vehicle id for the Sanchez. The first two parameters are the same with all command handlers, which you can read on the [[addEventHandler]] page. For this fact, you always have to define at least those two parameters to use any after that (for example to process text that was entered after the command, like in our example the vehicle model id).
Эта функция имеет несколько параметров: параметр, отвечающий за игрока, который ввел команду, параметр, имеющий в качестве значения введенную команду и параметр, содержащий текст, который следовал после команды, в нашем случае это "468" - идентификатор машины Sanchez. Первые два параметра такие же, как и у остальных обработчиков команд, о которых вы можете прочитать информацию на странице [[addEventHandler]]. Поэтому, вы всегда должны определить, по крайней мере, эти два параметра для использования чего-либо после них (например, для обработки текста, введенного после команды, как в нашем примере - идентификатора модели машины).


''Note: You have to add the command handler AFTER you defined the handler function, else it can't find it. The order of execution matters.''
''Обратите внимание: Вы можете добавить обработчик команды только ПОСЛЕ того, как вы определили функцию обработчика, иначе она не будет найдена. Порядок размещения функций имеет значение.''


====Writing the function====
====Написание функции====
In order to fill the function we created, we need to think about what we have to do:
Для того, чтобы написать код созданной функции, нам необходимо продумать детали того, что мы хотим сделать:
* Get the players position, so we know where to spawn the vehicle (we want it to appear right beside the player)
* Получить позицию игроков для того, чтобы знать куда поместить новую машину (допустим, что мы хотим, чтобы она появилась справа от игрока)
* Calculate the position we want to spawn the vehicle at (we don't want it to appear in the player)
* Вычислить позицию того места, куда необходимо поместить машину (это необходимо для того, чтобы она не появилась на месте игрока)
* Spawn the vehicle
* Создать машину
* Check if it has been spawned successfully, or output a message
* Проверить успешность создания машины или вывести сообщение


In order to achieve our goals, we have to use several functions. To find function we need to use, we should visit the [[Scripting Functions|Server Functions List]]. First we need a function to get the players position. Since players are Elements, we first jump to the '''Element functions''' where we find the [[getElementPosition]] function. By clicking on the function name in the list, you get to the function description. There we can see the syntax, what it returns and usually an example. The syntax shows us what arguments we can or have to submit.
Для того, чтобы выполнить поставленные задачи, мы должны использовать несколько функций. Чтобы найти подходящую для решения задачи функцию, мы должны посмотреть страницу [[Scripting Functions|Список функций серверного приложения]]. Сначала нам необходима функция для получения позиции игроков. Так как игроки относятся к [[RU/Element|'''элементам''']] (основным классам, описывающим игровые сущности или, проще говоря, игровые объекты), то мы сначала переходим к странице [[Server_Scripting_Functions#Element_functions|'''Element functions''']], где и находим функцию [[getElementPosition]]. Щелкнув по названию функции в списке, мы получаем описание функции. Тут же мы можем посмотреть синтаксис, возвращаемое значение и даже пример ее использования. Синтаксис показывает нам, какие аргументы необходимо передать функции.


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


The three ''float'' in front of the function name are the return type. In this case it means the function returns three floating point numbers. Within the parentheses, you can see what arguments you have to submit. In this case only the element whose position you want to get, which is the player in our example.
Три ''float'' перед названием функции - это тип возвращаемого значения. В этом случае, подобное означает, что функция возвращает три числа с плавающей точкой. В круглых скобках, вы можете увидеть аргументы, которые необходимо передать функции. В нашем случае имеется только аргумент типа ''element'', содержащий объект, чью позицию мы хотим получить (в нашем примере это игрок).


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


Next we want to ensure that the vehicle won't spawn directly in the player, so we add a few units to the ''x'' variable, which will make it spawn east from the player.
Далее мы хотим гарантировать то, что машина не создастся прямо на игроке, поэтому мы добавляем небольшое значение переменной ''x'', что дает на возможность создать машину правее от игрока.


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


Now we need another function, one to spawn a vehicle. We once again search for it on the [[Scripting Functions|Server Functions List]], this time - since we are talking about vehicles - in the '''Vehicle functions''' section, where we will choose [[createVehicle]]. In this functions' syntax, we only have one return type (which is more common), a vehicle element that points to the vehicle we just created. Also, we see that some arguments are enclosed within [ ] which means that those are optional.
Теперь нам необходима другая функция, а именно функция для создания машины. Мы снова начинаем ее поиск в [[Scripting Functions|списке функций серверного приложения]], в этот раз - так как речь идет о машинах - то ищем функцию в разделе [[Scripting_Functions#Vehicle_functions|'''Vehicle functions''']], в котором мы выбираем  [[createVehicle]]. В синтаксисе этой функции, нам необходимо только возвращаемое значение (которое является единственным), типа ''vehicle'', относящееся к ''element''. Это возвращаемое значение указывает на машину, которая только что создана. Также, вы вероятно обратили внимание на то, что некоторые аргументы заключены в квадратные скобки [ ], которые означают, что этот аргумент функции необязателен.


We already have all arguments we need for [[createVehicle]] in our function: The position we just calculated in the ''x,y,z'' variables and the model id that we provided through the command ("createvehicle 468") and can access in the function as ''vehicleModel'' variable.
Теперь у нас имеются все аргументы, необходимые для выполнения команды [[createVehicle]] внутри нашей функции: мы вычислили позицию по переменным ''x,y,z'' и знаем идентификатор модели, которую мы хотим создать с помощью команды ("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) -- get the position of the player
local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
x = x + 5 -- add 5 units to the x position
x = x + 5 -- добавить 5 единиц измерения к координате x позиции игрока
-- create the vehicle and store the returned vehicle element in the ''createdVehicle'' variable
-- создать машину и сохранить возвращенный элемент vehicle в переменной ''createdVehicle''
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
end
end
</syntaxhighlight>
</syntaxhighlight>


Of course this code can be improved in many ways, but at least we want to add a check whether the vehicle was created successfully or not. As we can read on the [[createVehicle]] page under '''Returns''', the function returns ''false'' when it was unable to create the vehicle. Thus, we check the value of the ''createVehicle'' variable.
Конечно, этот код может быть улучшен многими способами. По крайней мере, нам необходимо добавить проверку на успешное создание машины. На странице [[createVehicle]] мы можем прочитать в разделе '''Returns''' о том, что функция возвращает ''false'' в том случае, если неполучилось создать машину. Поэтому, нам достаточно проверить значение переменной ''createVehicle''.


Now we have our complete script:
Теперь у нас имеется полность завершенный сценарий:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function createVehicleForPlayer(thePlayer, command, vehicleModel)
function createVehicleForPlayer(thePlayer, command, vehicleModel)
local x,y,z = getElementPosition(thePlayer) -- get the position of the player
local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
x = x + 5 -- add 5 units to the x position
x = x + 5 -- добавить 5 единиц измерения к координате x позиции игрока
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
-- check if the return value was ''false''
-- проверка на возврат значения ''false''
if (createdVehicle == false) then
if (createdVehicle == false) then
-- if so, output a message to the chatbox, but only to this player.
-- если возвращено ''false'', то необходимо вывести сообщение пользователю в окно чата, но только тому игроку, который создавал машину.
outputChatBox("Failed to create vehicle.",thePlayer)
outputChatBox("Failed to create vehicle.",thePlayer)
end
end
Line 118: Line 118:
</syntaxhighlight>
</syntaxhighlight>


As you can see, we introduced another function with [[outputChatBox]]. By now, you should be able to explore the function's documentation page yourself.
Как вы можете увидеть, в последнем примере кода появилась еще одна функция [[outputChatBox]]. О ней вы можете самостоятельно узнать, посмотрев соответствующую страницу с документацией по этой функции.
 
==Что вы узнали==
Теперь вам уже немного известны файлы ресурсов, обработчики команд и принципы поиска функций в документации, но необходимо знать больше. Следующий раздел проведет краткий обзор по некоторым ресурсам, сопровождая при необходимости изложение материала ссылками на соответствующие страницы.


==What you need to know==
===Сценарии клиентской и серверной стороны===
You already read some things about resources, command handlers and finding functions in the documentation in the first paragraph, but there is much more to learn. This section will give you a rather short overview over some of these things, while linking to related pages if possible.
Вы возможно уже видели эти или похожие термины (сервер/клиент) на этом wiki-сайте. MTA поддерживает не только сценарии, выполняющиеся на сервере и обеспечивающие выполнение команд(похожих на ту, что была описаны выше) и другие возможности, но и также сценарии, выполняющиеся клиентским приложением MTA, которое игроки используют для соединения с игровым сервером. Причиной этому является тот факт, что некоторые возможности MTA обеспечиваются приложением клиентской стороны (например, графический пользовательский интерфейс). Другие возможности MTA работают лучше на стороне сервера или принципиально не могут быть реализованы на клиентской стороне и поэтому выполняются на стороне сервера.
===Clientside and Serverside scripts===
You may have already noticed these or similiar terms (Server/Client) somwhere on this wiki, mostly in conjunction with functions. MTA not only supports scripts that run on the server and provide commands (like the one we wrote above) or other features, but also scripts that run on the MTA client the players use to connect to the server. The reason for this is, that some features MTA provides have to be clientside (like a GUI - Graphical User Interface), others should be because they work better and still others are better off to be serverside or just don't work clientside.


Most scripts you will make (gamemodes, maps) will probably be serverside, like the one we wrote in the first section. If you run into something that can't be solved serverside, you will probably have to make it clientside. For a clientside script for example, you would create a ordinary script file (for example called ''client.lua'') and specify it in the meta.xml, like this:
Многие сценарии, которые вы будете писать (игровые режимы, карты) вероятно будут выполняться на стороне сервера, подобно тому, который был написан выше. Если вам необходимо выполнить что-либо, что нельзя выполнить на стороне сервера, вы вероятно сможете это выполнить на стороне клиента. Например, для сценария клиентской стороны, вы должны создать обычный файл сценария (например, с названием ''client.lua'') и определить его в файле meta.xml, следующим образом:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<script src="client.lua" type="client" />
<script src="client.lua" type="client" />
</syntaxhighlight>
</syntaxhighlight>
The ''type'' attribute defaults to 'server', so you only need to specify it for clientside scripts. When you do this, the clientside script will be downloaded to the player's computer once he connects to the server. Read more about [[Client side scripts]].
Атрибут ''type'' по умолчанию имеет значение 'server', поэтому вам необходимо определять его значение для сценариев клиентской стороны. После того, как вы выполнили это, сценарий клиентской стороны будет скачиваться на компьютер игрока при его соединении с сервером. Об этом вы можете также прочитать в статье [[Client side scripts|Сценарии клиентской стороны]].


===More complex resources===
===Более сложные ресурсы===
The previous section showed briefly how to add clientside scripts to the resource, but there is also much more possible. As mentioned at the very top of this page, resources can be pretty much everything. Their purpose is defined by what they do. Let's have some theoratical resources, by looking at the files it contains, the ''meta.xml'' and what they might do:
Предыдущий раздел кратко показал, как надо добавлять сценарии клиентской стороны в ресурсы, но на самом деле все обстоит немного сложнее. Как упоминалось в самом начале этой страницы, ресурсы могут быть чем угодно. Их цель - определить то, для чего они нужны. Далее приведены наиболее часто используемые ресурсы. Рассмотрим их содержимое, содержимое файла ''meta.xml'' и то, для чего они предназначены:


====First example - A utility script====
====Пример 1: Вспомогательный сценарий====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/admin_commands
/admin_commands
Line 149: Line 150:
</syntaxhighlight>
</syntaxhighlight>


* The ''commands.lua'' provides some admin commands, like banning a player, muting or something else that can be used to admin the server
* Файл ''commands.lua'' обеспечивает выполнение некоторых команд администратора, например, назначение наказаний провинившимся игрокам, или что-либо другое, что может быть полезным для администрирования сервера
* The ''client.lua'' provides a GUI to be able to perform the mentioned actions easily
* Файл ''client.lua'' обеспечивает графический пользовательский интерфейс для легкого выполнения описанных действий


This example might be running all the time (maybe even auto-started when the server starts) as it's useful during the whole gaming experience and also wont interfere with the gameplay, unless an admin decides to take some action of course.
Этот пример ресурса может быть в состоянии выполнения всё время (даже может запускаться автоматически при начале работы сервера), так как он может использоваться в течении всего игрового процесса и изменять игровой процесс, в случае если администратор решит выполнить какое-либо действие.


====Second example - A gamemode====
====Пример 2: Игровой режим ====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/counterstrike
/counterstrike
Line 169: Line 170:
</syntaxhighlight>
</syntaxhighlight>


* The ''counterstrike.lua'' contains similiar to the following features:
* Файл ''counterstrike.lua'' содержит следующие возможности:
** Let players choose their team and spawn them
** Позволяет игрокам выбирать команду, за которую они хотят играть и присоединяться к команде
** Provide them with weapons, targets and instructions (maybe read from a Map, see below)
** Обеспечивает игрокам возможность выбора оружия, цели игры и команды (информация подобного характера может также содержаться в файле игровой карты - об этом будет сказано ниже)
** Define the game's rules, e.g. when does the round end, what happens when a player dies
** Определяет правила игры,например, момент наступления конца раунда, какие действия должны произойти после гибели персонажа игрока.
** .. and maybe some more
** .. и возможно что-либо ещё
* The ''buymenu.lua'' is a clientside script and creates a menu to buy weapons
* Файл ''buymenu.lua'' - сценарий клиентской стороны для создания меню покупки оружия.


This example can be called a gamemode, since it not only intereferes with the gameplay, but actually defines the rules of it. The ''type'' attribute indicates that this example works with the [[Map manager]], yet another resource that was written by the QA Team to manage gamemodes and map loading. It is highly recommended that you base your gamemodes on the techniques it provides.
Этот пример может быть отнесен к игровому режиму потому как он не только связан с процессом игры, но и фактически определяет правила игры. Атрибут ''type'' показывает, что этот пример работает в [[Map manager]], хотя и существует другой ресурс, написанный QA Team для управления игровыми режимами и загрузки игровых карт. Его рекомендуется использовать, потому как ваш игровой решим будет основан на принципах, поддерживаемых им.


This also means that the gamemode probably won't run without a map. Gamemodes should always be as generic as possible. An example for a map is stated in the next example.
Это также означает, что игровой режим вероятно не сможет быть запущен без игровой карты. Игровые режимы должны всегда стремиться настолько использовать общие принципы, насколько это возможно. Далее приведен пример игровой карты.


====Third example - A Map====
====Пример 3: Игровая карта====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/cs-airport
/cs-airport
Line 195: Line 196:
</syntaxhighlight>
</syntaxhighlight>


* The ''airport.map'' in a XML file that provides information about the map to the gamemode, these may include:
* Файл ''airport.map'' в XML файле, обеспечивает информацию о игровой карте игровому режиму, которая может включать:
** Where the players should spawn, with what weapons, what teams there are
** Места, где на карте должны появляться игроки, с каким оружием, какие команды имеются
** What the targets are
** Какие цели имеются
** Weather, World Time, Timelimit
** Погода, время, ограничение времени
** Provide vehicles
** Возможные машины
* The ''airport.lua'' might contain map-specific features, that may include:
* файл ''airport.lua'' может содержать возможности характерные для конкретной игровой карты, которые в свою очередь могуть включать:
** Opening some door/make something explode when something specific happens
** Реализацию действий, которые могут произойти после открытия двери, ворот и т.п., взрыва чего-либо.
** Create or move some custom objects, or manipulate objects that are created through the .map file
** Создание и перемещение некоторых игровых объектов, или управление объектами, создаваемыми в файле .map
** .. anything else map-specific you can think of
** .. что-либо ещё, что может относиться к конкретной карте


As you can see, the ''type'' attribute changed to 'map', telling the [[Map manager]] that this resource is a map, while the ''gamemodes'' attribute tells it for which gamemodes this map is valid, in this case the gamemode from the above example.
Как вы можете увидеть, значение атрибута ''type'' изменено на 'map', это говорит [[Map manager]]о том, что этот ресурс является игровой картой, а атрибут ''gamemodes'' говорит о том, к каким игровым режимам относится эта игровая карта. В примере игровая карта относится к игровому режиму, описанному в примере выше.
What may come as a surprise is that there is also a script in the Map resource. Of course this is not necessarily needed in a map, but opens a wide range of possibilities for map makers to create their own world within the rules of the gamemode they create it for.
Для ресурса "игровая карта" может быть написан отдельный сценарий. Конечно, это не является необходимым для всех игровых карт, но в то же время открывает создателям игровых карт широкие возможности для создания своих собственных правил игры в игровом режиме, для которого они создают карту.


The ''airport.map'' file might look similiar to this:
Файл ''airport.map'' может иметь следующий вид:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<map mode="deathmatch" version="1.0">
<map mode="deathmatch" version="1.0">
Line 225: Line 226:
</syntaxhighlight>
</syntaxhighlight>


When a gamemode is started with a map, the map resources is automatically started by the mapmanager and the information it contains can be read by the gamemode resource. When the map changes, the current map resource is stopped and the next map resource is started.
Когда игровой режим запущен с игровой картой, mapmanager автоматически запускает ресурсы игровой карты и информация, которую они содержат может быть считана ресурсом игрового режима. При изменении игровой карты, выполнение ресурса текущей игровой карты останавливается и запускается выполнение ресурса следующей игровой карты.


===Events===
===События===
Events are the way MTA tells scripts about things that happen. For example when a player dies, the [[onPlayerWasted]] event is triggered. In order to perform any actions when a player dies, you have to prepare yourself similiar to adding a command handler, as shown in [[#Writing_the_script|the first chapter]].
События являются механизмом MTA сообщать сценариям о том, что произошло. Например, при смерти персонажа игрока, срабатывает событие [[onPlayerWasted]]. В нем выполняются какие-либо действия, которые необходимо выполнить при смерти персонажа игрока, вы можете подготовить что-то подобное для добавления обработчика команды, как показано в [[#Написание_сценария|разделе "Написание сценария"]].


This example will output a message with the name of the player who died:
В этом примере выводится сообщение, содержащее имя игрока, персонаж которого погиб:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function playerDied(totalAmmo, killer, killerWeapon, bodypart)
function playerDied(totalAmmo, killer, killerWeapon, bodypart)
Line 238: Line 239:
</syntaxhighlight>
</syntaxhighlight>


Instead of showing what arguments are needed, the documentation page for Events shows what parameters are passed to the handler function, similiar to the way a [[#About_command_handlers|command handler]] does, just that it is different from event to event. Another important point is the ''source'' variable, that exists in handler functions. It doesn't have to be added to the parameter list of the function, but it still exists. It has a different value from event to event, for player events (as in the example above) it is the player element.
Вместо отображения необходимых параметров, на страницах документации, посвященных событиям, показано какие параметры передаются в функцию-обработчик, подобно тому как сделано в [[#О_обработчиках_команд|обработчике команды]], только с тем отличием, что используется не команда, а событие. Другим немаловажным аспектом является переменная ''source'', которая имеется в обработчике функций. Она не добавляется в список параметров функции, но тем не менее используется. Она принимает различные значения в зависимости от события. Для событий, относящихся к игроку (как в в примере выше) она принимает значение типа ''player'', которое относится к ''элементам'' (''element'').


==Where to go from here==
==Заключение==
You should now be familiar with the most basic aspects of MTA scripting and also a bit with the documentation. The [[Main Page]] provides you with links to more information, Tutorials and References that allow a deeper look into the topics you desire to learn about.
Теперь вы знаете основные аспекты, использующиеся при написании сценариев в MTA, а также ознакомились с частью документации. [[RU/Main Page|Главная страница]] содержит ссылки на более подробную информацию, учебники и справочники, которые при желании позволят вам более глубже узнать многие вещи о MTA.


[[en:Scripting Introduction]]
[[en:Scripting Introduction]]
[[it:Introduzione allo scripting]]
[[it:Introduzione allo scripting]]

Revision as of 23:35, 8 February 2008

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

Создание простого сценария

Для начала давайте сделаем так, чтобы по команде игрока "createvehicle" рядом с игроком создавалась машина.

Подготовка

Как описывалось выше, ресурс является папкой или zip архивом, поэтому для начала мы должны создать папку. Название папки является названием ресурса. Это название используется для запуска или прекращения выполнения ресурса и для обращения к ресурсу в сценариях. В нашем примере, папку необходимо назвать commands.

Каждому ресурсу необходим файл meta.xml. В нашем случае, мы хотим создать сценарий, который обеспечит пользователю выполнение нескольких простых команд, поэтому нам необходимо сообщить серверу о необходимости загрузки файла сценария, в нашем случае таким файлом сценария пусть будет script.lua. Содержимое файла meta.xml:

<meta>
  <info author="YourName" description="A few simple commands" />
  <script src="script.lua" />
 </meta>

Теперь нам необходимо создать файл script.lua, о котором упоминалось выше, в той же самой директории, где расположен файл meta.xml. В результате содержимое папки commands должно быть таким:

/commands/meta.xml
/commands/script.lua

Написание сценария

Начнем с содержимого файла script.lua. Как описывалось выше, нам необходимо обеспечить команду, которая будет создавать машину рядом с игроком. Для начала нам необходимо создать функцию, которую мы будем вызывать, и обработчик команды, который позволит игроку вводить и выполнять команду в окне консоли.

-- создание функции, вызываемой обработчиком команды, с аргументами: thePlayer, command, vehicle
function createVehicleForPlayer(thePlayer, command, vehicle)
   -- код сценария для создания машины
end

-- создание обработчика команды
addCommandHandler("createvehicle", createVehicleForPlayer)

Обратите внимание: Имена функций в коде примеров являются ссылками на wiki-статьи, описывающие функции в документации.

О обработчиках команд

Первым аргументом addCommandHandler название команды, введенной игроком, второй аргумент - функция, которая будет вызвана, в нашем случае это createVehicleForPlayer.

Если вы уже знакомы с написанием сценариев, то вам наверняка приходилось вызывать функции следующего вида:

functionName(argument1, argument2, argument3, ..)

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

Например: Какой-нибудь игрок в процессе игры введет в окно консоли команду "createvehicle 468" для создания машины Sanchez, обработчик команды вызовет функцию createVehicleForPlayer , так же, как если бы у нас в коде сценария была строка:

createVehiceForPlayer(thePlayer,"createvehicle","468") -- thePlayer это игрок, который ввел команду

Эта функция имеет несколько параметров: параметр, отвечающий за игрока, который ввел команду, параметр, имеющий в качестве значения введенную команду и параметр, содержащий текст, который следовал после команды, в нашем случае это "468" - идентификатор машины Sanchez. Первые два параметра такие же, как и у остальных обработчиков команд, о которых вы можете прочитать информацию на странице addEventHandler. Поэтому, вы всегда должны определить, по крайней мере, эти два параметра для использования чего-либо после них (например, для обработки текста, введенного после команды, как в нашем примере - идентификатора модели машины).

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

Написание функции

Для того, чтобы написать код созданной функции, нам необходимо продумать детали того, что мы хотим сделать:

  • Получить позицию игроков для того, чтобы знать куда поместить новую машину (допустим, что мы хотим, чтобы она появилась справа от игрока)
  • Вычислить позицию того места, куда необходимо поместить машину (это необходимо для того, чтобы она не появилась на месте игрока)
  • Создать машину
  • Проверить успешность создания машины или вывести сообщение

Для того, чтобы выполнить поставленные задачи, мы должны использовать несколько функций. Чтобы найти подходящую для решения задачи функцию, мы должны посмотреть страницу Список функций серверного приложения. Сначала нам необходима функция для получения позиции игроков. Так как игроки относятся к элементам (основным классам, описывающим игровые сущности или, проще говоря, игровые объекты), то мы сначала переходим к странице Element functions, где и находим функцию getElementPosition. Щелкнув по названию функции в списке, мы получаем описание функции. Тут же мы можем посмотреть синтаксис, возвращаемое значение и даже пример ее использования. Синтаксис показывает нам, какие аргументы необходимо передать функции.

функция getElementPosition, имеет следующий синтаксис:

float, float, float getElementPosition ( element theElement )

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

function createVehicleForPlayer(thePlayer, command, vehicleModel)
	-- получить позицию и поместить ее в переменные x,y,z
	-- (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, относящееся к element. Это возвращаемое значение указывает на машину, которая только что создана. Также, вы вероятно обратили внимание на то, что некоторые аргументы заключены в квадратные скобки [ ], которые означают, что этот аргумент функции необязателен.

Теперь у нас имеются все аргументы, необходимые для выполнения команды createVehicle внутри нашей функции: мы вычислили позицию по переменным x,y,z и знаем идентификатор модели, которую мы хотим создать с помощью команды ("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
		-- если возвращено ''false'', то необходимо вывести сообщение пользователю в окно чата, но только тому игроку, который создавал машину.
		outputChatBox("Failed to create vehicle.",thePlayer)
	end
end
addCommandHandler("createvehicle", createVehicleForPlayer)

Как вы можете увидеть, в последнем примере кода появилась еще одна функция outputChatBox. О ней вы можете самостоятельно узнать, посмотрев соответствующую страницу с документацией по этой функции.

Что вы узнали

Теперь вам уже немного известны файлы ресурсов, обработчики команд и принципы поиска функций в документации, но необходимо знать больше. Следующий раздел проведет краткий обзор по некоторым ресурсам, сопровождая при необходимости изложение материала ссылками на соответствующие страницы.

Сценарии клиентской и серверной стороны

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

Многие сценарии, которые вы будете писать (игровые режимы, карты) вероятно будут выполняться на стороне сервера, подобно тому, который был написан выше. Если вам необходимо выполнить что-либо, что нельзя выполнить на стороне сервера, вы вероятно сможете это выполнить на стороне клиента. Например, для сценария клиентской стороны, вы должны создать обычный файл сценария (например, с названием client.lua) и определить его в файле meta.xml, следующим образом:

<script src="client.lua" type="client" />

Атрибут type по умолчанию имеет значение 'server', поэтому вам необходимо определять его значение для сценариев клиентской стороны. После того, как вы выполнили это, сценарий клиентской стороны будет скачиваться на компьютер игрока при его соединении с сервером. Об этом вы можете также прочитать в статье Сценарии клиентской стороны.

Более сложные ресурсы

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

Пример 1: Вспомогательный сценарий

/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 обеспечивает графический пользовательский интерфейс для легкого выполнения описанных действий

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

Пример 2: Игровой режим

/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 для управления игровыми режимами и загрузки игровых карт. Его рекомендуется использовать, потому как ваш игровой решим будет основан на принципах, поддерживаемых им.

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

Пример 3: Игровая карта

/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 автоматически запускает ресурсы игровой карты и информация, которую они содержат может быть считана ресурсом игрового режима. При изменении игровой карты, выполнение ресурса текущей игровой карты останавливается и запускается выполнение ресурса следующей игровой карты.

События

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

В этом примере выводится сообщение, содержащее имя игрока, персонаж которого погиб:

function playerDied(totalAmmo, killer, killerWeapon, bodypart)
	outputChatBox(getClientName(source).." died!")
end
addEventHandler("onPlayerWasted",getRootElement(),playerDied)

Вместо отображения необходимых параметров, на страницах документации, посвященных событиям, показано какие параметры передаются в функцию-обработчик, подобно тому как сделано в обработчике команды, только с тем отличием, что используется не команда, а событие. Другим немаловажным аспектом является переменная source, которая имеется в обработчике функций. Она не добавляется в список параметров функции, но тем не менее используется. Она принимает различные значения в зависимости от события. Для событий, относящихся к игроку (как в в примере выше) она принимает значение типа player, которое относится к элементам (element).

Заключение

Теперь вы знаете основные аспекты, использующиеся при написании сценариев в MTA, а также ознакомились с частью документации. Главная страница содержит ссылки на более подробную информацию, учебники и справочники, которые при желании позволят вам более глубже узнать многие вещи о MTA.