ZH-CN/脚本编写介绍: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 127: Line 127:
</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 function's 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|服务端函数列表]],这次因为要找的是和交通工具有关的,所以定位到 '''交通工具函数''',并阅读 [[createVehicle]] 的文档。根据该函数的调用语法,该函数只有一个返回类型(最常见的情况),表示的是创建了的交通工具元素。同样,我们可以看到在调用语法中有一些用方括号 [ ] 括起来的参数,这类参数说明它们是可选的,调用时可以不提供。


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" 所得到的交通工具 ID,可以通过 ''vehicleModel'' 参数得到该 ID。


<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 -- x 坐标增加 5 个单位
-- create the vehicle and store the returned vehicle element in the ''createdVehicle'' variable
        -- 创建交通工具并将返回值存入到 ''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]] 函数文档的 '''返回值''' 部分,该部分说明:若该函数返回 ''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 -- x 坐标增加 5 个单位
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.
                -- 如果是,将错误信息发送给该特定玩家
outputChatBox("Failed to create vehicle.",thePlayer)
outputChatBox("Failed to create vehicle.",thePlayer)
end
end
Line 157: Line 157:
</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. For more advanced scripting, please check out the [[Map manager|Map Manager]].
上例代码中,还介绍了另一个用于发送客户端信息的 [[outputChatBox]] 函数。现在,您应该有能力可以自行阅读 API 函数文档了。若需要进一步学习高级脚本编写,请阅读[[Map manager|地图管理器]]教程。


==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.
目前为止,您已经接触到及知悉了有关资源、指令处理器及如何在文档中寻找 API 函数,但要学的还有很多。本节将粗略告诉您有关这些学习内容,您可以自行阅读相关教程。
===Clientside and Serverside scripts===
===客户端及服务端脚本===
You may have already noticed these or similiar terms (Server/Client) somewhere 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.
您可能曾经了解或是看到过所谓 “客户端及服务端脚本” (Server/Client Script) 的概念或名称了。事实上,您不仅能够编写典型的运行在服务器之上的,用于提供游戏指令处理等需求的脚本;还能够编写运行在 MTA 玩家客户端之上的脚本。之可以编写客户端脚本,原因是一些 MTA 所提供的特殊功能只能在客户端上执行(例如图形操作界面),或是在客户端上执行一些代码比在服务端上执行效率要高些。


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'(即默认服务端脚本),因此只有在需要指定其是客户端脚本时才显式指定 ''type'' 属性。一个脚本文件一旦其 ''type'' 属性的值设置为 ''client'',则玩家连接到服务器时,该脚本文件会自动下载到玩家客户端。有关更多信息,请阅读[[客户端脚本]]教程。


===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 theoretical resources, by looking at the files it contains, the ''meta.xml'' and what they might do:
上一节简单介绍了如何添加一个客户端脚本,但其实您什么都可以做到。正如本教程开头提到过,资源可以是任何类型的游戏模块。这些资源本身做什么或提供什么功能,便决定了它们的类型是什么。首先我们来分析一下下面的这些资源:


====First example - A utility script====
====第一一个示例资源 —— 辅助类资源====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/admin_commands
/admin_commands
Line 188: Line 188:
</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====
====第二个示例资源 —— 游戏模式====
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
/counterstrike
/counterstrike
Line 208: Line 208:
</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.
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.

Revision as of 14:21, 11 November 2013

对于 MTA 服务器而言,“资源” (Resource) 是十分重要的一个概念。一个资源本身表现为一个包含了一系列文件的文件夹或压缩文件 (zip),外包含一个用于指示服务器如何加载资源以及资源所包含文件说明的元数据文件 (Meta File)。可把资源的概念视作是运行在操作系统之上的程序 —— 它可以被启动或停止执行,且多个资源可以同时运行在服务器上。

所谓脚本编程,本质上即是在编写资源。资源可以定义它自身的类型为游戏模式、地图等。MTA 自带一些可供您的游戏模式使用的可选辅助用资源;例如 maplimits,一个用于限制玩家行动范围的资源;或是 deathpickups,用于创建武器拾取物以供辅助死亡竞技 (Deathmatch) 游戏模式。

[[{{{image}}}|link=|]] Tip: 您应该使用支持 Lua 格式代码的编辑器以编写脚本,以提高脚本编写的效率。我们建议使用 Notepad++LuaEdit。我们也提供测试版的 MTA 脚本编辑器(目前仍在开发中)。

创建一个脚本

第一步,我们将开始一步一步学习如何编写一个能让玩家到处行走的简单脚本。

脚本都在哪里存放着?

首先让我们来看看脚本的文件结构。打开 MTA 服务器目录,并定位到以下路径:

server/mods/deathmatch/resources/

在该目录下,可以看到一系列 MTA 自带的示例脚本压缩文件。每个压缩文件都是一个 “资源”,在服务器启动时它们会被自动解压并被加载到服务器上运行。若需创建一个新资源,只需在该目录下新建一个任意名称的文件夹。在本教程中我们以 "myserver" 资源作为演示。

现在请定位到以下路径:

server/mods/deathmatch/resources/myserver/

定义您的资源

为了能够让服务器得知资源内所包含的数据,每个资源内都必须包含一个位于资源根目录下的 "meta.xml" 文件(本例即 "myserver" 文件夹为资源根目录)。因此我们需要新建该文件,并以记事本方式打开。

在 "meta.xml" 文件内输入以下的代码:

<meta>
     <info author="YourName" type="gamemode" name="My Server" description="My first MTA server" />
     <script src="script.lua" />
</meta>

在 "<info />" 标签中,有一个用于指定资源类型的 "type" 属性。以上代码中指定了该资源类型为 "gamemode"(游戏模式),其他可选的资源类型还有常规包含文件或 "map"(地图),后文将会详细解释。目前只需要知道游戏模式是所有服务器的必不可少的核心,任意服务器都必须要有一个游戏模式。

"<script />" 标签指明了该资源内所包含的脚本文件,后文将会详细解释。

创建一个简单的脚本

注意上例代码中的 "<script />" 标签中并没有将 .lua 文件指定在其他目录路径下,因此现在需要创建一个与 meta.xml 文件同目录下的 .lua 脚本文件;随后,请把以下代码复制到新创建的 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 以后的 MTA 版本中,也同样需要使用 "setCameraTarget" 函数以设置玩家摄像机的目标,否则玩家进入服务器后只会见到游戏内蓝色的天空。

source 变量表示的是事件的触发者。由于以上代码会在玩家进入服务器时被触发,因此您需要使用该变量以确定是哪位玩家进入了服务器。因此上例代码只会影响到新进入了服务器的玩家,而非服务器内的所有玩家。

上例代码中,我们可以看到一个 addEventHandler 函数;从中可看见 3 个参数:'onPlayerJoin',其表明何时代码会被触发;getRootElement(),其表明了可能的事件触发者(getRootElement() 表示的是游戏内的一切事物或玩家,因此该事件可能是由游戏内的任意事物或玩家所触发的)。以及 joinHandler,其表明哪个函数在该事件 ('onPlayerJoin') 触发后会被执行。其他的代码细节会在后文中详细介绍,现在就启动服务器然后测试一下代码效果吧!

执行脚本

只需要执行 server/ 目录下的可执行文件即可启动服务器。启动服务器后,首先可以从服务器后台上看到一系列的服务器基本信息;注意 port number(端口数)信息,在进入服务器前需要使用到该信息。随后服务器会加载所有位于 mods/deathmatch/resources 目录下的资源,最后会看到提示 "ready to accept connections!",即表明服务器启动成功。

在玩家进入服务器前,必须要首先加载游戏模式。在服务器后台输入指令 "start myserver" 并按下回车键发送指令。服务器便会立即启动您刚刚所创建的游戏模式,并列出该游戏模式内所有的脚本代码性错误及警告提示。现在可以启动 MTA 客户端,点击 "Quick Connect" 并输入您在服务器后台上所看到的服务器 IP 地址及端口数。如果没有错误,几秒过后玩家就会出生在 Los Santos。

接下来,我们将会在脚本中添加一条用于在玩家附近刷出交通工具的游戏指令。您可以跳过本章节并阅读更为高级的地图管理器教程;您也可以阅读图形操作界面 (GUI) 脚本编写介绍教程以学习如何在 MTA 下创建图形操作界面 (GUI) 及对其进行脚本编写。

创建一个简单的游戏指令

打开先前我们所创建的 "script.lua" 文件。上文提到,我们需要创建一个可在玩家附近刷出交通工具的游戏指令。首先我们需要定义一个用于处理玩家输入指令的函数,以及一个用于创建玩家可从客户端控制台输入游戏指令的指令处理器。

-- 定义一个由指令处理器所调用的函数,并提供三个参数:thePlayer, command, vehicleModel
function createVehicleForPlayer(thePlayer, command, vehicleModel)
   -- 创建交通工具的代码
end

-- 创建一个指令处理器
addCommandHandler("createvehicle", createVehicleForPlayer)

"提示:您可以点击示例代码中的函数名以查看该 API 函数的文档。"

有关指令处理器

addCommandHandler 的第一个参数表明了玩家可以从客户端输入的游戏指令(同时也表明新建了这个游戏指令);第二个参数是该游戏指令发送到服务端后所调用的函数,本例中该函数名为 "createVehicleForPlayer"。

如果您有一定的编程经验,您应当知道调用函数的方法是这样的:

functionName(参数1, 参数2, 参数3, ..)
functionName(thePlayer, commandName, argument3, ..)

看看上例代码,我们发现参数1 为 thePlayer,参数2 为 commandName。thePlayer 表明哪位玩家发送了该游戏指令;而 commandName 表明游戏指令字符串。因此如果玩家发送了指令 "/greet",commandName 便是 "greet"(不包含指令前面的斜杠 "/")。参数3 是玩家额外的输入,后文中将会提到。 请记住前两个参数(thePlayer 及 commandName)是必不可少的参数,但是您可以随意命名这些参数以符合您的代码风格。

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 函数

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 函数,然后我们看看这个 createVehicleForPlayer 函数是如何被调用的:

createVehicleForPlayer(thePlayer,"createvehicle","468") -- thePlayer 表示的是输入了 createvehicle 指令的玩家

可以看到,它提供了几个参数:输入了指令的玩家,指令字符串本身(不包括前面的斜杠 '/')以及核心指令 createvehicle 以后的任意文本,本例中 "468" 为核心指令以后的文本,其为 Sanchez 交通工具的 ID。所有的指令处理器中,前两个参数都是一样且必须有的(参见 addEventHandler 文档)。因此,任意的指令处理器中,您都必须得要先定义这两个基本参数,再附加任意数量的附加参数。(附加参数有多少个,核心指令后的附加指令信息就有多少;本例中,createvehicle 有一个表示交通工具 ID 的附加指令信息,因此附加参数数量同为一个)

"注意:必须要在定义了指令处理函数之后再创建指令处理器,否则指令处理器届时将无法找到其处理函数。"

编写函数

为了完成我们所创建的函数,我们得先想想我们要在该函数内完成的一些事:

  • 获取玩家位置以便知道在何处刷出交通工具(我们希望在玩家身边刷出)
  • 计算最理想的交通工具刷出点(我们不希望玩家会卡在车辆内)
  • 刷出交通工具
  • 检查交通工具是否成功刷出,如果没有则输出错误信息

为了实现以上的需求,我们需要使用一些 API 函数。可以在服务端函数列表中找到我们所需的函数。首先我们需要一个用于取得玩家位置的函数。由于玩家属于 “元素” (Element),我们找到 针对元素的 API 函数,并找到 getElementPosition 函数。单击该函数名便可阅读该函数的文档。文档内详细说明了函数的调用语法,返回值以及其示例代码。函数调用语法告诉我们在调用函数时应该提供什么参数。

getElementPosition 的调用语法为:

float, float, float getElementPosition ( element theElement )

函数名前的三个 "float" 表示的是返回值类型。本例中表示该函数返回三个浮点数(x、y 及 z)。括号内,可以看到调用该函数时所需提供的参数。本例中只需要传递一个表示欲获取其位置的元素,在这里即玩家。

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 -- x 坐标增加 5 个单位
end

现在我们需要另一个用于刷出车辆的函数。再次打开 服务端函数列表,这次因为要找的是和交通工具有关的,所以定位到 交通工具函数,并阅读 createVehicle 的文档。根据该函数的调用语法,该函数只有一个返回类型(最常见的情况),表示的是创建了的交通工具元素。同样,我们可以看到在调用语法中有一些用方括号 [ ] 括起来的参数,这类参数说明它们是可选的,调用时可以不提供。

在我们所定义的函数中,一切需要传递给 createVehicle 函数的参数都准备好了:计算好的 "x, y, z" 变量以及通过玩家输入的游戏指令 "createvehicle 468" 所得到的交通工具 ID,可以通过 vehicleModel 参数得到该 ID。

function createVehicleForPlayer(thePlayer, command, vehicleModel)
	local x,y,z = getElementPosition(thePlayer) -- 获取玩家位置
	x = x + 5 -- x 坐标增加 5 个单位
        -- 创建交通工具并将返回值存入到 ''createdVehicle'' 变量内
	local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
end

当然这些代码还有改善的余地,但至少我们还可以添加一个用于检测交通工具是否成功创建的代码。阅读 createVehicle 函数文档的 返回值 部分,该部分说明:若该函数返回 false,则说明交通工具创建失败。因此,我们需要检查 createVehicle 变量的值以检测交通工具是否创建成功。

以下是完整的脚本代码:

function createVehicleForPlayer(thePlayer, command, vehicleModel)
	local x,y,z = getElementPosition(thePlayer) -- 获取玩家位置
	x = x + 5 -- x 坐标增加 5 个单位
	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 函数。现在,您应该有能力可以自行阅读 API 函数文档了。若需要进一步学习高级脚本编写,请阅读地图管理器教程。

必知

目前为止,您已经接触到及知悉了有关资源、指令处理器及如何在文档中寻找 API 函数,但要学的还有很多。本节将粗略告诉您有关这些学习内容,您可以自行阅读相关教程。

客户端及服务端脚本

您可能曾经了解或是看到过所谓 “客户端及服务端脚本” (Server/Client Script) 的概念或名称了。事实上,您不仅能够编写典型的运行在服务器之上的,用于提供游戏指令处理等需求的脚本;还能够编写运行在 MTA 玩家客户端之上的脚本。之可以编写客户端脚本,原因是一些 MTA 所提供的特殊功能只能在客户端上执行(例如图形操作界面),或是在客户端上执行一些代码比在服务端上执行效率要高些。

大部分您所制作的资源(游戏模式、地图)可能都是服务端脚本,例如本教程前面所介绍的脚本。但如果您所编写的代码无法在服务端上执行,则您可能需要令其可在客户端上运行(即编写客户端脚本)。若要开始尝试编写一个客户端脚本,您需要创建一个脚本文件(例如,把它命名为 client.lua),并修改 meta.xml 如下:

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

type 属性默认值为 'server'(即默认服务端脚本),因此只有在需要指定其是客户端脚本时才显式指定 type 属性。一个脚本文件一旦其 type 属性的值设置为 client,则玩家连接到服务器时,该脚本文件会自动下载到玩家客户端。有关更多信息,请阅读客户端脚本教程。

更复杂的资源

上一节简单介绍了如何添加一个客户端脚本,但其实您什么都可以做到。正如本教程开头提到过,资源可以是任何类型的游戏模块。这些资源本身做什么或提供什么功能,便决定了它们的类型是什么。首先我们来分析一下下面的这些资源:

第一一个示例资源 —— 辅助类资源

/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 提供图形操作界面以简化玩家操作

该示例资源可以随时被使用(也可以设置为随服务器而自动启动),原因是该资源对于整个游戏流程而言有一定的帮助(管理服务器)且不会影响到正常的游戏过程。

第二个示例资源 —— 游戏模式

/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 是一个客户端脚本,其用于创建武器购买菜单(使用到了图形操作界面,因此必须写为客户端脚本)

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.

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

/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>
  • The airport.map in a XML file that provides information about the map to the gamemode, these may include:
    • 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:
    • 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
    • .. 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. 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:

<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>

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. For a more in-depth explanation and examples of how map resources are utilized in the main script, please visit the Writing Gamemodes page.

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 the first chapter.

This example will output a message with the name of the player who died:

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

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 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. As another example, you can take a look at the basic spawning player script in the first section to get an idea how source is used.

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.

[[{{{image}}}|link=|]] Note: From here we recommend reading the debugging tutorial. Good debugging skills are an absolute necessity when you are making scripts. We also recommend you to use the predefined variables list to help you with certain tasks and make scripting easier and faster.

See also: