<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[samp | open.mp 联机社区论坛 - 教程]]></title>
		<link>https://open-mp.cn/</link>
		<description><![CDATA[samp | open.mp 联机社区论坛 - https://open-mp.cn]]></description>
		<pubDate>Mon, 04 May 2026 12:37:57 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[[教程] 枚举器 enum 详细讲解 原文作者: iPLEOMAX]]></title>
			<link>https://open-mp.cn/showthread.php?tid=26</link>
			<pubDate>Sun, 22 Mar 2026 00:11:14 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=26</guid>
			<description><![CDATA[<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">枚举器</h3><br />
<br />
原文作者: iPLEOMAX<br />
<br />
关于枚举，有些细节很多脚本作者并不清楚。<br />
<br />
很多人都喜欢在脚本里用枚举来存玩家数据、车辆数据、房屋数据之类的，尤其是用户信息这块。<br />
<br />
一个很典型的写法是这样的：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_PLAYER_INFO<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SCORE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;MONEY,<br />
&nbsp;&nbsp;&nbsp;&nbsp;KILLS,<br />
&nbsp;&nbsp;&nbsp;&nbsp;DEATHS<br />
};<br />
<br />
new pInfo[MAX_PLAYERS][E_PLAYER_INFO];</code></div></div><br />
用起来大概是这样：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
public OnPlayerDeath(playerid, killerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;pInfo[playerid][DEATHS]++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(IsPlayerConnected(killerid) &amp;&amp; killerid != playerid)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pInfo[killerid][KILLS]++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
这段应该不难理解。<br />
<br />
现在我们看另一个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_PLAYER_INFO<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SCORE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;MONEY = 9,<br />
&nbsp;&nbsp;&nbsp;&nbsp;KILLS = 5,<br />
&nbsp;&nbsp;&nbsp;&nbsp;DEATHS = 56<br />
};<br />
<br />
new pInfo[MAX_PLAYERS][E_PLAYER_INFO];<br />
<br />
printf("%i | %i | %i | %i", pInfo[0][SCORE], pInfo[0][MONEY], pInfo[0][KILLS], pInfo[0][DEATHS]);</code></div></div><br />
你可能会觉得输出是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0 | 9 | 5 | 56</code>，对吧？<br />
<br />
如果你这么想，那就错了。实际上输出是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0 | 0 | 0 | 0</code>。<br />
<br />
你可能会以为枚举是用来存储数据的，但事实并非如此。我在枚举里写了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MONEY = 9</code>，然后在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 里用了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pInfo[0][MONEY]</code>，但编译器其实把它当成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pInfo[0][9]</code> 来处理，而不是什么 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_PLAYER_INFO:MONEY</code>。也就是说，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MONEY</code> 在这里只是作为一个<span style="font-weight: bold;" class="mycode_b">索引</span>来用的。<br />
<br />
所以枚举本质上<span style="font-weight: bold;" class="mycode_b">根本不是变量</span>，它其实就是一组<span style="font-weight: bold;" class="mycode_b">常量</span>，只不过帮你的数组索引起了个好记的名字罢了。<br />
<br />
好，我们再来深入一点，应该能让你理解得更清楚。<br />
<br />
举个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
const e_CAR1 = 0;<br />
const e_CAR2 = 1;<br />
const e_CAR3 = 2;<br />
<br />
new MyCars[3];<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR1] = 520;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR2] = 458;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR3] = 411;<br />
}</code></div></div><br />
现在我们用枚举重写一下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum e_TEST<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;e_CAR1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;e_CAR2,<br />
&nbsp;&nbsp;&nbsp;&nbsp;e_CAR3<br />
};<br />
<br />
new MyCars[e_TEST];<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR1] = 520;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR2] = 458;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR3] = 411;<br />
}</code></div></div><br />
这两段代码都能正常编译，做的事情也完全一样。你看出区别了吗？其实就只是代码写法不同而已。<br />
<br />
这个例子告诉我们，枚举干的事情和常量是一样的。不过枚举有些地方比常量或者宏定义（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const e_CAR1 = 0;</code> 或者 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define e_CAR1 0</code>）更好用，具体差异我们后面再说。<br />
<br />
首先你需要明白枚举的结构：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum TEST<br />
{<br />
&nbsp;&nbsp; Abc,<br />
&nbsp;&nbsp; Def,<br />
&nbsp;&nbsp; Ghi,<br />
};</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Abc</code> 是一个值为 0 的常量（差不多等于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const Abc = 0;</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define Abc 0</code>），<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Def</code> 是值为 1 的常量，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Ghi</code> 是值为 2 的常量。<br />
<br />
预编译器会自动给这些常量赋值，从 0 开始一直往上排。而用常量的时候，你得自己手动赋值。枚举则是自动帮你排好的。<br />
<br />
再看个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum TEST<br />
{<br />
&nbsp;&nbsp; e_ONE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 自动得到 0<br />
&nbsp;&nbsp; e_TWO,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 得到 1<br />
&nbsp;&nbsp; e_THREE,&nbsp;&nbsp;&nbsp;&nbsp;// 得到 2<br />
&nbsp;&nbsp; e_FOUR = 12,// 这里手动赋了 12，所以不再是 3 了<br />
&nbsp;&nbsp; e_FIVE,&nbsp;&nbsp;&nbsp;&nbsp; // 变成 13，因为上一个值是 12<br />
&nbsp;&nbsp; e_SIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 变成 14，上一个值是 13<br />
}</code></div></div><br />
看到了吧，如果你手动给某个枚举项赋了值，后面的项就会在此基础上依次加 1。<br />
<br />
再来看看更复杂的情况：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum DATA<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;INT,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 得到 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;STRING[10],&nbsp;&nbsp;&nbsp;&nbsp; // 得到 1，但因为是数组，一个位置不够，它会占 10 个位置<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 所以实际占用的索引是 1, 2, 3, 4, 5, 6, 7, 8, 9, 10<br />
&nbsp;&nbsp;&nbsp;&nbsp;INT2,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 得到 11，因为 STRING 最后一位是 10<br />
&nbsp;&nbsp;&nbsp;&nbsp;STRING2[10]&nbsp;&nbsp;&nbsp;&nbsp; // 从 12 开始，一直到 22，需要 10 个位置<br />
};</code></div></div><br />
运行下面的代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
printf("%i", _:DATA);</code></div></div><br />
结果输出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">22</code>。<br />
<br />
因为整个枚举的总大小是 22：<br />
INT 占 1 个 + STRING 占 10 个 + INT2 占 1 个 + STRING2 占 10 个 = 22。<br />
<br />
你可能会问，为什么我写 INT 是 1 而不是 0？因为这里我数的是<span style="font-weight: bold;" class="mycode_b">占用了多少个位置</span>，不是<span style="font-weight: bold;" class="mycode_b">从哪个位置开始</span>。如果问起始位置，那 INT 确实是 0。<br />
<br />
一个大小为 22 的块，索引范围是 0 到 21，总共 22 个位置。<br />
<br />
再试一下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
printf("%i", _:STRING);</code></div></div><br />
输出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code>。因为第一个位置（索引 0）被 INT 占了，所以 STRING 从索引 1 开始。<br />
<br />
每个枚举项占用的位置是这样的：<ul class="mycode_list"><li>INT：索引 0<br />
</li>
<li>STRING：索引 1 到 10<br />
</li>
<li>INT2：索引 11<br />
</li>
<li>STRING2：索引 12 到 21<br />
</li>
</ul>
<br />
运行这段：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new Array[DATA];<br />
printf("%i", sizeof Array);</code></div></div><br />
结果也是 22，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DATA</code> 的大小就是 22。<br />
<br />
所以，这个数组实际上相当于：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
Array[INT + STRING + INT2 + STRING2];</code></div></div>这行代码是编译不了的，只是帮你想明白结构而已。<br />
<br />
也就是说，用枚举的时候，你其实是用这些枚举常量作为数组的索引。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">另一个例子</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum TEST<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SomeInteger = 124,<br />
&nbsp;&nbsp;&nbsp;&nbsp;SomeString[12],<br />
&nbsp;&nbsp;&nbsp;&nbsp;Float:SomeFloat<br />
};<br />
<br />
public OnFilterScriptInit()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new var_TEST[TEST];<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var_TEST[SomeInteger] = 1337;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("1) 储存的值: %i, 常量: %i", var_TEST[SomeInteger], _:SomeInteger);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;format(var_TEST[SomeString], 12, "Hey!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("2) 储存的值: %s, 常量: %i", var_TEST[SomeString], _:SomeString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var_TEST[SomeFloat] = 2054.124;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("3) 储存的值: %f, 常量: %i", var_TEST[SomeFloat], _:SomeFloat);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
}</code></div></div><br />
输出结果：<br />
<ol type="1" class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">储存的值: 1337, 常量: 124</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">储存的值: Hey!, 常量: 125</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">储存的值: 2054.124023, 常量: 137</code><br />
</li>
</ol>
<br />
第一行，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeInteger</code> 的常量值是 124，我把 1337 存到了索引 124 的位置。<br />
<br />
第二行，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeString</code> 虽然定义了长度为 12，但输出常量值时显示的是 125。因为 125 是这个字符串的起始索引，它占了 125 到 136 这 12 个位置。<br />
<br />
第三行，浮点数正常显示，但 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeFloat</code> 的常量值是 137。你可能会想，它应该在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeString</code>（125）后面，应该是 126 才对？但别忘了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeString[12]</code> 是个数组，占了 12 个位置，所以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeFloat</code> 的起始索引是 125 + 12 = 137。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">一些额外的重要信息</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">枚举也可以作为标签使用：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_MY_TAG<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_FIRST = 4,<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_SECOND = 2<br />
}</code></div></div><br />
然后可以这样写：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new E_MY_TAG:SomeVar;</code></div></div>或者：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new E_MY_TAG:MyVariable = E_FIRST; // 不会报错，因为 E_FIRST 本来就是 E_MY_TAG 的一部分</code></div></div><br />
但是：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new data[E_MY_TAG];<br />
data[E_FIRST] = 7; // 编译错误，索引越界</code></div></div>因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_MY_TAG</code> 的大小是 3（枚举里最大索引是 2），而 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_FIRST</code> 的值是 4，已经超出范围了。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">匿名枚举：</span><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum // 没有名字<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_TEST[10] = 32,<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_VAR<br />
};<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new data[E_TEST]; // E_TEST 的值是 32，不是 10<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">强标签和弱标签：</span><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_STRONG // 名字以大写字母开头，生成的是强标签<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_VAR = 64<br />
};<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new Test = E_STRONG:E_VAR; <br />
&nbsp;&nbsp;&nbsp;&nbsp;// 会报“标签不匹配”的警告，因为 Test 没有 E_STRONG 标签<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum e_WEAK // 名字以小写字母开头，生成的是弱标签<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_VAR = 64<br />
};<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new Test = e_WEAK:E_VAR; <br />
&nbsp;&nbsp;&nbsp;&nbsp;// 没有警告<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
枚举的大概内容就是这些了，这也是为什么我们更喜欢用枚举而不是直接写常量的原因。<br />
<br />
<span style="font-style: italic;" class="mycode_i">感谢 Y_Less 的讲解。</span>]]></description>
			<content:encoded><![CDATA[<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">枚举器</h3><br />
<br />
原文作者: iPLEOMAX<br />
<br />
关于枚举，有些细节很多脚本作者并不清楚。<br />
<br />
很多人都喜欢在脚本里用枚举来存玩家数据、车辆数据、房屋数据之类的，尤其是用户信息这块。<br />
<br />
一个很典型的写法是这样的：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_PLAYER_INFO<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SCORE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;MONEY,<br />
&nbsp;&nbsp;&nbsp;&nbsp;KILLS,<br />
&nbsp;&nbsp;&nbsp;&nbsp;DEATHS<br />
};<br />
<br />
new pInfo[MAX_PLAYERS][E_PLAYER_INFO];</code></div></div><br />
用起来大概是这样：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
public OnPlayerDeath(playerid, killerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;pInfo[playerid][DEATHS]++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(IsPlayerConnected(killerid) &amp;&amp; killerid != playerid)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pInfo[killerid][KILLS]++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
这段应该不难理解。<br />
<br />
现在我们看另一个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_PLAYER_INFO<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SCORE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;MONEY = 9,<br />
&nbsp;&nbsp;&nbsp;&nbsp;KILLS = 5,<br />
&nbsp;&nbsp;&nbsp;&nbsp;DEATHS = 56<br />
};<br />
<br />
new pInfo[MAX_PLAYERS][E_PLAYER_INFO];<br />
<br />
printf("%i | %i | %i | %i", pInfo[0][SCORE], pInfo[0][MONEY], pInfo[0][KILLS], pInfo[0][DEATHS]);</code></div></div><br />
你可能会觉得输出是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0 | 9 | 5 | 56</code>，对吧？<br />
<br />
如果你这么想，那就错了。实际上输出是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0 | 0 | 0 | 0</code>。<br />
<br />
你可能会以为枚举是用来存储数据的，但事实并非如此。我在枚举里写了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MONEY = 9</code>，然后在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 里用了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pInfo[0][MONEY]</code>，但编译器其实把它当成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pInfo[0][9]</code> 来处理，而不是什么 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_PLAYER_INFO:MONEY</code>。也就是说，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MONEY</code> 在这里只是作为一个<span style="font-weight: bold;" class="mycode_b">索引</span>来用的。<br />
<br />
所以枚举本质上<span style="font-weight: bold;" class="mycode_b">根本不是变量</span>，它其实就是一组<span style="font-weight: bold;" class="mycode_b">常量</span>，只不过帮你的数组索引起了个好记的名字罢了。<br />
<br />
好，我们再来深入一点，应该能让你理解得更清楚。<br />
<br />
举个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
const e_CAR1 = 0;<br />
const e_CAR2 = 1;<br />
const e_CAR3 = 2;<br />
<br />
new MyCars[3];<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR1] = 520;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR2] = 458;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR3] = 411;<br />
}</code></div></div><br />
现在我们用枚举重写一下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum e_TEST<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;e_CAR1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;e_CAR2,<br />
&nbsp;&nbsp;&nbsp;&nbsp;e_CAR3<br />
};<br />
<br />
new MyCars[e_TEST];<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR1] = 520;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR2] = 458;<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyCars[e_CAR3] = 411;<br />
}</code></div></div><br />
这两段代码都能正常编译，做的事情也完全一样。你看出区别了吗？其实就只是代码写法不同而已。<br />
<br />
这个例子告诉我们，枚举干的事情和常量是一样的。不过枚举有些地方比常量或者宏定义（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const e_CAR1 = 0;</code> 或者 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define e_CAR1 0</code>）更好用，具体差异我们后面再说。<br />
<br />
首先你需要明白枚举的结构：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum TEST<br />
{<br />
&nbsp;&nbsp; Abc,<br />
&nbsp;&nbsp; Def,<br />
&nbsp;&nbsp; Ghi,<br />
};</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Abc</code> 是一个值为 0 的常量（差不多等于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const Abc = 0;</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define Abc 0</code>），<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Def</code> 是值为 1 的常量，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Ghi</code> 是值为 2 的常量。<br />
<br />
预编译器会自动给这些常量赋值，从 0 开始一直往上排。而用常量的时候，你得自己手动赋值。枚举则是自动帮你排好的。<br />
<br />
再看个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum TEST<br />
{<br />
&nbsp;&nbsp; e_ONE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 自动得到 0<br />
&nbsp;&nbsp; e_TWO,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 得到 1<br />
&nbsp;&nbsp; e_THREE,&nbsp;&nbsp;&nbsp;&nbsp;// 得到 2<br />
&nbsp;&nbsp; e_FOUR = 12,// 这里手动赋了 12，所以不再是 3 了<br />
&nbsp;&nbsp; e_FIVE,&nbsp;&nbsp;&nbsp;&nbsp; // 变成 13，因为上一个值是 12<br />
&nbsp;&nbsp; e_SIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 变成 14，上一个值是 13<br />
}</code></div></div><br />
看到了吧，如果你手动给某个枚举项赋了值，后面的项就会在此基础上依次加 1。<br />
<br />
再来看看更复杂的情况：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum DATA<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;INT,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 得到 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;STRING[10],&nbsp;&nbsp;&nbsp;&nbsp; // 得到 1，但因为是数组，一个位置不够，它会占 10 个位置<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 所以实际占用的索引是 1, 2, 3, 4, 5, 6, 7, 8, 9, 10<br />
&nbsp;&nbsp;&nbsp;&nbsp;INT2,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 得到 11，因为 STRING 最后一位是 10<br />
&nbsp;&nbsp;&nbsp;&nbsp;STRING2[10]&nbsp;&nbsp;&nbsp;&nbsp; // 从 12 开始，一直到 22，需要 10 个位置<br />
};</code></div></div><br />
运行下面的代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
printf("%i", _:DATA);</code></div></div><br />
结果输出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">22</code>。<br />
<br />
因为整个枚举的总大小是 22：<br />
INT 占 1 个 + STRING 占 10 个 + INT2 占 1 个 + STRING2 占 10 个 = 22。<br />
<br />
你可能会问，为什么我写 INT 是 1 而不是 0？因为这里我数的是<span style="font-weight: bold;" class="mycode_b">占用了多少个位置</span>，不是<span style="font-weight: bold;" class="mycode_b">从哪个位置开始</span>。如果问起始位置，那 INT 确实是 0。<br />
<br />
一个大小为 22 的块，索引范围是 0 到 21，总共 22 个位置。<br />
<br />
再试一下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
printf("%i", _:STRING);</code></div></div><br />
输出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code>。因为第一个位置（索引 0）被 INT 占了，所以 STRING 从索引 1 开始。<br />
<br />
每个枚举项占用的位置是这样的：<ul class="mycode_list"><li>INT：索引 0<br />
</li>
<li>STRING：索引 1 到 10<br />
</li>
<li>INT2：索引 11<br />
</li>
<li>STRING2：索引 12 到 21<br />
</li>
</ul>
<br />
运行这段：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new Array[DATA];<br />
printf("%i", sizeof Array);</code></div></div><br />
结果也是 22，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DATA</code> 的大小就是 22。<br />
<br />
所以，这个数组实际上相当于：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
Array[INT + STRING + INT2 + STRING2];</code></div></div>这行代码是编译不了的，只是帮你想明白结构而已。<br />
<br />
也就是说，用枚举的时候，你其实是用这些枚举常量作为数组的索引。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">另一个例子</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum TEST<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SomeInteger = 124,<br />
&nbsp;&nbsp;&nbsp;&nbsp;SomeString[12],<br />
&nbsp;&nbsp;&nbsp;&nbsp;Float:SomeFloat<br />
};<br />
<br />
public OnFilterScriptInit()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new var_TEST[TEST];<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var_TEST[SomeInteger] = 1337;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("1) 储存的值: %i, 常量: %i", var_TEST[SomeInteger], _:SomeInteger);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;format(var_TEST[SomeString], 12, "Hey!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("2) 储存的值: %s, 常量: %i", var_TEST[SomeString], _:SomeString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var_TEST[SomeFloat] = 2054.124;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("3) 储存的值: %f, 常量: %i", var_TEST[SomeFloat], _:SomeFloat);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
}</code></div></div><br />
输出结果：<br />
<ol type="1" class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">储存的值: 1337, 常量: 124</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">储存的值: Hey!, 常量: 125</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">储存的值: 2054.124023, 常量: 137</code><br />
</li>
</ol>
<br />
第一行，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeInteger</code> 的常量值是 124，我把 1337 存到了索引 124 的位置。<br />
<br />
第二行，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeString</code> 虽然定义了长度为 12，但输出常量值时显示的是 125。因为 125 是这个字符串的起始索引，它占了 125 到 136 这 12 个位置。<br />
<br />
第三行，浮点数正常显示，但 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeFloat</code> 的常量值是 137。你可能会想，它应该在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeString</code>（125）后面，应该是 126 才对？但别忘了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeString[12]</code> 是个数组，占了 12 个位置，所以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SomeFloat</code> 的起始索引是 125 + 12 = 137。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">一些额外的重要信息</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">枚举也可以作为标签使用：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_MY_TAG<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_FIRST = 4,<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_SECOND = 2<br />
}</code></div></div><br />
然后可以这样写：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new E_MY_TAG:SomeVar;</code></div></div>或者：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new E_MY_TAG:MyVariable = E_FIRST; // 不会报错，因为 E_FIRST 本来就是 E_MY_TAG 的一部分</code></div></div><br />
但是：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
new data[E_MY_TAG];<br />
data[E_FIRST] = 7; // 编译错误，索引越界</code></div></div>因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_MY_TAG</code> 的大小是 3（枚举里最大索引是 2），而 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_FIRST</code> 的值是 4，已经超出范围了。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">匿名枚举：</span><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum // 没有名字<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_TEST[10] = 32,<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_VAR<br />
};<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new data[E_TEST]; // E_TEST 的值是 32，不是 10<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">强标签和弱标签：</span><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum E_STRONG // 名字以大写字母开头，生成的是强标签<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_VAR = 64<br />
};<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new Test = E_STRONG:E_VAR; <br />
&nbsp;&nbsp;&nbsp;&nbsp;// 会报“标签不匹配”的警告，因为 Test 没有 E_STRONG 标签<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code class="language-cpp" data-lang="cpp"><br />
enum e_WEAK // 名字以小写字母开头，生成的是弱标签<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E_VAR = 64<br />
};<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new Test = e_WEAK:E_VAR; <br />
&nbsp;&nbsp;&nbsp;&nbsp;// 没有警告<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
枚举的大概内容就是这些了，这也是为什么我们更喜欢用枚举而不是直接写常量的原因。<br />
<br />
<span style="font-style: italic;" class="mycode_i">感谢 Y_Less 的讲解。</span>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[教程] Pawn 中的压缩字符串 原文作者: Emmet_]]></title>
			<link>https://open-mp.cn/showthread.php?tid=25</link>
			<pubDate>Sat, 21 Mar 2026 23:52:50 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=25</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">Pawn 中的压缩字符串</h2><br />
<br />
原文作者: Emmet_ 本篇教程仅为翻译搬运<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">引言</h3><br />
<br />
压缩字符串自 SA-MP 和 Pawn 诞生之初就已存在。然而，很多人并不了解压缩字符串以及它能节省多少内存！本教程将教你压缩字符串的基础知识，以及如何正确操作它们。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">什么是压缩字符串？</h3><br />
<br />
压缩字符串是一种数组，它将数据存储在<span style="font-weight: bold;" class="mycode_b">每个字节</span>中，而不是像普通数组那样存储在<span style="font-weight: bold;" class="mycode_b">每个单元格</span>中。压缩字符串以小端序存储（即低位字节在前），并且只能容纳 0 到 255 的 ASCII 字符，超出这个范围的数值会绕回。<br />
<br />
看这段代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[5];<br />
string[0] = 'a';<br />
string[1] = 'b';<br />
string[2] = 'c';<br />
string[3] = 'd';<br />
string[4] = '&#92;0';</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'a'</code> 存储在单元格 0，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'b'</code> 存储在单元格 1，依此类推。一个单元格基本上占用 4 个字节，所以算一下，上面的字符串大约占用 20 个字节，每个字符占用 4 个字节的空间。<br />
<br />
然而，使用下面的代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[5 char];<br />
string{0} = 'a';<br />
string{1} = 'b';<br />
string{2} = 'c';<br />
string{3} = 'd';<br />
string{4} = '&#92;0';</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'a'</code> 存储在字节 0，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'b'</code> 存储在字节 1，依此类推。实际上，上面的字符串只占用 8 个字节，仅包含 2 个单元格！<br />
<br />
你可能在想为什么这个字符串不是 5 个字节。使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">char</code> 修饰符会自动将数组大小向上取整到最近的 4 的倍数（例如，1 变成 4，3 变成 4，5 变成 8，23 变成 24，依此类推）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这个数组占用 5 个单元格，共 20 个字节。<br />
new string[5] = "abcd"; <br />
// 这个数组占用 2 个单元格，共 8 个字节。<br />
new string[5 char] = !"abcd";</code></div></div><br />
因此，使用压缩字符串可以节省 3 到 4 倍的内存！<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">适用场景</h3><br />
<br />
你可能认为压缩数组没什么用。如果这么想，那你就错了。压缩数组有很多用途，不仅仅是节省内存！<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">稀疏数组</h4><br />
<br />
首先，你可以阅读我关于稀疏数组的教程：<br />
<br />
<a href="https://sampforum.blast.hk/showthread.php?tid=480439" target="_blank" rel="noopener" class="mycode_url">https://sampforum.blast.hk/showthread.php?tid=480439</a><br />
<br />
稀疏数组就是那些大部分数据经常为空的数组。使用压缩数组可以轻松节省内存！<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MAX_ITEMS (64)<br />
// 8,192 个单元格 = 32,768 字节！<br />
new gData[MAX_ITEMS][128];<br />
// 2,048 个字节 = 8,192 个单元格！<br />
new gData[MAX_ITEMS][128 char];</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">不常使用的字符串</h4><br />
<br />
很多时候，你会把字符串保存到内存中，但很少使用它们（例如几乎不用）。对于这类数组，压缩数组非常适用。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">大量数据存储</h4><br />
<br />
回到上面的“稀疏数组”部分，如果你需要存储大量数据，最好使用压缩字符串。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">内存节省！</h4><br />
<br />
压缩数组能节省 4 倍的内存，既然可以用压缩数组，为什么还要用那些多占 4 倍内存的方式存储数据呢？<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">SA-MP 中的不支持情况</h3><br />
<br />
压缩字符串在纯 Pawn 中完美支持。但是，大多数 SA-MP 原生函数<span style="font-weight: bold;" class="mycode_b">不支持</span>压缩字符串，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerName</code> 等。<br />
<br />
如果你打算使用压缩字符串，就必须依赖 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">strpack</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">strunpack</code> 以及 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string.inc</code> 中的其他字符串函数。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">格式化字符串</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 函数不支持压缩字符串，因此你必须使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">strpack</code>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    string[128 char];<br />
strpack(string, "Hello world!");</code></div></div><br />
你也可以这样做：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new <br />
    string[128 char],<br />
    temp[128]<br />
;<br />
strpack(string, "Emmet");<br />
strunpack(temp, string);<br />
format(temp, sizeof(temp), "%s likes to eat %s.", temp, "Big Macs");<br />
strpack(string, temp);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">支持压缩字符串的函数</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string.inc</code> 中的所有字符串函数都同时支持压缩数组和非压缩数组。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">fread</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">valstr</code> 函数也接受一个可选的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pack</code> 参数来支持压缩数组，因此你不用担心它们是否能与压缩数组一起工作。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">访问数据</h3><br />
<br />
在 Pawn 中，非压缩数组将数据存储在<span style="font-weight: bold;" class="mycode_b">每个单元格</span>中。而压缩数组将数据存储在<span style="font-weight: bold;" class="mycode_b">每个字节</span>中，这意味着你不能像访问非压缩数组那样使用方括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">[]</code> 来访问和获取压缩数组中的数据。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误。<br />
if (g_PackedString[0] != '&#92;0')<br />
{<br />
    g_PackedString[0] = 'h';<br />
    g_PackedString[1] = 'i';<br />
}<br />
// 正确！<br />
if (g_PackedString{0} != '&#92;0')<br />
{<br />
    g_PackedString{0} = 'h'; <br />
    g_PackedString{1} = 'i';<br />
}</code></div></div><br />
另外，要设置一个压缩字符串，你需要在字符串前加上感叹号，以表示这是压缩输入。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误。这会尝试将字符串按单元格存储，这不是我们想要的！<br />
g_PackedString = "Hello world.";<br />
// 正确！<br />
g_PackedString = !"Hello world.";</code></div></div>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">Pawn 中的压缩字符串</h2><br />
<br />
原文作者: Emmet_ 本篇教程仅为翻译搬运<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">引言</h3><br />
<br />
压缩字符串自 SA-MP 和 Pawn 诞生之初就已存在。然而，很多人并不了解压缩字符串以及它能节省多少内存！本教程将教你压缩字符串的基础知识，以及如何正确操作它们。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">什么是压缩字符串？</h3><br />
<br />
压缩字符串是一种数组，它将数据存储在<span style="font-weight: bold;" class="mycode_b">每个字节</span>中，而不是像普通数组那样存储在<span style="font-weight: bold;" class="mycode_b">每个单元格</span>中。压缩字符串以小端序存储（即低位字节在前），并且只能容纳 0 到 255 的 ASCII 字符，超出这个范围的数值会绕回。<br />
<br />
看这段代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[5];<br />
string[0] = 'a';<br />
string[1] = 'b';<br />
string[2] = 'c';<br />
string[3] = 'd';<br />
string[4] = '&#92;0';</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'a'</code> 存储在单元格 0，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'b'</code> 存储在单元格 1，依此类推。一个单元格基本上占用 4 个字节，所以算一下，上面的字符串大约占用 20 个字节，每个字符占用 4 个字节的空间。<br />
<br />
然而，使用下面的代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[5 char];<br />
string{0} = 'a';<br />
string{1} = 'b';<br />
string{2} = 'c';<br />
string{3} = 'd';<br />
string{4} = '&#92;0';</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'a'</code> 存储在字节 0，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'b'</code> 存储在字节 1，依此类推。实际上，上面的字符串只占用 8 个字节，仅包含 2 个单元格！<br />
<br />
你可能在想为什么这个字符串不是 5 个字节。使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">char</code> 修饰符会自动将数组大小向上取整到最近的 4 的倍数（例如，1 变成 4，3 变成 4，5 变成 8，23 变成 24，依此类推）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这个数组占用 5 个单元格，共 20 个字节。<br />
new string[5] = "abcd"; <br />
// 这个数组占用 2 个单元格，共 8 个字节。<br />
new string[5 char] = !"abcd";</code></div></div><br />
因此，使用压缩字符串可以节省 3 到 4 倍的内存！<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">适用场景</h3><br />
<br />
你可能认为压缩数组没什么用。如果这么想，那你就错了。压缩数组有很多用途，不仅仅是节省内存！<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">稀疏数组</h4><br />
<br />
首先，你可以阅读我关于稀疏数组的教程：<br />
<br />
<a href="https://sampforum.blast.hk/showthread.php?tid=480439" target="_blank" rel="noopener" class="mycode_url">https://sampforum.blast.hk/showthread.php?tid=480439</a><br />
<br />
稀疏数组就是那些大部分数据经常为空的数组。使用压缩数组可以轻松节省内存！<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MAX_ITEMS (64)<br />
// 8,192 个单元格 = 32,768 字节！<br />
new gData[MAX_ITEMS][128];<br />
// 2,048 个字节 = 8,192 个单元格！<br />
new gData[MAX_ITEMS][128 char];</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">不常使用的字符串</h4><br />
<br />
很多时候，你会把字符串保存到内存中，但很少使用它们（例如几乎不用）。对于这类数组，压缩数组非常适用。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">大量数据存储</h4><br />
<br />
回到上面的“稀疏数组”部分，如果你需要存储大量数据，最好使用压缩字符串。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">内存节省！</h4><br />
<br />
压缩数组能节省 4 倍的内存，既然可以用压缩数组，为什么还要用那些多占 4 倍内存的方式存储数据呢？<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">SA-MP 中的不支持情况</h3><br />
<br />
压缩字符串在纯 Pawn 中完美支持。但是，大多数 SA-MP 原生函数<span style="font-weight: bold;" class="mycode_b">不支持</span>压缩字符串，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerName</code> 等。<br />
<br />
如果你打算使用压缩字符串，就必须依赖 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">strpack</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">strunpack</code> 以及 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string.inc</code> 中的其他字符串函数。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">格式化字符串</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 函数不支持压缩字符串，因此你必须使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">strpack</code>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    string[128 char];<br />
strpack(string, "Hello world!");</code></div></div><br />
你也可以这样做：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new <br />
    string[128 char],<br />
    temp[128]<br />
;<br />
strpack(string, "Emmet");<br />
strunpack(temp, string);<br />
format(temp, sizeof(temp), "%s likes to eat %s.", temp, "Big Macs");<br />
strpack(string, temp);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">支持压缩字符串的函数</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string.inc</code> 中的所有字符串函数都同时支持压缩数组和非压缩数组。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">fread</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">valstr</code> 函数也接受一个可选的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pack</code> 参数来支持压缩数组，因此你不用担心它们是否能与压缩数组一起工作。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">访问数据</h3><br />
<br />
在 Pawn 中，非压缩数组将数据存储在<span style="font-weight: bold;" class="mycode_b">每个单元格</span>中。而压缩数组将数据存储在<span style="font-weight: bold;" class="mycode_b">每个字节</span>中，这意味着你不能像访问非压缩数组那样使用方括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">[]</code> 来访问和获取压缩数组中的数据。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误。<br />
if (g_PackedString[0] != '&#92;0')<br />
{<br />
    g_PackedString[0] = 'h';<br />
    g_PackedString[1] = 'i';<br />
}<br />
// 正确！<br />
if (g_PackedString{0} != '&#92;0')<br />
{<br />
    g_PackedString{0} = 'h'; <br />
    g_PackedString{1} = 'i';<br />
}</code></div></div><br />
另外，要设置一个压缩字符串，你需要在字符串前加上感叹号，以表示这是压缩输入。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误。这会尝试将字符串按单元格存储，这不是我们想要的！<br />
g_PackedString = "Hello world.";<br />
// 正确！<br />
g_PackedString = !"Hello world.";</code></div></div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[修仙者篇] AMX 汇编文档]]></title>
			<link>https://open-mp.cn/showthread.php?tid=24</link>
			<pubDate>Sat, 21 Mar 2026 23:19:49 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=24</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> AMX 汇编</h2><br />
<br />
AMX 版本: 3.0<br />
<br />
AMX 文件版本: 8<br />
<br />
本文档是关于抽象机执行器（Abstract Machine eXecutor）汇编的<span style="font-style: italic;" class="mycode_i">非官方</span>文档。本文档的内容可能不准确且可能随时更改。<a href="http://#terminology" target="_blank" rel="noopener" class="mycode_url">术语部分</a>中定义的部分术语在官方手册中并未出现。它们是为了帮助读者理解而引入的辅助术语。<br />
<br />
本文档的目标读者是首次接触汇编语言的程序员。他们应根据需要点击超链接以收集背景信息。高级用户可跳过部分章节或将本文档用作快速参考指南。<br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 目录</h2><ul class="mycode_list"><li><a href="http://#prerequisites" target="_blank" rel="noopener" class="mycode_url">先决条件</a><br />
</li>
<li><a href="http://#terminology" target="_blank" rel="noopener" class="mycode_url">术语</a><br />
</li>
<li><a href="http://#term-amx" target="_blank" rel="noopener" class="mycode_url">抽象机执行器 (AMX)</a><br />
</li>
<li><a href="http://#term-amx-assembly" target="_blank" rel="noopener" class="mycode_url">AMX 汇编</a><br />
</li>
<li><a href="http://#term-amx-binary" target="_blank" rel="noopener" class="mycode_url">AMX 二进制</a><br />
</li>
<li><a href="http://#term-amx-instance" target="_blank" rel="noopener" class="mycode_url">AMX 实例</a><br />
</li>
<li><a href="http://#term-host-program" target="_blank" rel="noopener" class="mycode_url">宿主程序</a><br />
</li>
<li><a href="http://#term-extension-module" target="_blank" rel="noopener" class="mycode_url">扩展模块</a><br />
</li>
<li><a href="http://#basic-concepts" target="_blank" rel="noopener" class="mycode_url">基本概念</a><br />
</li>
<li><a href="http://#concept-cell" target="_blank" rel="noopener" class="mycode_url">单元格概念</a><br />
</li>
<li><a href="http://#concept-memory-addresses" target="_blank" rel="noopener" class="mycode_url">内存地址</a><br />
</li>
<li><a href="http://#concept-stack-heap" target="_blank" rel="noopener" class="mycode_url">栈与堆</a><br />
</li>
<li><a href="http://#concept-instructions" target="_blank" rel="noopener" class="mycode_url">指令</a><br />
</li>
<li><a href="http://#concept-spc-vna" target="_blank" rel="noopener" class="mycode_url">存储程序概念与冯·诺依曼体系结构</a><br />
</li>
<li><a href="http://#concept-hdc" target="_blank" rel="noopener" class="mycode_url">头、数据段、代码段</a><br />
</li>
<li><a href="http://#concept-registers" target="_blank" rel="noopener" class="mycode_url">寄存器</a><br />
</li>
<li><a href="http://#file-memory-layout" target="_blank" rel="noopener" class="mycode_url">文件与内存布局</a><br />
</li>
<li><a href="http://#instruction-set" target="_blank" rel="noopener" class="mycode_url">指令集</a><br />
</li>
<li><a href="http://#pawn-inline-assembly" target="_blank" rel="noopener" class="mycode_url">Pawn 内联汇编语法</a><br />
</li>
<li><a href="http://#instruction-table" target="_blank" rel="noopener" class="mycode_url">指令表</a><br />
</li>
<li><a href="http://#loadstore-instructions" target="_blank" rel="noopener" class="mycode_url">加载/存储指令</a><br />
</li>
<li><a href="http://#indexing-instructions" target="_blank" rel="noopener" class="mycode_url">索引指令</a><br />
</li>
<li><a href="http://#arithmetic-instructions" target="_blank" rel="noopener" class="mycode_url">算术指令</a><br />
</li>
<li><a href="http://#logical-instructions" target="_blank" rel="noopener" class="mycode_url">逻辑指令</a><br />
</li>
<li><a href="http://#relational-instructions" target="_blank" rel="noopener" class="mycode_url">关系指令</a><br />
</li>
<li><a href="http://#stack-manipulation-instructions" target="_blank" rel="noopener" class="mycode_url">栈操作指令</a><br />
</li>
<li><a href="http://#heap-instructions" target="_blank" rel="noopener" class="mycode_url">堆指令</a><br />
</li>
<li><a href="http://#control-register-manipulation-instructions" target="_blank" rel="noopener" class="mycode_url">控制寄存器操作指令</a><br />
</li>
<li><a href="http://#control-flow-instructions" target="_blank" rel="noopener" class="mycode_url">控制流指令</a><br />
</li>
<li><a href="http://#switch-case-instructions" target="_blank" rel="noopener" class="mycode_url">Switch-case 指令</a><br />
</li>
<li><a href="http://#call-stack-and-call-convention" target="_blank" rel="noopener" class="mycode_url">调用栈与调用约定</a><br />
</li>
<li><a href="http://#local-variables-and-function-frame" target="_blank" rel="noopener" class="mycode_url">局部变量与函数帧</a><br />
</li>
<li><a href="http://#call-convention" target="_blank" rel="noopener" class="mycode_url">调用约定</a><br />
</li>
<li><a href="http://#methods-passing-arguments" target="_blank" rel="noopener" class="mycode_url">参数传递方法</a><br />
</li>
<li><a href="http://#system-requests" target="_blank" rel="noopener" class="mycode_url">系统请求</a><br />
</li>
<li><a href="http://#multi-dimensional-arrays" target="_blank" rel="noopener" class="mycode_url">多维数组</a><br />
</li>
</ul>
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 先决条件</h2><ul class="mycode_list"><li>Pawn 脚本语言<br />
</li>
<li><a href="https://en.wikipedia.org/wiki/Binary_number" target="_blank" rel="noopener" class="mycode_url">二进制数制</a><br />
</li>
<li><a href="https://en.wikipedia.org/wiki/Hexadecimal" target="_blank" rel="noopener" class="mycode_url">十六进制数制</a><br />
</li>
<li>内存地址（理解<a href="https://en.wikipedia.org/wiki/Pointer_(computer_programming)" target="_blank" rel="noopener" class="mycode_url">指针</a>更佳）<br />
</li>
<li><a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)" target="_blank" rel="noopener" class="mycode_url">栈（作为抽象数据类型）</a><br />
</li>
</ul>
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 术语</h2><br />
&lt;a name="term-amx"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">抽象机执行器 (AMX)</span>：AMX 是我们感兴趣的<a href="https://en.wikipedia.org/wiki/Abstract_machine" target="_blank" rel="noopener" class="mycode_url">抽象机</a>（或<a href="https://en.wikipedia.org/wiki/Virtual_machine" target="_blank" rel="noopener" class="mycode_url">虚拟机</a>）。<br />
<br />
&lt;a name="term-amx-assembly"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">AMX 汇编</span>：AMX 的<a href="https://en.wikipedia.org/wiki/Assembly_language" target="_blank" rel="noopener" class="mycode_url">汇编语言</a>。<br />
<br />
&lt;a name="term-amx-binary"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">AMX 二进制</span>：AMX <a href="https://en.wikipedia.org/wiki/Executable" target="_blank" rel="noopener" class="mycode_url">二进制文件</a>是编译后生成的可执行文件（通常扩展名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code>）。<span style="font-style: italic;" class="mycode_i">术语 AMX 程序在某些上下文中可能指代 AMX 二进制文件。</span><br />
<br />
&lt;a name="term-amx-instance"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">AMX 实例</span>：每个加载的 AMX 二进制文件独立存在。加载后的程序称为 AMX 实例。<span style="font-style: italic;" class="mycode_i">术语 AMX 程序在某些上下文中可能指代 AMX 实例。</span><br />
<br />
&lt;a name="term-host-program"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">宿主程序</span>：嵌入 AMX 的程序称为宿主程序。以 <a href="http://sa-mp.com/" target="_blank" rel="noopener" class="mycode_url">San Andreas Multiplayer (SA-MP)</a> 或 <a href="https://open.mp/" target="_blank" rel="noopener" class="mycode_url">open.mp</a> 为例，服务器就是宿主程序。<br />
<br />
&lt;a name="term-extension-module"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">扩展模块</span>：扩展模块是一个独立的模块，通常动态链接到宿主程序，提供额外的原生函数。扩展模块通常被称为插件。<br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 基本概念</h2><br />
<ul class="mycode_list"><li>## &lt;a name="concept-cell"&gt;&lt;/a&gt; 单元格概念<br />
</li>
</ul>
<br />
Pawn 是一种无类型语言：没有数据类型。所有数据都作为原始二进制数据存储在一个单元格或一组单元格中。我们将使用<a href="https://en.wikipedia.org/wiki/Two%27s_complement" target="_blank" rel="noopener" class="mycode_url">有符号二进制补码表示法</a>来传达一个或多个单元格的内容，而不是显式地用二进制写出来。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a = 5, b = 'A';</code></div></div><br />
上述代码创建了两个独立的单元格，分别由 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code> 标识。单元格 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code> 将包含值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">5</code>，单元格 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code> 将包含值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">65</code>（字符 'A' 的 <a href="https://en.wikipedia.org/wiki/ASCII" target="_blank" rel="noopener" class="mycode_url">ASCII</a> 等效值）。<br />
<br />
为了弥补数据类型的缺失，Pawn 提供了为单元格添加标签的能力。这些标签仅仅是编译时的辅助工具，不会直接&lt;sup&gt;<a href="http://#bc-cc-note-1" target="_blank" rel="noopener" class="mycode_url">1</a>&lt;/sup&gt;出现在 AMX 二进制文件中。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float:x = 5.0, Float:y = 10.0, Float:z;<br />
&nbsp;&nbsp;z = x + y;</code></div></div><br />
上述代码创建了三个带有标签的单元格，由 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 标识。它们分别被初始化为值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">5.0</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">10.0</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0.0</code>（默认初始化为二进制零，也是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0.0</code>），其二进制表示符合<a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic#Internal_representation" target="_blank" rel="noopener" class="mycode_url">浮点数的正确表示</a>。编译器会记住遇到的变量的标签，并确保在变量被使用时生成正确的代码 &lt;sup&gt;<a href="http://#bc-cc-note-2" target="_blank" rel="noopener" class="mycode_url">2</a>&lt;/sup&gt;。在上述例子中，编译器在处理第二行时，会生成正确的代码来执行两个浮点数 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的加法。请记住，整数加法和浮点数加法的执行方式不同。编译器使用与单元格关联的标签来确定应对操作数执行哪种加法操作。<br />
<br />
编译完成后，变量的标签信息会丢失。生成的 AMX 二进制文件将包含对 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 中存储的数据执行浮点数加法并将结果存储在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 中的指令。<br />
在运行时，浮点数加法会在不考虑脚本中 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的标签原本是否为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 的情况下执行。<br />
<br />
&lt;a name="bc-cc-note-1"&gt;&lt;/a&gt; [[1]](#bc-cc-note-1) <span style="font-style: italic;" class="mycode_i">Pawn 语言提供了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">tagof</code> 运算符，它返回与标签关联的编译时 id，该 id 可以被存储。编译器还会在 AMX 二进制文件的标签表中创建一个公开可访问的标签列表。</span><br />
<br />
&lt;a name="bc-cc-note-2"&gt;&lt;/a&gt; [[2]](#bc-cc-note-2) <span style="font-style: italic;" class="mycode_i">Pawn 语言允许基于标签的运算符重载。编译器知道所有存在的运算符重载，并根据操作数的标签调用正确的重载。如果给定的操作数没有重载存在，编译器将默认使用无标签单元格的运算符（即整数算术）。</span><br />
<ul class="mycode_list"><li>## &lt;a name="concept-memory-addresses"&gt;&lt;/a&gt; 内存地址<br />
</li>
</ul>
AMX 遵循平坦的字节可寻址内存模型，即 AMX 内存可以被认为是一个线性的字节集合<br />
（<a href="https://en.wikipedia.org/wiki/Flat_memory_model" target="_blank" rel="noopener" class="mycode_url">平坦内存</a>），每个字节都有一个唯一的地址（<a href="https://en.wikipedia.org/wiki/Byte_addressing" target="_blank" rel="noopener" class="mycode_url">字节可寻址</a>）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a[5];</code></div></div><br />
上述代码创建了一个由五个单元格组成的数组，由 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code> 标识。这些单元格连续存储，即一个接一个地存储。假设单元格大小为 4 字节，如果存储 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a[0]</code> 的位置地址是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1000</code>，那么存储 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a[1]</code> 的位置地址将是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1004</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>data:&nbsp;&nbsp;&nbsp;&nbsp;a[0] | a[1] | a[2] | a[3] | a[4]<br />
&nbsp;&nbsp;address: 1000&nbsp;&nbsp; 1004&nbsp;&nbsp; 1008&nbsp;&nbsp; 1012&nbsp;&nbsp; 1016</code></div></div><br />
<span style="font-style: italic;" class="mycode_i">所需知识</span>：<a href="https://en.wikipedia.org/wiki/Base_address" target="_blank" rel="noopener" class="mycode_url">基地址</a>，<a href="https://en.wikipedia.org/wiki/Offset_(computer_science)" target="_blank" rel="noopener" class="mycode_url">相对地址</a><br />
<br />
<span style="font-style: italic;" class="mycode_i">所需知识</span>：<a href="https://en.wikipedia.org/wiki/Array_data_structure#Element_identifier_and_addressing_formulas" target="_blank" rel="noopener" class="mycode_url">数组数据结构，元素标识符和寻址公式</a><br />
<br />
<span style="font-style: italic;" class="mycode_i">另请参阅</span>：<a href="https://en.wikipedia.org/wiki/Endianness" target="_blank" rel="noopener" class="mycode_url">字节序</a><br />
<ul class="mycode_list"><li>## &lt;a name="concept-stack-heap"&gt;&lt;/a&gt; 栈和堆<br />
</li>
</ul>
每个 AMX 实例都包含一个<span style="font-style: italic;" class="mycode_i">内部</span> <a href="https://en.wikipedia.org/wiki/Call_stack" target="_blank" rel="noopener" class="mycode_url">程序栈</a>（也称为调用栈）和<a href="https://en.wikipedia.org/wiki/Memory_management#HEAP" target="_blank" rel="noopener" class="mycode_url">程序堆</a>。这些是 AMX 程序中的内存区域，专用于一组任务。<br />
<br />
栈负责：<ul class="mycode_list"><li>存储局部变量<br />
</li>
<li>存储函数参数<br />
</li>
<li>存储函数调用信息（例如参数个数）<br />
</li>
<li>提供临时存储<br />
</li>
</ul>
<br />
堆负责：<ul class="mycode_list"><li>为动态分配提供内存<br />
</li>
<li>存储作为引用/数组传递的默认参数<br />
</li>
<li>存储不是<a href="https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue" target="_blank" rel="noopener" class="mycode_url">左值</a>且作为可变参数传递的常量和表达式<br />
</li>
</ul>
<br />
###<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>f(argc, ...) { }<br />
&nbsp;&nbsp;main () <br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new a, b, c[100];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f(1, 25);<br />
&nbsp;&nbsp;}</code></div></div><br />
在上面的代码片段中，变量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">c</code> 和常量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code> 在栈上分配空间。常量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">25</code> 在堆上分配空间。引用和可变参数作为地址传递给函数。由于字面量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">25</code> 是一个常量且没有地址，因此在堆上分配了一个临时单元格来存储值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">25</code>。该单元格的地址被传递给函数。<br />
<ul class="mycode_list"><li>## &lt;a name="concept-instructions"&gt;&lt;/a&gt; 指令<br />
</li>
</ul>
<br />
<a href="https://en.wikipedia.org/wiki/Instruction_set_architecture#Instructions" target="_blank" rel="noopener" class="mycode_url">指令</a>是离散的原子执行单元。大多数指令执行简单的任务，如基本算术。高级结构（如循环和条件语句）可以简化为一系列简单的指令。<br />
<br />
例如，将值压入调用栈然后弹出的指令可能是：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>push 100<br />
&nbsp;&nbsp;pop</code></div></div><br />
<a href="https://en.wikipedia.org/wiki/Assembly_language#Assembler" target="_blank" rel="noopener" class="mycode_url">汇编器</a>为上述代码片段生成的二进制代码可能是：<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">push-opcode | 100 | pop-opcode</code><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0x0013 0x0064 0x0014</code> 或者可能是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0000 0000 0000 0000 0000 0000 0001 0011 0000 0000 0000 0000 0000 0000 0110 0100 0000 0000 0000 0000 0000 0000 0001 0100</code><br />
<br />
是的，它只是一系列比特位，CPU（或者在我们这里是抽象机）知道如何解释这些比特位。当为物理硬件上的执行汇编时，这种表示被称为<a href="https://en.wikipedia.org/wiki/Machine_code" target="_blank" rel="noopener" class="mycode_url">机器码（或原生码）</a>。在为假想 CPU（如 AMX）上的执行汇编时，这种表示被称为 <a href="https://en.wikipedia.org/wiki/P-code_machine" target="_blank" rel="noopener" class="mycode_url">p-code</a>。<br />
<br />
<span style="font-style: italic;" class="mycode_i">另请参阅：</span> <a href="https://en.wikipedia.org/wiki/Bytecode" target="_blank" rel="noopener" class="mycode_url">字节码</a><br />
<ul class="mycode_list"><li>## &lt;a name="concept-spc-vna"&gt;&lt;/a&gt; 存储程序概念与冯·诺依曼体系结构<br />
</li>
</ul>
<br />
代码像数据一样驻留在内存中的想法被称为<a href="https://en.wikipedia.org/wiki/Stored-program_computer" target="_blank" rel="noopener" class="mycode_url">存储程序概念</a>。这也意味着内存中的每条指令都有一个地址，就像数据一样。代码和数据都驻留在<span style="font-weight: bold;" class="mycode_b">同一内存</span>中的想法是<a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture" target="_blank" rel="noopener" class="mycode_url">冯·诺依曼体系结构</a>的一个原则。这也意味着所有代码和数据共享一个<a href="https://en.wikipedia.org/wiki/Address_space" target="_blank" rel="noopener" class="mycode_url">地址空间</a>。<br />
<br />
AMX 使用一个公共内存来存储代码和数据。<br />
<ul class="mycode_list"><li>## &lt;a name="concept-hdc"&gt;&lt;/a&gt; 头、数据段、代码段<br />
</li>
</ul>
<br />
可执行二进制文件及程序的内存结构根据其包含的内容被划分为逻辑上不同的区域。一个典型的二进制可执行文件至少包含一个头、一个代码段和一个数据段。头提供了程序本身的信息，例如<a href="https://en.wikipedia.org/wiki/Entry_point" target="_blank" rel="noopener" class="mycode_url">程序入口点</a>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>HEADER<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; DATA</code></div></div><br />
代码段以二进制形式（机器码/p-code）存储代码，而数据段存储数据，如全局变量和静态局部变量。<br />
<br />
程序的内存结构通常不同。除了代码段和数据段外，它通常还包含程序栈和程序堆的区域。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>HEADER<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; DATA<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; HEAP<br />
&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp; STACK</code></div></div><br />
AMX 二进制文件组织为三个部分：前缀、代码和数据（按顺序）。前缀部分包含有关 AMX 二进制文件的信息，例如代码和数据部分在二进制文件中的起始偏移量。代码部分存储 p-code，数据段存储全局变量和静态局部变量。<br />
<br />
堆栈区域是在 AMX 二进制文件加载到内存后，使用前缀部分中的信息创建的。<br />
<br />
<span style="font-style: italic;" class="mycode_i">另请参阅</span>：<a href="https://en.wikipedia.org/wiki/Memory_segmentation" target="_blank" rel="noopener" class="mycode_url">内存分段</a>，<a href="https://en.wikipedia.org/wiki/Data_segment" target="_blank" rel="noopener" class="mycode_url">数据段</a>，<a href="https://en.wikipedia.org/wiki/Code_segment" target="_blank" rel="noopener" class="mycode_url">代码段</a>，<a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format" target="_blank" rel="noopener" class="mycode_url">ELF 格式</a><br />
<ul class="mycode_list"><li>## &lt;a name="concept-registers"&gt;&lt;/a&gt; 寄存器<br />
</li>
</ul>
了解处理器和内存位于不同的位置至关重要。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>|-------|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|------------------|<br />
&nbsp;&nbsp;|&nbsp;&nbsp;CPU&nbsp;&nbsp;|&nbsp;&nbsp;=============== |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MEMORY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;|-------|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |------------------|</code></div></div><br />
内存存储数据，CPU 对数据进行操作。对于每次操作，处理器都必须将操作数从内存中取出并临时存储在 CPU 内部。这些临时存储位置被称为<a href="https://en.wikipedia.org/wiki/Processor_register" target="_blank" rel="noopener" class="mycode_url">寄存器</a>。这些寄存器可以容纳少量数据，范围在几个字节（通常为 2、4 或 8 字节）。<br />
<br />
假设处理器必须将两个变量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 相加，并将结果存储在变量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 中。一个典型的处理器会执行以下操作：<br />
<ol type="1" class="mycode_list"><li>从内存中取出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 的值（即从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 的地址读取）并将其存储在一个寄存器中，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R1</code><br />
</li>
<li>从内存中取出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的值（即从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的地址读取）并将其存储在一个寄存器中，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R2</code><br />
</li>
<li>将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R1</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R2</code> 的内容相加，并将结果存储在某寄存器中，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R3</code><br />
</li>
<li>将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R3</code> 的内容存储到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 中（写入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 的地址）<br />
</li>
</ol>
<br />
处理器包含不同<a href="https://en.wikipedia.org/wiki/Processor_register#Categories_of_registers" target="_blank" rel="noopener" class="mycode_url">类型的寄存器</a>，用于不同目的。一些寄存器专用于特定任务，一些寄存器可用于任何目的。上例中使用的那类寄存器属于通用寄存器。<br />
<br />
AMX 的寄存器集包括以下寄存器：<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">主寄存器 (PRI)</span>：通用寄存器（常用作<a href="https://en.wikipedia.org/wiki/Accumulator_(computing)" target="_blank" rel="noopener" class="mycode_url">累加器寄存器</a>）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">辅助寄存器 (ALT)</span>：通用寄存器（常用作地址寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">代码段寄存器 (COD)</span>：内存中代码段起始的绝对地址<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">数据段寄存器 (DAT)</span>：内存中数据段起始的绝对地址<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">当前指令指针 (CIP)</span>：下一条<span style="font-style: italic;" class="mycode_i">要执行指令</span>的地址（相对于 COD 寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">栈顶寄存器 (STP)</span>：栈顶的地址（相对于 DAT 寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">栈指针寄存器 (STK)</span>：栈上当前位置的地址（相对于 DAT 寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">帧指针寄存器 (FRM)</span>：栈中当前函数帧起始的地址（相对于 DAT 寄存器）（<span style="font-style: italic;" class="mycode_i">稍后解释</span>）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">堆指针 (HEA)</span>：堆顶的地址（相对于 DAT 寄存器）<br />
</li>
</ul>
<br />
在编写汇编代码时，地址通常不是绝对的；它们是相对于某个段或帧指针寄存器的。全局变量和字符串的地址相对于 DAT 寄存器。函数、指令和标签的地址相对于 COD 寄存器。这意味着变量或指令的绝对地址分别是相对地址加上 DAT 或 COD 寄存器的值。局部变量的地址相对于帧指针寄存器。这有点复杂，稍后会解释。<br />
<br />
<span style="font-style: italic;" class="mycode_i">从现在开始，当我们讨论代码地址和数据地址时，除非明确说明，否则暗示这些地址分别相对于 COD 寄存器和 DAT 寄存器。</span><br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 文件与内存布局</h2><br />
所有非调试 AMX 二进制文件按如下方式组织：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>START OF BINARY FILE<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PREFIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATA<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
END OF BINARY FILE</code></div></div><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">前缀</span>：包含程序的基本信息<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">代码</span>：包含代码<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">数据</span>：包含数据<br />
</li>
</ul>
<br />
<span style="font-style: italic;" class="mycode_i">注意：根据编译器的选项，前缀部分可能会被<a href="https://en.wikipedia.org/wiki/Data_structure_alignment" target="_blank" rel="noopener" class="mycode_url">填充</a>以使代码和数据部分对齐。</span><br />
<br />
<span style="font-style: italic;" class="mycode_i">注意：启用调试编译的脚本的二进制映像将在末尾附加符号调试信息。更多详情请参阅 Pawn 实现者指南。</span><br />
<br />
内存中的结构采用与二进制文件类似的结构，但额外包含一个栈和一个堆，这是使用前缀中的信息设置的。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>LOW ADDRESS (0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PREFIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATA<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HEAP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FREE SPACE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STACK<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
HIGH ADDRESS</code></div></div><br />
堆和栈共享一个公共的内存区域。它们从该区域的两端开始，并向相反方向增长。堆向高地址增长，栈向低地址增长。由于它们共享同一内存区域，因此可能会相互覆盖（当堆指针和栈指针碰撞时）。发生这种情况时，AMX 会中止并显示如下错误信息：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Script[gamemodes/TEST.amx]: Run time error 3: "Stack/heap collision (insufficient stack size)"</code></div></div><br />
根据编译器掌握的信息，它会估算并间接地在 AMX 二进制文件的前缀部分设置堆栈大小。然而，程序员可以使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma dynamic [estimated number of cells]</code> 指令提供自己对所需堆栈区域大小的估计。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">前缀部分的字段</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">类型</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">大小</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">size</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">内存映像的大小；不包括栈和堆</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">magic</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">指示格式和单元格大小</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">file version</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">格式版本</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">amx version</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">抽象机所需的最低版本</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">flags</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">是否存在符号调试信息、紧凑编码等。</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">defsize</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">表中记录的大小</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">cod</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">代码部分起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">dat</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">数据部分起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">hea</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">HEA 寄存器的初始值（标记数据段结束）</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">stp</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STP 寄存器的初始值（指示总内存需求）</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">cip</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CIP 寄存器的初始值（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code> 函数的地址；如果不存在则为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">-1</code>）</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">publics</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共函数表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">natives</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">原生函数表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">libraries</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">库表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">pubvars</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共变量表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">tags</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">标签表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">name table</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">名称表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">overlays</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">覆盖表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">publics</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共函数列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">natives</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">原生函数列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">libraries</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">库列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">pubvars</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共变量列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">tags</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共标签列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">overlays</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">覆盖列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">name table</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">符号名称列表</td>
 </tr>
</table>
<br />
<span style="font-style: italic;" class="mycode_i">注意：关于 magic、version 和 flags 字段中信息如何编码的详细信息，请参阅 Pawn 实现者指南。</span><br />
<br />
<span style="font-style: italic;" class="mycode_i">注意：前缀中的所有多字节字段都以<a href="https://en.wikipedia.org/wiki/Endianness" target="_blank" rel="noopener" class="mycode_url">小端格式</a>存储，无论 AMX 二进制文件是在哪个平台上生成或将在哪个平台上执行。</span><br />
<br />
可以看出，前缀由一个固定部分组成，后面跟着一系列表。除了名称表之外，表中的每条记录都由两个字段组成，如下所示：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">字段</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">大小</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">变量</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">单元格大小</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">变量</span></td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">名称字符串偏移量</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4 字节</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">从前缀起始到名称表中字符串的偏移量</td>
 </tr>
</table>
<br />
表中每条记录（除了名称表）的大小由前缀中的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">defsize</code> 字段给出：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">defsize</code> = 4 + 单元格大小。<br />
<br />
表中的每条记录都被分配了一个索引号。每个表的第一个记录被分配索引 0，后续记录的索引号是前一个记录索引加 1。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">名称表</span>：<br />
除了名称表本身之外，其他表中的记录包含一个指向字符串的指针。这些字符串作为以空字符结尾的 C 字符串存储在名称表中。此表中记录的大小是其包含的字符串的大小。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">公共函数表</span>：<br />
为脚本中定义的每个公共函数创建一条记录。这些记录包含公共函数的地址（函数第一条指令的地址）和指向相应公共函数名称的偏移量。表中记录的索引就是相应公共函数的索引。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">原生函数表</span>：<br />
为脚本中调用的每个原生函数创建一条记录。记录的第一个字段由编译器在二进制文件中设置为 0，但宿主程序在加载二进制文件时会将该字段初始化为函数的地址（位于宿主程序的地址空间中）。第二个字段包含指向原生函数名称的偏移量。表中记录的索引就是相应原生函数的索引。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">库表</span>：<br />
Pawn 语言提供了一个 pragma 指令 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma directive [library name]</code>，用于告知编译器调用的某些原生函数需要扩展模块。对于在脚本中调用了其原生函数的库，会在库表中创建一条记录。目的是告知宿主程序 AMX 程序依赖于一个扩展模块。记录的第一个字段供内部使用，在 AMX 二进制文件中设置为 0。另一个字段包含从前缀起始到名称表中库名称的偏移量。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">公共变量表</span>：<br />
为脚本中声明的每个公共变量创建一条记录。该记录包含公共变量的地址和指向公共变量名称的偏移量。表中记录的索引就是公共变量的索引。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">标签表</span>：<br />
与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sleep</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">exit</code> 语句一起使用的标签以及与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">tagof</code> 运算符一起使用的标签会被导出。为每个这样的标签创建一条记录。第一个字段包含标签 id 号，第二个字段存储指向标签名称的偏移量。<br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 指令集</h2><br />
<br />
&lt;a name="pawn-inline-assembly"&gt;&lt;/a&gt; Pawn 编译器接受的大部分 AMX 汇编指令可以用以下格式表示：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>mnemonic[.prefix][.register suffix] operand<br />
<br />
SHL.C.pri 3<br />
ZERO.alt<br />
ADD.C 100<br />
LIDX</code></div></div><br />
助记符给出了指令功能的提示。可选的前缀指示指令操作数的类型。可选的尾缀指示指令主要作用于哪个寄存器。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">前缀列表</span>：<ul class="mycode_list"><li>.C = 常量<br />
</li>
<li>.S = 栈<br />
</li>
<li>.I = 间接寻址<br />
</li>
<li>.B = 无 B 变体的变体&lt;sup&gt;\[需要更好的描述\]&lt;/sup&gt;<br />
</li>
<li>.ADR = 地址<br />
</li>
<li>.R = 重复<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">寄存器尾缀列表</span>：<ul class="mycode_list"><li>.pri = 主寄存器<br />
</li>
<li>.alt = 辅助寄存器<br />
</li>
</ul>
<br />
每条指令的二进制形式需要一个单元格来存储操作码，每个操作数还需要一个额外的单元格。绝大多数指令使用隐含寄存器作为操作数。这减少了所需显式操作数的数量，从而减小了代码段的大小并提高了性能。<br />
<br />
&lt;a name="instruction-table"&gt;&lt;/a&gt; <span style="font-style: italic;" class="mycode_i">阅读表格：</span><br />
<ol type="1" class="mycode_list"><li><span style="font-style: italic;" class="mycode_i">[address] 指的是存储在位置 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DAT + address</code> 的值</span><br />
</li>
<li><span style="font-style: italic;" class="mycode_i">语义列中使用的运算符执行与 Pawn 中相同的操作</span><br />
</li>
</ol>
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">操作码</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">助记符</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">操作数</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">语义</th>
 </tr>
</table>
 <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">1</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">LOAD.pri</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">address</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">PRI = [address]</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LOAD.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [address]</td>
 </tr>
</table>
   <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">3</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">LOAD.S.pri</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">offset</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">PRI = [FRM + offset]</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LOAD.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [FRM + offset]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">5</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [[address]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">6</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [[address]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">7</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.S.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [[FRM + offset]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">8</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [[FRM + offset]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">9</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LOAD.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [PRI]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">10</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LODB.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = 'number' of bytes from [PRI] (read 1/2/4 bytes)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">11</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CONST.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">12</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CONST.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">13</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADDR.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = FRM + offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADDR.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = FRM + offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">15</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">16</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">17</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.S.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">18</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">19</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[address]] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">20</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[address]] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">21</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.S.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[FRM + offset]] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">22</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[FRM + offset]] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">23</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[ALT] = PRI (full cell)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">24</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STRB.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number of bytes at [ALT] = PRI (store 1/2/4 bytes)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">25</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LIDX</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [ALT + (PRI x cell size)]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">26</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LIDX.B</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">shift</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [ALT + (PRI &lt;&lt; shift)]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">27</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">IDXADDR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT + (PRI x cell size) (calculate indexed address)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">28</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">IDXADDR.B</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">shift</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT + (PRI &lt;&lt; shift) (calculate indexed address)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">29</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALIGN.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">Little Endian: PRI ^= cell size - number</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">30</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALIGN.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">Little Endian: ALT ^= cell size - number</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">31</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = value contained in the selected register; 1=COD, 1=DAT, 2=HEA,3=STP, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">32</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">selected register = PRI; 2=HEA, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">33</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">MOVE.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">34</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">MOVE.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">35</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">XCHG</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">Exchange contents of PRI and ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">36</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">37</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">38</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.R</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">repeat (STK = STK - cell size, [STK] = PRI) 'number' times</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">39</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = value</td>
 </tr>
</table>
  <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">40</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">PUSH</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">address</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">STK = STK - cell size, [STK] = [address]</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">41</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = [FRM + offset]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">42</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">POP.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [STK], STK = STK + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">43</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">POP.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [STK], STK = STK + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">44</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STACK</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = STK, STK = STK + value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">45</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">HEAP</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = HEA, HEA = HEA + value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">46</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PROC</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = FRM, FRM = STK</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">47</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">RET</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">FRM = [STK], STK = STK + cell size, CIP = [STK], STK = STK + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">48</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">RETN</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">FRM = [STK], STK = STK + cell size, CIP = [STK], STK = STK + cell size, STK = STK + [STK] + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">49</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CALL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK − cell size, [STK] = CIP, CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">50</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CALL.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK − cell size, [STK] = CIP, CIP = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">51</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JUMP</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">53</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JZER</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI == 0 then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">54</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JNZ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI != 0 then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">55</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI == ALT then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">56</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JNEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI != ALT then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">57</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JLESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &lt; ALT (unsigned) then CIP = offset</td>
 </tr>
</table>
 <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">58</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">JLEQ</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">offset</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">if PRI &lt;= ALT (unsigned)  then CIP = offset</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">59</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JGRTR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &gt; ALT (unsigned) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">60</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JGEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &gt;= ALT (unsigned) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">61</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JSLESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &lt; ALT (signed) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">62</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JSLEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &lt;= ALT (signed) then CIP = offset</td>
 </tr>
</table>
 <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">63</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">JSGRTR</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">offset</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">if PRI &gt; ALT (signed) then CIP = offset</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">64</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JSGEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &gt;= ALT (signed) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">65</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;&lt; ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">66</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;&gt; ALT (without sign extension)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">67</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SSHR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;&gt; ALT (with sign extension)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">68</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHL.C.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;&lt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">69</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHL.C.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT &lt;&lt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">70</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHR.C.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;&gt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">71</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHR.C.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT &gt;&gt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">72</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SMUL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI * ALT (signed multiply)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">73</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SDIV</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI / ALT (signed divide), ALT = PRI mod ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">74</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SDIV.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT / PRI (signed divide), ALT = ALT mod PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">75</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">UMUL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI * ALT (unsigned multiply)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">76</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">UDIV</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI / ALT (unsigned divide), ALT = PRI mod ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">77</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">UDIV.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT / PRI (unsigned divide), ALT = ALT mod PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">78</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADD</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI + ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">79</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SUB</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI - ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">80</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SUB.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT - PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">81</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">AND</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &amp; ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">82</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">OR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &#124; ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">83</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">XOR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI ^ ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">84</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NOT</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = !PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">85</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NEG</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = -PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">86</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INVERT</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ~PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">87</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADD.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI + value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">88</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SMUL.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI * value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">89</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">90</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">91</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">92</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">93</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SIGN.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">sign extend the byte in PRI to a cell</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">94</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SIGN.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">sign extend the byte in ALT to a cell</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">95</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">EQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI == ALT ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">96</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI != ALT ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">97</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt; ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">98</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;= ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">99</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">GRTR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt; ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">100</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">GEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;= ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">101</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SLESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt; ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">102</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SLEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;= ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">103</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SGRTR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt; ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">104</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SGEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;= ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">105</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">EQ.C.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI == value ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">106</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">EQ.C.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT == value ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">107</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">108</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">109</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = [address] + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">110</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = [FRM + offset] + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">111</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[PRI] = [PRI] + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">112</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">113</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">114</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = [address] - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">115</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = [FRM + offset] - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">116</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[PRI] = [PRI] - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">117</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">MOVS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">copy 'number' bytes of non-overlapping memory from [PRI] to [ALT]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">118</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CMPS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">compare 'number' bytes of non-overlapping memory at [PRI] with [ALT]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">119</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">FILL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">fill 'number' bytes of memory from [ALT] with value in PRI (number must be multiple of cell size)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">120</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">HALT</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">0</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">abort execution (exit value in PRI)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">121</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">BOUNDS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">abort execution if PRI &gt; value or if PRI &lt; 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">122</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SYSREQ.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">call system service, service number in PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">123</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SYSREQ.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">call system service</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">128</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JUMP.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CIP = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">129</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SWITCH</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">compare PRI to the values in the case table (whose address is passed in the 'offset' argument) and jump to the associated address in the matching record</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">130</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CASETBL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">...</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">a variable number of case records follows this opcode, where each record takes two cells</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">131</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SWAP.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[STK] = PRI, PRI = [STK]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">132</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SWAP.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[STK] = ALT, ALT = [STK]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">133</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.ADR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = FRM + offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">134</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NOP</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">no operation</td>
 </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 加载/存储指令</h4><br />
<br />
当使用全局变量作为操作数时，编译器会替换该变量的地址。下面代码中的第一条加载指令，如果 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">some_global</code> 的地址是 1288，则实际上变成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#emit LOAD.pri 1288</code>。请注意，编译器替换的地址是从数据段起始的偏移量；因此，该地址是相对于 DAT 寄存器的。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new some_global = 10, another_global = 25;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.pri some_global // 将 'some_global' 的值加载到主寄存器<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.alt another_global&nbsp;&nbsp;// 将 'another_global' 的值加载到辅助寄存器<br />
}</code></div></div><br />
当使用局部变量时，编译器会替换从函数帧起始的偏移量。<span style="font-style: italic;" class="mycode_i">(稍后解释)</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;static s_local = 20; // 静态局部变量存储在数据段中<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new some_local = 10, another_local = 25; // 局部变量存储在栈中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.S.pri some_local // 将 'some_local' 的值加载到主寄存器<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.S.alt another_local&nbsp;&nbsp;// 将 'another_local' 的值加载到辅助寄存器<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.pri s_local // 注意静态局部变量的行为类似于全局变量<br />
}</code></div></div><br />
由于编译器会为全局变量替换地址，因此可以使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CONST.pri/CONST.alt</code> 来获取这些变量的地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new some_global;<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 10 // 将 10 放入主寄存器<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 50 // 将 50 放入辅助寄存器<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri some_global // 将 'some_global' 的地址存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt some_global // 将 'some_global' 的地址存储在辅助寄存器中<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new some_global;<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new some_local;<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ZERO.pri // 将零存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.pri some_global // 将主寄存器中存储的值（本例中为零）设置给 'some_global'<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 125<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.S.alt some_local // 将辅助寄存器中存储的值（125）设置给 'some_local'<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 索引指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new global_arr[10];<br />
main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt global_arr // 将 'global_arr' 的地址（'global_arr' 第一个元素的地址）加载到辅助寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 2 // 设置我们感兴趣的 'global_arr' 元素的索引<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LIDX // 现在主寄存器中存储的是 'global_arr[2]` 处存储的值<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt global_arr // 将 'global_arr' 的地址（第一个元素的地址）加载到辅助寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 2 // 设置我们感兴趣的 'global_arr' 元素的索引<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit IDXADDR // 现在主寄存器中存储的是 'global_arr[2]` 的地址<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 算术指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 4<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 5<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit SMUL // 现在主寄存器中是 20（SMUL 执行有符号乘法；UMUL 执行无符号乘法）<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADD // 将 5 加到 20（由于上一条指令，主寄存器中存储的是 20）<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADD.C 10 // 将 10 加到主寄存器；现在主寄存器中是 35<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit SUB.alt // 用 5 减去 35；现在主寄存器中是 -30<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit SMUL.C 2 // -30 乘以 2；得到 -60<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 逻辑指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 5 // .. 0000 0101<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 3 // ... 0000 0011<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit AND // 主寄存器现在包含 ... 0000 0001<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit XOR // 主寄存器现在包含 ... 0000 0110<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit INVERT // 对主寄存器中存储的值取反码<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit NEG // 对主寄存器中存储的值取补码（本质上是取负）<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">关系指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 5<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 8<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit EQ // 如果 5 == 8，则将主寄存器设置为 1，否则为 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LESS // 如果 0 &lt; 8，则将主寄存器设置为 1，否则为 0<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 栈操作指令</h4><br />
<br />
局部变量存储在栈上。详细说明将在后续章节中提供，但现在我们假设使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CONST.pri some_local</code> 会得到某个偏移量，该偏移量加上帧寄存器中存储的基地址即得数据地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new some_local = 25;<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADDR.alt some_local // 计算 'some_local' 的地址<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 100<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.I // 将 100 存储到 'some_local'<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 100<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.S.pri some_local // 实现上述代码功能的更好方法<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri some_local // 神秘地等价于 CONST.pri -4（稍后解释）<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit PUSH.C 100 // 将值 100 压入调用栈<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit POP.pri // 从栈中弹出一个值并将结果存储在主寄存器中<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit PUSH.pri // 推送主寄存器的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit PUSH.alt // 推送辅助寄存器的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit POP.pri<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit POP.alt // 最后 4 条指令有效地交换了主寄存器和辅助寄存器的内容<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit XCHG // 交换主寄存器和辅助寄存器内容的更好方法<br />
}</code></div></div><br />
局部数组位于栈上。因此，在使用索引指令之前，必须使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ADDR.alt/ADDR.pri</code> 来获取完整的地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new local_array[10];<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADDR.alt local_array // 加载存储在 'local_array' 中的值，即数组的地址<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 5<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LIDX // 有效地将 'local_array[5]' 的值存储在主寄存器中<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 堆指令</h4><br />
堆指针（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">HEA</code> 寄存器）指向堆的顶部。将堆指针向前移动 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 字节，我们就能有效地<br />
在堆上预留 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 字节。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit HEAP 16 // 为四个单元格预留空间（假设单元格为 4 字节）<br />
&nbsp;&nbsp;&nbsp;&nbsp; // 注意 HEAP 指令也将辅助寄存器设置为我们预留内存的起始地址<br />
&nbsp;&nbsp;&nbsp;&nbsp; // ALT = HEA, HEA += 16<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit CONST.pri 50<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit STOR.I // 有效地将值 50 存储在我们预留的堆区域的第一个单元格中<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit HEAP -16 // 归还预留的内存<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 控制寄存器操作指令</h4><br />
可以使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LCTRL</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SCTRL</code> 指令直接读取和修改专用寄存器的内容。<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">助记符</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">操作数</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">LCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = 所选寄存器中包含的值；0=COD, 1=DAT, 2=HEA, 3=STP, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">SCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">所选寄存器 = PRI；2=HEA, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
</table>
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; new cod, dat;<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit LCTRL 0 // 将 COD 段寄存器的值存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit STOR.S.pri cod<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit LCTRL 1 // 将 DAT 段寄存器的值存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit STOR.S.pri dat<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; printf("%d %d", cod, dat);<br />
}</code></div></div><br />
当函数名用作操作数时，编译器会用函数的地址替换它。替换的地址是相对于 COD 寄存器的。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>f()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("f() was called.");<br />
}<br />
<br />
main ()<br />
{<br />
&nbsp;&nbsp; #emit PUSH.C 0 // 参数占用的字节数（稍后解释）<br />
&nbsp;&nbsp; #emit LCTRL 6 // 获取 CIP 的值，即下一条指令（本例中的 ADD.C）的地址<br />
&nbsp;&nbsp; #emit ADD.C 28 // 计算 'f' 之后要执行的指令的地址（注意每个操作码和操作数都需要一个单元格）<br />
&nbsp;&nbsp; #emit PUSH.pri // 推送返回地址，以便 'f' 知道返回到哪里（稍后解释）<br />
&nbsp;&nbsp; #emit CONST.pri f // 将函数 'f' 的地址存储在 pri 中<br />
&nbsp;&nbsp; #emit SCTRL 6 // 将当前指令指针设置为存储在主寄存器中的值<br />
<br />
&nbsp;&nbsp; // 函数 'f' 执行<br />
&nbsp;&nbsp; // 函数 'f' 返回后，下一条指令（本例中的 NOP）将开始执行<br />
<br />
&nbsp;&nbsp; #emit NOP // 不执行任何操作的指令<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 控制流指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit JUMP check // 跳转到 check 标签<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;not_equal:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("1 is not equal to 2");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;equal:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("1 is equal to 2");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;check:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit CONST.pri 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit CONST.alt 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit JEQ equal // 如果主寄存器的值等于辅助寄存器的值，则跳转到 'equal'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit JUMP not_equal // 如果执行到这里，意味着两个寄存器的值不相等；因此跳转到 'not_equal'<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> Switch case 指令</h4><br />
<br />
switch-case 块使用<a href="https://en.wikipedia.org/wiki/Branch_table" target="_blank" rel="noopener" class="mycode_url">分支表</a>实现。分支表仅仅是由 case 值及其对应的跳转地址组成的元组列表。对于给定的 case 值，AMX 会搜索分支表并跳转到相应的跳转地址。分支表中的记录按 case 值的升序排列。这允许 AMX 对分支表执行二分搜索，但它也可能执行线性搜索。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SWITCH</code> 指令标记 switch-case 块的开始。它接受一个指向分支表（也位于代码段中）的偏移量作为操作数。分支表正式以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CASETBL</code> 操作码（仅作为标记，功能上未使用）开始，后跟一系列 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CASE</code> 记录，每条记录占用两个参数。第一条 case 记录的参数具有特殊含义：第一个参数是分支表中的 case 数量，第二个参数是默认 case 的偏移量。如果没有提供默认 case，则第二个参数包含 switch-case 块之后指令的偏移量。其余的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CASE</code> 记录包含 case 值及其对应的跳转地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>switch(expression)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 2: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 4: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 3: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 7: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 5: {}<br />
}</code></div></div><br />
编译器会添加指令来计算给定的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">expression</code>，其结果存储在主寄存器中。紧接着是一条 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SWITCH</code> 指令，它使 AMX 搜索分支表，查找与主寄存器中存储的值匹配的 case 值。如果找到匹配项，则执行跳转到匹配记录指向的地址；否则，跳转到默认地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>; 编译器通过在汇编输出中使用标签而不是实际的偏移量/地址，使阅读更容易<br />
; 每个标签都以前缀 "l." 开头<br />
<br />
switch 0 ; 注意这里的零是一个标签<br />
<br />
l.2 ; 标签 2<br />
&nbsp;&nbsp; jump 1 ; 跳转到标签 1<br />
l.3<br />
&nbsp;&nbsp; jump 1<br />
l.4<br />
&nbsp;&nbsp; jump 1<br />
l.5<br />
&nbsp;&nbsp; jump 1<br />
l.6<br />
&nbsp;&nbsp; jump 1<br />
<br />
l.0<br />
&nbsp;&nbsp;casetbl <br />
&nbsp;&nbsp;case 5 1 ; 记录数量，默认跳转地址（本例中为标签 1）<br />
&nbsp;&nbsp; case 2 2 ; 真正的第一条记录<br />
&nbsp;&nbsp; case 3 4 ; case 值: 3, 跳转标签: 4<br />
&nbsp;&nbsp; case 4 3 ; 编译器在实际二进制文件中会用正确的地址替换标签<br />
&nbsp;&nbsp; case 5 6 ; <br />
&nbsp;&nbsp; case 7 5 ; 最后一条记录<br />
<br />
 l.1<br />
&nbsp;&nbsp; ; 其余代码</code></div></div>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> AMX 汇编</h2><br />
<br />
AMX 版本: 3.0<br />
<br />
AMX 文件版本: 8<br />
<br />
本文档是关于抽象机执行器（Abstract Machine eXecutor）汇编的<span style="font-style: italic;" class="mycode_i">非官方</span>文档。本文档的内容可能不准确且可能随时更改。<a href="http://#terminology" target="_blank" rel="noopener" class="mycode_url">术语部分</a>中定义的部分术语在官方手册中并未出现。它们是为了帮助读者理解而引入的辅助术语。<br />
<br />
本文档的目标读者是首次接触汇编语言的程序员。他们应根据需要点击超链接以收集背景信息。高级用户可跳过部分章节或将本文档用作快速参考指南。<br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 目录</h2><ul class="mycode_list"><li><a href="http://#prerequisites" target="_blank" rel="noopener" class="mycode_url">先决条件</a><br />
</li>
<li><a href="http://#terminology" target="_blank" rel="noopener" class="mycode_url">术语</a><br />
</li>
<li><a href="http://#term-amx" target="_blank" rel="noopener" class="mycode_url">抽象机执行器 (AMX)</a><br />
</li>
<li><a href="http://#term-amx-assembly" target="_blank" rel="noopener" class="mycode_url">AMX 汇编</a><br />
</li>
<li><a href="http://#term-amx-binary" target="_blank" rel="noopener" class="mycode_url">AMX 二进制</a><br />
</li>
<li><a href="http://#term-amx-instance" target="_blank" rel="noopener" class="mycode_url">AMX 实例</a><br />
</li>
<li><a href="http://#term-host-program" target="_blank" rel="noopener" class="mycode_url">宿主程序</a><br />
</li>
<li><a href="http://#term-extension-module" target="_blank" rel="noopener" class="mycode_url">扩展模块</a><br />
</li>
<li><a href="http://#basic-concepts" target="_blank" rel="noopener" class="mycode_url">基本概念</a><br />
</li>
<li><a href="http://#concept-cell" target="_blank" rel="noopener" class="mycode_url">单元格概念</a><br />
</li>
<li><a href="http://#concept-memory-addresses" target="_blank" rel="noopener" class="mycode_url">内存地址</a><br />
</li>
<li><a href="http://#concept-stack-heap" target="_blank" rel="noopener" class="mycode_url">栈与堆</a><br />
</li>
<li><a href="http://#concept-instructions" target="_blank" rel="noopener" class="mycode_url">指令</a><br />
</li>
<li><a href="http://#concept-spc-vna" target="_blank" rel="noopener" class="mycode_url">存储程序概念与冯·诺依曼体系结构</a><br />
</li>
<li><a href="http://#concept-hdc" target="_blank" rel="noopener" class="mycode_url">头、数据段、代码段</a><br />
</li>
<li><a href="http://#concept-registers" target="_blank" rel="noopener" class="mycode_url">寄存器</a><br />
</li>
<li><a href="http://#file-memory-layout" target="_blank" rel="noopener" class="mycode_url">文件与内存布局</a><br />
</li>
<li><a href="http://#instruction-set" target="_blank" rel="noopener" class="mycode_url">指令集</a><br />
</li>
<li><a href="http://#pawn-inline-assembly" target="_blank" rel="noopener" class="mycode_url">Pawn 内联汇编语法</a><br />
</li>
<li><a href="http://#instruction-table" target="_blank" rel="noopener" class="mycode_url">指令表</a><br />
</li>
<li><a href="http://#loadstore-instructions" target="_blank" rel="noopener" class="mycode_url">加载/存储指令</a><br />
</li>
<li><a href="http://#indexing-instructions" target="_blank" rel="noopener" class="mycode_url">索引指令</a><br />
</li>
<li><a href="http://#arithmetic-instructions" target="_blank" rel="noopener" class="mycode_url">算术指令</a><br />
</li>
<li><a href="http://#logical-instructions" target="_blank" rel="noopener" class="mycode_url">逻辑指令</a><br />
</li>
<li><a href="http://#relational-instructions" target="_blank" rel="noopener" class="mycode_url">关系指令</a><br />
</li>
<li><a href="http://#stack-manipulation-instructions" target="_blank" rel="noopener" class="mycode_url">栈操作指令</a><br />
</li>
<li><a href="http://#heap-instructions" target="_blank" rel="noopener" class="mycode_url">堆指令</a><br />
</li>
<li><a href="http://#control-register-manipulation-instructions" target="_blank" rel="noopener" class="mycode_url">控制寄存器操作指令</a><br />
</li>
<li><a href="http://#control-flow-instructions" target="_blank" rel="noopener" class="mycode_url">控制流指令</a><br />
</li>
<li><a href="http://#switch-case-instructions" target="_blank" rel="noopener" class="mycode_url">Switch-case 指令</a><br />
</li>
<li><a href="http://#call-stack-and-call-convention" target="_blank" rel="noopener" class="mycode_url">调用栈与调用约定</a><br />
</li>
<li><a href="http://#local-variables-and-function-frame" target="_blank" rel="noopener" class="mycode_url">局部变量与函数帧</a><br />
</li>
<li><a href="http://#call-convention" target="_blank" rel="noopener" class="mycode_url">调用约定</a><br />
</li>
<li><a href="http://#methods-passing-arguments" target="_blank" rel="noopener" class="mycode_url">参数传递方法</a><br />
</li>
<li><a href="http://#system-requests" target="_blank" rel="noopener" class="mycode_url">系统请求</a><br />
</li>
<li><a href="http://#multi-dimensional-arrays" target="_blank" rel="noopener" class="mycode_url">多维数组</a><br />
</li>
</ul>
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 先决条件</h2><ul class="mycode_list"><li>Pawn 脚本语言<br />
</li>
<li><a href="https://en.wikipedia.org/wiki/Binary_number" target="_blank" rel="noopener" class="mycode_url">二进制数制</a><br />
</li>
<li><a href="https://en.wikipedia.org/wiki/Hexadecimal" target="_blank" rel="noopener" class="mycode_url">十六进制数制</a><br />
</li>
<li>内存地址（理解<a href="https://en.wikipedia.org/wiki/Pointer_(computer_programming)" target="_blank" rel="noopener" class="mycode_url">指针</a>更佳）<br />
</li>
<li><a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)" target="_blank" rel="noopener" class="mycode_url">栈（作为抽象数据类型）</a><br />
</li>
</ul>
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 术语</h2><br />
&lt;a name="term-amx"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">抽象机执行器 (AMX)</span>：AMX 是我们感兴趣的<a href="https://en.wikipedia.org/wiki/Abstract_machine" target="_blank" rel="noopener" class="mycode_url">抽象机</a>（或<a href="https://en.wikipedia.org/wiki/Virtual_machine" target="_blank" rel="noopener" class="mycode_url">虚拟机</a>）。<br />
<br />
&lt;a name="term-amx-assembly"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">AMX 汇编</span>：AMX 的<a href="https://en.wikipedia.org/wiki/Assembly_language" target="_blank" rel="noopener" class="mycode_url">汇编语言</a>。<br />
<br />
&lt;a name="term-amx-binary"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">AMX 二进制</span>：AMX <a href="https://en.wikipedia.org/wiki/Executable" target="_blank" rel="noopener" class="mycode_url">二进制文件</a>是编译后生成的可执行文件（通常扩展名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code>）。<span style="font-style: italic;" class="mycode_i">术语 AMX 程序在某些上下文中可能指代 AMX 二进制文件。</span><br />
<br />
&lt;a name="term-amx-instance"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">AMX 实例</span>：每个加载的 AMX 二进制文件独立存在。加载后的程序称为 AMX 实例。<span style="font-style: italic;" class="mycode_i">术语 AMX 程序在某些上下文中可能指代 AMX 实例。</span><br />
<br />
&lt;a name="term-host-program"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">宿主程序</span>：嵌入 AMX 的程序称为宿主程序。以 <a href="http://sa-mp.com/" target="_blank" rel="noopener" class="mycode_url">San Andreas Multiplayer (SA-MP)</a> 或 <a href="https://open.mp/" target="_blank" rel="noopener" class="mycode_url">open.mp</a> 为例，服务器就是宿主程序。<br />
<br />
&lt;a name="term-extension-module"&gt;&lt;/a&gt;<span style="font-weight: bold;" class="mycode_b">扩展模块</span>：扩展模块是一个独立的模块，通常动态链接到宿主程序，提供额外的原生函数。扩展模块通常被称为插件。<br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 基本概念</h2><br />
<ul class="mycode_list"><li>## &lt;a name="concept-cell"&gt;&lt;/a&gt; 单元格概念<br />
</li>
</ul>
<br />
Pawn 是一种无类型语言：没有数据类型。所有数据都作为原始二进制数据存储在一个单元格或一组单元格中。我们将使用<a href="https://en.wikipedia.org/wiki/Two%27s_complement" target="_blank" rel="noopener" class="mycode_url">有符号二进制补码表示法</a>来传达一个或多个单元格的内容，而不是显式地用二进制写出来。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a = 5, b = 'A';</code></div></div><br />
上述代码创建了两个独立的单元格，分别由 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code> 标识。单元格 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code> 将包含值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">5</code>，单元格 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code> 将包含值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">65</code>（字符 'A' 的 <a href="https://en.wikipedia.org/wiki/ASCII" target="_blank" rel="noopener" class="mycode_url">ASCII</a> 等效值）。<br />
<br />
为了弥补数据类型的缺失，Pawn 提供了为单元格添加标签的能力。这些标签仅仅是编译时的辅助工具，不会直接&lt;sup&gt;<a href="http://#bc-cc-note-1" target="_blank" rel="noopener" class="mycode_url">1</a>&lt;/sup&gt;出现在 AMX 二进制文件中。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float:x = 5.0, Float:y = 10.0, Float:z;<br />
&nbsp;&nbsp;z = x + y;</code></div></div><br />
上述代码创建了三个带有标签的单元格，由 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 标识。它们分别被初始化为值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">5.0</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">10.0</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0.0</code>（默认初始化为二进制零，也是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0.0</code>），其二进制表示符合<a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic#Internal_representation" target="_blank" rel="noopener" class="mycode_url">浮点数的正确表示</a>。编译器会记住遇到的变量的标签，并确保在变量被使用时生成正确的代码 &lt;sup&gt;<a href="http://#bc-cc-note-2" target="_blank" rel="noopener" class="mycode_url">2</a>&lt;/sup&gt;。在上述例子中，编译器在处理第二行时，会生成正确的代码来执行两个浮点数 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的加法。请记住，整数加法和浮点数加法的执行方式不同。编译器使用与单元格关联的标签来确定应对操作数执行哪种加法操作。<br />
<br />
编译完成后，变量的标签信息会丢失。生成的 AMX 二进制文件将包含对 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 中存储的数据执行浮点数加法并将结果存储在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 中的指令。<br />
在运行时，浮点数加法会在不考虑脚本中 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的标签原本是否为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 的情况下执行。<br />
<br />
&lt;a name="bc-cc-note-1"&gt;&lt;/a&gt; [[1]](#bc-cc-note-1) <span style="font-style: italic;" class="mycode_i">Pawn 语言提供了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">tagof</code> 运算符，它返回与标签关联的编译时 id，该 id 可以被存储。编译器还会在 AMX 二进制文件的标签表中创建一个公开可访问的标签列表。</span><br />
<br />
&lt;a name="bc-cc-note-2"&gt;&lt;/a&gt; [[2]](#bc-cc-note-2) <span style="font-style: italic;" class="mycode_i">Pawn 语言允许基于标签的运算符重载。编译器知道所有存在的运算符重载，并根据操作数的标签调用正确的重载。如果给定的操作数没有重载存在，编译器将默认使用无标签单元格的运算符（即整数算术）。</span><br />
<ul class="mycode_list"><li>## &lt;a name="concept-memory-addresses"&gt;&lt;/a&gt; 内存地址<br />
</li>
</ul>
AMX 遵循平坦的字节可寻址内存模型，即 AMX 内存可以被认为是一个线性的字节集合<br />
（<a href="https://en.wikipedia.org/wiki/Flat_memory_model" target="_blank" rel="noopener" class="mycode_url">平坦内存</a>），每个字节都有一个唯一的地址（<a href="https://en.wikipedia.org/wiki/Byte_addressing" target="_blank" rel="noopener" class="mycode_url">字节可寻址</a>）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a[5];</code></div></div><br />
上述代码创建了一个由五个单元格组成的数组，由 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code> 标识。这些单元格连续存储，即一个接一个地存储。假设单元格大小为 4 字节，如果存储 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a[0]</code> 的位置地址是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1000</code>，那么存储 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a[1]</code> 的位置地址将是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1004</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>data:&nbsp;&nbsp;&nbsp;&nbsp;a[0] | a[1] | a[2] | a[3] | a[4]<br />
&nbsp;&nbsp;address: 1000&nbsp;&nbsp; 1004&nbsp;&nbsp; 1008&nbsp;&nbsp; 1012&nbsp;&nbsp; 1016</code></div></div><br />
<span style="font-style: italic;" class="mycode_i">所需知识</span>：<a href="https://en.wikipedia.org/wiki/Base_address" target="_blank" rel="noopener" class="mycode_url">基地址</a>，<a href="https://en.wikipedia.org/wiki/Offset_(computer_science)" target="_blank" rel="noopener" class="mycode_url">相对地址</a><br />
<br />
<span style="font-style: italic;" class="mycode_i">所需知识</span>：<a href="https://en.wikipedia.org/wiki/Array_data_structure#Element_identifier_and_addressing_formulas" target="_blank" rel="noopener" class="mycode_url">数组数据结构，元素标识符和寻址公式</a><br />
<br />
<span style="font-style: italic;" class="mycode_i">另请参阅</span>：<a href="https://en.wikipedia.org/wiki/Endianness" target="_blank" rel="noopener" class="mycode_url">字节序</a><br />
<ul class="mycode_list"><li>## &lt;a name="concept-stack-heap"&gt;&lt;/a&gt; 栈和堆<br />
</li>
</ul>
每个 AMX 实例都包含一个<span style="font-style: italic;" class="mycode_i">内部</span> <a href="https://en.wikipedia.org/wiki/Call_stack" target="_blank" rel="noopener" class="mycode_url">程序栈</a>（也称为调用栈）和<a href="https://en.wikipedia.org/wiki/Memory_management#HEAP" target="_blank" rel="noopener" class="mycode_url">程序堆</a>。这些是 AMX 程序中的内存区域，专用于一组任务。<br />
<br />
栈负责：<ul class="mycode_list"><li>存储局部变量<br />
</li>
<li>存储函数参数<br />
</li>
<li>存储函数调用信息（例如参数个数）<br />
</li>
<li>提供临时存储<br />
</li>
</ul>
<br />
堆负责：<ul class="mycode_list"><li>为动态分配提供内存<br />
</li>
<li>存储作为引用/数组传递的默认参数<br />
</li>
<li>存储不是<a href="https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue" target="_blank" rel="noopener" class="mycode_url">左值</a>且作为可变参数传递的常量和表达式<br />
</li>
</ul>
<br />
###<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>f(argc, ...) { }<br />
&nbsp;&nbsp;main () <br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new a, b, c[100];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f(1, 25);<br />
&nbsp;&nbsp;}</code></div></div><br />
在上面的代码片段中，变量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">c</code> 和常量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code> 在栈上分配空间。常量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">25</code> 在堆上分配空间。引用和可变参数作为地址传递给函数。由于字面量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">25</code> 是一个常量且没有地址，因此在堆上分配了一个临时单元格来存储值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">25</code>。该单元格的地址被传递给函数。<br />
<ul class="mycode_list"><li>## &lt;a name="concept-instructions"&gt;&lt;/a&gt; 指令<br />
</li>
</ul>
<br />
<a href="https://en.wikipedia.org/wiki/Instruction_set_architecture#Instructions" target="_blank" rel="noopener" class="mycode_url">指令</a>是离散的原子执行单元。大多数指令执行简单的任务，如基本算术。高级结构（如循环和条件语句）可以简化为一系列简单的指令。<br />
<br />
例如，将值压入调用栈然后弹出的指令可能是：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>push 100<br />
&nbsp;&nbsp;pop</code></div></div><br />
<a href="https://en.wikipedia.org/wiki/Assembly_language#Assembler" target="_blank" rel="noopener" class="mycode_url">汇编器</a>为上述代码片段生成的二进制代码可能是：<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">push-opcode | 100 | pop-opcode</code><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0x0013 0x0064 0x0014</code> 或者可能是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0000 0000 0000 0000 0000 0000 0001 0011 0000 0000 0000 0000 0000 0000 0110 0100 0000 0000 0000 0000 0000 0000 0001 0100</code><br />
<br />
是的，它只是一系列比特位，CPU（或者在我们这里是抽象机）知道如何解释这些比特位。当为物理硬件上的执行汇编时，这种表示被称为<a href="https://en.wikipedia.org/wiki/Machine_code" target="_blank" rel="noopener" class="mycode_url">机器码（或原生码）</a>。在为假想 CPU（如 AMX）上的执行汇编时，这种表示被称为 <a href="https://en.wikipedia.org/wiki/P-code_machine" target="_blank" rel="noopener" class="mycode_url">p-code</a>。<br />
<br />
<span style="font-style: italic;" class="mycode_i">另请参阅：</span> <a href="https://en.wikipedia.org/wiki/Bytecode" target="_blank" rel="noopener" class="mycode_url">字节码</a><br />
<ul class="mycode_list"><li>## &lt;a name="concept-spc-vna"&gt;&lt;/a&gt; 存储程序概念与冯·诺依曼体系结构<br />
</li>
</ul>
<br />
代码像数据一样驻留在内存中的想法被称为<a href="https://en.wikipedia.org/wiki/Stored-program_computer" target="_blank" rel="noopener" class="mycode_url">存储程序概念</a>。这也意味着内存中的每条指令都有一个地址，就像数据一样。代码和数据都驻留在<span style="font-weight: bold;" class="mycode_b">同一内存</span>中的想法是<a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture" target="_blank" rel="noopener" class="mycode_url">冯·诺依曼体系结构</a>的一个原则。这也意味着所有代码和数据共享一个<a href="https://en.wikipedia.org/wiki/Address_space" target="_blank" rel="noopener" class="mycode_url">地址空间</a>。<br />
<br />
AMX 使用一个公共内存来存储代码和数据。<br />
<ul class="mycode_list"><li>## &lt;a name="concept-hdc"&gt;&lt;/a&gt; 头、数据段、代码段<br />
</li>
</ul>
<br />
可执行二进制文件及程序的内存结构根据其包含的内容被划分为逻辑上不同的区域。一个典型的二进制可执行文件至少包含一个头、一个代码段和一个数据段。头提供了程序本身的信息，例如<a href="https://en.wikipedia.org/wiki/Entry_point" target="_blank" rel="noopener" class="mycode_url">程序入口点</a>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>HEADER<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; DATA</code></div></div><br />
代码段以二进制形式（机器码/p-code）存储代码，而数据段存储数据，如全局变量和静态局部变量。<br />
<br />
程序的内存结构通常不同。除了代码段和数据段外，它通常还包含程序栈和程序堆的区域。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>HEADER<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; DATA<br />
&nbsp;&nbsp;-------<br />
&nbsp;&nbsp; HEAP<br />
&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp; STACK</code></div></div><br />
AMX 二进制文件组织为三个部分：前缀、代码和数据（按顺序）。前缀部分包含有关 AMX 二进制文件的信息，例如代码和数据部分在二进制文件中的起始偏移量。代码部分存储 p-code，数据段存储全局变量和静态局部变量。<br />
<br />
堆栈区域是在 AMX 二进制文件加载到内存后，使用前缀部分中的信息创建的。<br />
<br />
<span style="font-style: italic;" class="mycode_i">另请参阅</span>：<a href="https://en.wikipedia.org/wiki/Memory_segmentation" target="_blank" rel="noopener" class="mycode_url">内存分段</a>，<a href="https://en.wikipedia.org/wiki/Data_segment" target="_blank" rel="noopener" class="mycode_url">数据段</a>，<a href="https://en.wikipedia.org/wiki/Code_segment" target="_blank" rel="noopener" class="mycode_url">代码段</a>，<a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format" target="_blank" rel="noopener" class="mycode_url">ELF 格式</a><br />
<ul class="mycode_list"><li>## &lt;a name="concept-registers"&gt;&lt;/a&gt; 寄存器<br />
</li>
</ul>
了解处理器和内存位于不同的位置至关重要。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>|-------|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|------------------|<br />
&nbsp;&nbsp;|&nbsp;&nbsp;CPU&nbsp;&nbsp;|&nbsp;&nbsp;=============== |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MEMORY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;|-------|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |------------------|</code></div></div><br />
内存存储数据，CPU 对数据进行操作。对于每次操作，处理器都必须将操作数从内存中取出并临时存储在 CPU 内部。这些临时存储位置被称为<a href="https://en.wikipedia.org/wiki/Processor_register" target="_blank" rel="noopener" class="mycode_url">寄存器</a>。这些寄存器可以容纳少量数据，范围在几个字节（通常为 2、4 或 8 字节）。<br />
<br />
假设处理器必须将两个变量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 相加，并将结果存储在变量 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 中。一个典型的处理器会执行以下操作：<br />
<ol type="1" class="mycode_list"><li>从内存中取出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 的值（即从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 的地址读取）并将其存储在一个寄存器中，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R1</code><br />
</li>
<li>从内存中取出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的值（即从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">y</code> 的地址读取）并将其存储在一个寄存器中，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R2</code><br />
</li>
<li>将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R1</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R2</code> 的内容相加，并将结果存储在某寄存器中，比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R3</code><br />
</li>
<li>将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">R3</code> 的内容存储到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 中（写入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">z</code> 的地址）<br />
</li>
</ol>
<br />
处理器包含不同<a href="https://en.wikipedia.org/wiki/Processor_register#Categories_of_registers" target="_blank" rel="noopener" class="mycode_url">类型的寄存器</a>，用于不同目的。一些寄存器专用于特定任务，一些寄存器可用于任何目的。上例中使用的那类寄存器属于通用寄存器。<br />
<br />
AMX 的寄存器集包括以下寄存器：<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">主寄存器 (PRI)</span>：通用寄存器（常用作<a href="https://en.wikipedia.org/wiki/Accumulator_(computing)" target="_blank" rel="noopener" class="mycode_url">累加器寄存器</a>）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">辅助寄存器 (ALT)</span>：通用寄存器（常用作地址寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">代码段寄存器 (COD)</span>：内存中代码段起始的绝对地址<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">数据段寄存器 (DAT)</span>：内存中数据段起始的绝对地址<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">当前指令指针 (CIP)</span>：下一条<span style="font-style: italic;" class="mycode_i">要执行指令</span>的地址（相对于 COD 寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">栈顶寄存器 (STP)</span>：栈顶的地址（相对于 DAT 寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">栈指针寄存器 (STK)</span>：栈上当前位置的地址（相对于 DAT 寄存器）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">帧指针寄存器 (FRM)</span>：栈中当前函数帧起始的地址（相对于 DAT 寄存器）（<span style="font-style: italic;" class="mycode_i">稍后解释</span>）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">堆指针 (HEA)</span>：堆顶的地址（相对于 DAT 寄存器）<br />
</li>
</ul>
<br />
在编写汇编代码时，地址通常不是绝对的；它们是相对于某个段或帧指针寄存器的。全局变量和字符串的地址相对于 DAT 寄存器。函数、指令和标签的地址相对于 COD 寄存器。这意味着变量或指令的绝对地址分别是相对地址加上 DAT 或 COD 寄存器的值。局部变量的地址相对于帧指针寄存器。这有点复杂，稍后会解释。<br />
<br />
<span style="font-style: italic;" class="mycode_i">从现在开始，当我们讨论代码地址和数据地址时，除非明确说明，否则暗示这些地址分别相对于 COD 寄存器和 DAT 寄存器。</span><br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 文件与内存布局</h2><br />
所有非调试 AMX 二进制文件按如下方式组织：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>START OF BINARY FILE<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PREFIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATA<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
END OF BINARY FILE</code></div></div><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">前缀</span>：包含程序的基本信息<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">代码</span>：包含代码<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">数据</span>：包含数据<br />
</li>
</ul>
<br />
<span style="font-style: italic;" class="mycode_i">注意：根据编译器的选项，前缀部分可能会被<a href="https://en.wikipedia.org/wiki/Data_structure_alignment" target="_blank" rel="noopener" class="mycode_url">填充</a>以使代码和数据部分对齐。</span><br />
<br />
<span style="font-style: italic;" class="mycode_i">注意：启用调试编译的脚本的二进制映像将在末尾附加符号调试信息。更多详情请参阅 Pawn 实现者指南。</span><br />
<br />
内存中的结构采用与二进制文件类似的结构，但额外包含一个栈和一个堆，这是使用前缀中的信息设置的。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>LOW ADDRESS (0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PREFIX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CODE<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATA<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HEAP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FREE SPACE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STACK<br />
&nbsp;&nbsp;&nbsp;&nbsp;| ---------------------- |<br />
HIGH ADDRESS</code></div></div><br />
堆和栈共享一个公共的内存区域。它们从该区域的两端开始，并向相反方向增长。堆向高地址增长，栈向低地址增长。由于它们共享同一内存区域，因此可能会相互覆盖（当堆指针和栈指针碰撞时）。发生这种情况时，AMX 会中止并显示如下错误信息：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Script[gamemodes/TEST.amx]: Run time error 3: "Stack/heap collision (insufficient stack size)"</code></div></div><br />
根据编译器掌握的信息，它会估算并间接地在 AMX 二进制文件的前缀部分设置堆栈大小。然而，程序员可以使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma dynamic [estimated number of cells]</code> 指令提供自己对所需堆栈区域大小的估计。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">前缀部分的字段</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">类型</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">大小</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">size</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">内存映像的大小；不包括栈和堆</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">magic</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">指示格式和单元格大小</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">file version</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">格式版本</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">amx version</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">抽象机所需的最低版本</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">flags</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">是否存在符号调试信息、紧凑编码等。</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">defsize</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">表中记录的大小</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">cod</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">代码部分起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">dat</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">数据部分起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">hea</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">HEA 寄存器的初始值（标记数据段结束）</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">stp</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STP 寄存器的初始值（指示总内存需求）</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">cip</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CIP 寄存器的初始值（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code> 函数的地址；如果不存在则为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">-1</code>）</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">publics</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共函数表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">natives</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">原生函数表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">libraries</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">库表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">pubvars</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共变量表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">tags</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">标签表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">name table</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">名称表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">overlays</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">覆盖表起始的偏移量</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">publics</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共函数列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">natives</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">原生函数列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">libraries</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">库列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">pubvars</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共变量列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">tags</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">公共标签列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">overlays</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">覆盖列表</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">name table</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">可变</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">符号名称列表</td>
 </tr>
</table>
<br />
<span style="font-style: italic;" class="mycode_i">注意：关于 magic、version 和 flags 字段中信息如何编码的详细信息，请参阅 Pawn 实现者指南。</span><br />
<br />
<span style="font-style: italic;" class="mycode_i">注意：前缀中的所有多字节字段都以<a href="https://en.wikipedia.org/wiki/Endianness" target="_blank" rel="noopener" class="mycode_url">小端格式</a>存储，无论 AMX 二进制文件是在哪个平台上生成或将在哪个平台上执行。</span><br />
<br />
可以看出，前缀由一个固定部分组成，后面跟着一系列表。除了名称表之外，表中的每条记录都由两个字段组成，如下所示：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">字段</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">大小</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">变量</span></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">单元格大小</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-style: italic;" class="mycode_i">变量</span></td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">名称字符串偏移量</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">4 字节</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">从前缀起始到名称表中字符串的偏移量</td>
 </tr>
</table>
<br />
表中每条记录（除了名称表）的大小由前缀中的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">defsize</code> 字段给出：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">defsize</code> = 4 + 单元格大小。<br />
<br />
表中的每条记录都被分配了一个索引号。每个表的第一个记录被分配索引 0，后续记录的索引号是前一个记录索引加 1。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">名称表</span>：<br />
除了名称表本身之外，其他表中的记录包含一个指向字符串的指针。这些字符串作为以空字符结尾的 C 字符串存储在名称表中。此表中记录的大小是其包含的字符串的大小。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">公共函数表</span>：<br />
为脚本中定义的每个公共函数创建一条记录。这些记录包含公共函数的地址（函数第一条指令的地址）和指向相应公共函数名称的偏移量。表中记录的索引就是相应公共函数的索引。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">原生函数表</span>：<br />
为脚本中调用的每个原生函数创建一条记录。记录的第一个字段由编译器在二进制文件中设置为 0，但宿主程序在加载二进制文件时会将该字段初始化为函数的地址（位于宿主程序的地址空间中）。第二个字段包含指向原生函数名称的偏移量。表中记录的索引就是相应原生函数的索引。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">库表</span>：<br />
Pawn 语言提供了一个 pragma 指令 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma directive [library name]</code>，用于告知编译器调用的某些原生函数需要扩展模块。对于在脚本中调用了其原生函数的库，会在库表中创建一条记录。目的是告知宿主程序 AMX 程序依赖于一个扩展模块。记录的第一个字段供内部使用，在 AMX 二进制文件中设置为 0。另一个字段包含从前缀起始到名称表中库名称的偏移量。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">公共变量表</span>：<br />
为脚本中声明的每个公共变量创建一条记录。该记录包含公共变量的地址和指向公共变量名称的偏移量。表中记录的索引就是公共变量的索引。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">标签表</span>：<br />
与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sleep</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">exit</code> 语句一起使用的标签以及与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">tagof</code> 运算符一起使用的标签会被导出。为每个这样的标签创建一条记录。第一个字段包含标签 id 号，第二个字段存储指向标签名称的偏移量。<br />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;"> 指令集</h2><br />
<br />
&lt;a name="pawn-inline-assembly"&gt;&lt;/a&gt; Pawn 编译器接受的大部分 AMX 汇编指令可以用以下格式表示：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>mnemonic[.prefix][.register suffix] operand<br />
<br />
SHL.C.pri 3<br />
ZERO.alt<br />
ADD.C 100<br />
LIDX</code></div></div><br />
助记符给出了指令功能的提示。可选的前缀指示指令操作数的类型。可选的尾缀指示指令主要作用于哪个寄存器。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">前缀列表</span>：<ul class="mycode_list"><li>.C = 常量<br />
</li>
<li>.S = 栈<br />
</li>
<li>.I = 间接寻址<br />
</li>
<li>.B = 无 B 变体的变体&lt;sup&gt;\[需要更好的描述\]&lt;/sup&gt;<br />
</li>
<li>.ADR = 地址<br />
</li>
<li>.R = 重复<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">寄存器尾缀列表</span>：<ul class="mycode_list"><li>.pri = 主寄存器<br />
</li>
<li>.alt = 辅助寄存器<br />
</li>
</ul>
<br />
每条指令的二进制形式需要一个单元格来存储操作码，每个操作数还需要一个额外的单元格。绝大多数指令使用隐含寄存器作为操作数。这减少了所需显式操作数的数量，从而减小了代码段的大小并提高了性能。<br />
<br />
&lt;a name="instruction-table"&gt;&lt;/a&gt; <span style="font-style: italic;" class="mycode_i">阅读表格：</span><br />
<ol type="1" class="mycode_list"><li><span style="font-style: italic;" class="mycode_i">[address] 指的是存储在位置 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DAT + address</code> 的值</span><br />
</li>
<li><span style="font-style: italic;" class="mycode_i">语义列中使用的运算符执行与 Pawn 中相同的操作</span><br />
</li>
</ol>
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">操作码</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">助记符</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">操作数</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">语义</th>
 </tr>
</table>
 <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">1</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">LOAD.pri</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">address</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">PRI = [address]</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LOAD.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [address]</td>
 </tr>
</table>
   <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">3</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">LOAD.S.pri</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">offset</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">PRI = [FRM + offset]</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LOAD.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [FRM + offset]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">5</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [[address]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">6</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [[address]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">7</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.S.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [[FRM + offset]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">8</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LREF.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [[FRM + offset]]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">9</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LOAD.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [PRI]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">10</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LODB.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = 'number' of bytes from [PRI] (read 1/2/4 bytes)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">11</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CONST.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">12</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CONST.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">13</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADDR.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = FRM + offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADDR.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = FRM + offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">15</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">16</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">17</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.S.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">18</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">19</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[address]] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">20</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[address]] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">21</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.S.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[FRM + offset]] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">22</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SREF.S.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[[FRM + offset]] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">23</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STOR.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[ALT] = PRI (full cell)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">24</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STRB.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number of bytes at [ALT] = PRI (store 1/2/4 bytes)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">25</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LIDX</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [ALT + (PRI x cell size)]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">26</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LIDX.B</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">shift</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [ALT + (PRI &lt;&lt; shift)]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">27</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">IDXADDR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT + (PRI x cell size) (calculate indexed address)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">28</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">IDXADDR.B</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">shift</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT + (PRI &lt;&lt; shift) (calculate indexed address)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">29</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALIGN.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">Little Endian: PRI ^= cell size - number</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">30</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALIGN.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">Little Endian: ALT ^= cell size - number</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">31</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = value contained in the selected register; 1=COD, 1=DAT, 2=HEA,3=STP, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">32</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">selected register = PRI; 2=HEA, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">33</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">MOVE.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">34</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">MOVE.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">35</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">XCHG</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">Exchange contents of PRI and ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">36</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">37</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">38</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.R</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">repeat (STK = STK - cell size, [STK] = PRI) 'number' times</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">39</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = value</td>
 </tr>
</table>
  <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">40</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">PUSH</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">address</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">STK = STK - cell size, [STK] = [address]</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">41</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = [FRM + offset]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">42</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">POP.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = [STK], STK = STK + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">43</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">POP.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = [STK], STK = STK + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">44</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STACK</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = STK, STK = STK + value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">45</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">HEAP</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = HEA, HEA = HEA + value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">46</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PROC</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = FRM, FRM = STK</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">47</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">RET</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">FRM = [STK], STK = STK + cell size, CIP = [STK], STK = STK + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">48</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">RETN</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">FRM = [STK], STK = STK + cell size, CIP = [STK], STK = STK + cell size, STK = STK + [STK] + cell size</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">49</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CALL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK − cell size, [STK] = CIP, CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">50</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CALL.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK − cell size, [STK] = CIP, CIP = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">51</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JUMP</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">53</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JZER</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI == 0 then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">54</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JNZ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI != 0 then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">55</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI == ALT then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">56</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JNEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI != ALT then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">57</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JLESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &lt; ALT (unsigned) then CIP = offset</td>
 </tr>
</table>
 <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">58</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">JLEQ</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">offset</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">if PRI &lt;= ALT (unsigned)  then CIP = offset</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">59</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JGRTR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &gt; ALT (unsigned) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">60</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JGEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &gt;= ALT (unsigned) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">61</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JSLESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &lt; ALT (signed) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">62</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JSLEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &lt;= ALT (signed) then CIP = offset</td>
 </tr>
</table>
 <br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">63</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">JSGRTR</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">offset</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">if PRI &gt; ALT (signed) then CIP = offset</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">64</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JSGEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">if PRI &gt;= ALT (signed) then CIP = offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">65</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;&lt; ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">66</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;&gt; ALT (without sign extension)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">67</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SSHR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;&gt; ALT (with sign extension)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">68</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHL.C.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;&lt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">69</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHL.C.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT &lt;&lt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">70</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHR.C.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;&gt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">71</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SHR.C.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT &gt;&gt; value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">72</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SMUL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI * ALT (signed multiply)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">73</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SDIV</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI / ALT (signed divide), ALT = PRI mod ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">74</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SDIV.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT / PRI (signed divide), ALT = ALT mod PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">75</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">UMUL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI * ALT (unsigned multiply)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">76</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">UDIV</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI / ALT (unsigned divide), ALT = PRI mod ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">77</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">UDIV.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT / PRI (unsigned divide), ALT = ALT mod PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">78</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADD</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI + ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">79</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SUB</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI - ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">80</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SUB.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT - PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">81</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">AND</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &amp; ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">82</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">OR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &#124; ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">83</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">XOR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI ^ ALT</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">84</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NOT</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = !PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">85</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NEG</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = -PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">86</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INVERT</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ~PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">87</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ADD.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI + value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">88</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SMUL.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI * value</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">89</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">90</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">91</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">92</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ZERO.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">93</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SIGN.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">sign extend the byte in PRI to a cell</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">94</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SIGN.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">sign extend the byte in ALT to a cell</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">95</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">EQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI == ALT ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">96</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI != ALT ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">97</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt; ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">98</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">LEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;= ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">99</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">GRTR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt; ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">100</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">GEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;= ALT ? 1 : 0 (unsigned)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">101</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SLESS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt; ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">102</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SLEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &lt;= ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">103</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SGRTR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt; ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">104</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SGEQ</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI &gt;= ALT ? 1 : 0 (signed)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">105</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">EQ.C.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI == value ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">106</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">EQ.C.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = ALT == value ? 1 : 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">107</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">108</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">109</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = [address] + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">110</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = [FRM + offset] + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">111</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">INC.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[PRI] = [PRI] + 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">112</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = PRI - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">113</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">ALT = ALT - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">114</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">address</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[address] = [address] - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">115</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.S</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[FRM + offset] = [FRM + offset] - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">116</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">DEC.I</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[PRI] = [PRI] - 1</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">117</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">MOVS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">copy 'number' bytes of non-overlapping memory from [PRI] to [ALT]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">118</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CMPS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">compare 'number' bytes of non-overlapping memory at [PRI] with [ALT]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">119</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">FILL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">number</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">fill 'number' bytes of memory from [ALT] with value in PRI (number must be multiple of cell size)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">120</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">HALT</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">0</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">abort execution (exit value in PRI)</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">121</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">BOUNDS</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">abort execution if PRI &gt; value or if PRI &lt; 0</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">122</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SYSREQ.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">call system service, service number in PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">123</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SYSREQ.C</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">value</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">call system service</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">128</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">JUMP.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CIP = PRI</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">129</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SWITCH</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">compare PRI to the values in the case table (whose address is passed in the 'offset' argument) and jump to the associated address in the matching record</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">130</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">CASETBL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">...</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">a variable number of case records follows this opcode, where each record takes two cells</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">131</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SWAP.pri</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[STK] = PRI, PRI = [STK]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">132</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">SWAP.alt</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">[STK] = ALT, ALT = [STK]</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">133</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PUSH.ADR</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">offset</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">STK = STK - cell size, [STK] = FRM + offset</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">134</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">NOP</td>
 <td style="border:1px solid #ddd;padding:6px 10px;"></td>
 <td style="border:1px solid #ddd;padding:6px 10px;">no operation</td>
 </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 加载/存储指令</h4><br />
<br />
当使用全局变量作为操作数时，编译器会替换该变量的地址。下面代码中的第一条加载指令，如果 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">some_global</code> 的地址是 1288，则实际上变成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#emit LOAD.pri 1288</code>。请注意，编译器替换的地址是从数据段起始的偏移量；因此，该地址是相对于 DAT 寄存器的。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new some_global = 10, another_global = 25;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.pri some_global // 将 'some_global' 的值加载到主寄存器<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.alt another_global&nbsp;&nbsp;// 将 'another_global' 的值加载到辅助寄存器<br />
}</code></div></div><br />
当使用局部变量时，编译器会替换从函数帧起始的偏移量。<span style="font-style: italic;" class="mycode_i">(稍后解释)</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;static s_local = 20; // 静态局部变量存储在数据段中<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new some_local = 10, another_local = 25; // 局部变量存储在栈中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.S.pri some_local // 将 'some_local' 的值加载到主寄存器<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.S.alt another_local&nbsp;&nbsp;// 将 'another_local' 的值加载到辅助寄存器<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LOAD.pri s_local // 注意静态局部变量的行为类似于全局变量<br />
}</code></div></div><br />
由于编译器会为全局变量替换地址，因此可以使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CONST.pri/CONST.alt</code> 来获取这些变量的地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new some_global;<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 10 // 将 10 放入主寄存器<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 50 // 将 50 放入辅助寄存器<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri some_global // 将 'some_global' 的地址存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt some_global // 将 'some_global' 的地址存储在辅助寄存器中<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new some_global;<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new some_local;<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ZERO.pri // 将零存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.pri some_global // 将主寄存器中存储的值（本例中为零）设置给 'some_global'<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 125<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.S.alt some_local // 将辅助寄存器中存储的值（125）设置给 'some_local'<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 索引指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new global_arr[10];<br />
main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt global_arr // 将 'global_arr' 的地址（'global_arr' 第一个元素的地址）加载到辅助寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 2 // 设置我们感兴趣的 'global_arr' 元素的索引<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LIDX // 现在主寄存器中存储的是 'global_arr[2]` 处存储的值<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt global_arr // 将 'global_arr' 的地址（第一个元素的地址）加载到辅助寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 2 // 设置我们感兴趣的 'global_arr' 元素的索引<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit IDXADDR // 现在主寄存器中存储的是 'global_arr[2]` 的地址<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 算术指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 4<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 5<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit SMUL // 现在主寄存器中是 20（SMUL 执行有符号乘法；UMUL 执行无符号乘法）<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADD // 将 5 加到 20（由于上一条指令，主寄存器中存储的是 20）<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADD.C 10 // 将 10 加到主寄存器；现在主寄存器中是 35<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit SUB.alt // 用 5 减去 35；现在主寄存器中是 -30<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit SMUL.C 2 // -30 乘以 2；得到 -60<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 逻辑指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 5 // .. 0000 0101<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 3 // ... 0000 0011<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit AND // 主寄存器现在包含 ... 0000 0001<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit XOR // 主寄存器现在包含 ... 0000 0110<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit INVERT // 对主寄存器中存储的值取反码<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit NEG // 对主寄存器中存储的值取补码（本质上是取负）<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">关系指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 5<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.alt 8<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit EQ // 如果 5 == 8，则将主寄存器设置为 1，否则为 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LESS // 如果 0 &lt; 8，则将主寄存器设置为 1，否则为 0<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 栈操作指令</h4><br />
<br />
局部变量存储在栈上。详细说明将在后续章节中提供，但现在我们假设使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CONST.pri some_local</code> 会得到某个偏移量，该偏移量加上帧寄存器中存储的基地址即得数据地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new some_local = 25;<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADDR.alt some_local // 计算 'some_local' 的地址<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 100<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.I // 将 100 存储到 'some_local'<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 100<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit STOR.S.pri some_local // 实现上述代码功能的更好方法<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri some_local // 神秘地等价于 CONST.pri -4（稍后解释）<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit PUSH.C 100 // 将值 100 压入调用栈<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit POP.pri // 从栈中弹出一个值并将结果存储在主寄存器中<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit PUSH.pri // 推送主寄存器的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit PUSH.alt // 推送辅助寄存器的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit POP.pri<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit POP.alt // 最后 4 条指令有效地交换了主寄存器和辅助寄存器的内容<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit XCHG // 交换主寄存器和辅助寄存器内容的更好方法<br />
}</code></div></div><br />
局部数组位于栈上。因此，在使用索引指令之前，必须使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ADDR.alt/ADDR.pri</code> 来获取完整的地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new local_array[10];<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit ADDR.alt local_array // 加载存储在 'local_array' 中的值，即数组的地址<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit CONST.pri 5<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit LIDX // 有效地将 'local_array[5]' 的值存储在主寄存器中<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 堆指令</h4><br />
堆指针（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">HEA</code> 寄存器）指向堆的顶部。将堆指针向前移动 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 字节，我们就能有效地<br />
在堆上预留 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">x</code> 字节。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit HEAP 16 // 为四个单元格预留空间（假设单元格为 4 字节）<br />
&nbsp;&nbsp;&nbsp;&nbsp; // 注意 HEAP 指令也将辅助寄存器设置为我们预留内存的起始地址<br />
&nbsp;&nbsp;&nbsp;&nbsp; // ALT = HEA, HEA += 16<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit CONST.pri 50<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit STOR.I // 有效地将值 50 存储在我们预留的堆区域的第一个单元格中<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit HEAP -16 // 归还预留的内存<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 控制寄存器操作指令</h4><br />
可以使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LCTRL</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SCTRL</code> 指令直接读取和修改专用寄存器的内容。<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
 <tr>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">助记符</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">操作数</th>
 <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">LCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">PRI = 所选寄存器中包含的值；0=COD, 1=DAT, 2=HEA, 3=STP, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
 <tr>
 <td style="border:1px solid #ddd;padding:6px 10px;">SCTRL</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">index</td>
 <td style="border:1px solid #ddd;padding:6px 10px;">所选寄存器 = PRI；2=HEA, 4=STK, 5=FRM, 6=CIP</td>
 </tr>
</table>
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main ()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; new cod, dat;<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit LCTRL 0 // 将 COD 段寄存器的值存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit STOR.S.pri cod<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit LCTRL 1 // 将 DAT 段寄存器的值存储在主寄存器中<br />
&nbsp;&nbsp;&nbsp;&nbsp; #emit STOR.S.pri dat<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; printf("%d %d", cod, dat);<br />
}</code></div></div><br />
当函数名用作操作数时，编译器会用函数的地址替换它。替换的地址是相对于 COD 寄存器的。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>f()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("f() was called.");<br />
}<br />
<br />
main ()<br />
{<br />
&nbsp;&nbsp; #emit PUSH.C 0 // 参数占用的字节数（稍后解释）<br />
&nbsp;&nbsp; #emit LCTRL 6 // 获取 CIP 的值，即下一条指令（本例中的 ADD.C）的地址<br />
&nbsp;&nbsp; #emit ADD.C 28 // 计算 'f' 之后要执行的指令的地址（注意每个操作码和操作数都需要一个单元格）<br />
&nbsp;&nbsp; #emit PUSH.pri // 推送返回地址，以便 'f' 知道返回到哪里（稍后解释）<br />
&nbsp;&nbsp; #emit CONST.pri f // 将函数 'f' 的地址存储在 pri 中<br />
&nbsp;&nbsp; #emit SCTRL 6 // 将当前指令指针设置为存储在主寄存器中的值<br />
<br />
&nbsp;&nbsp; // 函数 'f' 执行<br />
&nbsp;&nbsp; // 函数 'f' 返回后，下一条指令（本例中的 NOP）将开始执行<br />
<br />
&nbsp;&nbsp; #emit NOP // 不执行任何操作的指令<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> 控制流指令</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;#emit JUMP check // 跳转到 check 标签<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;not_equal:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("1 is not equal to 2");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;equal:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("1 is equal to 2");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;check:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit CONST.pri 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit CONST.alt 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit JEQ equal // 如果主寄存器的值等于辅助寄存器的值，则跳转到 'equal'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #emit JUMP not_equal // 如果执行到这里，意味着两个寄存器的值不相等；因此跳转到 'not_equal'<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;"> Switch case 指令</h4><br />
<br />
switch-case 块使用<a href="https://en.wikipedia.org/wiki/Branch_table" target="_blank" rel="noopener" class="mycode_url">分支表</a>实现。分支表仅仅是由 case 值及其对应的跳转地址组成的元组列表。对于给定的 case 值，AMX 会搜索分支表并跳转到相应的跳转地址。分支表中的记录按 case 值的升序排列。这允许 AMX 对分支表执行二分搜索，但它也可能执行线性搜索。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SWITCH</code> 指令标记 switch-case 块的开始。它接受一个指向分支表（也位于代码段中）的偏移量作为操作数。分支表正式以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CASETBL</code> 操作码（仅作为标记，功能上未使用）开始，后跟一系列 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CASE</code> 记录，每条记录占用两个参数。第一条 case 记录的参数具有特殊含义：第一个参数是分支表中的 case 数量，第二个参数是默认 case 的偏移量。如果没有提供默认 case，则第二个参数包含 switch-case 块之后指令的偏移量。其余的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CASE</code> 记录包含 case 值及其对应的跳转地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>switch(expression)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 2: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 4: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 3: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 7: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;case 5: {}<br />
}</code></div></div><br />
编译器会添加指令来计算给定的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">expression</code>，其结果存储在主寄存器中。紧接着是一条 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SWITCH</code> 指令，它使 AMX 搜索分支表，查找与主寄存器中存储的值匹配的 case 值。如果找到匹配项，则执行跳转到匹配记录指向的地址；否则，跳转到默认地址。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>; 编译器通过在汇编输出中使用标签而不是实际的偏移量/地址，使阅读更容易<br />
; 每个标签都以前缀 "l." 开头<br />
<br />
switch 0 ; 注意这里的零是一个标签<br />
<br />
l.2 ; 标签 2<br />
&nbsp;&nbsp; jump 1 ; 跳转到标签 1<br />
l.3<br />
&nbsp;&nbsp; jump 1<br />
l.4<br />
&nbsp;&nbsp; jump 1<br />
l.5<br />
&nbsp;&nbsp; jump 1<br />
l.6<br />
&nbsp;&nbsp; jump 1<br />
<br />
l.0<br />
&nbsp;&nbsp;casetbl <br />
&nbsp;&nbsp;case 5 1 ; 记录数量，默认跳转地址（本例中为标签 1）<br />
&nbsp;&nbsp; case 2 2 ; 真正的第一条记录<br />
&nbsp;&nbsp; case 3 4 ; case 值: 3, 跳转标签: 4<br />
&nbsp;&nbsp; case 4 3 ; 编译器在实际二进制文件中会用正确的地址替换标签<br />
&nbsp;&nbsp; case 5 6 ; <br />
&nbsp;&nbsp; case 7 5 ; 最后一条记录<br />
<br />
 l.1<br />
&nbsp;&nbsp; ; 其余代码</code></div></div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[wiki系列] openmp/samp 关键字：指令]]></title>
			<link>https://open-mp.cn/showthread.php?tid=23</link>
			<pubDate>Sat, 21 Mar 2026 23:06:33 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=23</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 关键字：指令</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#assert" target="_blank" rel="noopener" class="mycode_url">1 #assert</a><br />
</li>
<li><a href="http://#define" target="_blank" rel="noopener" class="mycode_url">2 #define</a><br />
</li>
<li><a href="http://#else" target="_blank" rel="noopener" class="mycode_url">3 #else</a><br />
</li>
<li><a href="http://#elseif" target="_blank" rel="noopener" class="mycode_url">4 #elseif</a><br />
</li>
<li><a href="http://#emit" target="_blank" rel="noopener" class="mycode_url">5 #emit</a><br />
</li>
<li><a href="http://#endif" target="_blank" rel="noopener" class="mycode_url">6 #endif</a><br />
</li>
<li><a href="http://#endinput-endscript" target="_blank" rel="noopener" class="mycode_url">7 #endinput , #endscript</a><br />
</li>
<li><a href="http://#error" target="_blank" rel="noopener" class="mycode_url">8 #error</a><br />
</li>
<li><a href="http://#if" target="_blank" rel="noopener" class="mycode_url">9 #if</a><br />
</li>
<li><a href="http://#include" target="_blank" rel="noopener" class="mycode_url">10 #include</a><br />
</li>
<li><a href="http://#pragma" target="_blank" rel="noopener" class="mycode_url">11 #pragma</a><br />
</li>
<li><a href="http://#pragma-information" target="_blank" rel="noopener" class="mycode_url">11.1 说明</a><br />
</li>
<li><a href="http://#pragma-list" target="_blank" rel="noopener" class="mycode_url">11.2 列表</a><br />
</li>
<li><a href="http://#pragma-examples" target="_blank" rel="noopener" class="mycode_url">11.3 示例</a><br />
</li>
<li><a href="http://#pragma-deprecated" target="_blank" rel="noopener" class="mycode_url">11.3.1 已弃用（Deprecated）</a><br />
</li>
<li><a href="http://#tryinclude" target="_blank" rel="noopener" class="mycode_url">12 #tryinclude</a><br />
</li>
<li><a href="http://#undef" target="_blank" rel="noopener" class="mycode_url">13 #undef</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#assert</h3><br />
<br />
此指令会检查常量表达式是否为真，如果不为真则停止编译。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 10<br />
#assert MOO &gt; 5</code></div></div><br />
以上代码可以正常编译。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 1<br />
#assert MOO &gt; 5</code></div></div><br />
以上代码无法编译，会产生致命错误。<br />
<br />
这类似于：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 1<br />
#if MOO &lt;= 5<br />
    #error Moo check failed<br />
#endif</code></div></div><br />
但是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#assert</code> 会给出以下错误信息：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"Assertation failed: 1 &gt; 5"</code></div></div><br />
而第二种写法会给出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"User error: Moo check failed"</code></div></div><br />
哪种错误信息更实用，则视情况而定。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#define</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 是一个文本替换指令。只要在代码中找到被定义的符号（宏名），就会将其替换为定义的内容。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 7<br />
printf("%d", MOO);</code></div></div><br />
会被替换为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", 7);</code></div></div><br />
这也是为什么反编译后的代码中看不到任何 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code>，因为所有指令都在预处理器阶段处理完毕。定义的内容不一定是数字：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PL new i = 0; i &lt; MAX_PLAYERS; i++) if (IsPlayerConnected(i)<br />
for (PL)<br />
{<br />
    printf("%d connected", i);<br />
}</code></div></div><br />
会编译成大家熟悉（或讨厌）的玩家循环。注意括号的使用：一部分来自 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code> 语句，一部分来自宏本身。<br />
<br />
另一个鲜为人知的特性是：定义可以跨行（通过在行尾加上反斜杠 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 来转义换行）。一般来说换行会结束定义，但下面这样是有效的：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PL &#92;<br />
    new i = 0; i &lt; MAX_PLAYERS; i++) &#92;<br />
        if (IsPlayerConnected(i)<br />
for (PL)<br />
{<br />
    printf("%d connected", i);<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 字符表示定义继续到下一行。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 的第三个重要特性是支持参数（宏参数）。参数用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%0</code> 到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%9</code> 表示，用法与普通函数参数类似：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO(%0) &#92;<br />
    ((%0) * 7)<br />
printf("%d", MOO(6));</code></div></div><br />
输出结果为 42（不是随意选的）。注意宏里多余的括号——这是因为宏是纯文本替换，所以实际编译成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", ((6) * 7));</code></div></div><br />
这样是安全的。但看下面这个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", MOO(5 + 6));</code></div></div><br />
你会期望结果是 77（(5 + 6) * 7）。加上括号后确实如此；如果去掉括号：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO(%0) &#92;<br />
    %0 * 7<br />
printf("%d", MOO(5 + 6));</code></div></div><br />
实际会变成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", 5 + 6 * 7);</code></div></div><br />
由于运算优先级（BODMAS），结果变为 47（5 + (6 * 7)），这就完全错误了。<br />
<br />
关于参数还有一个有趣的事实：如果传入的参数数量超过定义的数量，最后一个参数会包含所有多余的部分。例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PP(%0,%1) &#92;<br />
    printf(%0, %1)<br />
PP("%s %s %s", "hi", "hello", "hi");</code></div></div><br />
实际会打印：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>hi hello hi</code></div></div><br />
因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%1</code> 包含了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"hi", "hello", "hi"</code>。你可能还注意到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#</code> 可以把字面量转换成字符串，这是 openmp(samp) 特有的功能，这里只是为了区分参数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#else</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#else</code> 相当于普通 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code>，但用于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 条件。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#elseif</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#elseif</code> 相当于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code>，但用于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 条件。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 10<br />
#if MOO == 9<br />
    printf("if");<br />
#elseif MOO == 8<br />
    printf("else if");<br />
#else<br />
    printf("else");<br />
#endif</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#emit</h3><br />
<br />
此指令在 pawn-lang.pdf 的表格中并未列出，但实际存在。它相当于内联汇编器，如果你熟悉 AMX 字节码，可以用它直接插入 AMX 操作码。唯一限制是每次只能带一个参数。<br />
<br />
语法：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#emit &lt;opcode&gt; &lt;argument&gt;</code><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;argument&gt;</code> 可以是小数、整数或（局部/全局）符号（变量、函数、标签）。<br />
<br />
操作码列表及其含义可在 Pawn Toolkit ver. 3664 中找到。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#endif</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#endif</code> 相当于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 的结束括号。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 不使用大括号，所有条件内容一直持续到对应的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#endif</code>。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#endinput , #endscript</h3><br />
<br />
此指令停止当前文件的包含（不再继续读取该文件）。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#error</h3><br />
<br />
此指令立即停止编译，并输出自定义错误信息。示例见 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#assert</code>。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#if</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 是预处理器版本的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code>。你可以精确控制哪些代码被编译、哪些不被编译。例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
if (LIMIT &lt; 10)<br />
{<br />
    printf("Limit too low");<br />
}</code></div></div><br />
会编译成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if (10 &lt; 10)<br />
{<br />
    printf("Limit too low");<br />
}</code></div></div><br />
编译器知道这个条件永远为假，因此会给出“常量表达式”警告。但既然永远不会成立，为什么还要保留这段代码呢？你可以直接删掉，但之后别人修改 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT</code> 重新编译时就无法检查了。这就是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 的作用。<br />
<br />
普通 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 在常量表达式时会警告，而 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> <span style="font-weight: bold;" class="mycode_b">必须</span> 是常量表达式：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
#if LIMIT &lt; 10<br />
    #error Limit too low<br />
#endif</code></div></div><br />
这样会在编译时就检查限制是否过小，如果是则直接报错，而不用运行脚本测试。同时也不会生成多余的代码。注意 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 不强制使用括号（虽然复杂表达式可能需要）。<br />
<br />
另一个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
if (LIMIT &lt; 10)<br />
{<br />
    printf("Limit less than 10");<br />
}<br />
else<br />
{<br />
    printf("Limit equal to or above 10");<br />
}</code></div></div><br />
同样是常量检查，会产生警告，而且两个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 都会被编译（尽管我们知道只会执行一个）。用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 改写后：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
#if LIMIT &lt; 10<br />
    printf("Limit less than 10");<br />
#else<br />
    printf("Limit equal to or above 10");<br />
#endif</code></div></div><br />
这样只有需要的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 会被编译，另一个仍保留在源代码中（方便以后改 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT</code>），但不会占用最终编译后的代码空间，也不会每次运行都执行无用的判断。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#include</h3><br />
<br />
此指令会把指定文件的所有代码插入到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 所在的位置。有两种包含方式：相对路径（用双引号）和系统路径（用尖括号，我自己起的名称，如果你有更好的叫法请告诉我）。<br />
<br />
相对包含使用双引号，路径相对于当前文件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include "me.pwn"</code></div></div><br />
会包含与当前文件同目录下的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">me.pwn</code>。<br />
<br />
系统包含使用尖括号，从 Pawn 编译器所在目录下的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">include</code> 文件夹（或其父目录的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">include</code> 文件夹）中查找：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;me&gt;</code></div></div><br />
会包含 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/include/me.inc</code>（注意没有扩展名；如果文件不是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.p</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code>，可以指定扩展名）。<br />
<br />
两种方式都支持子目录：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include "folder/me.pwn"<br />
#include &lt;folder/me&gt;</code></div></div><br />
如果文件不存在，编译会立即失败。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#pragma</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">说明</h4><br />
<br />
这是最复杂的指令之一。它提供了一系列选项来控制脚本的编译行为。例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#pragma ctrlchar '&#36;'</code></div></div><br />
会把转义字符从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 改成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&#36;</code>，所以换行符不再是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"\r\n"</code>，而是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"&#36;r&#36;n"</code>。<br />
<br />
很多选项原本是为嵌入式系统设计的，用来限制 PC 上几乎无限制的资源。这里只列出与 openmp(samp) 相关的选项（完整列表见 pawn-lang.pdf）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">列表</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">名称</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">值</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">codepage</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">名称/值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置字符串使用的 Unicode 码页</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">compress</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">1/0</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">openmp(samp) 不支持，请勿使用</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">deprecated</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">符号名称</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">如果使用该符号会产生警告，用于提示有更好的替代版本</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">dynamic</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">值（通常是 2 的幂）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置栈和堆内存大小（单位：cells）。出现“excessive memory usage”警告时需要设置</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">library</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">dll 名称</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在 openmp(samp) 中经常被误用。它指定本文件中的原生函数来自哪个 DLL，并非把文件定义为库</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">pack</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">1/0</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">交换 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!""</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">""</code> 的含义（详见 pawn-lang.pdf 中的打包字符串说明）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">tabsize</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">经常被误用。用于设置制表符宽度，避免因空格和制表符混用产生的警告。openmp(samp) 默认设为 4（qawno 编辑器中制表符宽度）。设为 0 会关闭所有缩进警告，但强烈不推荐（会导致代码难以阅读）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">unused</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">符号名称</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">类似 deprecated，用于抑制“symbol is never used”警告。推荐使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code>，但某些情况（如函数参数）无法使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 时才用此方式</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例</h4><br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">已弃用（Deprecated）</h5><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    gOldVariable = 5;<br />
#pragma deprecated gOldVariable<br />
main()<br />
{<br />
    printf("%d", gOldVariable);<br />
}</code></div></div><br />
使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gOldVariable</code> 时会产生警告，提示不应再使用它。主要用于函数更新 API 时保留向下兼容性。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#tryinclude</h3><br />
<br />
类似于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code>，但如果文件不存在，编译不会失败。这非常适合根据用户是否安装了特定插件（或插件的 include 文件）来选择性包含功能。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">myinc.inc：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#if defined _MY_INC_INC<br />
    #endinput<br />
#endif<br />
#define _MY_INC_INC<br />
stock MyIncFunc()<br />
{<br />
    printf("Hello");<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">主脚本：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#tryinclude &lt;myinc&gt;<br />
main()<br />
{<br />
    #if defined _MY_INC_INC<br />
        MyIncFunc();<br />
    #endif<br />
}</code></div></div><br />
只有当 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">myinc.inc</code> 存在并被成功包含时，才会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyIncFunc()</code>。这对 IRC 插件等需要检测插件是否安装的情况非常有用。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#undef</h3><br />
<br />
移除之前定义的宏或常量符号。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 10<br />
printf("%d", MOO);<br />
#undef MOO<br />
printf("%d", MOO);</code></div></div><br />
第二个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 会编译失败，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MOO</code> 已被取消定义。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum<br />
{<br />
    e_example = 300<br />
};<br />
printf("%d", e_example);<br />
#undef e_example<br />
printf("%d", e_example); // 致命错误</code></div></div><hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 关键字：指令</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#assert" target="_blank" rel="noopener" class="mycode_url">1 #assert</a><br />
</li>
<li><a href="http://#define" target="_blank" rel="noopener" class="mycode_url">2 #define</a><br />
</li>
<li><a href="http://#else" target="_blank" rel="noopener" class="mycode_url">3 #else</a><br />
</li>
<li><a href="http://#elseif" target="_blank" rel="noopener" class="mycode_url">4 #elseif</a><br />
</li>
<li><a href="http://#emit" target="_blank" rel="noopener" class="mycode_url">5 #emit</a><br />
</li>
<li><a href="http://#endif" target="_blank" rel="noopener" class="mycode_url">6 #endif</a><br />
</li>
<li><a href="http://#endinput-endscript" target="_blank" rel="noopener" class="mycode_url">7 #endinput , #endscript</a><br />
</li>
<li><a href="http://#error" target="_blank" rel="noopener" class="mycode_url">8 #error</a><br />
</li>
<li><a href="http://#if" target="_blank" rel="noopener" class="mycode_url">9 #if</a><br />
</li>
<li><a href="http://#include" target="_blank" rel="noopener" class="mycode_url">10 #include</a><br />
</li>
<li><a href="http://#pragma" target="_blank" rel="noopener" class="mycode_url">11 #pragma</a><br />
</li>
<li><a href="http://#pragma-information" target="_blank" rel="noopener" class="mycode_url">11.1 说明</a><br />
</li>
<li><a href="http://#pragma-list" target="_blank" rel="noopener" class="mycode_url">11.2 列表</a><br />
</li>
<li><a href="http://#pragma-examples" target="_blank" rel="noopener" class="mycode_url">11.3 示例</a><br />
</li>
<li><a href="http://#pragma-deprecated" target="_blank" rel="noopener" class="mycode_url">11.3.1 已弃用（Deprecated）</a><br />
</li>
<li><a href="http://#tryinclude" target="_blank" rel="noopener" class="mycode_url">12 #tryinclude</a><br />
</li>
<li><a href="http://#undef" target="_blank" rel="noopener" class="mycode_url">13 #undef</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#assert</h3><br />
<br />
此指令会检查常量表达式是否为真，如果不为真则停止编译。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 10<br />
#assert MOO &gt; 5</code></div></div><br />
以上代码可以正常编译。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 1<br />
#assert MOO &gt; 5</code></div></div><br />
以上代码无法编译，会产生致命错误。<br />
<br />
这类似于：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 1<br />
#if MOO &lt;= 5<br />
    #error Moo check failed<br />
#endif</code></div></div><br />
但是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#assert</code> 会给出以下错误信息：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"Assertation failed: 1 &gt; 5"</code></div></div><br />
而第二种写法会给出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"User error: Moo check failed"</code></div></div><br />
哪种错误信息更实用，则视情况而定。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#define</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 是一个文本替换指令。只要在代码中找到被定义的符号（宏名），就会将其替换为定义的内容。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 7<br />
printf("%d", MOO);</code></div></div><br />
会被替换为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", 7);</code></div></div><br />
这也是为什么反编译后的代码中看不到任何 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code>，因为所有指令都在预处理器阶段处理完毕。定义的内容不一定是数字：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PL new i = 0; i &lt; MAX_PLAYERS; i++) if (IsPlayerConnected(i)<br />
for (PL)<br />
{<br />
    printf("%d connected", i);<br />
}</code></div></div><br />
会编译成大家熟悉（或讨厌）的玩家循环。注意括号的使用：一部分来自 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code> 语句，一部分来自宏本身。<br />
<br />
另一个鲜为人知的特性是：定义可以跨行（通过在行尾加上反斜杠 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 来转义换行）。一般来说换行会结束定义，但下面这样是有效的：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PL &#92;<br />
    new i = 0; i &lt; MAX_PLAYERS; i++) &#92;<br />
        if (IsPlayerConnected(i)<br />
for (PL)<br />
{<br />
    printf("%d connected", i);<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 字符表示定义继续到下一行。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 的第三个重要特性是支持参数（宏参数）。参数用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%0</code> 到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%9</code> 表示，用法与普通函数参数类似：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO(%0) &#92;<br />
    ((%0) * 7)<br />
printf("%d", MOO(6));</code></div></div><br />
输出结果为 42（不是随意选的）。注意宏里多余的括号——这是因为宏是纯文本替换，所以实际编译成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", ((6) * 7));</code></div></div><br />
这样是安全的。但看下面这个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", MOO(5 + 6));</code></div></div><br />
你会期望结果是 77（(5 + 6) * 7）。加上括号后确实如此；如果去掉括号：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO(%0) &#92;<br />
    %0 * 7<br />
printf("%d", MOO(5 + 6));</code></div></div><br />
实际会变成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("%d", 5 + 6 * 7);</code></div></div><br />
由于运算优先级（BODMAS），结果变为 47（5 + (6 * 7)），这就完全错误了。<br />
<br />
关于参数还有一个有趣的事实：如果传入的参数数量超过定义的数量，最后一个参数会包含所有多余的部分。例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PP(%0,%1) &#92;<br />
    printf(%0, %1)<br />
PP("%s %s %s", "hi", "hello", "hi");</code></div></div><br />
实际会打印：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>hi hello hi</code></div></div><br />
因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%1</code> 包含了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"hi", "hello", "hi"</code>。你可能还注意到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#</code> 可以把字面量转换成字符串，这是 openmp(samp) 特有的功能，这里只是为了区分参数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#else</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#else</code> 相当于普通 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code>，但用于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 条件。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#elseif</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#elseif</code> 相当于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code>，但用于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 条件。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 10<br />
#if MOO == 9<br />
    printf("if");<br />
#elseif MOO == 8<br />
    printf("else if");<br />
#else<br />
    printf("else");<br />
#endif</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#emit</h3><br />
<br />
此指令在 pawn-lang.pdf 的表格中并未列出，但实际存在。它相当于内联汇编器，如果你熟悉 AMX 字节码，可以用它直接插入 AMX 操作码。唯一限制是每次只能带一个参数。<br />
<br />
语法：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#emit &lt;opcode&gt; &lt;argument&gt;</code><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;argument&gt;</code> 可以是小数、整数或（局部/全局）符号（变量、函数、标签）。<br />
<br />
操作码列表及其含义可在 Pawn Toolkit ver. 3664 中找到。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#endif</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#endif</code> 相当于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 的结束括号。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 不使用大括号，所有条件内容一直持续到对应的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#endif</code>。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#endinput , #endscript</h3><br />
<br />
此指令停止当前文件的包含（不再继续读取该文件）。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#error</h3><br />
<br />
此指令立即停止编译，并输出自定义错误信息。示例见 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#assert</code>。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#if</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 是预处理器版本的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code>。你可以精确控制哪些代码被编译、哪些不被编译。例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
if (LIMIT &lt; 10)<br />
{<br />
    printf("Limit too low");<br />
}</code></div></div><br />
会编译成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if (10 &lt; 10)<br />
{<br />
    printf("Limit too low");<br />
}</code></div></div><br />
编译器知道这个条件永远为假，因此会给出“常量表达式”警告。但既然永远不会成立，为什么还要保留这段代码呢？你可以直接删掉，但之后别人修改 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT</code> 重新编译时就无法检查了。这就是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 的作用。<br />
<br />
普通 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 在常量表达式时会警告，而 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> <span style="font-weight: bold;" class="mycode_b">必须</span> 是常量表达式：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
#if LIMIT &lt; 10<br />
    #error Limit too low<br />
#endif</code></div></div><br />
这样会在编译时就检查限制是否过小，如果是则直接报错，而不用运行脚本测试。同时也不会生成多余的代码。注意 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 不强制使用括号（虽然复杂表达式可能需要）。<br />
<br />
另一个例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
if (LIMIT &lt; 10)<br />
{<br />
    printf("Limit less than 10");<br />
}<br />
else<br />
{<br />
    printf("Limit equal to or above 10");<br />
}</code></div></div><br />
同样是常量检查，会产生警告，而且两个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 都会被编译（尽管我们知道只会执行一个）。用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 改写后：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define LIMIT 10<br />
#if LIMIT &lt; 10<br />
    printf("Limit less than 10");<br />
#else<br />
    printf("Limit equal to or above 10");<br />
#endif</code></div></div><br />
这样只有需要的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 会被编译，另一个仍保留在源代码中（方便以后改 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT</code>），但不会占用最终编译后的代码空间，也不会每次运行都执行无用的判断。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#include</h3><br />
<br />
此指令会把指定文件的所有代码插入到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 所在的位置。有两种包含方式：相对路径（用双引号）和系统路径（用尖括号，我自己起的名称，如果你有更好的叫法请告诉我）。<br />
<br />
相对包含使用双引号，路径相对于当前文件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include "me.pwn"</code></div></div><br />
会包含与当前文件同目录下的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">me.pwn</code>。<br />
<br />
系统包含使用尖括号，从 Pawn 编译器所在目录下的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">include</code> 文件夹（或其父目录的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">include</code> 文件夹）中查找：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;me&gt;</code></div></div><br />
会包含 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/include/me.inc</code>（注意没有扩展名；如果文件不是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.p</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code>，可以指定扩展名）。<br />
<br />
两种方式都支持子目录：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include "folder/me.pwn"<br />
#include &lt;folder/me&gt;</code></div></div><br />
如果文件不存在，编译会立即失败。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#pragma</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">说明</h4><br />
<br />
这是最复杂的指令之一。它提供了一系列选项来控制脚本的编译行为。例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#pragma ctrlchar '&#36;'</code></div></div><br />
会把转义字符从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 改成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&#36;</code>，所以换行符不再是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"\r\n"</code>，而是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"&#36;r&#36;n"</code>。<br />
<br />
很多选项原本是为嵌入式系统设计的，用来限制 PC 上几乎无限制的资源。这里只列出与 openmp(samp) 相关的选项（完整列表见 pawn-lang.pdf）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">列表</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">名称</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">值</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">codepage</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">名称/值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置字符串使用的 Unicode 码页</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">compress</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">1/0</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">openmp(samp) 不支持，请勿使用</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">deprecated</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">符号名称</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">如果使用该符号会产生警告，用于提示有更好的替代版本</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">dynamic</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">值（通常是 2 的幂）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置栈和堆内存大小（单位：cells）。出现“excessive memory usage”警告时需要设置</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">library</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">dll 名称</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在 openmp(samp) 中经常被误用。它指定本文件中的原生函数来自哪个 DLL，并非把文件定义为库</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">pack</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">1/0</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">交换 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!""</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">""</code> 的含义（详见 pawn-lang.pdf 中的打包字符串说明）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">tabsize</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">经常被误用。用于设置制表符宽度，避免因空格和制表符混用产生的警告。openmp(samp) 默认设为 4（qawno 编辑器中制表符宽度）。设为 0 会关闭所有缩进警告，但强烈不推荐（会导致代码难以阅读）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">unused</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">符号名称</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">类似 deprecated，用于抑制“symbol is never used”警告。推荐使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code>，但某些情况（如函数参数）无法使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 时才用此方式</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例</h4><br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">已弃用（Deprecated）</h5><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    gOldVariable = 5;<br />
#pragma deprecated gOldVariable<br />
main()<br />
{<br />
    printf("%d", gOldVariable);<br />
}</code></div></div><br />
使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gOldVariable</code> 时会产生警告，提示不应再使用它。主要用于函数更新 API 时保留向下兼容性。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#tryinclude</h3><br />
<br />
类似于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code>，但如果文件不存在，编译不会失败。这非常适合根据用户是否安装了特定插件（或插件的 include 文件）来选择性包含功能。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">myinc.inc：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#if defined _MY_INC_INC<br />
    #endinput<br />
#endif<br />
#define _MY_INC_INC<br />
stock MyIncFunc()<br />
{<br />
    printf("Hello");<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">主脚本：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#tryinclude &lt;myinc&gt;<br />
main()<br />
{<br />
    #if defined _MY_INC_INC<br />
        MyIncFunc();<br />
    #endif<br />
}</code></div></div><br />
只有当 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">myinc.inc</code> 存在并被成功包含时，才会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyIncFunc()</code>。这对 IRC 插件等需要检测插件是否安装的情况非常有用。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">#undef</h3><br />
<br />
移除之前定义的宏或常量符号。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MOO 10<br />
printf("%d", MOO);<br />
#undef MOO<br />
printf("%d", MOO);</code></div></div><br />
第二个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf</code> 会编译失败，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MOO</code> 已被取消定义。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum<br />
{<br />
    e_example = 300<br />
};<br />
printf("%d", e_example);<br />
#undef e_example<br />
printf("%d", e_example); // 致命错误</code></div></div><hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[wiki系列] openmp/samp 关键字：运算符]]></title>
			<link>https://open-mp.cn/showthread.php?tid=22</link>
			<pubDate>Sat, 21 Mar 2026 23:06:11 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=22</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 关键字：运算符</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#char" target="_blank" rel="noopener" class="mycode_url">1 char</a><br />
</li>
<li><a href="http://#defined" target="_blank" rel="noopener" class="mycode_url">2 defined</a><br />
</li>
<li><a href="http://#sizeof" target="_blank" rel="noopener" class="mycode_url">3 sizeof</a><br />
</li>
<li><a href="http://#state" target="_blank" rel="noopener" class="mycode_url">4 state</a><br />
</li>
<li><a href="http://#tagof" target="_blank" rel="noopener" class="mycode_url">5 tagof</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">char</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">char</code> 返回存放给定数量<span style="font-weight: bold;" class="mycode_b">字符</span>（打包字符串）所需的 <span style="font-weight: bold;" class="mycode_b">cells</span> 数量。  <br />
即：存放给定字节数所需的 4 字节 cells 数量。<br />
<br />
示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>4 char</code></div></div><br />
返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>3 char</code></div></div><br />
返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code>（你不能拥有 3/4 个变量）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>256 char</code></div></div><br />
返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">64</code>（256 ÷ 4）。<br />
<br />
此运算符通常用于变量声明：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar[40 char];</code></div></div><br />
会创建一个<span style="font-weight: bold;" class="mycode_b">10 cells</span>大小的数组。<br />
<br />
更多关于打包字符串（packed strings）的细节，请阅读 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pawn-lang.pdf</code>。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">defined</h3><br />
<br />
检查一个符号（symbol）是否存在。通常用于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 语句：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar = 5;<br />
#if defined someVar<br />
    printf("%d", someVar);<br />
#else<br />
    #error The variable 'someVar' isn't defined<br />
#endif</code></div></div><br />
最常见的用法是检查某个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 是否存在，并据此生成不同代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define FILTERSCRIPT<br />
#if defined FILTERSCRIPT<br />
public OnFilterScriptInit()<br />
{<br />
    return 1;<br />
}<br />
#else<br />
public OnGameModeInit()<br />
{<br />
    return 1;<br />
}<br />
#endif</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">sizeof</h3><br />
<br />
返回数组<span style="font-weight: bold;" class="mycode_b">元素</span>（ELEMENTS）的数量：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar[10];<br />
printf("%d", sizeof (someVar));</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>10</code></div></div><br />
二维数组示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar[2][10];<br />
printf("%d %d", sizeof (someVar), sizeof (someVar[]));</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>2 10</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">state</h3><br />
<br />
此关键字与 PAWN 自动机（autonoma）代码相关，因此本文不做介绍。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">tagof</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">tagof</code> 返回一个代表变量<span style="font-weight: bold;" class="mycode_b">标签</span>（tag）的数字：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar,<br />
    Float:someFloat;<br />
printf("%d %d", tagof (someVar), tagof (someFloat));</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>-./,)),(-*,( -1073741820</code></div></div><br />
这其实是一个轻微的显示 bug，但本质上代表：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>0x80000000 0xC0000004</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用：检查变量是否为 Float</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float: fValue = 6.9;<br />
new tag = tagof (fValue);<br />
if (tag == tagof (Float:))<br />
    print("float");<br />
else<br />
    print("not a float");</code></div></div><hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 关键字：运算符</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#char" target="_blank" rel="noopener" class="mycode_url">1 char</a><br />
</li>
<li><a href="http://#defined" target="_blank" rel="noopener" class="mycode_url">2 defined</a><br />
</li>
<li><a href="http://#sizeof" target="_blank" rel="noopener" class="mycode_url">3 sizeof</a><br />
</li>
<li><a href="http://#state" target="_blank" rel="noopener" class="mycode_url">4 state</a><br />
</li>
<li><a href="http://#tagof" target="_blank" rel="noopener" class="mycode_url">5 tagof</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">char</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">char</code> 返回存放给定数量<span style="font-weight: bold;" class="mycode_b">字符</span>（打包字符串）所需的 <span style="font-weight: bold;" class="mycode_b">cells</span> 数量。  <br />
即：存放给定字节数所需的 4 字节 cells 数量。<br />
<br />
示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>4 char</code></div></div><br />
返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>3 char</code></div></div><br />
返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1</code>（你不能拥有 3/4 个变量）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>256 char</code></div></div><br />
返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">64</code>（256 ÷ 4）。<br />
<br />
此运算符通常用于变量声明：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar[40 char];</code></div></div><br />
会创建一个<span style="font-weight: bold;" class="mycode_b">10 cells</span>大小的数组。<br />
<br />
更多关于打包字符串（packed strings）的细节，请阅读 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pawn-lang.pdf</code>。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">defined</h3><br />
<br />
检查一个符号（symbol）是否存在。通常用于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 语句：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar = 5;<br />
#if defined someVar<br />
    printf("%d", someVar);<br />
#else<br />
    #error The variable 'someVar' isn't defined<br />
#endif</code></div></div><br />
最常见的用法是检查某个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 是否存在，并据此生成不同代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define FILTERSCRIPT<br />
#if defined FILTERSCRIPT<br />
public OnFilterScriptInit()<br />
{<br />
    return 1;<br />
}<br />
#else<br />
public OnGameModeInit()<br />
{<br />
    return 1;<br />
}<br />
#endif</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">sizeof</h3><br />
<br />
返回数组<span style="font-weight: bold;" class="mycode_b">元素</span>（ELEMENTS）的数量：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar[10];<br />
printf("%d", sizeof (someVar));</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>10</code></div></div><br />
二维数组示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar[2][10];<br />
printf("%d %d", sizeof (someVar), sizeof (someVar[]));</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>2 10</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">state</h3><br />
<br />
此关键字与 PAWN 自动机（autonoma）代码相关，因此本文不做介绍。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">tagof</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">tagof</code> 返回一个代表变量<span style="font-weight: bold;" class="mycode_b">标签</span>（tag）的数字：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    someVar,<br />
    Float:someFloat;<br />
printf("%d %d", tagof (someVar), tagof (someFloat));</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>-./,)),(-*,( -1073741820</code></div></div><br />
这其实是一个轻微的显示 bug，但本质上代表：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>0x80000000 0xC0000004</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用：检查变量是否为 Float</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float: fValue = 6.9;<br />
new tag = tagof (fValue);<br />
if (tag == tagof (Float:))<br />
    print("float");<br />
else<br />
    print("not a float");</code></div></div><hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[wiki系列] openmp/samp 关键字：初始值设定项]]></title>
			<link>https://open-mp.cn/showthread.php?tid=21</link>
			<pubDate>Sat, 21 Mar 2026 23:05:31 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=21</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 关键字：初始值设定项</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#const" target="_blank" rel="noopener" class="mycode_url">1 const</a><br />
</li>
<li><a href="http://#enum" target="_blank" rel="noopener" class="mycode_url">2 enum</a><br />
</li>
<li><a href="http://#forward" target="_blank" rel="noopener" class="mycode_url">3 forward</a><br />
</li>
<li><a href="http://#native" target="_blank" rel="noopener" class="mycode_url">4 native</a><br />
</li>
<li><a href="http://#new" target="_blank" rel="noopener" class="mycode_url">5 new</a><br />
</li>
<li><a href="http://#operator" target="_blank" rel="noopener" class="mycode_url">6 operator</a><br />
</li>
<li><a href="http://#public" target="_blank" rel="noopener" class="mycode_url">7 public</a><br />
</li>
<li><a href="http://#static" target="_blank" rel="noopener" class="mycode_url">8 static</a><br />
</li>
<li><a href="http://#stock" target="_blank" rel="noopener" class="mycode_url">9 stock</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">const</h3><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new const<br />
    MY_CONSTANT[] = {1, 2, 3};</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 并不常用，但它用于声明一个<span style="font-weight: bold;" class="mycode_b">无法被代码修改</span>的变量。它的用途包括：让函数的数组参数编译得更高效，或者创建一个类似 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 但却是数组的常量。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 是一个修饰符，必须与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 或其他变量声明关键字搭配使用。如果你尝试修改 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 变量，编译器会报错。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">enum</h3><br />
<br />
枚举（enum）是一个非常实用的系统，用于表示大量数据并快速修改常量。主要用途有三类：<ul class="mycode_list"><li>替代一大堆 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 语句<br />
</li>
<li>用符号名称表示数组下标（其实本质相同，只是写法不同）<br />
</li>
<li>创建新的标签（tag）<br />
</li>
</ul>
<br />
最常见的用法是定义数组结构：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_ARRAY<br />
{<br />
    E_MY_ARRAY_MONEY,<br />
    E_MY_ARRAY_GUN<br />
}<br />
new<br />
    gPlayerData[MAX_PLAYERS][E_MY_ARRAY];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;<br />
    gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;<br />
}</code></div></div><br />
这会为每个玩家创建一个包含两个槽位的数组。连接时，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_MY_ARRAY_MONEY</code> 槽位设为 0，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_MY_ARRAY_GUN</code> 槽位设为 5。<br />
<br />
如果不用 enum，代码会变成这样：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    gPlayerData[MAX_PLAYERS][2];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][0] = 0;<br />
    gPlayerData[playerid][1] = 5;<br />
}</code></div></div><br />
可读性明显变差——下标 0 和 1 分别代表什么？而且扩展性差：如果要在中间插入一个新槽位，就得手动把所有 1 改成 2，非常容易出错。而使用 enum，只需添加一行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_ARRAY<br />
{<br />
    E_MY_ARRAY_MONEY,<br />
    E_MY_ARRAY_AMMO,<br />
    E_MY_ARRAY_GUN<br />
}<br />
new<br />
    gPlayerData[MAX_PLAYERS][E_MY_ARRAY];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;<br />
    gPlayerData[playerid][E_MY_ARRAY_AMMO] = 100;<br />
    gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;<br />
}</code></div></div><br />
重新编译后，所有索引自动更新。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 的完整格式与工作原理</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum NAME (modifier)<br />
{<br />
    NAME_ENTRY_1 = value,<br />
    NAME_ENTRY_2 = value,<br />
    ...<br />
    NAME_ENTRY_N = value<br />
}</code></div></div><br />
大部分内容是隐含的。默认 modifier 为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(+= 1)</code>，表示每个值都是前一个值 + 1：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE<br />
{<br />
    E_EXAMPLE_0,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_0 = 0</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_1 = 1</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_2 = 2</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE = 3</code>（枚举名本身等于最后一个值）。<br />
<br />
修改 modifier 的例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE (+= 5)<br />
{<br />
    E_EXAMPLE_0,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0, 5, 10, 15</code>。如果声明 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new gEnumArray[E_EXAMPLE];</code>，数组大小为 15，但只能通过枚举名访问 0、5、10（仍可使用普通数字访问）。<br />
<br />
另一个例子（乘法）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE (*= 2)<br />
{<br />
    E_EXAMPLE_0,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
全部变为 0。解决方法是手动指定初始值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE (*= 2)<br />
{<br />
    E_EXAMPLE_0 = 1,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1, 2, 4, 8</code>。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">提示</span>：数组用途时强烈建议只用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">+= 1</code>，其他 modifier 容易导致混乱。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 中可以包含数组</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE<br />
{<br />
    E_EXAMPLE_0[10],<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_0 = 0</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_1 = 10</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_2 = 11</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE = 12</code>（而不是很多人以为的 0、1、2、3）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 项可以带标签</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_ARRAY<br />
{<br />
    E_MY_ARRAY_MONEY,<br />
    E_MY_ARRAY_AMMO,<br />
    Float:E_MY_ARRAY_HEALTH,<br />
    E_MY_ARRAY_GUN<br />
}<br />
new<br />
    gPlayerData[MAX_PLAYERS][E_MY_ARRAY];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;<br />
    gPlayerData[playerid][E_MY_ARRAY_AMMO] = 100;<br />
    gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;<br />
    gPlayerData[playerid][E_MY_ARRAY_HEALTH] = 50.0;  // 不会产生标签不匹配警告<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 本身也可以作为标签使用（位标志）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_TAG (&lt;&lt;= 1)<br />
{<br />
    E_MY_TAG_NONE,<br />
    E_MY_TAG_VAL_1 = 1,<br />
    E_MY_TAG_VAL_2,<br />
    E_MY_TAG_VAL_3,<br />
    E_MY_TAG_VAL_4<br />
}<br />
new<br />
    E_MY_TAG:gMyTagVar = E_MY_TAG_VAL_2 | E_MY_TAG_VAL_3;</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gMyTagVar</code> 值为 6（4 | 2），并带有自定义标签。直接赋值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gMyTagVar = 7;</code> 会产生标签不匹配警告，但可以用强制转换绕过：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>gMyTagVar = E_MY_TAG:7;</code></div></div><br />
进阶用法（掩码 + 组合）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_TAG (&lt;&lt;= 1)<br />
{<br />
    E_MY_TAG_NONE,<br />
    E_MY_TAG_MASK = 0xFF,<br />
    E_MY_TAG_VAL_1 = 0x100,<br />
    E_MY_TAG_VAL_2,<br />
    E_MY_TAG_VAL_3,<br />
    E_MY_TAG_VAL_4<br />
}<br />
new<br />
    E_MY_TAG:gMyTagVar = E_MY_TAG_VAL_2 | E_MY_TAG_VAL_3 | (E_MY_TAG:7 &amp; E_MY_TAG_MASK);</code></div></div><br />
结果为 1543（0x0607）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用无名 enum 替代 #define</h4><br />
<br />
传统写法：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define TEAM_NONE  0<br />
#define TEAM_COP    1<br />
#define TEAM_ROBBER 2<br />
#define TEAM_CIV    3<br />
#define TEAM_CLERK  4<br />
#define TEAM_DRIVER 5</code></div></div><br />
改用 enum 自动赋值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum<br />
{<br />
    TEAM_NONE,<br />
    TEAM_COP,<br />
    TEAM_ROBBER,<br />
    TEAM_CIV,<br />
    TEAM_CLERK,<br />
    TEAM_DRIVER<br />
}</code></div></div><br />
值完全相同，使用方式也一样。<br />
<br />
更强大的位标志写法（推荐）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum (&lt;&lt;= 1)<br />
{<br />
    TEAM_NONE,<br />
    TEAM_COP = 1,<br />
    TEAM_ROBBER,<br />
    TEAM_CIV,<br />
    TEAM_CLERK,<br />
    TEAM_DRIVER,<br />
    TEAM_ADMIN<br />
}</code></div></div><br />
现在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TEAM_COP = 1</code>（二进制 00000001）、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TEAM_ROBBER = 2</code>（00000010）等。一个变量就能同时表示多个团队：<br />
<ul class="mycode_list"><li>添加团队：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gPlayerTeam[playerid] |= TEAM_COP;</code><br />
</li>
<li>移除团队：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gPlayerTeam[playerid] &amp;= ~TEAM_COP;</code><br />
</li>
<li>检查是否在团队：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (gPlayerTeam[playerid] &amp; TEAM_COP)</code><br />
</li>
</ul>
<br />
非常简洁且强大。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">forward</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 用于告诉编译器“这个函数稍后会定义”。所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数都<span style="font-weight: bold;" class="mycode_b">必须</span> forward，也可以用于其他地方。<br />
<br />
语法：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunction(playerid, const string[]);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunction(playerid, const string[]);<br />
public MyPublicFunction(playerid, const string[])<br />
{<br />
}</code></div></div><br />
除了 public 函数外，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 还能解决一种罕见的“reparse”警告（当函数返回带标签的值如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 时，在声明前被调用）：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">有警告的写法：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{<br />
    new Float:myVar = MyFloatFunction();<br />
}<br />
Float:MyFloatFunction()<br />
{<br />
    return 5.0;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">解决方法 1（函数前置）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Float:MyFloatFunction()<br />
{<br />
    return 5.0;<br />
}<br />
main()<br />
{<br />
    new Float:myVar = MyFloatFunction();<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">解决方法 2（forward）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward Float:MyFloatFunction();<br />
main()<br />
{<br />
    new Float:myVar = MyFloatFunction();<br />
}<br />
Float:MyFloatFunction()<br />
{<br />
    return 5.0;<br />
}</code></div></div><br />
注意：forward 也要带返回值标签。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">native</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code> 函数是由虚拟机（openmp(samp) 服务器或插件）提供的函数，而不是脚本自己定义的。你只能声明已存在于 openmp(samp) 或插件中的 native。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">用途 1</span>：让自定义函数出现在 qawno 右侧函数列表中（即使是假的）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/*<br />
native MyFunction(playerid);<br />
*/</code></div></div><br />
注释会被 qawno 识别加入列表，但编译器会忽略。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">用途 2</span>：重命名 / 重载函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>native my_print(const string[]) = print;</code></div></div><br />
现在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 函数在脚本中已不存在（但服务器内部仍存在）。你可以重新定义它：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>print(const string[])<br />
{<br />
    my_print("Someone called print()");<br />
    my_print(string);<br />
}</code></div></div><br />
以后所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print()</code> 调用都会先执行你的代码，再调用原函数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">new</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 是变量声明的核心关键字之一。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    myVar = 5;</code></div></div><br />
创建变量并赋值为 5。未赋值时默认为 0：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myVar;<br />
printf("%d", myVar);  // 输出 0</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">作用域</span>（scope）由大括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code> 决定，声明在括号内的变量只能在该括号内使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if (a == 1)<br />
{<br />
    new myVar = 5;<br />
    printf("%d", myVar);        // 可以<br />
    if (myVar == 1)<br />
    {<br />
        printf("%d", myVar);    // 可以<br />
    }<br />
}<br />
// 这里无法使用 myVar，会报错<br />
printf("%d", myVar);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">全局变量</span>（在函数外声明）从声明位置之后可在整个脚本中使用（包括 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 的其他文件）。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">static</span> 与 <span style="font-weight: bold;" class="mycode_b">new</span> 的区别详见下方 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 部分。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">operator</h3><br />
<br />
允许为自定义标签重载运算符。<br />
<br />
示例（大端序转换）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock BigEndian:operator=(b)<br />
{<br />
    return BigEndian:(((b &gt;&gt;&gt; 24) &amp; 0x000000FF) | ((b &gt;&gt;&gt; 8) &amp; 0x0000FF00) | ((b &lt;&lt; 8) &amp; 0x00FF0000) | ((b &lt;&lt; 24) &amp; 0xFF000000));<br />
}<br />
main()<br />
{<br />
    new BigEndian:a = 7;<br />
    printf("%d", _:a);  // 输出 117440512（因为小端序读取大端序数据）<br />
}</code></div></div><br />
可重载的运算符：<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">+, -, *, /, %, ++, --, ==, !=, &lt;, &gt;, &lt;=, &gt;=, !, =</code><br />
<br />
你可以让运算符做任何事（不一定是原本功能）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock BigEndian:operator+(BigEndian:a, BigEndian:b)<br />
{<br />
    return BigEndian:42;<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a + b</code> 永远返回 42。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">public</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 让函数对虚拟机可见，允许 openmp(samp) 服务器从外部直接调用（而非仅在脚本内部调用）。也可用于变量（允许服务器读写），但 openmp(samp) 中极少使用。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数的名称会存储在 .amx 文件中（普通函数只存地址），这也是反编译的难点之一。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">通过名称调用 public 函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunc();<br />
main()<br />
{<br />
    CallLocalFunction("MyPublicFunc", "");<br />
}<br />
public MyPublicFunc()<br />
{<br />
    printf("Hello");<br />
}</code></div></div><br />
也可使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">@</code> 前缀：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunc();<br />
forward @MyOtherPublicFunc(var);<br />
main()<br />
{<br />
    CallLocalFunction("MyPublicFunc", "");<br />
    SetTimerEx("@MyOtherPublicFunc", 5000, 0, "i", 7);<br />
}<br />
public MyPublicFunc()<br />
{<br />
    printf("Hello");<br />
}<br />
@MyOtherPublicFunc(var)<br />
{<br />
    printf("%d", var);<br />
}</code></div></div><br />
所有 openmp(samp) 回调（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerConnect</code>）都是 public，由服务器自动调用。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数也可以像普通函数一样直接调用（速度更快）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunc();<br />
main()<br />
{<br />
    MyPublicFunc();  // 直接调用，比 CallLocalFunction 快<br />
}<br />
public MyPublicFunc()<br />
{<br />
    printf("Hello");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">static</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 全局变量类似 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code>，但作用域更小（仅限于声明所在的文件或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#section</code>）。<br />
<br />
对比 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 的跨文件可见性，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 仅限本文件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// file2.pwn 中无法访问 file1.pwn 里的 static 变量</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">局部 static</span>：作用域与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 相同（仅大括号内），但<span style="font-weight: bold;" class="mycode_b">值在函数多次调用间保留</span>（不像 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 每次重置）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunc()<br />
{<br />
    new i = 0;<br />
    printf("%d", i);<br />
    i++;<br />
    printf("%d", i);<br />
}</code></div></div><br />
调用 4 次输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>0 1<br />
0 1<br />
0 1<br />
0 1</code></div></div><br />
改为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 后：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>0 1<br />
1 2<br />
2 3<br />
3 4</code></div></div><br />
初始化值仅在<span style="font-weight: bold;" class="mycode_b">第一次</span>调用时生效。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 函数只能在声明所在文件中调用，适合“私有”函数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">stock</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 用于声明可能不会被使用的变量或函数，避免产生“unused”警告。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new stock<br />
    gMayBeUsedVar;<br />
static stock<br />
    g_sMayBeUsedVar;</code></div></div><br />
如果被使用则编译保留；如果未使用则<span style="font-weight: bold;" class="mycode_b">完全剔除</span>（不像 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma unused</code> 只隐藏警告）。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">最常见用途</span>：编写库时。库作者无法预知用户会用哪些函数，使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 可避免大量无用警告。<br />
<br />
```pawn<br />
stock Func1()<br />
{<br />
printf("Hello");<br />
}<br />
<br />
stock Func2()<br />
{<br />
printf("Hi");<br />
}<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 关键字：初始值设定项</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#const" target="_blank" rel="noopener" class="mycode_url">1 const</a><br />
</li>
<li><a href="http://#enum" target="_blank" rel="noopener" class="mycode_url">2 enum</a><br />
</li>
<li><a href="http://#forward" target="_blank" rel="noopener" class="mycode_url">3 forward</a><br />
</li>
<li><a href="http://#native" target="_blank" rel="noopener" class="mycode_url">4 native</a><br />
</li>
<li><a href="http://#new" target="_blank" rel="noopener" class="mycode_url">5 new</a><br />
</li>
<li><a href="http://#operator" target="_blank" rel="noopener" class="mycode_url">6 operator</a><br />
</li>
<li><a href="http://#public" target="_blank" rel="noopener" class="mycode_url">7 public</a><br />
</li>
<li><a href="http://#static" target="_blank" rel="noopener" class="mycode_url">8 static</a><br />
</li>
<li><a href="http://#stock" target="_blank" rel="noopener" class="mycode_url">9 stock</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">const</h3><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new const<br />
    MY_CONSTANT[] = {1, 2, 3};</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 并不常用，但它用于声明一个<span style="font-weight: bold;" class="mycode_b">无法被代码修改</span>的变量。它的用途包括：让函数的数组参数编译得更高效，或者创建一个类似 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 但却是数组的常量。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 是一个修饰符，必须与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 或其他变量声明关键字搭配使用。如果你尝试修改 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 变量，编译器会报错。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">enum</h3><br />
<br />
枚举（enum）是一个非常实用的系统，用于表示大量数据并快速修改常量。主要用途有三类：<ul class="mycode_list"><li>替代一大堆 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 语句<br />
</li>
<li>用符号名称表示数组下标（其实本质相同，只是写法不同）<br />
</li>
<li>创建新的标签（tag）<br />
</li>
</ul>
<br />
最常见的用法是定义数组结构：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_ARRAY<br />
{<br />
    E_MY_ARRAY_MONEY,<br />
    E_MY_ARRAY_GUN<br />
}<br />
new<br />
    gPlayerData[MAX_PLAYERS][E_MY_ARRAY];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;<br />
    gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;<br />
}</code></div></div><br />
这会为每个玩家创建一个包含两个槽位的数组。连接时，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_MY_ARRAY_MONEY</code> 槽位设为 0，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_MY_ARRAY_GUN</code> 槽位设为 5。<br />
<br />
如果不用 enum，代码会变成这样：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    gPlayerData[MAX_PLAYERS][2];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][0] = 0;<br />
    gPlayerData[playerid][1] = 5;<br />
}</code></div></div><br />
可读性明显变差——下标 0 和 1 分别代表什么？而且扩展性差：如果要在中间插入一个新槽位，就得手动把所有 1 改成 2，非常容易出错。而使用 enum，只需添加一行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_ARRAY<br />
{<br />
    E_MY_ARRAY_MONEY,<br />
    E_MY_ARRAY_AMMO,<br />
    E_MY_ARRAY_GUN<br />
}<br />
new<br />
    gPlayerData[MAX_PLAYERS][E_MY_ARRAY];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;<br />
    gPlayerData[playerid][E_MY_ARRAY_AMMO] = 100;<br />
    gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;<br />
}</code></div></div><br />
重新编译后，所有索引自动更新。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 的完整格式与工作原理</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum NAME (modifier)<br />
{<br />
    NAME_ENTRY_1 = value,<br />
    NAME_ENTRY_2 = value,<br />
    ...<br />
    NAME_ENTRY_N = value<br />
}</code></div></div><br />
大部分内容是隐含的。默认 modifier 为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(+= 1)</code>，表示每个值都是前一个值 + 1：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE<br />
{<br />
    E_EXAMPLE_0,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_0 = 0</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_1 = 1</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_2 = 2</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE = 3</code>（枚举名本身等于最后一个值）。<br />
<br />
修改 modifier 的例子：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE (+= 5)<br />
{<br />
    E_EXAMPLE_0,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0, 5, 10, 15</code>。如果声明 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new gEnumArray[E_EXAMPLE];</code>，数组大小为 15，但只能通过枚举名访问 0、5、10（仍可使用普通数字访问）。<br />
<br />
另一个例子（乘法）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE (*= 2)<br />
{<br />
    E_EXAMPLE_0,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
全部变为 0。解决方法是手动指定初始值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE (*= 2)<br />
{<br />
    E_EXAMPLE_0 = 1,<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">1, 2, 4, 8</code>。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">提示</span>：数组用途时强烈建议只用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">+= 1</code>，其他 modifier 容易导致混乱。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 中可以包含数组</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_EXAMPLE<br />
{<br />
    E_EXAMPLE_0[10],<br />
    E_EXAMPLE_1,<br />
    E_EXAMPLE_2<br />
}</code></div></div><br />
结果：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_0 = 0</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_1 = 10</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE_2 = 11</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_EXAMPLE = 12</code>（而不是很多人以为的 0、1、2、3）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 项可以带标签</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_ARRAY<br />
{<br />
    E_MY_ARRAY_MONEY,<br />
    E_MY_ARRAY_AMMO,<br />
    Float:E_MY_ARRAY_HEALTH,<br />
    E_MY_ARRAY_GUN<br />
}<br />
new<br />
    gPlayerData[MAX_PLAYERS][E_MY_ARRAY];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;<br />
    gPlayerData[playerid][E_MY_ARRAY_AMMO] = 100;<br />
    gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;<br />
    gPlayerData[playerid][E_MY_ARRAY_HEALTH] = 50.0;  // 不会产生标签不匹配警告<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">enum 本身也可以作为标签使用（位标志）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_TAG (&lt;&lt;= 1)<br />
{<br />
    E_MY_TAG_NONE,<br />
    E_MY_TAG_VAL_1 = 1,<br />
    E_MY_TAG_VAL_2,<br />
    E_MY_TAG_VAL_3,<br />
    E_MY_TAG_VAL_4<br />
}<br />
new<br />
    E_MY_TAG:gMyTagVar = E_MY_TAG_VAL_2 | E_MY_TAG_VAL_3;</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gMyTagVar</code> 值为 6（4 | 2），并带有自定义标签。直接赋值 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gMyTagVar = 7;</code> 会产生标签不匹配警告，但可以用强制转换绕过：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>gMyTagVar = E_MY_TAG:7;</code></div></div><br />
进阶用法（掩码 + 组合）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum E_MY_TAG (&lt;&lt;= 1)<br />
{<br />
    E_MY_TAG_NONE,<br />
    E_MY_TAG_MASK = 0xFF,<br />
    E_MY_TAG_VAL_1 = 0x100,<br />
    E_MY_TAG_VAL_2,<br />
    E_MY_TAG_VAL_3,<br />
    E_MY_TAG_VAL_4<br />
}<br />
new<br />
    E_MY_TAG:gMyTagVar = E_MY_TAG_VAL_2 | E_MY_TAG_VAL_3 | (E_MY_TAG:7 &amp; E_MY_TAG_MASK);</code></div></div><br />
结果为 1543（0x0607）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用无名 enum 替代 #define</h4><br />
<br />
传统写法：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define TEAM_NONE  0<br />
#define TEAM_COP    1<br />
#define TEAM_ROBBER 2<br />
#define TEAM_CIV    3<br />
#define TEAM_CLERK  4<br />
#define TEAM_DRIVER 5</code></div></div><br />
改用 enum 自动赋值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum<br />
{<br />
    TEAM_NONE,<br />
    TEAM_COP,<br />
    TEAM_ROBBER,<br />
    TEAM_CIV,<br />
    TEAM_CLERK,<br />
    TEAM_DRIVER<br />
}</code></div></div><br />
值完全相同，使用方式也一样。<br />
<br />
更强大的位标志写法（推荐）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum (&lt;&lt;= 1)<br />
{<br />
    TEAM_NONE,<br />
    TEAM_COP = 1,<br />
    TEAM_ROBBER,<br />
    TEAM_CIV,<br />
    TEAM_CLERK,<br />
    TEAM_DRIVER,<br />
    TEAM_ADMIN<br />
}</code></div></div><br />
现在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TEAM_COP = 1</code>（二进制 00000001）、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TEAM_ROBBER = 2</code>（00000010）等。一个变量就能同时表示多个团队：<br />
<ul class="mycode_list"><li>添加团队：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gPlayerTeam[playerid] |= TEAM_COP;</code><br />
</li>
<li>移除团队：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gPlayerTeam[playerid] &amp;= ~TEAM_COP;</code><br />
</li>
<li>检查是否在团队：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (gPlayerTeam[playerid] &amp; TEAM_COP)</code><br />
</li>
</ul>
<br />
非常简洁且强大。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">forward</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 用于告诉编译器“这个函数稍后会定义”。所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数都<span style="font-weight: bold;" class="mycode_b">必须</span> forward，也可以用于其他地方。<br />
<br />
语法：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunction(playerid, const string[]);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunction(playerid, const string[]);<br />
public MyPublicFunction(playerid, const string[])<br />
{<br />
}</code></div></div><br />
除了 public 函数外，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 还能解决一种罕见的“reparse”警告（当函数返回带标签的值如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 时，在声明前被调用）：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">有警告的写法：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{<br />
    new Float:myVar = MyFloatFunction();<br />
}<br />
Float:MyFloatFunction()<br />
{<br />
    return 5.0;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">解决方法 1（函数前置）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Float:MyFloatFunction()<br />
{<br />
    return 5.0;<br />
}<br />
main()<br />
{<br />
    new Float:myVar = MyFloatFunction();<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">解决方法 2（forward）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward Float:MyFloatFunction();<br />
main()<br />
{<br />
    new Float:myVar = MyFloatFunction();<br />
}<br />
Float:MyFloatFunction()<br />
{<br />
    return 5.0;<br />
}</code></div></div><br />
注意：forward 也要带返回值标签。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">native</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code> 函数是由虚拟机（openmp(samp) 服务器或插件）提供的函数，而不是脚本自己定义的。你只能声明已存在于 openmp(samp) 或插件中的 native。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">用途 1</span>：让自定义函数出现在 qawno 右侧函数列表中（即使是假的）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/*<br />
native MyFunction(playerid);<br />
*/</code></div></div><br />
注释会被 qawno 识别加入列表，但编译器会忽略。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">用途 2</span>：重命名 / 重载函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>native my_print(const string[]) = print;</code></div></div><br />
现在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 函数在脚本中已不存在（但服务器内部仍存在）。你可以重新定义它：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>print(const string[])<br />
{<br />
    my_print("Someone called print()");<br />
    my_print(string);<br />
}</code></div></div><br />
以后所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print()</code> 调用都会先执行你的代码，再调用原函数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">new</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 是变量声明的核心关键字之一。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    myVar = 5;</code></div></div><br />
创建变量并赋值为 5。未赋值时默认为 0：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myVar;<br />
printf("%d", myVar);  // 输出 0</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">作用域</span>（scope）由大括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code> 决定，声明在括号内的变量只能在该括号内使用。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if (a == 1)<br />
{<br />
    new myVar = 5;<br />
    printf("%d", myVar);        // 可以<br />
    if (myVar == 1)<br />
    {<br />
        printf("%d", myVar);    // 可以<br />
    }<br />
}<br />
// 这里无法使用 myVar，会报错<br />
printf("%d", myVar);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">全局变量</span>（在函数外声明）从声明位置之后可在整个脚本中使用（包括 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 的其他文件）。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">static</span> 与 <span style="font-weight: bold;" class="mycode_b">new</span> 的区别详见下方 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 部分。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">operator</h3><br />
<br />
允许为自定义标签重载运算符。<br />
<br />
示例（大端序转换）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock BigEndian:operator=(b)<br />
{<br />
    return BigEndian:(((b &gt;&gt;&gt; 24) &amp; 0x000000FF) | ((b &gt;&gt;&gt; 8) &amp; 0x0000FF00) | ((b &lt;&lt; 8) &amp; 0x00FF0000) | ((b &lt;&lt; 24) &amp; 0xFF000000));<br />
}<br />
main()<br />
{<br />
    new BigEndian:a = 7;<br />
    printf("%d", _:a);  // 输出 117440512（因为小端序读取大端序数据）<br />
}</code></div></div><br />
可重载的运算符：<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">+, -, *, /, %, ++, --, ==, !=, &lt;, &gt;, &lt;=, &gt;=, !, =</code><br />
<br />
你可以让运算符做任何事（不一定是原本功能）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock BigEndian:operator+(BigEndian:a, BigEndian:b)<br />
{<br />
    return BigEndian:42;<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a + b</code> 永远返回 42。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">public</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 让函数对虚拟机可见，允许 openmp(samp) 服务器从外部直接调用（而非仅在脚本内部调用）。也可用于变量（允许服务器读写），但 openmp(samp) 中极少使用。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数的名称会存储在 .amx 文件中（普通函数只存地址），这也是反编译的难点之一。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">通过名称调用 public 函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunc();<br />
main()<br />
{<br />
    CallLocalFunction("MyPublicFunc", "");<br />
}<br />
public MyPublicFunc()<br />
{<br />
    printf("Hello");<br />
}</code></div></div><br />
也可使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">@</code> 前缀：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunc();<br />
forward @MyOtherPublicFunc(var);<br />
main()<br />
{<br />
    CallLocalFunction("MyPublicFunc", "");<br />
    SetTimerEx("@MyOtherPublicFunc", 5000, 0, "i", 7);<br />
}<br />
public MyPublicFunc()<br />
{<br />
    printf("Hello");<br />
}<br />
@MyOtherPublicFunc(var)<br />
{<br />
    printf("%d", var);<br />
}</code></div></div><br />
所有 openmp(samp) 回调（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerConnect</code>）都是 public，由服务器自动调用。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数也可以像普通函数一样直接调用（速度更快）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward MyPublicFunc();<br />
main()<br />
{<br />
    MyPublicFunc();  // 直接调用，比 CallLocalFunction 快<br />
}<br />
public MyPublicFunc()<br />
{<br />
    printf("Hello");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">static</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 全局变量类似 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code>，但作用域更小（仅限于声明所在的文件或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#section</code>）。<br />
<br />
对比 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 的跨文件可见性，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 仅限本文件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// file2.pwn 中无法访问 file1.pwn 里的 static 变量</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">局部 static</span>：作用域与 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 相同（仅大括号内），但<span style="font-weight: bold;" class="mycode_b">值在函数多次调用间保留</span>（不像 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 每次重置）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunc()<br />
{<br />
    new i = 0;<br />
    printf("%d", i);<br />
    i++;<br />
    printf("%d", i);<br />
}</code></div></div><br />
调用 4 次输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>0 1<br />
0 1<br />
0 1<br />
0 1</code></div></div><br />
改为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 后：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>0 1<br />
1 2<br />
2 3<br />
3 4</code></div></div><br />
初始化值仅在<span style="font-weight: bold;" class="mycode_b">第一次</span>调用时生效。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 函数只能在声明所在文件中调用，适合“私有”函数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">stock</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 用于声明可能不会被使用的变量或函数，避免产生“unused”警告。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new stock<br />
    gMayBeUsedVar;<br />
static stock<br />
    g_sMayBeUsedVar;</code></div></div><br />
如果被使用则编译保留；如果未使用则<span style="font-weight: bold;" class="mycode_b">完全剔除</span>（不像 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma unused</code> 只隐藏警告）。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">最常见用途</span>：编写库时。库作者无法预知用户会用哪些函数，使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 可避免大量无用警告。<br />
<br />
```pawn<br />
stock Func1()<br />
{<br />
printf("Hello");<br />
}<br />
<br />
stock Func2()<br />
{<br />
printf("Hi");<br />
}<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[wiki系列] openmp/samp 控制结构]]></title>
			<link>https://open-mp.cn/showthread.php?tid=20</link>
			<pubDate>Sat, 21 Mar 2026 23:04:54 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=20</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 控制结构</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#conditionals" target="_blank" rel="noopener" class="mycode_url">1 条件语句</a><br />
</li>
<li><a href="http://#if" target="_blank" rel="noopener" class="mycode_url">1.1 if</a><br />
</li>
<li><a href="http://#operators" target="_blank" rel="noopener" class="mycode_url">1.2 运算符</a><br />
</li>
<li><a href="http://#brackets" target="_blank" rel="noopener" class="mycode_url">1.3 括号</a><br />
</li>
<li><a href="http://#else" target="_blank" rel="noopener" class="mycode_url">1.4 else</a><br />
</li>
<li><a href="http://#else-if" target="_blank" rel="noopener" class="mycode_url">1.5 else if</a><br />
</li>
<li><a href="http://#ternary" target="_blank" rel="noopener" class="mycode_url">1.6 ?:（三元运算符）</a><br />
</li>
<li><a href="http://#loops" target="_blank" rel="noopener" class="mycode_url">2 循环</a><br />
</li>
<li><a href="http://#while" target="_blank" rel="noopener" class="mycode_url">2.1 while ()</a><br />
</li>
<li><a href="http://#for" target="_blank" rel="noopener" class="mycode_url">2.2 for ()</a><br />
</li>
<li><a href="http://#do-while" target="_blank" rel="noopener" class="mycode_url">2.3 do-while</a><br />
</li>
<li><a href="http://#if-goto" target="_blank" rel="noopener" class="mycode_url">2.4 if-goto</a><br />
</li>
<li><a href="http://#oboe" target="_blank" rel="noopener" class="mycode_url">2.5 OBOE（Off By One Error）</a><br />
</li>
<li><a href="http://#switch" target="_blank" rel="noopener" class="mycode_url">3 switch</a><br />
</li>
<li><a href="http://#switch-2" target="_blank" rel="noopener" class="mycode_url">3.1 switch</a><br />
</li>
<li><a href="http://#case" target="_blank" rel="noopener" class="mycode_url">3.2 case</a><br />
</li>
<li><a href="http://#default" target="_blank" rel="noopener" class="mycode_url">3.3 default</a><br />
</li>
<li><a href="http://#single-line-statements" target="_blank" rel="noopener" class="mycode_url">4 单行语句</a><br />
</li>
<li><a href="http://#goto" target="_blank" rel="noopener" class="mycode_url">4.1 goto</a><br />
</li>
<li><a href="http://#break" target="_blank" rel="noopener" class="mycode_url">4.2 break</a><br />
</li>
<li><a href="http://#continue" target="_blank" rel="noopener" class="mycode_url">4.3 continue</a><br />
</li>
<li><a href="http://#return" target="_blank" rel="noopener" class="mycode_url">4.4 return</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">条件语句</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">if</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 语句会检查某个条件是否成立，如果成立则执行对应代码。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
if (a == 5)<br />
{<br />
    print("a is 5");<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 后面的括号内是<span style="font-weight: bold;" class="mycode_b">条件</span>，你可以进行多种判断（详见运算符部分）。<br />
<br />
条件中不仅可以是变量，也可以是函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if (SomeFunction() == 5)<br />
{<br />
    print("SomeFunction() is 5");<br />
}</code></div></div><br />
还可以组合多个条件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5,<br />
    b = 3;<br />
if (a == 5 &amp;&amp; b != 3)<br />
{<br />
    print("Won't be printed");<br />
}</code></div></div><br />
上面检查 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a == 5</code> <span style="font-weight: bold;" class="mycode_b">并且</span> <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b != 3</code>，但 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code> 是 3，所以整个条件为假。<br />
<br />
使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">||</code>（或）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5,<br />
    b = 3;<br />
if (a == 5 || b != 3)<br />
{<br />
    print("Will be printed");<br />
}</code></div></div><br />
只要有一个条件为真，整个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 就成立（即使 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b != 3</code> 为假，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a == 5</code> 为真）。<br />
<br />
还可以链式比较（无需显式写多个 &amp;&amp;）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    idx = 3;<br />
if (0 &lt; idx &lt; 5)<br />
{<br />
    print("idx is greater than 0 and less than 5!");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">运算符</h4><br />
<br />
条件判断中常用的运算符及其含义：<br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">比较运算符</h5><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">==</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left == Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">!=</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边不等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left != Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&gt;</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边大于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &gt; Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&gt;=</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边大于等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &gt;= Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&lt;</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边小于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &lt; Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&lt;=</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边小于等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &lt;= Right)</code></td>
  </tr>
</table>
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">逻辑运算符</h5><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&amp;&amp;</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">并且（AND）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &amp;&amp; Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">或者（OR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left || Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">!</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">非（NOT）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!Variable)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">都不（NOR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!(Left || Right))</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不是都（NAND）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!(Left &amp;&amp; Right))</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">异或（XOR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!(Left &amp;&amp; Right) &amp;&amp; (Left || Right))</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">同或（NXOR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if ((Left &amp;&amp; Right) || !(Left || Right))</code></td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">括号</h4><br />
<br />
括号决定运算顺序：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 3,<br />
    b = 3,<br />
    c = 1;<br />
if (a == 5 &amp;&amp; b == 3 || c == 1)<br />
{<br />
    print("Will this be called?");<br />
}</code></div></div><br />
有两种可能的解释：<br />
<br />
<ol type="1" class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(a == 5 &amp;&amp; b == 3) || c == 1</code>  <br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a == 5 &amp;&amp; (b == 3 || c == 1)</code><br />
</li>
</ol>
<br />
第一种：先判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a==5 &amp;&amp; b==3</code>（为假），再判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">c==1</code>（为真），整体为真。  <br />
第二种：先判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b==3 || c==1</code>（为真），再判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a==5</code>（为假），整体为假。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">强烈建议始终使用括号</span>，既能明确逻辑，也能避免歧义。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">else</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code> 在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 条件不成立时执行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
if (a == 3)  // 假<br />
{<br />
    print("Won't be called");<br />
}<br />
else<br />
{<br />
    print("Will be called as the check failed");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">else if</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 用于在第一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 不成立时继续检查其他条件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
if (a == 1)<br />
{<br />
    print("Will be called if a is 1");<br />
}<br />
else if (a == 5)<br />
{<br />
    print("Will be called if a is 5");<br />
}<br />
else<br />
{<br />
    print("All other numbers");<br />
}</code></div></div><br />
你可以连续写多个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code>，但一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 组中只能有一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code>。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 只在最初的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 失败时才检查，且变量值以检查开始时的状态为准。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">?:（三元运算符）</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">?</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">:</code> 组合成三元运算符，可将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if-else</code> 写在单行内：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a,<br />
    b = 3;<br />
if (b == 3)<br />
{<br />
    a = 5;<br />
}<br />
else<br />
{<br />
    a = 7;<br />
}</code></div></div><br />
可简化为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a,<br />
    b = 3;<br />
a = (b == 3) ? 5 : 7;</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(条件) ? 真值 : 假值</code><br />
<br />
也可以嵌套（类似多个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code>）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a,<br />
    b = 3;<br />
a = (b == 1) ? 2 : (b == 2) ? 3 : (b == 3) ? 4 : 5;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">循环</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">while ()</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 循环在条件成立时重复执行代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 9;<br />
while (a &lt; 10)<br />
{<br />
    // 循环内的代码<br />
    a++;<br />
}</code></div></div><br />
每次到达 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">}</code> 时会回到条件重新判断。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">for ()</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code> 是压缩版的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 循环，包含三部分：初始化、条件、递增。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new a = 9; a &lt; 10; a++)<br />
{<br />
    // 循环内的代码<br />
}</code></div></div><br />
常用遍历玩家示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new i, a = GetMaxPlayers(); i &lt; a; i++)<br />
{<br />
    if (IsPlayerConnected(i))<br />
    {<br />
        // do something<br />
    }<br />
}</code></div></div><br />
三部分均可省略（留空）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a = 9;<br />
for ( ; a &lt; 10; )<br />
{<br />
    a++;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">do-while</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 先执行代码，再判断条件，因此<span style="font-weight: bold;" class="mycode_b">至少执行一次</span>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 10;<br />
do<br />
{<br />
    // 循环内的代码<br />
    a++;<br />
}<br />
while (a &lt; 10);  // 注意分号</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">if-goto</h4><br />
<br />
循环本质上就是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> + <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">goto</code> 的结构化形式（不推荐直接使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">goto</code>）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 9;<br />
loop_start:<br />
if (a &lt; 10)<br />
{<br />
    // 循环内的代码<br />
    a++;<br />
    goto loop_start;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">OBOE（Off By One Error）</h4><br />
<br />
OBOE 是最常见的循环错误之一——循环多跑或少跑一次。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 0,<br />
    b[10];<br />
while (a &lt;= sizeof (b))<br />
{<br />
    b[a] = 0;<br />
}</code></div></div><br />
上面会尝试访问 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b[10]</code>（越界），导致 OOB（Out Of Bounds）错误。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">特别注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 永远至少执行一次，更容易出现 OBOE。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">switch</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">switch</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 是结构化的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if / else if / else</code>，更清晰：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
switch (a)<br />
{<br />
    case 1:<br />
    {<br />
        // 不会执行<br />
    }<br />
    case 2:<br />
    {<br />
        // 不会执行<br />
    }<br />
    case 5:<br />
    {<br />
        // 会执行<br />
    }<br />
    default:<br />
    {<br />
        // 不会执行<br />
    }<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 只调用一次判断表达式（比连续 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 更高效）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">case</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 支持单个值、列表或范围：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>case 1, 2, 3, 4:    // 列表<br />
case 1 .. 4:        // 范围（推荐连续数字）</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">default</h4><br />
<br />
相当于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code>，所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 都不匹配时执行。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">单行语句</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">goto</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">goto</code> 直接跳转到标签（不推荐使用，会破坏程序流程）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">break</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">break</code> 立即跳出当前循环：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new a = 0; a &lt; 10; a++)<br />
{<br />
    if (a == 5) break;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">continue</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">continue</code> 跳过本次循环剩余代码，直接进入下一次迭代：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new a = 0; a &lt; 3; a++)<br />
{<br />
    if (a == 1) continue;<br />
    printf("a = %d", a);<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>a = 0<br />
a = 2</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：在某些循环（尤其是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code>）中使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">continue</code> 时要小心，可能导致无限循环。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">return</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 立即结束当前函数，返回到调用处：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{<br />
    print("1");<br />
    MyFunction(1);<br />
    print("3");<br />
}<br />
MyFunction(num)<br />
{<br />
    if (num == 1)<br />
    {<br />
        return;  // 直接返回，不执行下面的 print<br />
    }<br />
    print("2");<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1<br />
3</code></div></div><br />
也可以返回具体值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>return 27;</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：如果函数有时返回值，有时不返回值，必须在所有路径都显式 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 一个值。<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 控制结构</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SA-MP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#conditionals" target="_blank" rel="noopener" class="mycode_url">1 条件语句</a><br />
</li>
<li><a href="http://#if" target="_blank" rel="noopener" class="mycode_url">1.1 if</a><br />
</li>
<li><a href="http://#operators" target="_blank" rel="noopener" class="mycode_url">1.2 运算符</a><br />
</li>
<li><a href="http://#brackets" target="_blank" rel="noopener" class="mycode_url">1.3 括号</a><br />
</li>
<li><a href="http://#else" target="_blank" rel="noopener" class="mycode_url">1.4 else</a><br />
</li>
<li><a href="http://#else-if" target="_blank" rel="noopener" class="mycode_url">1.5 else if</a><br />
</li>
<li><a href="http://#ternary" target="_blank" rel="noopener" class="mycode_url">1.6 ?:（三元运算符）</a><br />
</li>
<li><a href="http://#loops" target="_blank" rel="noopener" class="mycode_url">2 循环</a><br />
</li>
<li><a href="http://#while" target="_blank" rel="noopener" class="mycode_url">2.1 while ()</a><br />
</li>
<li><a href="http://#for" target="_blank" rel="noopener" class="mycode_url">2.2 for ()</a><br />
</li>
<li><a href="http://#do-while" target="_blank" rel="noopener" class="mycode_url">2.3 do-while</a><br />
</li>
<li><a href="http://#if-goto" target="_blank" rel="noopener" class="mycode_url">2.4 if-goto</a><br />
</li>
<li><a href="http://#oboe" target="_blank" rel="noopener" class="mycode_url">2.5 OBOE（Off By One Error）</a><br />
</li>
<li><a href="http://#switch" target="_blank" rel="noopener" class="mycode_url">3 switch</a><br />
</li>
<li><a href="http://#switch-2" target="_blank" rel="noopener" class="mycode_url">3.1 switch</a><br />
</li>
<li><a href="http://#case" target="_blank" rel="noopener" class="mycode_url">3.2 case</a><br />
</li>
<li><a href="http://#default" target="_blank" rel="noopener" class="mycode_url">3.3 default</a><br />
</li>
<li><a href="http://#single-line-statements" target="_blank" rel="noopener" class="mycode_url">4 单行语句</a><br />
</li>
<li><a href="http://#goto" target="_blank" rel="noopener" class="mycode_url">4.1 goto</a><br />
</li>
<li><a href="http://#break" target="_blank" rel="noopener" class="mycode_url">4.2 break</a><br />
</li>
<li><a href="http://#continue" target="_blank" rel="noopener" class="mycode_url">4.3 continue</a><br />
</li>
<li><a href="http://#return" target="_blank" rel="noopener" class="mycode_url">4.4 return</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">条件语句</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">if</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 语句会检查某个条件是否成立，如果成立则执行对应代码。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
if (a == 5)<br />
{<br />
    print("a is 5");<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 后面的括号内是<span style="font-weight: bold;" class="mycode_b">条件</span>，你可以进行多种判断（详见运算符部分）。<br />
<br />
条件中不仅可以是变量，也可以是函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if (SomeFunction() == 5)<br />
{<br />
    print("SomeFunction() is 5");<br />
}</code></div></div><br />
还可以组合多个条件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5,<br />
    b = 3;<br />
if (a == 5 &amp;&amp; b != 3)<br />
{<br />
    print("Won't be printed");<br />
}</code></div></div><br />
上面检查 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a == 5</code> <span style="font-weight: bold;" class="mycode_b">并且</span> <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b != 3</code>，但 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b</code> 是 3，所以整个条件为假。<br />
<br />
使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">||</code>（或）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5,<br />
    b = 3;<br />
if (a == 5 || b != 3)<br />
{<br />
    print("Will be printed");<br />
}</code></div></div><br />
只要有一个条件为真，整个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 就成立（即使 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b != 3</code> 为假，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a == 5</code> 为真）。<br />
<br />
还可以链式比较（无需显式写多个 &amp;&amp;）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    idx = 3;<br />
if (0 &lt; idx &lt; 5)<br />
{<br />
    print("idx is greater than 0 and less than 5!");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">运算符</h4><br />
<br />
条件判断中常用的运算符及其含义：<br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">比较运算符</h5><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">==</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left == Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">!=</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边不等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left != Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&gt;</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边大于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &gt; Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&gt;=</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边大于等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &gt;= Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&lt;</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边小于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &lt; Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&lt;=</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左边小于等于右边</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &lt;= Right)</code></td>
  </tr>
</table>
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">逻辑运算符</h5><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">&amp;&amp;</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">并且（AND）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left &amp;&amp; Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">或者（OR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (Left || Right)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">!</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">非（NOT）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!Variable)</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">都不（NOR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!(Left || Right))</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不是都（NAND）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!(Left &amp;&amp; Right))</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">异或（XOR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if (!(Left &amp;&amp; Right) &amp;&amp; (Left || Right))</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">同或（NXOR）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if ((Left &amp;&amp; Right) || !(Left || Right))</code></td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">括号</h4><br />
<br />
括号决定运算顺序：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 3,<br />
    b = 3,<br />
    c = 1;<br />
if (a == 5 &amp;&amp; b == 3 || c == 1)<br />
{<br />
    print("Will this be called?");<br />
}</code></div></div><br />
有两种可能的解释：<br />
<br />
<ol type="1" class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(a == 5 &amp;&amp; b == 3) || c == 1</code>  <br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a == 5 &amp;&amp; (b == 3 || c == 1)</code><br />
</li>
</ol>
<br />
第一种：先判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a==5 &amp;&amp; b==3</code>（为假），再判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">c==1</code>（为真），整体为真。  <br />
第二种：先判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b==3 || c==1</code>（为真），再判断 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">a==5</code>（为假），整体为假。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">强烈建议始终使用括号</span>，既能明确逻辑，也能避免歧义。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">else</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code> 在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 条件不成立时执行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
if (a == 3)  // 假<br />
{<br />
    print("Won't be called");<br />
}<br />
else<br />
{<br />
    print("Will be called as the check failed");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">else if</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 用于在第一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 不成立时继续检查其他条件：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
if (a == 1)<br />
{<br />
    print("Will be called if a is 1");<br />
}<br />
else if (a == 5)<br />
{<br />
    print("Will be called if a is 5");<br />
}<br />
else<br />
{<br />
    print("All other numbers");<br />
}</code></div></div><br />
你可以连续写多个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code>，但一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 组中只能有一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code>。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 只在最初的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 失败时才检查，且变量值以检查开始时的状态为准。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">?:（三元运算符）</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">?</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">:</code> 组合成三元运算符，可将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if-else</code> 写在单行内：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a,<br />
    b = 3;<br />
if (b == 3)<br />
{<br />
    a = 5;<br />
}<br />
else<br />
{<br />
    a = 7;<br />
}</code></div></div><br />
可简化为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a,<br />
    b = 3;<br />
a = (b == 3) ? 5 : 7;</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(条件) ? 真值 : 假值</code><br />
<br />
也可以嵌套（类似多个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code>）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a,<br />
    b = 3;<br />
a = (b == 1) ? 2 : (b == 2) ? 3 : (b == 3) ? 4 : 5;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">循环</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">while ()</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 循环在条件成立时重复执行代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 9;<br />
while (a &lt; 10)<br />
{<br />
    // 循环内的代码<br />
    a++;<br />
}</code></div></div><br />
每次到达 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">}</code> 时会回到条件重新判断。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">for ()</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code> 是压缩版的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 循环，包含三部分：初始化、条件、递增。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new a = 9; a &lt; 10; a++)<br />
{<br />
    // 循环内的代码<br />
}</code></div></div><br />
常用遍历玩家示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new i, a = GetMaxPlayers(); i &lt; a; i++)<br />
{<br />
    if (IsPlayerConnected(i))<br />
    {<br />
        // do something<br />
    }<br />
}</code></div></div><br />
三部分均可省略（留空）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a = 9;<br />
for ( ; a &lt; 10; )<br />
{<br />
    a++;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">do-while</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 先执行代码，再判断条件，因此<span style="font-weight: bold;" class="mycode_b">至少执行一次</span>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 10;<br />
do<br />
{<br />
    // 循环内的代码<br />
    a++;<br />
}<br />
while (a &lt; 10);  // 注意分号</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">if-goto</h4><br />
<br />
循环本质上就是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> + <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">goto</code> 的结构化形式（不推荐直接使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">goto</code>）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 9;<br />
loop_start:<br />
if (a &lt; 10)<br />
{<br />
    // 循环内的代码<br />
    a++;<br />
    goto loop_start;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">OBOE（Off By One Error）</h4><br />
<br />
OBOE 是最常见的循环错误之一——循环多跑或少跑一次。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 0,<br />
    b[10];<br />
while (a &lt;= sizeof (b))<br />
{<br />
    b[a] = 0;<br />
}</code></div></div><br />
上面会尝试访问 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">b[10]</code>（越界），导致 OOB（Out Of Bounds）错误。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">特别注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 永远至少执行一次，更容易出现 OBOE。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">switch</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">switch</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 是结构化的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if / else if / else</code>，更清晰：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
    a = 5;<br />
switch (a)<br />
{<br />
    case 1:<br />
    {<br />
        // 不会执行<br />
    }<br />
    case 2:<br />
    {<br />
        // 不会执行<br />
    }<br />
    case 5:<br />
    {<br />
        // 会执行<br />
    }<br />
    default:<br />
    {<br />
        // 不会执行<br />
    }<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 只调用一次判断表达式（比连续 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 更高效）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">case</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 支持单个值、列表或范围：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>case 1, 2, 3, 4:    // 列表<br />
case 1 .. 4:        // 范围（推荐连续数字）</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">default</h4><br />
<br />
相当于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else</code>，所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 都不匹配时执行。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">单行语句</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">goto</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">goto</code> 直接跳转到标签（不推荐使用，会破坏程序流程）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">break</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">break</code> 立即跳出当前循环：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new a = 0; a &lt; 10; a++)<br />
{<br />
    if (a == 5) break;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">continue</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">continue</code> 跳过本次循环剩余代码，直接进入下一次迭代：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new a = 0; a &lt; 3; a++)<br />
{<br />
    if (a == 1) continue;<br />
    printf("a = %d", a);<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>a = 0<br />
a = 2</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：在某些循环（尤其是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code>）中使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">continue</code> 时要小心，可能导致无限循环。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">return</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 立即结束当前函数，返回到调用处：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main()<br />
{<br />
    print("1");<br />
    MyFunction(1);<br />
    print("3");<br />
}<br />
MyFunction(num)<br />
{<br />
    if (num == 1)<br />
    {<br />
        return;  // 直接返回，不执行下面的 print<br />
    }<br />
    print("2");<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1<br />
3</code></div></div><br />
也可以返回具体值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>return 27;</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：如果函数有时返回值，有时不返回值，必须在所有路径都显式 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 一个值。<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[wiki系列] openmp/samp脚本基础]]></title>
			<link>https://open-mp.cn/showthread.php?tid=19</link>
			<pubDate>Sat, 21 Mar 2026 22:34:25 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=19</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 脚本基础</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SAMP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#starting-out" target="_blank" rel="noopener" class="mycode_url">1 入门！</a><br />
</li>
<li><a href="http://#include" target="_blank" rel="noopener" class="mycode_url">1.1 Include</a><br />
</li>
<li><a href="http://#calls" target="_blank" rel="noopener" class="mycode_url">1.2 调用</a><br />
</li>
<li><a href="http://#statements" target="_blank" rel="noopener" class="mycode_url">1.3 语句</a><br />
</li>
<li><a href="http://#functions" target="_blank" rel="noopener" class="mycode_url">2 函数</a><br />
</li>
<li><a href="http://#calling" target="_blank" rel="noopener" class="mycode_url">2.1 调用</a><br />
</li>
<li><a href="http://#defining" target="_blank" rel="noopener" class="mycode_url">2.2 定义</a><br />
</li>
<li><a href="http://#parameters" target="_blank" rel="noopener" class="mycode_url">2.3 参数</a><br />
</li>
<li><a href="http://#variables" target="_blank" rel="noopener" class="mycode_url">3 变量</a><br />
</li>
<li><a href="http://#declaration" target="_blank" rel="noopener" class="mycode_url">3.1 声明</a><br />
</li>
<li><a href="http://#setting" target="_blank" rel="noopener" class="mycode_url">3.2 赋值</a><br />
</li>
<li><a href="http://#arrays" target="_blank" rel="noopener" class="mycode_url">3.3 数组</a><br />
</li>
<li><a href="http://#declaration-2" target="_blank" rel="noopener" class="mycode_url">3.3.1 声明</a><br />
</li>
<li><a href="http://#accessing" target="_blank" rel="noopener" class="mycode_url">3.3.2 访问</a><br />
</li>
<li><a href="http://#example" target="_blank" rel="noopener" class="mycode_url">3.3.3 示例</a><br />
</li>
<li><a href="http://#strings" target="_blank" rel="noopener" class="mycode_url">3.4 字符串</a><br />
</li>
<li><a href="http://#basic-use" target="_blank" rel="noopener" class="mycode_url">3.4.1 基本用法</a><br />
</li>
<li><a href="http://#escape-character" target="_blank" rel="noopener" class="mycode_url">3.4.2 转义字符</a><br />
</li>
<li><a href="http://#tags" target="_blank" rel="noopener" class="mycode_url">3.5 标签</a><br />
</li>
<li><a href="http://#scope" target="_blank" rel="noopener" class="mycode_url">3.6 作用域</a><br />
</li>
<li><a href="http://#local" target="_blank" rel="noopener" class="mycode_url">3.6.1 局部（local）</a><br />
</li>
<li><a href="http://#static-local" target="_blank" rel="noopener" class="mycode_url">3.6.2 静态局部（static local）</a><br />
</li>
<li><a href="http://#global" target="_blank" rel="noopener" class="mycode_url">3.6.3 全局（global）</a><br />
</li>
<li><a href="http://#global-static" target="_blank" rel="noopener" class="mycode_url">3.6.4 全局静态（global static）</a><br />
</li>
<li><a href="http://#control-structures" target="_blank" rel="noopener" class="mycode_url">4 控制结构</a><br />
</li>
<li><a href="http://#keywords" target="_blank" rel="noopener" class="mycode_url">5 关键字</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">入门！</h3><br />
<br />
下面是一个可能最简单的脚本示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
我们将逐一讲解各个部分，先从第一行开始。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Include</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;</code></div></div><br />
这一行会把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/includes/open.mp.inc</code> 文件中的所有代码加载到你的脚本中，这样你就可以使用它提供的一切内容。其中它还包含了：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;args&gt;<br />
#include &lt;console&gt;<br />
#include &lt;core&gt;<br />
#include &lt;file&gt;<br />
#include &lt;float&gt;<br />
#include &lt;string&gt;<br />
#include &lt;time&gt;<br />
#include &lt;omp_core&gt;<br />
#include &lt;omp_player&gt;<br />
#include &lt;omp_actor&gt;<br />
#include &lt;omp_checkpoint&gt;<br />
#include &lt;omp_class&gt;<br />
#include &lt;omp_database&gt;<br />
#include &lt;omp_dialog&gt;<br />
#include &lt;omp_gangzone&gt;<br />
#include &lt;omp_http&gt;<br />
#include &lt;omp_menu&gt;<br />
#include &lt;omp_network&gt;<br />
#include &lt;omp_object&gt;<br />
#include &lt;omp_pickup&gt;<br />
#include &lt;omp_textdraw&gt;<br />
#include &lt;omp_variable&gt;<br />
#include &lt;omp_vehicle&gt;<br />
#include &lt;omp_textlabel&gt;<br />
#include &lt;omp_npc&gt;</code></div></div><br />
这些文件包含了 open.mp(samp) 的所有核心功能，因此只需这一行，你就拥有了 open.mp(samp) 的全部函数（函数后面会详细说明）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">调用</h4><br />
<br />
接下来是函数调用的两部分。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code> 是你自己编写代码的函数，由外部调用；<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print(string[])</code> 是代码在别处定义、由你调用的函数。目前这个脚本只会加载、打印一行字符串（即在服务器控制台输出 “Hello World!”，不带引号——这是所有脚本语言的传统），然后结束。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>return 1;</code></div></div><br />
这条语句将值 1 返回给调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code> 的地方，告诉它执行结果（具体返回值在这里不重要，但在其他地方很重要）。<br />
<br />
你现在已经写出了第一个（非常基础）的脚本。如果你在 qawno 中选择“文件 → 新建”，它会给你一个更大的模板，包含所有回调（见下文），包括 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code>（严格来说它不是回调，但行为类似）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">语句</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 行都以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">;</code>（分号）结尾，分号表示一条<span style="font-weight: bold;" class="mycode_b">语句</span>的结束（语句是一组函数和运算符的组合，用于完成某项操作，类似自然语言中的句子）。大多数人把每条语句写在单独一行，但这不是必须的，只是为了更清晰。下面这种写法同样有效：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1; <br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code>（大括号）用于将一组语句组合在一起执行（类似自然语言中的段落）。如果你写成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main() <br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;</code></div></div><br />
编译器会报错，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1;</code> 没有被括起来，不属于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code> 函数。大括号将多条语句组合成一条<span style="font-weight: bold;" class="mycode_b">复合语句</span>，而函数体只能包含一条语句。没有大括号时，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 是两条独立的语句，函数只能有一条，所以第二条语句就游离在函数之外，这是非法的。<br />
<br />
不过，你也可以用逗号运算符 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">,</code> 来扩展复合语句，但不推荐这样做（不是最佳编码习惯）。示例如下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main() <br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!"), return 1;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">函数</h3><br />
<br />
函数是一段完成特定任务的代码，可以从其他地方调用。它还可以将执行结果返回给调用它的地方。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">调用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>print("Hello World!");</code></div></div><br />
如“入门”部分所述，这会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 函数（定义在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">open.mp.inc</code> 中，所以需要 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code>），并让它在服务器控制台显示 “Hello World!”。<br />
<br />
函数由<span style="font-weight: bold;" class="mycode_b">函数名</span>（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code>）和<span style="font-weight: bold;" class="mycode_b">参数列表</span>（用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">()</code> 括起来）组成。参数列表向函数传递额外数据。如果没有参数，你就需要成千上万个函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printa();<br />
printaa();<br />
printab();<br />
...</code></div></div><br />
函数可以有任意数量的参数（从 0 开始，至少支持 128 个）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("Hello World!", 1, 2, 3, 4, 5, 6);</code></div></div><br />
现在不用关心这个函数具体做什么，只需知道它有 7 个参数，用逗号分隔。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">定义</h4><br />
<br />
除了调用已有函数，你也可以自己编写并调用函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return MyFunction();<br />
}<br />
<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
这段代码功能与最初的示例完全相同，只是结构不同。当模式启动时 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code> 被自动调用，它再调用自定义函数 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction()</code>。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction()</code> 在控制台打印消息，然后返回 1 给 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code> 再把这个值返回给服务器。<br />
<br />
因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return MyFunction();</code> 是一条完整语句，你也可以写成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main() return MyFunction();<br />
<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
但大多数人为了清晰起见还是分开写。你也可以完全不使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction</code> 的返回值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyFunction();<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">参数</h4><br />
<br />
参数是一种特殊的<span style="font-weight: bold;" class="mycode_b">变量</span>，你不需要自己声明，它来自调用函数的地方：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return MyFunction("Hello World!");<br />
}<br />
<br />
MyFunction(const string[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print(string);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
这段代码功能相同，但现在我们把要显示的内容传给了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction()</code>。调用时把字符串 “Hello World!” 传递给函数，存储在名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string</code> 的变量中（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">[]</code> 表示这是一个数组，后面会解释）。然后调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code>，把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string</code> 的内容传给它（没有引号，所以它是一个变量）。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">变量</h3><br />
<br />
变量本质上是内存中的一块空间，用于存储数据，可以随时读取和修改。变量由一个或多个 <span style="font-weight: bold;" class="mycode_b">cell</span> 组成，一个 cell 是 32 位（4 字节），默认有符号，可存储 -2147483648 到 2147483647（注意 -2147483648 在 PAWN 中定义不完善，显示时可能异常）。由多个 cell 组成的变量叫<span style="font-weight: bold;" class="mycode_b">数组</span>，字符串是一种特殊的数组，每个 cell 存放一个字符（打包字符串每个 cell 可存 4 个字符，但这里不讨论）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明</h4><br />
<br />
要创建一个新变量，必须先声明它：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable;</code></div></div><br />
这会创建一个名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">myVariable</code> 的变量，初始值为 0。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">赋值</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 7;</code></div></div><br />
声明变量并设置初始值为 7。现在打印它会显示 7。要打印非字符串变量，需要使用前面提到的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf()</code>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 7;<br />
<br />
printf("%d", myVariable);</code></div></div><br />
现在只需知道这会在服务器控制台输出变量的值（当前是 7）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 7;<br />
<br />
printf("%d", myVariable);<br />
<br />
myVariable = 8;<br />
<br />
printf("%d", myVariable);</code></div></div><br />
这段代码会先打印 7，然后把变量改为 8，再打印新的值。<br />
<br />
变量操作示例（更多运算符请参考其他章节）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myVariable = myVariable + 4;&nbsp;&nbsp; // 等价于<br />
myVariable += 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 增加 4<br />
<br />
myVariable -= 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 减少 4<br />
myVariable *= 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 乘以 4<br />
myVariable /= 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 除以 4</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">数组</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明</h4><br />
<br />
数组是一种可以同时存储多个数据、动态访问的变量。数组大小在编译时就固定了，必须提前知道需要多少个槽位。最常见的例子是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 数组，每个玩家一个槽位，确保数据不会互相干扰。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[5];</code></div></div><br />
这会创建一个有 5 个槽位的数组。<span style="font-weight: bold;" class="mycode_b">不能</span>这样做：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 5,<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[myVariable];&nbsp;&nbsp;// 错误！</code></div></div><br />
因为 PAWN 在编译时就分配内存，数组大小必须是常量。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">访问</h4><br />
<br />
要给数组某个位置赋值，必须指定下标（index），下标可以是变量：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[5];<br />
<br />
myArray[2] = 7;</code></div></div><br />
数组现在的内容是：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0, 0, 7, 0, 0</code><br />
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：下标从 0 开始计数，而不是 1。<br />
<br />
如果你尝试访问 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">myArray[5]</code>（超出范围），可能会导致服务器崩溃。<br />
<br />
下标可以是数字、变量，甚至是返回值的函数。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[5],<br />
&nbsp;&nbsp;&nbsp;&nbsp;myIndex = 2;<br />
<br />
myArray[myIndex] = 7;</code></div></div><br />
数组中的元素可以像普通变量一样使用：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myArray[2] = myArray[2] + 1;<br />
myArray[2] += 1;<br />
myArray[2]++;</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例</h4><br />
<br />
最常见的数组是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 数组（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 是一个常量，默认 1000）。下面对比用普通变量和数组处理 4 个玩家数据（假设 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 为 4）：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">传统写法（4 个变量）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;gPlayer0, gPlayer1, gPlayer2, gPlayer3;<br />
<br />
SetPlayerValue(playerid, value)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;switch (playerid)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 0: gPlayer0 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 1: gPlayer1 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 2: gPlayer2 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 3: gPlayer3 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">数组写法（推荐）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;gPlayers[MAX_PLAYERS];<br />
<br />
SetPlayerValue(playerid, value)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;gPlayers[playerid] = value;<br />
}</code></div></div><br />
数组写法无论玩家数量多少，都只需要一行代码，清晰且高效。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">字符串</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基本用法</h4><br />
<br />
字符串是一种特殊的数组，用于存放多个字符组成文本。每个字符默认占用一个 cell。字符串以 <span style="font-weight: bold;" class="mycode_b">NULL 终止</span>（遇到 0 就结束，不是字符 '0'）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString[16] = "Hello World!";</code></div></div><br />
这会创建一个可容纳 15 个字符的字符串，初始值为 “Hello World!”。内部实际存储为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>104 101 108 108 111 0 x x x x x x x x x x</code></div></div><br />
（0 是终止符，后面的 x 无关紧要）<br />
<br />
你可以像操作数组一样修改字符串：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString[16] = "Hello World!";<br />
<br />
myString[1] = 97;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 97 是 'a'</code></div></div><br />
结果变为 “hallo”。<br />
<br />
更易读的写法：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myString[1] = 'a';</code></div></div><br />
单引号表示单个字符。<br />
<br />
把某个位置设为终止符：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myString[1] = '&#92;0';&nbsp;&nbsp; // 或 = 0;</code></div></div><br />
字符串会变成 “h”。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">转义字符</h4><br />
<br />
反斜杠 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 是特殊字符，用于创建无法直接输入的字符：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString[4] = "&#92;"";&nbsp;&nbsp; // 字符串内容就是一个双引号 "</code></div></div><br />
常用转义序列：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">转义符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\0</code> / <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">EOS</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">NULL 字符</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串结束</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\n</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">换行</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">Linux 新行（Windows 也可用）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\r</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">回车</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">Windows 新行用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\r\n</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\\</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">反斜杠</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">实际输出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\'</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">单引号</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在单引号中用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'\' '</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\"</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">双引号</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在字符串中用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\xNNN;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">十六进制字符</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">用十六进制值设置字符</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\NNN;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">十进制字符</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">用十进制值设置字符</td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">标签</h3><br />
<br />
标签是变量的额外信息，用于定义其用途和可使用范围。标签分为强标签（首字母大写）和弱标签。<br />
<br />
示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;Float:a = 6.0;</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 就是标签，表示这是一个浮点数（小数）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>native SetGravity(Float:gravity);</code></div></div><br />
这要求参数必须是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 类型：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SetGravity(6.0);<br />
<br />
new Float:fGrav = 5.0;<br />
<br />
SetGravity(fGrav);</code></div></div><br />
使用错误标签会产生 <span style="font-weight: bold;" class="mycode_b">tag mismatch</span> 警告：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SetGravity(MyTag:7);&nbsp;&nbsp;// 错误</code></div></div><br />
标签区分大小写。<br />
<br />
你可以自定义标签：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myTag: variable = 0,<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;AppleTag: another = 1;</code></div></div><br />
直接相加时需要用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">_: </code> 去除标签，否则会报标签不匹配。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">作用域</h3><br />
<br />
作用域决定变量在哪里可用。主要有四种：局部、静态局部、全局、全局静态。变量必须先声明后使用。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">局部（local）</h4><br />
<br />
在函数内用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 声明：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunc()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new var1 = 4;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", var1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new var2 = 8;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%d %d", var1, var2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// var2 已失效<br />
}<br />
// var1 已失效</code></div></div><br />
局部变量每次进入函数都会重置：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new i = 0; i &lt; 3; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new j = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1<br />
1<br />
1</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">静态局部（static local）</h4><br />
<br />
与局部变量作用域相同，但值会在函数多次调用间保留：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new i = 0; i &lt; 3; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;static j = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1<br />
2<br />
3</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">全局（global）</h4><br />
<br />
在函数外声明，可在任何函数中使用，且永不重置：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;gMyVar = 4;<br />
<br />
MyFunc()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", gMyVar);<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">全局静态（global static）</h4><br />
<br />
与全局类似，但<span style="font-weight: bold;" class="mycode_b">仅限声明所在文件</span>使用：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">File1.pwn</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>static<br />
&nbsp;&nbsp;&nbsp;&nbsp;gs_MyVar = 4;<br />
<br />
MyFunc()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", gs_MyVar);<br />
}<br />
<br />
#include "File2"</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">File2.pwn</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunc2()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// gs_MyVar 在这里不存在<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", gs_MyVar);&nbsp;&nbsp;// 错误<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 也可用于函数，实现类似“私有”函数的效果。<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">[wiki系列] openmp/samp 脚本基础</h2><br />
<br />
<span style="font-weight: bold;" class="mycode_b">来自 SAMP Wiki</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<ul class="mycode_list"><li><a href="http://#starting-out" target="_blank" rel="noopener" class="mycode_url">1 入门！</a><br />
</li>
<li><a href="http://#include" target="_blank" rel="noopener" class="mycode_url">1.1 Include</a><br />
</li>
<li><a href="http://#calls" target="_blank" rel="noopener" class="mycode_url">1.2 调用</a><br />
</li>
<li><a href="http://#statements" target="_blank" rel="noopener" class="mycode_url">1.3 语句</a><br />
</li>
<li><a href="http://#functions" target="_blank" rel="noopener" class="mycode_url">2 函数</a><br />
</li>
<li><a href="http://#calling" target="_blank" rel="noopener" class="mycode_url">2.1 调用</a><br />
</li>
<li><a href="http://#defining" target="_blank" rel="noopener" class="mycode_url">2.2 定义</a><br />
</li>
<li><a href="http://#parameters" target="_blank" rel="noopener" class="mycode_url">2.3 参数</a><br />
</li>
<li><a href="http://#variables" target="_blank" rel="noopener" class="mycode_url">3 变量</a><br />
</li>
<li><a href="http://#declaration" target="_blank" rel="noopener" class="mycode_url">3.1 声明</a><br />
</li>
<li><a href="http://#setting" target="_blank" rel="noopener" class="mycode_url">3.2 赋值</a><br />
</li>
<li><a href="http://#arrays" target="_blank" rel="noopener" class="mycode_url">3.3 数组</a><br />
</li>
<li><a href="http://#declaration-2" target="_blank" rel="noopener" class="mycode_url">3.3.1 声明</a><br />
</li>
<li><a href="http://#accessing" target="_blank" rel="noopener" class="mycode_url">3.3.2 访问</a><br />
</li>
<li><a href="http://#example" target="_blank" rel="noopener" class="mycode_url">3.3.3 示例</a><br />
</li>
<li><a href="http://#strings" target="_blank" rel="noopener" class="mycode_url">3.4 字符串</a><br />
</li>
<li><a href="http://#basic-use" target="_blank" rel="noopener" class="mycode_url">3.4.1 基本用法</a><br />
</li>
<li><a href="http://#escape-character" target="_blank" rel="noopener" class="mycode_url">3.4.2 转义字符</a><br />
</li>
<li><a href="http://#tags" target="_blank" rel="noopener" class="mycode_url">3.5 标签</a><br />
</li>
<li><a href="http://#scope" target="_blank" rel="noopener" class="mycode_url">3.6 作用域</a><br />
</li>
<li><a href="http://#local" target="_blank" rel="noopener" class="mycode_url">3.6.1 局部（local）</a><br />
</li>
<li><a href="http://#static-local" target="_blank" rel="noopener" class="mycode_url">3.6.2 静态局部（static local）</a><br />
</li>
<li><a href="http://#global" target="_blank" rel="noopener" class="mycode_url">3.6.3 全局（global）</a><br />
</li>
<li><a href="http://#global-static" target="_blank" rel="noopener" class="mycode_url">3.6.4 全局静态（global static）</a><br />
</li>
<li><a href="http://#control-structures" target="_blank" rel="noopener" class="mycode_url">4 控制结构</a><br />
</li>
<li><a href="http://#keywords" target="_blank" rel="noopener" class="mycode_url">5 关键字</a><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">入门！</h3><br />
<br />
下面是一个可能最简单的脚本示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
我们将逐一讲解各个部分，先从第一行开始。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Include</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;</code></div></div><br />
这一行会把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/includes/open.mp.inc</code> 文件中的所有代码加载到你的脚本中，这样你就可以使用它提供的一切内容。其中它还包含了：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;args&gt;<br />
#include &lt;console&gt;<br />
#include &lt;core&gt;<br />
#include &lt;file&gt;<br />
#include &lt;float&gt;<br />
#include &lt;string&gt;<br />
#include &lt;time&gt;<br />
#include &lt;omp_core&gt;<br />
#include &lt;omp_player&gt;<br />
#include &lt;omp_actor&gt;<br />
#include &lt;omp_checkpoint&gt;<br />
#include &lt;omp_class&gt;<br />
#include &lt;omp_database&gt;<br />
#include &lt;omp_dialog&gt;<br />
#include &lt;omp_gangzone&gt;<br />
#include &lt;omp_http&gt;<br />
#include &lt;omp_menu&gt;<br />
#include &lt;omp_network&gt;<br />
#include &lt;omp_object&gt;<br />
#include &lt;omp_pickup&gt;<br />
#include &lt;omp_textdraw&gt;<br />
#include &lt;omp_variable&gt;<br />
#include &lt;omp_vehicle&gt;<br />
#include &lt;omp_textlabel&gt;<br />
#include &lt;omp_npc&gt;</code></div></div><br />
这些文件包含了 open.mp(samp) 的所有核心功能，因此只需这一行，你就拥有了 open.mp(samp) 的全部函数（函数后面会详细说明）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">调用</h4><br />
<br />
接下来是函数调用的两部分。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code> 是你自己编写代码的函数，由外部调用；<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print(string[])</code> 是代码在别处定义、由你调用的函数。目前这个脚本只会加载、打印一行字符串（即在服务器控制台输出 “Hello World!”，不带引号——这是所有脚本语言的传统），然后结束。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>return 1;</code></div></div><br />
这条语句将值 1 返回给调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code> 的地方，告诉它执行结果（具体返回值在这里不重要，但在其他地方很重要）。<br />
<br />
你现在已经写出了第一个（非常基础）的脚本。如果你在 qawno 中选择“文件 → 新建”，它会给你一个更大的模板，包含所有回调（见下文），包括 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code>（严格来说它不是回调，但行为类似）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">语句</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 行都以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">;</code>（分号）结尾，分号表示一条<span style="font-weight: bold;" class="mycode_b">语句</span>的结束（语句是一组函数和运算符的组合，用于完成某项操作，类似自然语言中的句子）。大多数人把每条语句写在单独一行，但这不是必须的，只是为了更清晰。下面这种写法同样有效：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1; <br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code>（大括号）用于将一组语句组合在一起执行（类似自然语言中的段落）。如果你写成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main() <br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;</code></div></div><br />
编译器会报错，因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1;</code> 没有被括起来，不属于 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main</code> 函数。大括号将多条语句组合成一条<span style="font-weight: bold;" class="mycode_b">复合语句</span>，而函数体只能包含一条语句。没有大括号时，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 和 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 是两条独立的语句，函数只能有一条，所以第二条语句就游离在函数之外，这是非法的。<br />
<br />
不过，你也可以用逗号运算符 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">,</code> 来扩展复合语句，但不推荐这样做（不是最佳编码习惯）。示例如下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>main() <br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!"), return 1;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">函数</h3><br />
<br />
函数是一段完成特定任务的代码，可以从其他地方调用。它还可以将执行结果返回给调用它的地方。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">调用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>print("Hello World!");</code></div></div><br />
如“入门”部分所述，这会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code> 函数（定义在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">open.mp.inc</code> 中，所以需要 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code>），并让它在服务器控制台显示 “Hello World!”。<br />
<br />
函数由<span style="font-weight: bold;" class="mycode_b">函数名</span>（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code>）和<span style="font-weight: bold;" class="mycode_b">参数列表</span>（用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">()</code> 括起来）组成。参数列表向函数传递额外数据。如果没有参数，你就需要成千上万个函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printa();<br />
printaa();<br />
printab();<br />
...</code></div></div><br />
函数可以有任意数量的参数（从 0 开始，至少支持 128 个）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("Hello World!", 1, 2, 3, 4, 5, 6);</code></div></div><br />
现在不用关心这个函数具体做什么，只需知道它有 7 个参数，用逗号分隔。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">定义</h4><br />
<br />
除了调用已有函数，你也可以自己编写并调用函数：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return MyFunction();<br />
}<br />
<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
这段代码功能与最初的示例完全相同，只是结构不同。当模式启动时 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code> 被自动调用，它再调用自定义函数 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction()</code>。<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction()</code> 在控制台打印消息，然后返回 1 给 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code>，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main()</code> 再把这个值返回给服务器。<br />
<br />
因为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return MyFunction();</code> 是一条完整语句，你也可以写成：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main() return MyFunction();<br />
<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
但大多数人为了清晰起见还是分开写。你也可以完全不使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction</code> 的返回值：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyFunction();<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("Hello World!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">参数</h4><br />
<br />
参数是一种特殊的<span style="font-weight: bold;" class="mycode_b">变量</span>，你不需要自己声明，它来自调用函数的地方：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return MyFunction("Hello World!");<br />
}<br />
<br />
MyFunction(const string[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;print(string);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
这段代码功能相同，但现在我们把要显示的内容传给了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MyFunction()</code>。调用时把字符串 “Hello World!” 传递给函数，存储在名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string</code> 的变量中（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">[]</code> 表示这是一个数组，后面会解释）。然后调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">print</code>，把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">string</code> 的内容传给它（没有引号，所以它是一个变量）。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">变量</h3><br />
<br />
变量本质上是内存中的一块空间，用于存储数据，可以随时读取和修改。变量由一个或多个 <span style="font-weight: bold;" class="mycode_b">cell</span> 组成，一个 cell 是 32 位（4 字节），默认有符号，可存储 -2147483648 到 2147483647（注意 -2147483648 在 PAWN 中定义不完善，显示时可能异常）。由多个 cell 组成的变量叫<span style="font-weight: bold;" class="mycode_b">数组</span>，字符串是一种特殊的数组，每个 cell 存放一个字符（打包字符串每个 cell 可存 4 个字符，但这里不讨论）。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明</h4><br />
<br />
要创建一个新变量，必须先声明它：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable;</code></div></div><br />
这会创建一个名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">myVariable</code> 的变量，初始值为 0。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">赋值</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 7;</code></div></div><br />
声明变量并设置初始值为 7。现在打印它会显示 7。要打印非字符串变量，需要使用前面提到的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">printf()</code>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 7;<br />
<br />
printf("%d", myVariable);</code></div></div><br />
现在只需知道这会在服务器控制台输出变量的值（当前是 7）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 7;<br />
<br />
printf("%d", myVariable);<br />
<br />
myVariable = 8;<br />
<br />
printf("%d", myVariable);</code></div></div><br />
这段代码会先打印 7，然后把变量改为 8，再打印新的值。<br />
<br />
变量操作示例（更多运算符请参考其他章节）：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myVariable = myVariable + 4;&nbsp;&nbsp; // 等价于<br />
myVariable += 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 增加 4<br />
<br />
myVariable -= 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 减少 4<br />
myVariable *= 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 乘以 4<br />
myVariable /= 4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 除以 4</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">数组</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明</h4><br />
<br />
数组是一种可以同时存储多个数据、动态访问的变量。数组大小在编译时就固定了，必须提前知道需要多少个槽位。最常见的例子是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 数组，每个玩家一个槽位，确保数据不会互相干扰。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[5];</code></div></div><br />
这会创建一个有 5 个槽位的数组。<span style="font-weight: bold;" class="mycode_b">不能</span>这样做：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myVariable = 5,<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[myVariable];&nbsp;&nbsp;// 错误！</code></div></div><br />
因为 PAWN 在编译时就分配内存，数组大小必须是常量。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">访问</h4><br />
<br />
要给数组某个位置赋值，必须指定下标（index），下标可以是变量：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[5];<br />
<br />
myArray[2] = 7;</code></div></div><br />
数组现在的内容是：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0, 0, 7, 0, 0</code><br />
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：下标从 0 开始计数，而不是 1。<br />
<br />
如果你尝试访问 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">myArray[5]</code>（超出范围），可能会导致服务器崩溃。<br />
<br />
下标可以是数字、变量，甚至是返回值的函数。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myArray[5],<br />
&nbsp;&nbsp;&nbsp;&nbsp;myIndex = 2;<br />
<br />
myArray[myIndex] = 7;</code></div></div><br />
数组中的元素可以像普通变量一样使用：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myArray[2] = myArray[2] + 1;<br />
myArray[2] += 1;<br />
myArray[2]++;</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例</h4><br />
<br />
最常见的数组是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 数组（<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 是一个常量，默认 1000）。下面对比用普通变量和数组处理 4 个玩家数据（假设 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 为 4）：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">传统写法（4 个变量）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;gPlayer0, gPlayer1, gPlayer2, gPlayer3;<br />
<br />
SetPlayerValue(playerid, value)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;switch (playerid)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 0: gPlayer0 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 1: gPlayer1 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 2: gPlayer2 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 3: gPlayer3 = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">数组写法（推荐）：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;gPlayers[MAX_PLAYERS];<br />
<br />
SetPlayerValue(playerid, value)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;gPlayers[playerid] = value;<br />
}</code></div></div><br />
数组写法无论玩家数量多少，都只需要一行代码，清晰且高效。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">字符串</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基本用法</h4><br />
<br />
字符串是一种特殊的数组，用于存放多个字符组成文本。每个字符默认占用一个 cell。字符串以 <span style="font-weight: bold;" class="mycode_b">NULL 终止</span>（遇到 0 就结束，不是字符 '0'）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString[16] = "Hello World!";</code></div></div><br />
这会创建一个可容纳 15 个字符的字符串，初始值为 “Hello World!”。内部实际存储为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>104 101 108 108 111 0 x x x x x x x x x x</code></div></div><br />
（0 是终止符，后面的 x 无关紧要）<br />
<br />
你可以像操作数组一样修改字符串：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString[16] = "Hello World!";<br />
<br />
myString[1] = 97;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 97 是 'a'</code></div></div><br />
结果变为 “hallo”。<br />
<br />
更易读的写法：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myString[1] = 'a';</code></div></div><br />
单引号表示单个字符。<br />
<br />
把某个位置设为终止符：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>myString[1] = '&#92;0';&nbsp;&nbsp; // 或 = 0;</code></div></div><br />
字符串会变成 “h”。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">转义字符</h4><br />
<br />
反斜杠 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code> 是特殊字符，用于创建无法直接输入的字符：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString[4] = "&#92;"";&nbsp;&nbsp; // 字符串内容就是一个双引号 "</code></div></div><br />
常用转义序列：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">转义符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\0</code> / <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">EOS</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">NULL 字符</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串结束</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\n</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">换行</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">Linux 新行（Windows 也可用）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\r</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">回车</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">Windows 新行用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\r\n</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\\</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">反斜杠</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">实际输出 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\'</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">单引号</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在单引号中用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">'\' '</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\"</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">双引号</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在字符串中用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\xNNN;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">十六进制字符</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">用十六进制值设置字符</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\NNN;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">十进制字符</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">用十进制值设置字符</td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">标签</h3><br />
<br />
标签是变量的额外信息，用于定义其用途和可使用范围。标签分为强标签（首字母大写）和弱标签。<br />
<br />
示例：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;Float:a = 6.0;</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 就是标签，表示这是一个浮点数（小数）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>native SetGravity(Float:gravity);</code></div></div><br />
这要求参数必须是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float</code> 类型：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SetGravity(6.0);<br />
<br />
new Float:fGrav = 5.0;<br />
<br />
SetGravity(fGrav);</code></div></div><br />
使用错误标签会产生 <span style="font-weight: bold;" class="mycode_b">tag mismatch</span> 警告：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SetGravity(MyTag:7);&nbsp;&nbsp;// 错误</code></div></div><br />
标签区分大小写。<br />
<br />
你可以自定义标签：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myTag: variable = 0,<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;AppleTag: another = 1;</code></div></div><br />
直接相加时需要用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">_: </code> 去除标签，否则会报标签不匹配。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">作用域</h3><br />
<br />
作用域决定变量在哪里可用。主要有四种：局部、静态局部、全局、全局静态。变量必须先声明后使用。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">局部（local）</h4><br />
<br />
在函数内用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 声明：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunc()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new var1 = 4;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", var1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new var2 = 8;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%d %d", var1, var2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// var2 已失效<br />
}<br />
// var1 已失效</code></div></div><br />
局部变量每次进入函数都会重置：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new i = 0; i &lt; 3; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new j = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1<br />
1<br />
1</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">静态局部（static local）</h4><br />
<br />
与局部变量作用域相同，但值会在函数多次调用间保留：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>for (new i = 0; i &lt; 3; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;static j = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />
}</code></div></div><br />
输出：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1<br />
2<br />
3</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">全局（global）</h4><br />
<br />
在函数外声明，可在任何函数中使用，且永不重置：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new<br />
&nbsp;&nbsp;&nbsp;&nbsp;gMyVar = 4;<br />
<br />
MyFunc()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", gMyVar);<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">全局静态（global static）</h4><br />
<br />
与全局类似，但<span style="font-weight: bold;" class="mycode_b">仅限声明所在文件</span>使用：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">File1.pwn</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>static<br />
&nbsp;&nbsp;&nbsp;&nbsp;gs_MyVar = 4;<br />
<br />
MyFunc()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", gs_MyVar);<br />
}<br />
<br />
#include "File2"</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">File2.pwn</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunc2()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// gs_MyVar 在这里不存在<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("%d", gs_MyVar);&nbsp;&nbsp;// 错误<br />
}</code></div></div><br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 也可用于函数，实现类似“私有”函数的效果。<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[SAMP 迁移到 openmp 完整指南 + pawn 编译报错全解析]]></title>
			<link>https://open-mp.cn/showthread.php?tid=18</link>
			<pubDate>Fri, 20 Mar 2026 22:36:25 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=18</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">SAMP 迁移到 openmp 完整指南 + pawn 编译报错全解析</h2><br />
<br />
<hr class="mycode_hr" />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>本篇适合：<ul class="mycode_list"><li>已有 SA-MP 服务器，想迁移到 open.mp 的开发者<br />
</li>
<li>在编译时遇到错误不知道怎么处理的新手</blockquote>
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第一部分：迁移步骤</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第一步：下载 open.mp 服务端</h4><br />
<br />
前往 <a href="https://github.com/openmultiplayer/open.mp/releases" target="_blank" rel="noopener" class="mycode_url">https://github.com/openmultiplayer/open.mp/releases</a> 下载最新版本。<br />
<ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">open.mp-win-x86.zip</code> — Windows 服务器<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">open.mp-linux-x86.tar.gz</code> — Linux 服务器<br />
</li>
</ul>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第二步：解压</h4><br />
<br />
目录结构<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>omp-server/<br />
├── components/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← open.mp 原生组件（某些插件放这里而不是 plugins）<br />
├── filterscripts/&nbsp;&nbsp; ← 过滤脚本（辅助脚本）<br />
├── gamemodes/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 游戏模式（主脚本 .amx 放这里）<br />
├── models/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 自定义模型文件（.txd .dff）<br />
├── plugins/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 旧版插件（.dll 或 .so）<br />
├── qawno/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← Pawn 编辑器 + include 头文件<br />
│&nbsp;&nbsp; └── include/&nbsp;&nbsp;&nbsp;&nbsp; ← 把 .inc 头文件放这里<br />
├── scriptfiles/&nbsp;&nbsp;&nbsp;&nbsp; ← INI 文件等资料<br />
├── bans.json&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 封禁列表<br />
├── config.json&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 服务器配置（替代 SA-MP 的 server.cfg）<br />
└── omp-server.exe&nbsp;&nbsp; ← 服务器主程序</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第三步：放置脚本插件文件</h4><br />
<ul class="mycode_list"><li>把你的游戏模式 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 源文件放入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gamemodes/</code> 文件夹<br />
</li>
<li>把所需的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 头文件（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sscanf2.inc</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">streamer.inc</code>）放入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/include/</code><br />
</li>
<li>把插件文件（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">streamer.dll</code>）放入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code><br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">YSI 用户</span>：需要升级到 <a href="https://github.com/pawn-lang/YSI-Includes/releases" target="_blank" rel="noopener" class="mycode_url">YSI-5.x</a>，YSI-4 与 open.mp 不兼容。</blockquote>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">FCNPC 用户</span>：FCNPC 插件已被官方 open.mp NPC 组件取代，转换代码即可使用。</blockquote>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">YSF 用户</span>：open.mp 已内置了大多数 YSF 的原生函数，不再需要 YSF。</blockquote>
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：有些插件需要放进 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">components/</code> 而不是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，具体查阅以下清单：<br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">常见插件</h5><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">插件</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">状态</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">备注</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Streamer</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，正常加载</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">MySQL R41-4</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，正常加载</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">CrashDetect</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">开发调试，放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Whirlpool</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code> 但不建议使用</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">PawnPlus</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，open.mp 对其有专项优化</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">pawn-memory</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">JIT</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">代码稳定后可用来提升性能，放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Profiler</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">性能分析工具，放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">FileManager</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">sscanf</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/Y-Less/sscanf/releases/tag/v2.13.8" target="_blank" rel="noopener" class="mycode_url">sscanf 2.13.8</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Pawn.CMD</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/katursis/Pawn.CMD/releases/tag/3.4.0-omp" target="_blank" rel="noopener" class="mycode_url">3.4.0-omp</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Pawn.RakNet</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/katursis/Pawn.RakNet/releases/tag/1.6.0-omp" target="_blank" rel="noopener" class="mycode_url">1.6.0-omp</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">sampvoice</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/AmyrAhmady/sampvoice/releases/tag/v3.1.5-omp" target="_blank" rel="noopener" class="mycode_url">v3.1.5-omp</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">discord-connector</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/maddinat0r/samp-discord-connector/releases/tag/v0.3.6-pre" target="_blank" rel="noopener" class="mycode_url">v0.3.6-pre</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">rustext</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">⚠️ 需升级</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/ziggi/rustext/releases/tag/v2.0.11" target="_blank" rel="noopener" class="mycode_url">v2.0.11-nomemhack</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">keylistener</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">⚠️ 需升级</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/edgyaf/keylistener/releases/tag/1.1.2-pr" target="_blank" rel="noopener" class="mycode_url">1.1.2-pr</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">BCrypt</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/Sreyas-Sreelal/samp-bcrypt" target="_blank" rel="noopener" class="mycode_url">samp-bcrypt</a>，密码哈希推荐方案</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">SHA256_PassHash</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 中已标记为废弃，改用 BCrypt</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">nativechecker</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 已内置 native 检查机制，不再需要</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">YSF</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 已内置大多数 YSF 原生函数，不再需要</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">SKY</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">改用 <span style="font-weight: bold;" class="mycode_b">Pawn.RakNet</span></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">中文名插件</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 有内置函数可实现兼容中文昵称</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">FCNPC</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">❌ 不兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 官方内置 NPC 组件，性能更好，不再需要它</td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<ul class="mycode_list"><li>plugins/    ← 旧版（legacy）插件放这里，在 config.json 的 legacy_plugins 里加载<br />
</li>
<li>components/ ← open.mp 原生组件放这里，服务器启动时自动加载，无需配置<br />
</li>
</ul>
<br />
以上资料来源个人经验和 open.mp/docs/server/Installation<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第四步：修改 #include</h4><br />
<br />
打开你的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件，把第一行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;a_samp&gt;</code></div></div><br />
改为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;</code></div></div><br />
然后按 <span style="font-weight: bold;" class="mycode_b">F5</span> 编译。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第五步：配置 config.json</h4><br />
<br />
用记事本打开 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">config.json</code>，按需修改：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">加载主图：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"main_scripts": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;"你的脚本文件名 1"<br />
]</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">加载插件：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"legacy_plugins": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;"mysql",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"sscanf",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"streamer"<br />
]</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">加载过滤脚本：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"side_scripts": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;"filterscripts/你的过滤脚本名"<br />
]</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">设置 RCON 密码：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"rcon": {<br />
&nbsp;&nbsp;&nbsp;&nbsp;"allow_teleport": false,<br />
&nbsp;&nbsp;&nbsp;&nbsp;"enable": false,<br />
&nbsp;&nbsp;&nbsp;&nbsp;"password": "你的强密码"<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>如何把旧的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">server.cfg</code> 转换为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">config.json</code>，参考官方文档：https://www.open.mp/docs/server/config.json</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第六步：启动服务器</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Windows：</span> 双击 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">omp-server.exe</code><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Linux：</span><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>chmod +x omp-server<br />
./omp-server</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第二部分：SA-MP 到 open.mp 的变化</h3><br />
<br />
有以下几个变化<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更一：拼写统一为英式英语</h4><br />
<br />
open.mp 将所有函数名统一为英式拼写，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Color</code> 改为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Colour</code>，例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SA-MP 写法（会报 warning）<br />
TextDrawBoxColor(textid, 0xFF0000FF);<br />
TextDrawColor(textid, 0xFFFFFFFF);<br />
<br />
// open.mp 正确写法<br />
TextDrawBoxColour(textid, 0xFF0000FF);<br />
TextDrawColour(textid, 0xFFFFFFFF);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">批量替换方法</span>：在你的编辑器里按 <span style="font-weight: bold;" class="mycode_b">Ctrl+H</span>，把所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.....Color</code> 替换为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.....Colour</code>。<br />
<br />
如果不想逐个修改，可以在 include 顶部加上：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MIXED_SPELLINGS<br />
#include &lt;open.mp&gt;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更二：GetPlayerPoolSize 等函数已移除</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerPoolSize()</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetVehiclePoolSize()</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetActorPoolSize()</code> 这三个函数在 open.mp 中已被移除，因为它们本身就存在 bug（返回的是最高 ID 而不是数量，而且没有玩家时会返回错误数据）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：这些函数不存在了<br />
for(new i = 0; i &lt;= GetPlayerPoolSize(); i++) { }<br />
<br />
// 正确：直接用 MAX_PLAYERS<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(IsPlayerConnected(i)) { }<br />
}<br />
<br />
// 或者用 foreach（需要 YSI）<br />
foreach(new i : Player) { }</code></div></div><br />
同理：<ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerPoolSize()</code> → 换成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetVehiclePoolSize()</code> → 换成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_VEHICLES</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetActorPoolSize()</code> → 换成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_ACTORS</code><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更三：死亡不再自动扣 100 元</h4><br />
<br />
SA-MP 中玩家死亡后会自动扣除 100 元（住院费）。open.mp 移除了这个机制，让脚本自己管理金钱。<br />
<br />
如果你的脚本之前为了「修复」这个扣钱机制，在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerSpawn</code> 里手动加了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GivePlayerMoney(playerid, 100)</code>，现在<span style="font-weight: bold;" class="mycode_b">应该删掉这行</span>，否则玩家死亡后反而会多 100 元。<br />
<br />
如果你的脚本确实依赖这个「死亡扣钱」功能，在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code> 里手动加上：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerDeath(playerid, killerid, WEAPON:reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;GivePlayerMoney(playerid, -100); // 手动模拟死亡扣款<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更四：HideMenuForPlayer 行为修正</h4><br />
<br />
SA-MP 中 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">HideMenuForPlayer</code> 会忽略你传入的菜单 ID，直接关掉玩家当前打开的任意菜单。<br />
<br />
open.mp 修正了这个行为，现在它只会关闭你指定的那个菜单。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SA-MP 的老写法（在 open.mp 里可能不按预期工作）<br />
HideMenuForPlayer(gShopMenu, playerid);<br />
<br />
// open.mp 正确写法：先获取玩家当前菜单再关闭<br />
HideMenuForPlayer(GetPlayerMenu(playerid), playerid);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更五：SetPlayerAttachedObject 不再跨模式保留</h4><br />
<br />
SA-MP 中玩家身上的附加物件（attached objects）在游戏模式重启后仍然保留。open.mp 修正了这个行为，重启后附加物件会消失。<br />
<br />
如果你需要在模式重启后保留玩家的附加物件，需要在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerConnect</code> 里重新为他设置。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更六：GameText 样式统一（不再渐变）</h4><br />
<br />
SA-MP 中有些 GameText 样式会闪烁、有些会忽略时间参数。open.mp 统一用 TextDraw 重新实现了这些样式，外观相同但不再渐变。如果你的玩家反馈 GameText 显示效果有变化，这是正常现象。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">自动升级工具</h4><br />
<br />
open.mp 提供了一个自动升级工具，可以批量修复旧代码中的 tag 问题、const 问题和拼写问题：<br />
<ul class="mycode_list"><li>工具已包含在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/upgrader/</code> 文件夹中<br />
</li>
<li>在线版本：https://github.com/openmultiplayer/upgrade<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">建议先用工具跑一遍，再手动处理剩余的报错。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第三部分：编译错误与警告完全手册</h3><br />
<br />
编译器报的信息分两种：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">error（错误）</span>：必须修复，否则无法生成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code> 文件<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">warning（警告）</span>：可以运行，但代码存在潜在问题，建议修复<br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">常见 Error（错误）</h3><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 001: expected token</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：期望某个符号但没找到，通常是缺少分号、括号不匹配。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：缺少分号<br />
new gold = 100<br />
SetPlayerHealth(playerid, 100.0)<br />
<br />
// 正确<br />
new gold = 100;<br />
SetPlayerHealth(playerid, 100.0);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：括号不匹配<br />
if(gold &gt; 0<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ...<br />
}<br />
<br />
// 正确<br />
if(gold &gt; 0)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ...<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 017: undefined symbol "xxx"</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：用了一个没有定义过的变量、函数或常量。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">最常见的三种原因：</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. 名字拼写错误</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误<br />
SenClientMessage(playerid, -1, "hello"); // 少了 d<br />
new scroe = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 字母顺序错了<br />
<br />
// 正确<br />
SendClientMessage(playerid, -1, "hello");<br />
new score = 0;</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">2. SetTimerEx 的目标函数忘记 forward</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：没有 forward，运行时找不到函数<br />
SetTimerEx("MyFunc", 1000, false, "i", playerid);<br />
<br />
public MyFunc(playerid) { return 1; }<br />
<br />
<br />
// 正确：使用前先 forward<br />
forward MyFunc(playerid);<br />
<br />
SetTimerEx("MyFunc", 1000, false, "i", playerid);<br />
<br />
public MyFunc(playerid) { return 1; }</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">3. 变量在使用之前没有声明</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：先用再声明<br />
gold += 100;<br />
new gold = 0;<br />
<br />
// 正确：先声明再用<br />
new gold = 0;<br />
gold += 100;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 021: symbol already defined "xxx"</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：同一个名字被定义了两次。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：同名变量重复声明<br />
new gold = 0;<br />
new gold = 100; // 重复了<br />
<br />
// 错误：同名函数重复定义<br />
MyFunction() { return 1; }<br />
MyFunction() { return 0; } // 重复了</code></div></div><br />
也可能是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件被 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 了两次，导致里面的函数被重复引入。<br />
<br />
解决方法：在每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件顶部加防重复引入守卫：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#if defined _MY_INC<br />
&nbsp;&nbsp;&nbsp;&nbsp;#endinput<br />
#endif<br />
#define _MY_INC</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 025: function heading differs from prototype</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 声明的参数和实际 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数的参数不一致，或者参数类型不匹配。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：forward 和 public 参数不一致<br />
forward MyFunc(playerid);<br />
public MyFunc(playerid, value) { return 1; } // 多了一个参数</code></div></div><br />
open.mp 特别常见的情况是回调参数的 tag 不匹配：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误（SA-MP 写法）<br />
public OnPlayerDeath(playerid, killerid, reason)<br />
<br />
// 正确（open.mp 要求 WEAPON: tag）<br />
public OnPlayerDeath(playerid, killerid, WEAPON:reason)</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误<br />
public OnPlayerEditAttachedObject(playerid, response, index, modelid, boneid, ...)<br />
<br />
// 正确（open.mp 要求 EDIT_RESPONSE: tag）<br />
public OnPlayerEditAttachedObject(playerid, EDIT_RESPONSE:response, index, modelid, boneid, ...)</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 010: invalid function or declaration</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：函数定义或声明的语法写错了。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：函数名后面缺括号<br />
MyFunction<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
// 正确<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 029: invalid expression, assumed zero</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：表达式写法不合法，通常是运算符用错或者判断写法有问题。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：判断用了单等号（赋值）而不是双等号（比较）<br />
if(gold = 100) { }&nbsp;&nbsp;// 这是赋值，不是比较<br />
<br />
// 正确<br />
if(gold == 100) { }</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 035: argument type mismatch (argument N)</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：函数调用时，第 N 个参数的类型与函数期望的类型不符。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：SetPlayerHealth 需要 Float，传了整数<br />
SetPlayerHealth(playerid, 100);<br />
<br />
// 正确：加小数点<br />
SetPlayerHealth(playerid, 100.0);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：传了字符串给需要整数的参数<br />
SetPlayerSkin(playerid, "86");<br />
<br />
// 正确<br />
SetPlayerSkin(playerid, 86);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 047: array sizes do not match</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：把一个数组赋值给另一个数组，但两者大小不一样。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a[10];<br />
new b[20];<br />
a = b; // 错误：大小不同，不能直接赋值<br />
<br />
// 正确：用 for 循环逐元素复制，或者用 memcpy<br />
for(new i = 0; i &lt; 10; i++) a[i] = b[i];</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 004: function not implemented</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：只有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 声明，没有对应的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数体。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：只 forward 了，没有写函数体<br />
forward MyFunc(playerid);<br />
// 下面没有 public MyFunc ...<br />
<br />
// 正确：forward 之后要有对应的实现<br />
forward MyFunc(playerid);<br />
public MyFunc(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">常见 Warning（警告）</h3><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 213: tag mismatch</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：变量或参数的 tag（类型标签）不匹配。这是迁移到 open.mp 最常见的警告。<br />
<br />
open.mp 为很多函数参数增加了 tag，让编译器能检查你传的值是否合理：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：传了普通整数而不是 bool<br />
TogglePlayerControllable(playerid, 1);<br />
<br />
// 正确：用 true/false<br />
TogglePlayerControllable(playerid, true);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：传了数字而不是枚举值<br />
TextDrawFont(textid, 1);<br />
GivePlayerWeapon(playerid, 4, 1);<br />
<br />
// 正确：用枚举常量<br />
TextDrawFont(textid, TEXT_DRAW_FONT_1);<br />
GivePlayerWeapon(playerid, WEAPON_KNIFE, 1);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">如果暂时不想处理这些警告</span>，可以在顶部加：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define NO_TAGS<br />
#include &lt;open.mp&gt;<br />
<br />
// 或者只关闭 213 号警告<br />
#pragma warning disable 213</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 234: function is deprecated</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：你用的函数已经过时，open.mp 建议换用新的写法。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">TextDrawColor → TextDrawColour</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>TextDrawColor(textid, 0xFFFFFFFF);&nbsp;&nbsp; // 警告<br />
TextDrawColour(textid, 0xFFFFFFFF);&nbsp;&nbsp;// 正确</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">GetPlayerPoolSize / GetVehiclePoolSize / GetActorPoolSize</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>GetPlayerPoolSize()&nbsp;&nbsp;// 警告：已移除<br />
MAX_PLAYERS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 正确</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">SHA256_PassHash（不安全的密码哈希）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SHA256_PassHash(...); // 警告：SHA-256 不安全<br />
// 改用 BCrypt：https://github.com/Sreyas-Sreelal/samp-bcrypt</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 214 / 239: const 相关警告</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：把字符串或数组传给没有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 修饰的参数，或者反过来。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：参数应该是 const<br />
public MyFunction(string[])<br />
// 正确：加上 const<br />
public MyFunction(const string[])</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 203: symbol is never used</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：你声明了一个变量或函数，但从来没有使用过。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：声明了但没用<br />
new iUnusedVar = 0;<br />
<br />
MyUnusedFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
解决方法：删掉没用的变量/函数，或者用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 修饰函数告诉编译器「不用也不要警告」：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock MyMaybeUnusedFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 204: symbol is assigned a value that is never used</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：给变量赋值了，但这个值从来没被读取。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new iResult = SomeFunction(); // 警告：iResult 赋了值但后面没用到</code></div></div><br />
通常意味着这行代码没有实际效果，检查是否逻辑有误。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 211: possibly unintended assignment</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 条件里用了单等号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">=</code>，可能是误把赋值写成了比较。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：这是赋值，不是比较，结果永远为 true<br />
if(gold = 100) { }<br />
<br />
// 正确：比较用双等号<br />
if(gold == 100) { }</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 219: local variable shadows a variable at a higher level</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：在内层作用域声明了一个和外层同名的变量，内层的「遮住」了外层的，容易引发逻辑混乱。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 100; // 外层<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new gold = 50; // 警告：这个 gold 遮住了外层的 gold<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 在这个函数里，gold 指的是 50 那个<br />
}</code></div></div><br />
解决方法：给内层变量换个名字，或者直接用外层变量。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 225: unreachable code</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：有一段代码永远不会被执行到，通常是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 后面还有代码。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "这行永远不会执行"); // 警告<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 209: function should return a value</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：函数应该有返回值，但某个分支没有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：else 分支没有 return<br />
MyFunction(iValue)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(iValue &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 如果 iValue &lt;= 0，函数执行完没有 return<br />
}<br />
<br />
// 正确：所有分支都要有 return<br />
MyFunction(iValue)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(iValue &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 202: number of arguments does not match definition</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：调用函数时传入的参数数量和函数定义不一致。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数定义需要 2 个参数<br />
MyFunction(playerid, value)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
// 警告：只传了 1 个参数<br />
MyFunction(playerid);<br />
<br />
// 正确：传够参数<br />
MyFunction(playerid, 100);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">运行时报错（服务器控制台）</h3><br />
<br />
这些不是编译错误，而是服务器运行时打印在控制台的提示。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Couldn't announce legacy network to open.mp list</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>[Info] Couldn't announce legacy network to open.mp list.<br />
[Info] [Server Error] Status: 406</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：服务器无法被 open.mp 的服务器列表访问到。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">原因</span>：<ul class="mycode_list"><li>你在本地运行，没有公网 IP<br />
</li>
<li>防火墙阻止了对应端口<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">影响</span>：<span style="font-weight: bold;" class="mycode_b">不影响服务器正常运行</span>，玩家仍然可以通过 IP 直连，只是不会显示在公开服务器列表里。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Insufficient specifiers given to format</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>[Warning] Insufficient specifiers given to `format`: "?" &lt; 1</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code> 函数里，格式字符串中的占位符数量少于你传入的参数数量。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new str[32];<br />
new name[32] = "Tom";<br />
<br />
format(str, sizeof(str), "Hello", name); // 警告：格式字符串里没有 %s，但传了 name<br />
<br />
// 正确<br />
format(str, sizeof(str), "Hello %s", name);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">有用的资源</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">资源</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">地址</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 官方文档</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://open.mp/docs" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 新增函数列表</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://open.mp/docs/server/omp-functions" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/server/omp-functions</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">config.json 配置说明</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://www.open.mp/docs/server/config.json" target="_blank" rel="noopener" class="mycode_url">https://www.open.mp/docs/server/config.json</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">自动升级工具</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/openmultiplayer/upgrade" target="_blank" rel="noopener" class="mycode_url">https://github.com/openmultiplayer/upgrade</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">官方 Discord</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://discord.gg/samp" target="_blank" rel="noopener" class="mycode_url">https://discord.gg/samp</a></td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">延伸阅读</h3><br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">地址</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/samp-stdlib/tree/consistency-overhaul" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/samp-stdlib...y-overhaul</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">更新后的 SA:MP 包含文件，增加了常量正确性及更多标签。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/samp-incognito/samp-streamer-plugin/pull/435" target="_blank" rel="noopener" class="mycode_url">https://github.com/samp-incognito/samp-s...n/pull/435</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">一个流加载器插件的拉取请求，提供了关于此标签系统的更多信息。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/compiler/wiki/What's-new#const-correctness" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/compiler/wi...orrectness</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">编译器的变更，错误地将常量正确性列为“破坏性”变更。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/compiler/wiki/Const-Correctness" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/compiler/wi...orrectness</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">关于常量正确性及代码更新的更多信息。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/sa-mp-fixes/" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/sa-mp-fixes/</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">许多修复的起源，包括若干已集成至 open.mp 但未在此列出的细微修复。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/compiler/raw/master/doc/pawn-lang.pdf" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/compiler/ra...n-lang.pdf</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">获取有关强标签与弱标签的更多信息。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/openmultiplayer/upgrade" target="_blank" rel="noopener" class="mycode_url">https://github.com/openmultiplayer/upgrade</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">一个可自动完成大量标签与常量正确性升级的工具。</td>
  </tr>
</table>
<br />
如果您在运行服务器时仍有问题，请加入官方的 open.mp Discord 服务器：https://discord.gg/samp<br />
<br />
在 <a href="https://discord.com/channels/231799104731217931/966398440051445790" target="_blank" rel="noopener" class="mycode_url">#openmp-support</a> 频道提问。<br />
<br />
或者在我们的社区群求助: 673335567<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">SAMP 迁移到 openmp 完整指南 + pawn 编译报错全解析</h2><br />
<br />
<hr class="mycode_hr" />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>本篇适合：<ul class="mycode_list"><li>已有 SA-MP 服务器，想迁移到 open.mp 的开发者<br />
</li>
<li>在编译时遇到错误不知道怎么处理的新手</blockquote>
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第一部分：迁移步骤</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第一步：下载 open.mp 服务端</h4><br />
<br />
前往 <a href="https://github.com/openmultiplayer/open.mp/releases" target="_blank" rel="noopener" class="mycode_url">https://github.com/openmultiplayer/open.mp/releases</a> 下载最新版本。<br />
<ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">open.mp-win-x86.zip</code> — Windows 服务器<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">open.mp-linux-x86.tar.gz</code> — Linux 服务器<br />
</li>
</ul>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第二步：解压</h4><br />
<br />
目录结构<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>omp-server/<br />
├── components/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← open.mp 原生组件（某些插件放这里而不是 plugins）<br />
├── filterscripts/&nbsp;&nbsp; ← 过滤脚本（辅助脚本）<br />
├── gamemodes/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 游戏模式（主脚本 .amx 放这里）<br />
├── models/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 自定义模型文件（.txd .dff）<br />
├── plugins/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 旧版插件（.dll 或 .so）<br />
├── qawno/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← Pawn 编辑器 + include 头文件<br />
│&nbsp;&nbsp; └── include/&nbsp;&nbsp;&nbsp;&nbsp; ← 把 .inc 头文件放这里<br />
├── scriptfiles/&nbsp;&nbsp;&nbsp;&nbsp; ← INI 文件等资料<br />
├── bans.json&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 封禁列表<br />
├── config.json&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 服务器配置（替代 SA-MP 的 server.cfg）<br />
└── omp-server.exe&nbsp;&nbsp; ← 服务器主程序</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第三步：放置脚本插件文件</h4><br />
<ul class="mycode_list"><li>把你的游戏模式 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 源文件放入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gamemodes/</code> 文件夹<br />
</li>
<li>把所需的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 头文件（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sscanf2.inc</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">streamer.inc</code>）放入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/include/</code><br />
</li>
<li>把插件文件（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">streamer.dll</code>）放入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code><br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">YSI 用户</span>：需要升级到 <a href="https://github.com/pawn-lang/YSI-Includes/releases" target="_blank" rel="noopener" class="mycode_url">YSI-5.x</a>，YSI-4 与 open.mp 不兼容。</blockquote>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">FCNPC 用户</span>：FCNPC 插件已被官方 open.mp NPC 组件取代，转换代码即可使用。</blockquote>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">YSF 用户</span>：open.mp 已内置了大多数 YSF 的原生函数，不再需要 YSF。</blockquote>
<br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：有些插件需要放进 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">components/</code> 而不是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，具体查阅以下清单：<br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">常见插件</h5><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">插件</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">状态</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">备注</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Streamer</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，正常加载</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">MySQL R41-4</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，正常加载</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">CrashDetect</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">开发调试，放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Whirlpool</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code> 但不建议使用</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">PawnPlus</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code>，open.mp 对其有专项优化</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">pawn-memory</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">JIT</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">代码稳定后可用来提升性能，放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Profiler</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">性能分析工具，放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">FileManager</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">放 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">sscanf</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/Y-Less/sscanf/releases/tag/v2.13.8" target="_blank" rel="noopener" class="mycode_url">sscanf 2.13.8</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Pawn.CMD</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/katursis/Pawn.CMD/releases/tag/3.4.0-omp" target="_blank" rel="noopener" class="mycode_url">3.4.0-omp</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">Pawn.RakNet</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/katursis/Pawn.RakNet/releases/tag/1.6.0-omp" target="_blank" rel="noopener" class="mycode_url">1.6.0-omp</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">sampvoice</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/AmyrAhmady/sampvoice/releases/tag/v3.1.5-omp" target="_blank" rel="noopener" class="mycode_url">v3.1.5-omp</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">discord-connector</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 放 components/</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/maddinat0r/samp-discord-connector/releases/tag/v0.3.6-pre" target="_blank" rel="noopener" class="mycode_url">v0.3.6-pre</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">rustext</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">⚠️ 需升级</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/ziggi/rustext/releases/tag/v2.0.11" target="_blank" rel="noopener" class="mycode_url">v2.0.11-nomemhack</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">keylistener</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">⚠️ 需升级</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">使用 <a href="https://github.com/edgyaf/keylistener/releases/tag/1.1.2-pr" target="_blank" rel="noopener" class="mycode_url">1.1.2-pr</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">BCrypt</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">✅ 兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/Sreyas-Sreelal/samp-bcrypt" target="_blank" rel="noopener" class="mycode_url">samp-bcrypt</a>，密码哈希推荐方案</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">SHA256_PassHash</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 中已标记为废弃，改用 BCrypt</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">nativechecker</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 已内置 native 检查机制，不再需要</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">YSF</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 已内置大多数 YSF 原生函数，不再需要</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">SKY</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">改用 <span style="font-weight: bold;" class="mycode_b">Pawn.RakNet</span></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">中文名插件</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">? 有替代</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 有内置函数可实现兼容中文昵称</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><span style="font-weight: bold;" class="mycode_b">FCNPC</span></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">❌ 不兼容</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 官方内置 NPC 组件，性能更好，不再需要它</td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<ul class="mycode_list"><li>plugins/    ← 旧版（legacy）插件放这里，在 config.json 的 legacy_plugins 里加载<br />
</li>
<li>components/ ← open.mp 原生组件放这里，服务器启动时自动加载，无需配置<br />
</li>
</ul>
<br />
以上资料来源个人经验和 open.mp/docs/server/Installation<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第四步：修改 #include</h4><br />
<br />
打开你的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件，把第一行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;a_samp&gt;</code></div></div><br />
改为：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;</code></div></div><br />
然后按 <span style="font-weight: bold;" class="mycode_b">F5</span> 编译。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第五步：配置 config.json</h4><br />
<br />
用记事本打开 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">config.json</code>，按需修改：<br />
<br />
<span style="font-weight: bold;" class="mycode_b">加载主图：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"main_scripts": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;"你的脚本文件名 1"<br />
]</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">加载插件：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"legacy_plugins": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;"mysql",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"sscanf",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"streamer"<br />
]</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">加载过滤脚本：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"side_scripts": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;"filterscripts/你的过滤脚本名"<br />
]</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">设置 RCON 密码：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"rcon": {<br />
&nbsp;&nbsp;&nbsp;&nbsp;"allow_teleport": false,<br />
&nbsp;&nbsp;&nbsp;&nbsp;"enable": false,<br />
&nbsp;&nbsp;&nbsp;&nbsp;"password": "你的强密码"<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>如何把旧的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">server.cfg</code> 转换为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">config.json</code>，参考官方文档：https://www.open.mp/docs/server/config.json</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第六步：启动服务器</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Windows：</span> 双击 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">omp-server.exe</code><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Linux：</span><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>chmod +x omp-server<br />
./omp-server</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第二部分：SA-MP 到 open.mp 的变化</h3><br />
<br />
有以下几个变化<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更一：拼写统一为英式英语</h4><br />
<br />
open.mp 将所有函数名统一为英式拼写，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Color</code> 改为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Colour</code>，例如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SA-MP 写法（会报 warning）<br />
TextDrawBoxColor(textid, 0xFF0000FF);<br />
TextDrawColor(textid, 0xFFFFFFFF);<br />
<br />
// open.mp 正确写法<br />
TextDrawBoxColour(textid, 0xFF0000FF);<br />
TextDrawColour(textid, 0xFFFFFFFF);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">批量替换方法</span>：在你的编辑器里按 <span style="font-weight: bold;" class="mycode_b">Ctrl+H</span>，把所有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.....Color</code> 替换为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.....Colour</code>。<br />
<br />
如果不想逐个修改，可以在 include 顶部加上：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MIXED_SPELLINGS<br />
#include &lt;open.mp&gt;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更二：GetPlayerPoolSize 等函数已移除</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerPoolSize()</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetVehiclePoolSize()</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetActorPoolSize()</code> 这三个函数在 open.mp 中已被移除，因为它们本身就存在 bug（返回的是最高 ID 而不是数量，而且没有玩家时会返回错误数据）。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：这些函数不存在了<br />
for(new i = 0; i &lt;= GetPlayerPoolSize(); i++) { }<br />
<br />
// 正确：直接用 MAX_PLAYERS<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(IsPlayerConnected(i)) { }<br />
}<br />
<br />
// 或者用 foreach（需要 YSI）<br />
foreach(new i : Player) { }</code></div></div><br />
同理：<ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerPoolSize()</code> → 换成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetVehiclePoolSize()</code> → 换成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_VEHICLES</code><br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetActorPoolSize()</code> → 换成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_ACTORS</code><br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更三：死亡不再自动扣 100 元</h4><br />
<br />
SA-MP 中玩家死亡后会自动扣除 100 元（住院费）。open.mp 移除了这个机制，让脚本自己管理金钱。<br />
<br />
如果你的脚本之前为了「修复」这个扣钱机制，在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerSpawn</code> 里手动加了 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GivePlayerMoney(playerid, 100)</code>，现在<span style="font-weight: bold;" class="mycode_b">应该删掉这行</span>，否则玩家死亡后反而会多 100 元。<br />
<br />
如果你的脚本确实依赖这个「死亡扣钱」功能，在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code> 里手动加上：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerDeath(playerid, killerid, WEAPON:reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;GivePlayerMoney(playerid, -100); // 手动模拟死亡扣款<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更四：HideMenuForPlayer 行为修正</h4><br />
<br />
SA-MP 中 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">HideMenuForPlayer</code> 会忽略你传入的菜单 ID，直接关掉玩家当前打开的任意菜单。<br />
<br />
open.mp 修正了这个行为，现在它只会关闭你指定的那个菜单。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SA-MP 的老写法（在 open.mp 里可能不按预期工作）<br />
HideMenuForPlayer(gShopMenu, playerid);<br />
<br />
// open.mp 正确写法：先获取玩家当前菜单再关闭<br />
HideMenuForPlayer(GetPlayerMenu(playerid), playerid);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更五：SetPlayerAttachedObject 不再跨模式保留</h4><br />
<br />
SA-MP 中玩家身上的附加物件（attached objects）在游戏模式重启后仍然保留。open.mp 修正了这个行为，重启后附加物件会消失。<br />
<br />
如果你需要在模式重启后保留玩家的附加物件，需要在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerConnect</code> 里重新为他设置。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变更六：GameText 样式统一（不再渐变）</h4><br />
<br />
SA-MP 中有些 GameText 样式会闪烁、有些会忽略时间参数。open.mp 统一用 TextDraw 重新实现了这些样式，外观相同但不再渐变。如果你的玩家反馈 GameText 显示效果有变化，这是正常现象。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">自动升级工具</h4><br />
<br />
open.mp 提供了一个自动升级工具，可以批量修复旧代码中的 tag 问题、const 问题和拼写问题：<br />
<ul class="mycode_list"><li>工具已包含在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/upgrader/</code> 文件夹中<br />
</li>
<li>在线版本：https://github.com/openmultiplayer/upgrade<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">建议先用工具跑一遍，再手动处理剩余的报错。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第三部分：编译错误与警告完全手册</h3><br />
<br />
编译器报的信息分两种：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">error（错误）</span>：必须修复，否则无法生成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code> 文件<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">warning（警告）</span>：可以运行，但代码存在潜在问题，建议修复<br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">常见 Error（错误）</h3><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 001: expected token</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：期望某个符号但没找到，通常是缺少分号、括号不匹配。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：缺少分号<br />
new gold = 100<br />
SetPlayerHealth(playerid, 100.0)<br />
<br />
// 正确<br />
new gold = 100;<br />
SetPlayerHealth(playerid, 100.0);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：括号不匹配<br />
if(gold &gt; 0<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ...<br />
}<br />
<br />
// 正确<br />
if(gold &gt; 0)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ...<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 017: undefined symbol "xxx"</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：用了一个没有定义过的变量、函数或常量。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">最常见的三种原因：</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. 名字拼写错误</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误<br />
SenClientMessage(playerid, -1, "hello"); // 少了 d<br />
new scroe = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 字母顺序错了<br />
<br />
// 正确<br />
SendClientMessage(playerid, -1, "hello");<br />
new score = 0;</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">2. SetTimerEx 的目标函数忘记 forward</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：没有 forward，运行时找不到函数<br />
SetTimerEx("MyFunc", 1000, false, "i", playerid);<br />
<br />
public MyFunc(playerid) { return 1; }<br />
<br />
<br />
// 正确：使用前先 forward<br />
forward MyFunc(playerid);<br />
<br />
SetTimerEx("MyFunc", 1000, false, "i", playerid);<br />
<br />
public MyFunc(playerid) { return 1; }</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">3. 变量在使用之前没有声明</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：先用再声明<br />
gold += 100;<br />
new gold = 0;<br />
<br />
// 正确：先声明再用<br />
new gold = 0;<br />
gold += 100;</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 021: symbol already defined "xxx"</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：同一个名字被定义了两次。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：同名变量重复声明<br />
new gold = 0;<br />
new gold = 100; // 重复了<br />
<br />
// 错误：同名函数重复定义<br />
MyFunction() { return 1; }<br />
MyFunction() { return 0; } // 重复了</code></div></div><br />
也可能是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件被 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 了两次，导致里面的函数被重复引入。<br />
<br />
解决方法：在每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件顶部加防重复引入守卫：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#if defined _MY_INC<br />
&nbsp;&nbsp;&nbsp;&nbsp;#endinput<br />
#endif<br />
#define _MY_INC</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 025: function heading differs from prototype</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 声明的参数和实际 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数的参数不一致，或者参数类型不匹配。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：forward 和 public 参数不一致<br />
forward MyFunc(playerid);<br />
public MyFunc(playerid, value) { return 1; } // 多了一个参数</code></div></div><br />
open.mp 特别常见的情况是回调参数的 tag 不匹配：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误（SA-MP 写法）<br />
public OnPlayerDeath(playerid, killerid, reason)<br />
<br />
// 正确（open.mp 要求 WEAPON: tag）<br />
public OnPlayerDeath(playerid, killerid, WEAPON:reason)</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误<br />
public OnPlayerEditAttachedObject(playerid, response, index, modelid, boneid, ...)<br />
<br />
// 正确（open.mp 要求 EDIT_RESPONSE: tag）<br />
public OnPlayerEditAttachedObject(playerid, EDIT_RESPONSE:response, index, modelid, boneid, ...)</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 010: invalid function or declaration</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：函数定义或声明的语法写错了。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：函数名后面缺括号<br />
MyFunction<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
// 正确<br />
MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 029: invalid expression, assumed zero</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：表达式写法不合法，通常是运算符用错或者判断写法有问题。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：判断用了单等号（赋值）而不是双等号（比较）<br />
if(gold = 100) { }&nbsp;&nbsp;// 这是赋值，不是比较<br />
<br />
// 正确<br />
if(gold == 100) { }</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 035: argument type mismatch (argument N)</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：函数调用时，第 N 个参数的类型与函数期望的类型不符。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：SetPlayerHealth 需要 Float，传了整数<br />
SetPlayerHealth(playerid, 100);<br />
<br />
// 正确：加小数点<br />
SetPlayerHealth(playerid, 100.0);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：传了字符串给需要整数的参数<br />
SetPlayerSkin(playerid, "86");<br />
<br />
// 正确<br />
SetPlayerSkin(playerid, 86);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 047: array sizes do not match</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：把一个数组赋值给另一个数组，但两者大小不一样。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a[10];<br />
new b[20];<br />
a = b; // 错误：大小不同，不能直接赋值<br />
<br />
// 正确：用 for 循环逐元素复制，或者用 memcpy<br />
for(new i = 0; i &lt; 10; i++) a[i] = b[i];</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">error 004: function not implemented</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：只有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 声明，没有对应的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数体。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 错误：只 forward 了，没有写函数体<br />
forward MyFunc(playerid);<br />
// 下面没有 public MyFunc ...<br />
<br />
// 正确：forward 之后要有对应的实现<br />
forward MyFunc(playerid);<br />
public MyFunc(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">常见 Warning（警告）</h3><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 213: tag mismatch</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：变量或参数的 tag（类型标签）不匹配。这是迁移到 open.mp 最常见的警告。<br />
<br />
open.mp 为很多函数参数增加了 tag，让编译器能检查你传的值是否合理：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：传了普通整数而不是 bool<br />
TogglePlayerControllable(playerid, 1);<br />
<br />
// 正确：用 true/false<br />
TogglePlayerControllable(playerid, true);</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：传了数字而不是枚举值<br />
TextDrawFont(textid, 1);<br />
GivePlayerWeapon(playerid, 4, 1);<br />
<br />
// 正确：用枚举常量<br />
TextDrawFont(textid, TEXT_DRAW_FONT_1);<br />
GivePlayerWeapon(playerid, WEAPON_KNIFE, 1);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">如果暂时不想处理这些警告</span>，可以在顶部加：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define NO_TAGS<br />
#include &lt;open.mp&gt;<br />
<br />
// 或者只关闭 213 号警告<br />
#pragma warning disable 213</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 234: function is deprecated</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：你用的函数已经过时，open.mp 建议换用新的写法。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">TextDrawColor → TextDrawColour</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>TextDrawColor(textid, 0xFFFFFFFF);&nbsp;&nbsp; // 警告<br />
TextDrawColour(textid, 0xFFFFFFFF);&nbsp;&nbsp;// 正确</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">GetPlayerPoolSize / GetVehiclePoolSize / GetActorPoolSize</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>GetPlayerPoolSize()&nbsp;&nbsp;// 警告：已移除<br />
MAX_PLAYERS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 正确</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">SHA256_PassHash（不安全的密码哈希）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SHA256_PassHash(...); // 警告：SHA-256 不安全<br />
// 改用 BCrypt：https://github.com/Sreyas-Sreelal/samp-bcrypt</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 214 / 239: const 相关警告</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：把字符串或数组传给没有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 修饰的参数，或者反过来。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：参数应该是 const<br />
public MyFunction(string[])<br />
// 正确：加上 const<br />
public MyFunction(const string[])</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 203: symbol is never used</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：你声明了一个变量或函数，但从来没有使用过。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：声明了但没用<br />
new iUnusedVar = 0;<br />
<br />
MyUnusedFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
解决方法：删掉没用的变量/函数，或者用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 修饰函数告诉编译器「不用也不要警告」：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock MyMaybeUnusedFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 204: symbol is assigned a value that is never used</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：给变量赋值了，但这个值从来没被读取。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new iResult = SomeFunction(); // 警告：iResult 赋了值但后面没用到</code></div></div><br />
通常意味着这行代码没有实际效果，检查是否逻辑有误。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 211: possibly unintended assignment</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 条件里用了单等号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">=</code>，可能是误把赋值写成了比较。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：这是赋值，不是比较，结果永远为 true<br />
if(gold = 100) { }<br />
<br />
// 正确：比较用双等号<br />
if(gold == 100) { }</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 219: local variable shadows a variable at a higher level</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：在内层作用域声明了一个和外层同名的变量，内层的「遮住」了外层的，容易引发逻辑混乱。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 100; // 外层<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new gold = 50; // 警告：这个 gold 遮住了外层的 gold<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 在这个函数里，gold 指的是 50 那个<br />
}</code></div></div><br />
解决方法：给内层变量换个名字，或者直接用外层变量。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 225: unreachable code</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：有一段代码永远不会被执行到，通常是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code> 后面还有代码。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>MyFunction()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "这行永远不会执行"); // 警告<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 209: function should return a value</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：函数应该有返回值，但某个分支没有 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 警告：else 分支没有 return<br />
MyFunction(iValue)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(iValue &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 如果 iValue &lt;= 0，函数执行完没有 return<br />
}<br />
<br />
// 正确：所有分支都要有 return<br />
MyFunction(iValue)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(iValue &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">warning 202: number of arguments does not match definition</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：调用函数时传入的参数数量和函数定义不一致。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数定义需要 2 个参数<br />
MyFunction(playerid, value)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
// 警告：只传了 1 个参数<br />
MyFunction(playerid);<br />
<br />
// 正确：传够参数<br />
MyFunction(playerid, 100);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">运行时报错（服务器控制台）</h3><br />
<br />
这些不是编译错误，而是服务器运行时打印在控制台的提示。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Couldn't announce legacy network to open.mp list</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>[Info] Couldn't announce legacy network to open.mp list.<br />
[Info] [Server Error] Status: 406</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：服务器无法被 open.mp 的服务器列表访问到。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">原因</span>：<ul class="mycode_list"><li>你在本地运行，没有公网 IP<br />
</li>
<li>防火墙阻止了对应端口<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">影响</span>：<span style="font-weight: bold;" class="mycode_b">不影响服务器正常运行</span>，玩家仍然可以通过 IP 直连，只是不会显示在公开服务器列表里。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Insufficient specifiers given to format</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>[Warning] Insufficient specifiers given to `format`: "?" &lt; 1</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">含义</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code> 函数里，格式字符串中的占位符数量少于你传入的参数数量。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new str[32];<br />
new name[32] = "Tom";<br />
<br />
format(str, sizeof(str), "Hello", name); // 警告：格式字符串里没有 %s，但传了 name<br />
<br />
// 正确<br />
format(str, sizeof(str), "Hello %s", name);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">有用的资源</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">资源</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">地址</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 官方文档</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://open.mp/docs" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">open.mp 新增函数列表</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://open.mp/docs/server/omp-functions" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/server/omp-functions</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">config.json 配置说明</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://www.open.mp/docs/server/config.json" target="_blank" rel="noopener" class="mycode_url">https://www.open.mp/docs/server/config.json</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">自动升级工具</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/openmultiplayer/upgrade" target="_blank" rel="noopener" class="mycode_url">https://github.com/openmultiplayer/upgrade</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">官方 Discord</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://discord.gg/samp" target="_blank" rel="noopener" class="mycode_url">https://discord.gg/samp</a></td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">延伸阅读</h3><br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">地址</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">描述</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/samp-stdlib/tree/consistency-overhaul" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/samp-stdlib...y-overhaul</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">更新后的 SA:MP 包含文件，增加了常量正确性及更多标签。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/samp-incognito/samp-streamer-plugin/pull/435" target="_blank" rel="noopener" class="mycode_url">https://github.com/samp-incognito/samp-s...n/pull/435</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">一个流加载器插件的拉取请求，提供了关于此标签系统的更多信息。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/compiler/wiki/What's-new#const-correctness" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/compiler/wi...orrectness</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">编译器的变更，错误地将常量正确性列为“破坏性”变更。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/compiler/wiki/Const-Correctness" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/compiler/wi...orrectness</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">关于常量正确性及代码更新的更多信息。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/sa-mp-fixes/" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/sa-mp-fixes/</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">许多修复的起源，包括若干已集成至 open.mp 但未在此列出的细微修复。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/pawn-lang/compiler/raw/master/doc/pawn-lang.pdf" target="_blank" rel="noopener" class="mycode_url">https://github.com/pawn-lang/compiler/ra...n-lang.pdf</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">获取有关强标签与弱标签的更多信息。</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="https://github.com/openmultiplayer/upgrade" target="_blank" rel="noopener" class="mycode_url">https://github.com/openmultiplayer/upgrade</a></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">一个可自动完成大量标签与常量正确性升级的工具。</td>
  </tr>
</table>
<br />
如果您在运行服务器时仍有问题，请加入官方的 open.mp Discord 服务器：https://discord.gg/samp<br />
<br />
在 <a href="https://discord.com/channels/231799104731217931/966398440051445790" target="_blank" rel="noopener" class="mycode_url">#openmp-support</a> 频道提问。<br />
<br />
或者在我们的社区群求助: 673335567<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[零基础开发openmp/SAMP服务器基础教程 - 第一章]]></title>
			<link>https://open-mp.cn/showthread.php?tid=17</link>
			<pubDate>Fri, 20 Mar 2026 21:38:31 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=17</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">零基础开发openmp/SAMP服务器基础教程 - 第一章</h2><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">写给完全没接触过编程的你</h4><br />
<br />
零基础开发openmp/SAMP服务器基础教程一共有三个篇章，此为第一篇，按顺序学习阅读即可<br />
<br />
<hr class="mycode_hr" />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>这篇文章不会让你马上写出任何代码。<br />
它只做一件事：<span style="font-weight: bold;" class="mycode_b">让你在打开编辑器之前，脑子里先有一张地图。</span><br />
有了这张地图，后面学什么都会快很多。</blockquote>
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">你可能正处于这样的处境</h4><br />
<br />
你玩过 SAMP 联机，看到别的服务器有各种有趣的玩法，心里想：这个我也想做。<br />
<br />
然后你搜了一下教程，打开了一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件，看到满屏的英文字母和括号符号，看不懂。<br />
<br />
然后关掉了。<br />
<br />
这不是你的问题。是大多数教程默认你已经有一些基础，直接跳过了最重要的第一步——<span style="font-weight: bold;" class="mycode_b">建立认知</span>。<br />
<br />
这篇文章就是来补这一步的。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">理解底层逻辑</h4><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>理解这些尤为重要，是一切的起点。本篇将优先使用新手能理解的大白话进行讲解。</blockquote>
<br />
计算机是一个非常听话但非常死板的工具，先忘掉代码，我们来聊聊计算机到底是什么。<br />
<br />
比方说地图导航软件<br />
<br />
你输入目的地，导航会告诉你：前方 200 米左转，然后直行 500 米，到达目的地。<br />
<br />
导航给出的是一步一步的<span style="font-weight: bold;" class="mycode_b">指令</span>，你只需要跟着做。如果你在它说左转的时候右转了，它不会生气，也不会猜你的意思，它只会重新计算，继续给你下一条指令。<br />
<br />
计算机就是这样的。<br />
<br />
它只会严格地、一条接一条地执行你给它的指令。<br />
<br />
它不会猜，不会发挥，不会应该是这个意思吧帮你圆场。你说什么，它做什么。你没说的，它绝对不做。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">而编程，就是把你的想法翻译成计算机能看懂的指令。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">这件事没有你想的那么神秘</h4><br />
<br />
很多人会觉得这是某种神秘的技术，像外星文字一样难以理解。<br />
<br />
但你其实每天都在做类似的事情。<br />
<br />
假设你要告诉一个<span style="font-weight: bold;" class="mycode_b">什么都不懂</span>的人，怎么帮你冲一杯咖啡，你会怎么说？<br />
<br />
你不能说帮我冲杯咖啡，因为他不知道冲咖啡是什么意思。<br />
<br />
你需要说：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1. 走到茶水间<br />
2. 从柜子里取出咖啡粉<br />
3. 打开水壶，确认里面有水<br />
4. 按下水壶开关，等待水烧开<br />
5. 取出一个杯子<br />
6. 在杯子里放入一勺咖啡粉<br />
7. 把烧开的水倒进杯子里<br />
8. 搅拌均匀</code></div></div><br />
你写的这份说明书，其实就是一段程序。<br />
<br />
你是在把帮我冲咖啡这个模糊的想法，拆分成一步一步清晰的指令。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">编程做的事情，和这个完全一样。</span><br />
<br />
唯一的区别是：你的指令不是写给人看的，是写给计算机看的，所以要用计算机能懂的语法来写。<br />
<br />
学编程，本质上是在学把事情说清楚，编程里真正难的不是记住语法，而是<span style="font-weight: bold;" class="mycode_b">把你的想法说得足够清楚、足够准确</span>，清楚到计算机能执行。想法是模糊的。你需要把它变得更具体，这就是代码背后的思维过程。语法是最后才出现的东西，在这之前，你要先把逻辑想清楚。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">为什么代码要用奇怪的语法写？</h4><br />
<br />
为什么不能直接用中文写？直接告诉电脑给玩家 100 块钱不行吗？<br />
<br />
因为计算机本身只认识 0 和 1，它不理解任何人类语言。<br />
<br />
所以人们发明了编程语言——它是人和计算机之间的翻译官。<br />
<br />
编程语言的语法比中文严格得多，但也简单得多。<br />
<br />
中文有几万个汉字，有各种语气、歧义、修辞。编程语言通常只有几十个固定的关键词，每一个词只有一个意思，没有歧义。<br />
<br />
比如在 Pawn 里：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if&nbsp;&nbsp; → 如果<br />
else → 否则<br />
new&nbsp;&nbsp;→ 新建一个变量（容器）<br />
return → 返回一个结果，并结束</code></div></div><br />
就这些，你能用的词总共就这么多。其他所有千变万化的功能，都是用这些基础词拼出来的。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">所以，代码并不是在用一门你不认识的语言说话，它只是在用一套更严格的格式，表达你本来就会表达的逻辑。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">不会就查，查了才会</h4><br />
<br />
open.mp 有完整的官方文档，里面列出了所有可用的函数和回调，以及每个函数怎么用、参数是什么意思。<br />
<br />
地址：https://open.mp/docs<br />
<br />
养成看文档的习惯，这是最重要的自学能力。当你查了文档、搜了搜索引擎，还是搞不定，这时候可以去问人<br />
<br />
<span style="font-weight: bold;" class="mycode_b">不好的问法：</span>为什么我的代码不行？<br />
<br />
<span style="font-weight: bold;" class="mycode_b">好的问法：</span>我想实现玩家加入时显示欢迎消息，我写了这段代码（贴上代码），编译没有报错，但玩家加入时没有收到消息，请问可能是什么原因？<br />
<br />
把你的代码、你的预期、你观察到的现象都说清楚，别人才能帮你快速定位问题。你描述问题的清晰程度，决定了你能得到帮助的速度。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">报错，是编译器在帮你</h4><br />
<br />
报错信息是编译器（帮你把代码翻译成计算机能运行的文件的工具）在帮你找问题。<br />
<br />
报错信息通常会告诉你两件事：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">哪一行出了问题</span>（行号）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">出了什么问题</span>（错误描述）<br />
</li>
</ul>
<br />
就算是工作了十年的程序员，每天也在面对 bug（程序里的错误）。<br />
<br />
但是pawn相对简单很多，熟悉了之后，有时都不需要实际测试都可以直接通过看代码预判出运行的效果。<br />
<br />
<hr class="mycode_hr" />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">进入正题</h2><br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">Pawn 是什么</h3><br />
<br />
Pawn 是一种为游戏服务器设计的轻量脚本语言，不是通用高级语言。<br />
<br />
对于想学习编程的人来说，它是一个很好的起点——因为你写的代码可以立刻在游戏里看到效果，这种即时反馈会让你进步很快。<br />
<br />
本质上，这是在用C 语言的思维写游戏逻辑。学会 Pawn 的人，以后转 C/C++、Rust 都很快。在国外有不少人通过 SA-MP 开发找到了工作，后来接触到了 C++、PHP、JavaScript 等更复杂的方向。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">脚本文件是什么</h3><br />
<br />
你写的 Pawn 代码保存在一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件里，这就是你的脚本源码。<br />
<br />
写完后需要经过<span style="font-weight: bold;" class="mycode_b">编译</span>，把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 变成服务器能运行的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code> 文件，服务器加载的是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code>，不是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>你写的代码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编译&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;服务器运行<br />
myscript.pwn&nbsp;&nbsp;→&nbsp;&nbsp;myscript.amx&nbsp;&nbsp;→&nbsp;&nbsp;open.mp 加载执行</code></div></div><br />
这个过程就像你写了一份中文食谱，翻译成机器能理解的语言，机器才能按步骤操作。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">单线程</h3><br />
<br />
目前你只需要知道一件事：<span style="font-weight: bold;" class="mycode_b">Pawn 服务器是单线程的</span>。<br />
<br />
单线程意味着：整个服务器只有一条流水线，所有逻辑、计算只能排着队一个一个处理，同一时间只能执行一条指令。<br />
<br />
举个例子：假设你写了一段代码需要执行 1 秒钟，那在这 1 秒内，服务器上其他所有事情都会停下来等它跑完，包括玩家的移动同步、其他玩家的操作响应。<br />
<br />
早期玩过 RPG 服的应该有印象——每到发薪日，服务器会卡顿一下。就是因为给所有玩家结算工资的代码在单线程里跑完之前，所有事件都被暂停了。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">结论：写代码要注重性能，避免一段逻辑执行时间过长。单条简单的加减、判断代码几乎是瞬间完成的（微秒级别），这类代码完全不用担心。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">理解 Tick（帧）</h3><br />
<br />
open.mp 默认每秒运行 <span style="font-weight: bold;" class="mycode_b">30 个 tick（帧）</span>，也就是每秒打包、更新、同步 30 次数据。<br />
<br />
如果网络不好（玩家或服务器任意一方），就可能出现某次 tick 的数据包没有成功传输，也就是俗称的<span style="font-weight: bold;" class="mycode_b">丢包</span>。<br />
<br />
比如连续两秒没收到玩家的位置数据，第三秒突然收到了，就会出现我们常见的<span style="font-weight: bold;" class="mycode_b">瞬移</span>现象。网络好的情况下，每帧数据几乎全部到达，玩家动作就很平滑。<br />
<br />
即使你什么逻辑都没写，open.mp 每个 tick 也会自动同步这些基础数据：<br />
<ul class="mycode_list"><li>玩家位置、朝向<br />
</li>
<li>玩家动作状态<br />
</li>
<li>武器信息<br />
</li>
<li>血量和护甲<br />
</li>
<li>车辆位置、朝向<br />
</li>
<li>玩家按键状态<br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">从玩家操作到游戏表现，完整流程</h3><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>玩家操作<br />
&nbsp;&nbsp;↓<br />
客户端生成数据包，通过 UDP 发送到服务端<br />
&nbsp;&nbsp;↓<br />
服务端接收数据包，自动触发对应的回调函数<br />
&nbsp;&nbsp;↓<br />
回调内的 Pawn 代码执行，修改服务器内存里的数据<br />
&nbsp;&nbsp;↓<br />
Tick 结束，服务器把最新数据同步给所有客户端<br />
&nbsp;&nbsp;↓<br />
玩家在游戏里看到最终表现</code></div></div><br />
不同的玩家操作，会触发不同的回调：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">玩家操作</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">触发的回调</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">移动位置</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerUpdate</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">开枪</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerWeaponShot</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">按下按键</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerKeyStateChange</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">操作对话框</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnDialogResponse</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">死亡</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code></td>
  </tr>
</table>
<br />
<span style="font-weight: bold;" class="mycode_b">举个例子：友伤保护</span><br />
<br />
当玩家开枪，触发 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerWeaponShot</code>。在这个回调里，你可以判断被击中的是不是队友，如果是队友就让伤害为 0：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(IsTeamMate(playerid, hitid))<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0; // 返回 0 = 取消这次子弹伤害<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1; // 返回 1 = 允许子弹正常造成伤害<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">再举个例子：对话框治疗</span><br />
<br />
当玩家操作对话框，触发 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnDialogResponse</code>。判断玩家选了哪个选项，然后执行对应逻辑：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(listitem == 2) // 第三个选项（listitem 从 0 开始，0=第一个，1=第二个，2=第三个）<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetPlayerHealth(playerid, 100.0); // 设置血量为 100<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">listitem</code> 从 <span style="font-weight: bold;" class="mycode_b">0</span> 开始计数，第一个选项是 0，第二个是 1，第三个是 2，以此类推。这是新手非常容易犯错的地方。</blockquote>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">关于作弊</h3><br />
<br />
服务器收到的数据，默认是信任客户端发来的。作弊工具就是利用这一点，篡改客户端发出的数据包（比如把血量改成 10000、位置瞬移到某处），服务器收到后会直接把这些数据同步给其他玩家，其他人就会看到无敌血条、飞天瞬移。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerMoney</code> 获取的就是客户端发来的金钱数据。如果你没有用服务端自己的变量记录玩家金钱，就相当于完全信任了客户端，没有任何验证。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">解决方法：重要的数据（血量、金钱、等级等）永远在服务端自己维护，不信任客户端发来的数值。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">什么是回调（Callback）</h3><br />
<br />
回调是服务端<span style="font-weight: bold;" class="mycode_b">自动触发</span>的函数，触发时机是服务端提前定好的，你不需要手动调用它。<br />
<br />
你能做的是：在这个函数里写你自己的逻辑。<br />
<br />
所有服务端自带的回调都以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public On</code> 开头，比如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 当有玩家连入服务器时，这里的代码会自动执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
public OnPlayerDeath(playerid, killerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 当有玩家死亡时，这里的代码会自动执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">public 是什么意思</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 表示这个函数是公开的，可以被服务端直接调用。服务端自带的回调必须加 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code>，否则服务端找不到它，触发时就不会执行你写的代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">return 1 是什么意思</h4><br />
<br />
函数执行完毕后，需要返回一个结果告诉服务端处理完了。<br />
<ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1</code> = 正常处理，允许默认行为继续<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 0</code> = 在某些回调里代表拦截/取消这次事件（比如上面的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerWeaponShot</code> 返回 0 取消伤害）<br />
</li>
</ul>
<br />
具体每个回调返回 0 和 1 各代表什么，查文档就知道。新手阶段统一写 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1</code> 不会出大问题。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">每个回调都是一个独立的房间</h4><br />
<br />
回调的范围 = 花括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code> 包着的所有内容。从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{</code> 到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">}</code> 之间的所有代码都属于这个回调。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 房间开始<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 这里的代码属于 OnPlayerConnect<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 玩家连入时执行<br />
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 房间结束</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">什么是函数</h3><br />
<br />
函数是一个<span style="font-weight: bold;" class="mycode_b">工具</span>，你不需要知道它内部怎么实现的，只需要知道怎么用、给它传什么参数、它会做什么事。<br />
<br />
就像微波炉：你不需要知道微波炉的电路原理，只需要把食物放进去、设好时间、按启动，它就帮你加热。<br />
<br />
服务端自带大约 1000 个左右的函数，每个函数从名字上就能大致猜到它的作用：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SetPlayerHealth(playerid, Float:health)&nbsp;&nbsp;// 设置玩家血量<br />
SetPlayerSkin(playerid, skinid)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 修改玩家皮肤<br />
SendClientMessage(playerid, color, msg) // 给玩家发送聊天消息<br />
GivePlayerMoney(playerid, money)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 给玩家钱（负数是扣钱）<br />
GetPlayerPos(playerid, Float:x, Float:y, Float:z) // 获取玩家坐标</code></div></div><br />
括号里是参数，告诉函数对谁做做什么。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">能不能自己创建函数</h3><br />
<br />
可以。当你发现一段代码要重复写很多次，就该把它打包成函数。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 没有函数：每次都要重复写<br />
GivePlayerMoney(playerid, 500);<br />
SetPlayerHealth(playerid, 100.0);<br />
SendClientMessage(playerid, -1, "欢迎奖励已发放");<br />
<br />
// 下一个地方又要写一遍...<br />
GivePlayerMoney(playerid, 500);<br />
SetPlayerHealth(playerid, 100.0);<br />
SendClientMessage(playerid, -1, "欢迎奖励已发放");</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 有了函数：打包一次，随时调用<br />
GiveWelcomeReward(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;GivePlayerMoney(playerid, 500);<br />
&nbsp;&nbsp;&nbsp;&nbsp;SetPlayerHealth(playerid, 100.0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "欢迎奖励已发放");<br />
}<br />
<br />
// 需要用的地方只需要一行<br />
GiveWelcomeReward(playerid);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">什么时候该建函数？</span> 一段逻辑在两个以上的地方用到，或者逻辑比较复杂、需要给它起个名字方便理解，就建函数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">能不能用别人写好的函数</h3><br />
<br />
可以，这就是<span style="font-weight: bold;" class="mycode_b">安装插件和依赖库</span>。<br />
<br />
你不需要为了拧一颗螺丝自己炼钢做螺丝刀，直接去五金店买一把就好了。<br />
<br />
别人做好的功能，打包成插件，你直接引入使用，不需要知道内部原理。<br />
<br />
不过在用之前可以留意几点：<ul class="mycode_list"><li>它会不会消耗大量服务器性能？<br />
</li>
<li>作者是否持续维护？<br />
</li>
<li>社区是否有人在用、有没有已知的 bug？<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">去哪里找？</span> Github 搜索，或者 open.mp 官方推荐列表：https://open.mp/docs/awesome<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">回调的执行顺序</h3><br />
<br />
回调不是按固定顺序排好的，而是<span style="font-weight: bold;" class="mycode_b">由 tick 中收到了什么数据来决定</span>。<br />
<br />
玩家没有做某个操作，对应的回调就不会触发。<br />
<br />
如果一个玩家在同一个 tick 内同时触发了多个操作（极罕见），服务器会把这些事件排成队列，在单线程里一个接一个处理。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">但回调内部的代码，是严格从上到下一行一行执行的。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">代码写在哪里</h3><br />
<br />
所有实际运行的代码，都必须写在某个回调的花括号里面。<br />
<br />
写在外面的只能是：变量声明、函数定义、常量定义。<br />
<br />
你自己写的函数，不会自动运行，必须在某个回调里主动调用它，才会被执行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这个函数不会自动运行<br />
MyFunction(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "你好");<br />
}<br />
<br />
// 必须在某个回调里调用它，才会执行<br />
public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyFunction(playerid); // ← 在这里调用，玩家连入时才会执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
可以把服务器想象成一台自动售货机：投币（玩家操作）会触发里面固定的机械流程（服务端回调）。你想加功能，只能在原有流程的某个环节里接线（在回调里调用你自己写的函数），你的代码不会凭空自己运行。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">决定你高度的关键因素</h3><br />
<br />
掌握了上面这些，你已经理解了 open.mp 服务端运行的核心原理。剩下的，本质上都是数学和逻辑问题。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">但有一件事只能靠你自己做：查文档。</span><br />
<br />
你能实现什么功能，取决于你知道多少回调和函数的存在。不需要把所有函数都背下来，但你需要通过不断查阅，建立起自己的工具库认知——知道有什么工具可以用，需要的时候去查怎么用。<br />
<br />
官方文档：https://open.mp/docs<br />
<br />
交流群：673335567<br />
<br />
新手最常犯的错误是：遇到不会的功能，直接问别人这个怎么做，但别人告诉你思路了，你又不知道用哪个函数实现。<br />
<br />
根本原因是对现有工具了解太少。<span style="font-weight: bold;" class="mycode_b">多看文档，多看别人的开源脚本</span>，这是没有捷径的积累过程。<br />
<br />
你知道的越多，能做的就越多。<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">零基础开发openmp/SAMP服务器基础教程 - 第一章</h2><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">写给完全没接触过编程的你</h4><br />
<br />
零基础开发openmp/SAMP服务器基础教程一共有三个篇章，此为第一篇，按顺序学习阅读即可<br />
<br />
<hr class="mycode_hr" />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>这篇文章不会让你马上写出任何代码。<br />
它只做一件事：<span style="font-weight: bold;" class="mycode_b">让你在打开编辑器之前，脑子里先有一张地图。</span><br />
有了这张地图，后面学什么都会快很多。</blockquote>
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">你可能正处于这样的处境</h4><br />
<br />
你玩过 SAMP 联机，看到别的服务器有各种有趣的玩法，心里想：这个我也想做。<br />
<br />
然后你搜了一下教程，打开了一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件，看到满屏的英文字母和括号符号，看不懂。<br />
<br />
然后关掉了。<br />
<br />
这不是你的问题。是大多数教程默认你已经有一些基础，直接跳过了最重要的第一步——<span style="font-weight: bold;" class="mycode_b">建立认知</span>。<br />
<br />
这篇文章就是来补这一步的。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">理解底层逻辑</h4><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>理解这些尤为重要，是一切的起点。本篇将优先使用新手能理解的大白话进行讲解。</blockquote>
<br />
计算机是一个非常听话但非常死板的工具，先忘掉代码，我们来聊聊计算机到底是什么。<br />
<br />
比方说地图导航软件<br />
<br />
你输入目的地，导航会告诉你：前方 200 米左转，然后直行 500 米，到达目的地。<br />
<br />
导航给出的是一步一步的<span style="font-weight: bold;" class="mycode_b">指令</span>，你只需要跟着做。如果你在它说左转的时候右转了，它不会生气，也不会猜你的意思，它只会重新计算，继续给你下一条指令。<br />
<br />
计算机就是这样的。<br />
<br />
它只会严格地、一条接一条地执行你给它的指令。<br />
<br />
它不会猜，不会发挥，不会应该是这个意思吧帮你圆场。你说什么，它做什么。你没说的，它绝对不做。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">而编程，就是把你的想法翻译成计算机能看懂的指令。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">这件事没有你想的那么神秘</h4><br />
<br />
很多人会觉得这是某种神秘的技术，像外星文字一样难以理解。<br />
<br />
但你其实每天都在做类似的事情。<br />
<br />
假设你要告诉一个<span style="font-weight: bold;" class="mycode_b">什么都不懂</span>的人，怎么帮你冲一杯咖啡，你会怎么说？<br />
<br />
你不能说帮我冲杯咖啡，因为他不知道冲咖啡是什么意思。<br />
<br />
你需要说：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1. 走到茶水间<br />
2. 从柜子里取出咖啡粉<br />
3. 打开水壶，确认里面有水<br />
4. 按下水壶开关，等待水烧开<br />
5. 取出一个杯子<br />
6. 在杯子里放入一勺咖啡粉<br />
7. 把烧开的水倒进杯子里<br />
8. 搅拌均匀</code></div></div><br />
你写的这份说明书，其实就是一段程序。<br />
<br />
你是在把帮我冲咖啡这个模糊的想法，拆分成一步一步清晰的指令。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">编程做的事情，和这个完全一样。</span><br />
<br />
唯一的区别是：你的指令不是写给人看的，是写给计算机看的，所以要用计算机能懂的语法来写。<br />
<br />
学编程，本质上是在学把事情说清楚，编程里真正难的不是记住语法，而是<span style="font-weight: bold;" class="mycode_b">把你的想法说得足够清楚、足够准确</span>，清楚到计算机能执行。想法是模糊的。你需要把它变得更具体，这就是代码背后的思维过程。语法是最后才出现的东西，在这之前，你要先把逻辑想清楚。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">为什么代码要用奇怪的语法写？</h4><br />
<br />
为什么不能直接用中文写？直接告诉电脑给玩家 100 块钱不行吗？<br />
<br />
因为计算机本身只认识 0 和 1，它不理解任何人类语言。<br />
<br />
所以人们发明了编程语言——它是人和计算机之间的翻译官。<br />
<br />
编程语言的语法比中文严格得多，但也简单得多。<br />
<br />
中文有几万个汉字，有各种语气、歧义、修辞。编程语言通常只有几十个固定的关键词，每一个词只有一个意思，没有歧义。<br />
<br />
比如在 Pawn 里：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>if&nbsp;&nbsp; → 如果<br />
else → 否则<br />
new&nbsp;&nbsp;→ 新建一个变量（容器）<br />
return → 返回一个结果，并结束</code></div></div><br />
就这些，你能用的词总共就这么多。其他所有千变万化的功能，都是用这些基础词拼出来的。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">所以，代码并不是在用一门你不认识的语言说话，它只是在用一套更严格的格式，表达你本来就会表达的逻辑。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">不会就查，查了才会</h4><br />
<br />
open.mp 有完整的官方文档，里面列出了所有可用的函数和回调，以及每个函数怎么用、参数是什么意思。<br />
<br />
地址：https://open.mp/docs<br />
<br />
养成看文档的习惯，这是最重要的自学能力。当你查了文档、搜了搜索引擎，还是搞不定，这时候可以去问人<br />
<br />
<span style="font-weight: bold;" class="mycode_b">不好的问法：</span>为什么我的代码不行？<br />
<br />
<span style="font-weight: bold;" class="mycode_b">好的问法：</span>我想实现玩家加入时显示欢迎消息，我写了这段代码（贴上代码），编译没有报错，但玩家加入时没有收到消息，请问可能是什么原因？<br />
<br />
把你的代码、你的预期、你观察到的现象都说清楚，别人才能帮你快速定位问题。你描述问题的清晰程度，决定了你能得到帮助的速度。<br />
<br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">报错，是编译器在帮你</h4><br />
<br />
报错信息是编译器（帮你把代码翻译成计算机能运行的文件的工具）在帮你找问题。<br />
<br />
报错信息通常会告诉你两件事：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">哪一行出了问题</span>（行号）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">出了什么问题</span>（错误描述）<br />
</li>
</ul>
<br />
就算是工作了十年的程序员，每天也在面对 bug（程序里的错误）。<br />
<br />
但是pawn相对简单很多，熟悉了之后，有时都不需要实际测试都可以直接通过看代码预判出运行的效果。<br />
<br />
<hr class="mycode_hr" />
<br />
<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">进入正题</h2><br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">Pawn 是什么</h3><br />
<br />
Pawn 是一种为游戏服务器设计的轻量脚本语言，不是通用高级语言。<br />
<br />
对于想学习编程的人来说，它是一个很好的起点——因为你写的代码可以立刻在游戏里看到效果，这种即时反馈会让你进步很快。<br />
<br />
本质上，这是在用C 语言的思维写游戏逻辑。学会 Pawn 的人，以后转 C/C++、Rust 都很快。在国外有不少人通过 SA-MP 开发找到了工作，后来接触到了 C++、PHP、JavaScript 等更复杂的方向。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">脚本文件是什么</h3><br />
<br />
你写的 Pawn 代码保存在一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件里，这就是你的脚本源码。<br />
<br />
写完后需要经过<span style="font-weight: bold;" class="mycode_b">编译</span>，把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 变成服务器能运行的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code> 文件，服务器加载的是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.amx</code>，不是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code>。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>你写的代码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编译&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;服务器运行<br />
myscript.pwn&nbsp;&nbsp;→&nbsp;&nbsp;myscript.amx&nbsp;&nbsp;→&nbsp;&nbsp;open.mp 加载执行</code></div></div><br />
这个过程就像你写了一份中文食谱，翻译成机器能理解的语言，机器才能按步骤操作。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">单线程</h3><br />
<br />
目前你只需要知道一件事：<span style="font-weight: bold;" class="mycode_b">Pawn 服务器是单线程的</span>。<br />
<br />
单线程意味着：整个服务器只有一条流水线，所有逻辑、计算只能排着队一个一个处理，同一时间只能执行一条指令。<br />
<br />
举个例子：假设你写了一段代码需要执行 1 秒钟，那在这 1 秒内，服务器上其他所有事情都会停下来等它跑完，包括玩家的移动同步、其他玩家的操作响应。<br />
<br />
早期玩过 RPG 服的应该有印象——每到发薪日，服务器会卡顿一下。就是因为给所有玩家结算工资的代码在单线程里跑完之前，所有事件都被暂停了。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">结论：写代码要注重性能，避免一段逻辑执行时间过长。单条简单的加减、判断代码几乎是瞬间完成的（微秒级别），这类代码完全不用担心。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">理解 Tick（帧）</h3><br />
<br />
open.mp 默认每秒运行 <span style="font-weight: bold;" class="mycode_b">30 个 tick（帧）</span>，也就是每秒打包、更新、同步 30 次数据。<br />
<br />
如果网络不好（玩家或服务器任意一方），就可能出现某次 tick 的数据包没有成功传输，也就是俗称的<span style="font-weight: bold;" class="mycode_b">丢包</span>。<br />
<br />
比如连续两秒没收到玩家的位置数据，第三秒突然收到了，就会出现我们常见的<span style="font-weight: bold;" class="mycode_b">瞬移</span>现象。网络好的情况下，每帧数据几乎全部到达，玩家动作就很平滑。<br />
<br />
即使你什么逻辑都没写，open.mp 每个 tick 也会自动同步这些基础数据：<br />
<ul class="mycode_list"><li>玩家位置、朝向<br />
</li>
<li>玩家动作状态<br />
</li>
<li>武器信息<br />
</li>
<li>血量和护甲<br />
</li>
<li>车辆位置、朝向<br />
</li>
<li>玩家按键状态<br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">从玩家操作到游戏表现，完整流程</h3><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>玩家操作<br />
&nbsp;&nbsp;↓<br />
客户端生成数据包，通过 UDP 发送到服务端<br />
&nbsp;&nbsp;↓<br />
服务端接收数据包，自动触发对应的回调函数<br />
&nbsp;&nbsp;↓<br />
回调内的 Pawn 代码执行，修改服务器内存里的数据<br />
&nbsp;&nbsp;↓<br />
Tick 结束，服务器把最新数据同步给所有客户端<br />
&nbsp;&nbsp;↓<br />
玩家在游戏里看到最终表现</code></div></div><br />
不同的玩家操作，会触发不同的回调：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">玩家操作</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">触发的回调</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">移动位置</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerUpdate</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">开枪</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerWeaponShot</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">按下按键</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerKeyStateChange</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">操作对话框</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnDialogResponse</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">死亡</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code></td>
  </tr>
</table>
<br />
<span style="font-weight: bold;" class="mycode_b">举个例子：友伤保护</span><br />
<br />
当玩家开枪，触发 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerWeaponShot</code>。在这个回调里，你可以判断被击中的是不是队友，如果是队友就让伤害为 0：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(IsTeamMate(playerid, hitid))<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0; // 返回 0 = 取消这次子弹伤害<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1; // 返回 1 = 允许子弹正常造成伤害<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">再举个例子：对话框治疗</span><br />
<br />
当玩家操作对话框，触发 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnDialogResponse</code>。判断玩家选了哪个选项，然后执行对应逻辑：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(listitem == 2) // 第三个选项（listitem 从 0 开始，0=第一个，1=第二个，2=第三个）<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetPlayerHealth(playerid, 100.0); // 设置血量为 100<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">listitem</code> 从 <span style="font-weight: bold;" class="mycode_b">0</span> 开始计数，第一个选项是 0，第二个是 1，第三个是 2，以此类推。这是新手非常容易犯错的地方。</blockquote>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">关于作弊</h3><br />
<br />
服务器收到的数据，默认是信任客户端发来的。作弊工具就是利用这一点，篡改客户端发出的数据包（比如把血量改成 10000、位置瞬移到某处），服务器收到后会直接把这些数据同步给其他玩家，其他人就会看到无敌血条、飞天瞬移。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GetPlayerMoney</code> 获取的就是客户端发来的金钱数据。如果你没有用服务端自己的变量记录玩家金钱，就相当于完全信任了客户端，没有任何验证。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">解决方法：重要的数据（血量、金钱、等级等）永远在服务端自己维护，不信任客户端发来的数值。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">什么是回调（Callback）</h3><br />
<br />
回调是服务端<span style="font-weight: bold;" class="mycode_b">自动触发</span>的函数，触发时机是服务端提前定好的，你不需要手动调用它。<br />
<br />
你能做的是：在这个函数里写你自己的逻辑。<br />
<br />
所有服务端自带的回调都以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public On</code> 开头，比如：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 当有玩家连入服务器时，这里的代码会自动执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
public OnPlayerDeath(playerid, killerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 当有玩家死亡时，这里的代码会自动执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">public 是什么意思</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 表示这个函数是公开的，可以被服务端直接调用。服务端自带的回调必须加 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code>，否则服务端找不到它，触发时就不会执行你写的代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">return 1 是什么意思</h4><br />
<br />
函数执行完毕后，需要返回一个结果告诉服务端处理完了。<br />
<ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1</code> = 正常处理，允许默认行为继续<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 0</code> = 在某些回调里代表拦截/取消这次事件（比如上面的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerWeaponShot</code> 返回 0 取消伤害）<br />
</li>
</ul>
<br />
具体每个回调返回 0 和 1 各代表什么，查文档就知道。新手阶段统一写 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1</code> 不会出大问题。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">每个回调都是一个独立的房间</h4><br />
<br />
回调的范围 = 花括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code> 包着的所有内容。从 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{</code> 到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">}</code> 之间的所有代码都属于这个回调。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 房间开始<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 这里的代码属于 OnPlayerConnect<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 玩家连入时执行<br />
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 房间结束</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">什么是函数</h3><br />
<br />
函数是一个<span style="font-weight: bold;" class="mycode_b">工具</span>，你不需要知道它内部怎么实现的，只需要知道怎么用、给它传什么参数、它会做什么事。<br />
<br />
就像微波炉：你不需要知道微波炉的电路原理，只需要把食物放进去、设好时间、按启动，它就帮你加热。<br />
<br />
服务端自带大约 1000 个左右的函数，每个函数从名字上就能大致猜到它的作用：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SetPlayerHealth(playerid, Float:health)&nbsp;&nbsp;// 设置玩家血量<br />
SetPlayerSkin(playerid, skinid)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 修改玩家皮肤<br />
SendClientMessage(playerid, color, msg) // 给玩家发送聊天消息<br />
GivePlayerMoney(playerid, money)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 给玩家钱（负数是扣钱）<br />
GetPlayerPos(playerid, Float:x, Float:y, Float:z) // 获取玩家坐标</code></div></div><br />
括号里是参数，告诉函数对谁做做什么。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">能不能自己创建函数</h3><br />
<br />
可以。当你发现一段代码要重复写很多次，就该把它打包成函数。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 没有函数：每次都要重复写<br />
GivePlayerMoney(playerid, 500);<br />
SetPlayerHealth(playerid, 100.0);<br />
SendClientMessage(playerid, -1, "欢迎奖励已发放");<br />
<br />
// 下一个地方又要写一遍...<br />
GivePlayerMoney(playerid, 500);<br />
SetPlayerHealth(playerid, 100.0);<br />
SendClientMessage(playerid, -1, "欢迎奖励已发放");</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 有了函数：打包一次，随时调用<br />
GiveWelcomeReward(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;GivePlayerMoney(playerid, 500);<br />
&nbsp;&nbsp;&nbsp;&nbsp;SetPlayerHealth(playerid, 100.0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "欢迎奖励已发放");<br />
}<br />
<br />
// 需要用的地方只需要一行<br />
GiveWelcomeReward(playerid);</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">什么时候该建函数？</span> 一段逻辑在两个以上的地方用到，或者逻辑比较复杂、需要给它起个名字方便理解，就建函数。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">能不能用别人写好的函数</h3><br />
<br />
可以，这就是<span style="font-weight: bold;" class="mycode_b">安装插件和依赖库</span>。<br />
<br />
你不需要为了拧一颗螺丝自己炼钢做螺丝刀，直接去五金店买一把就好了。<br />
<br />
别人做好的功能，打包成插件，你直接引入使用，不需要知道内部原理。<br />
<br />
不过在用之前可以留意几点：<ul class="mycode_list"><li>它会不会消耗大量服务器性能？<br />
</li>
<li>作者是否持续维护？<br />
</li>
<li>社区是否有人在用、有没有已知的 bug？<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">去哪里找？</span> Github 搜索，或者 open.mp 官方推荐列表：https://open.mp/docs/awesome<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">回调的执行顺序</h3><br />
<br />
回调不是按固定顺序排好的，而是<span style="font-weight: bold;" class="mycode_b">由 tick 中收到了什么数据来决定</span>。<br />
<br />
玩家没有做某个操作，对应的回调就不会触发。<br />
<br />
如果一个玩家在同一个 tick 内同时触发了多个操作（极罕见），服务器会把这些事件排成队列，在单线程里一个接一个处理。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">但回调内部的代码，是严格从上到下一行一行执行的。</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">代码写在哪里</h3><br />
<br />
所有实际运行的代码，都必须写在某个回调的花括号里面。<br />
<br />
写在外面的只能是：变量声明、函数定义、常量定义。<br />
<br />
你自己写的函数，不会自动运行，必须在某个回调里主动调用它，才会被执行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这个函数不会自动运行<br />
MyFunction(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "你好");<br />
}<br />
<br />
// 必须在某个回调里调用它，才会执行<br />
public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;MyFunction(playerid); // ← 在这里调用，玩家连入时才会执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
可以把服务器想象成一台自动售货机：投币（玩家操作）会触发里面固定的机械流程（服务端回调）。你想加功能，只能在原有流程的某个环节里接线（在回调里调用你自己写的函数），你的代码不会凭空自己运行。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">决定你高度的关键因素</h3><br />
<br />
掌握了上面这些，你已经理解了 open.mp 服务端运行的核心原理。剩下的，本质上都是数学和逻辑问题。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">但有一件事只能靠你自己做：查文档。</span><br />
<br />
你能实现什么功能，取决于你知道多少回调和函数的存在。不需要把所有函数都背下来，但你需要通过不断查阅，建立起自己的工具库认知——知道有什么工具可以用，需要的时候去查怎么用。<br />
<br />
官方文档：https://open.mp/docs<br />
<br />
交流群：673335567<br />
<br />
新手最常犯的错误是：遇到不会的功能，直接问别人这个怎么做，但别人告诉你思路了，你又不知道用哪个函数实现。<br />
<br />
根本原因是对现有工具了解太少。<span style="font-weight: bold;" class="mycode_b">多看文档，多看别人的开源脚本</span>，这是没有捷径的积累过程。<br />
<br />
你知道的越多，能做的就越多。<br />
<br />
<hr class="mycode_hr" />
<br />
#GTA# #圣安地列斯# #侠盗猎车手# #圣安地列斯联机# #samp# #gta联机# #gtasa联机# #openmp# #omp# #open.mp# #gtasa#<br />
<br />
社区交流群: 673335567<br />
<br />
论坛: <a href="https://open-mp.cn/" target="_blank" rel="noopener" class="mycode_url">https://open-mp.cn/</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[samp/openmp MySQL 数据库教程]]></title>
			<link>https://open-mp.cn/showthread.php?tid=16</link>
			<pubDate>Fri, 20 Mar 2026 20:55:32 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=16</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">samp/openmp MySQL 数据库教程</h2><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">数据保存：读、查、改、删</h4><br />
<br />
<hr class="mycode_hr" />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>这篇教程只<span style="font-weight: bold;" class="mycode_b">教你用代码操作数据库里的数据</span>。<br />
不涉及登录注册系统，只讲最核心的数据库操作原理和用法。</blockquote>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第一章：数据库？</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">数据库在哪？</span><br />
<br />
你可以把数据库当成一个 <span style="font-weight: bold;" class="mycode_b">Excel 文件</span>，它就在你电脑硬盘上。<br />
<br />
这个 Excel 文件里有很多张表格，每张表格存某一类型的数据，比如玩家数据 载具数据 房屋数据：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>数据库（openmp）<br />
├── players 表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 存玩家数据<br />
│&nbsp;&nbsp; ├── id | name | gold | level | skin<br />
│&nbsp;&nbsp; ├──&nbsp;&nbsp;1 | Tom&nbsp;&nbsp;| 5000 |&nbsp;&nbsp;&nbsp;&nbsp;10 |&nbsp;&nbsp;287<br />
│&nbsp;&nbsp; └──&nbsp;&nbsp;2 | Jane | 2000 |&nbsp;&nbsp;&nbsp;&nbsp; 5 |&nbsp;&nbsp; 86<br />
│<br />
├── houses 表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 存房产数据<br />
│&nbsp;&nbsp; └── ...<br />
│<br />
└── vehicle 表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 存载具数据<br />
&nbsp;&nbsp;&nbsp;&nbsp;└── ...</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">为什么不用 .ini 文件或者 .txt 文件存？</span><br />
<br />
可以，但MySQL数据库的优势：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">高并发处理能力</span>：不会阻塞主线程，支持非阻塞/异步查询<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">速度快</span>：性能强劲，毫秒级返回结果，不需要历遍查找数据<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">安全</span>：数据安全可靠，也可以设置定时备份数据<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">灵活</span>：可以使用SQL语句执行各种复杂的数据库操作<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">维护管理</span>：可视化工具可直接管理、修改、备份数据<br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第二章：为什么要连接数据库？</h3><br />
<br />
数据库是一个<span style="font-weight: bold;" class="mycode_b">独立运行的软件</span>（MySQL），它和你的 open.mp 服务端是两个程序。<br />
<br />
就像你用 QQ 发消息，你要先登录QQ<span style="font-weight: bold;" class="mycode_b">连接</span>腾讯的服务器，才能使用它发消息。<br />
<br />
你的 Pawn 脚本要操作数据库，也需要先<span style="font-weight: bold;" class="mycode_b">建立连接</span>，告诉数据库：<br />
<ul class="mycode_list"><li>我是谁（用户名/密码）<br />
</li>
<li>我要操作哪个数据库<br />
</li>
</ul>
<br />
建立连接之后，你才能往里面读数据、写数据。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第三章：安装准备</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">3.1 在本地安装 MySQL</h4><br />
<br />
下载 MariaDB Server （80多mb）<br />
<br />
下载地址：<a href="https://mariadb.org/download/" target="_blank" rel="noopener" class="mycode_url">https://mariadb.org/download/</a><br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">安装过程有两点需要注意</h5><br />
<ul class="mycode_list"><li>在user settings步骤的时候需要你创建一个密码，这个密码你在后面连接的时候需要用到<br />
</li>
</ul>
<ul class="mycode_list"><li>确认TCP port是3306<br />
</li>
</ul>
<br />
MariaDB 安装包自带 HeidiSQL，安装完成之后你的桌面会有一个快捷方式：HeidiSQL，这是一个可视化数据库管理工具，不会操作的新手，网上也有非常多的视频教程更加直观，我就不多说了<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">3.2 下载 MySQL R41-4 插件</h4><br />
<br />
下载地址：<a href="https://github.com/pBlueG/SA-MP-MySQL/releases/tag/R41-4" target="_blank" rel="noopener" class="mycode_url">https://github.com/pBlueG/SA-MP-MySQL/re.../tag/R41-4</a><br />
<br />
解压后，把文件按下表复制到服务端对应位置：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">文件</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">复制到</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/mysql.dll</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code> 目录</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">libmariadb.dll</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端<span style="font-weight: bold;" class="mycode_b">根目录</span>（和 omp-server.exe 同级）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">log-core.dll</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端<span style="font-weight: bold;" class="mycode_b">根目录</span></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pawno/include/a_mysql.inc</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/include/</code> 目录</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">3.3 在 config.json 里加载插件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"pawn": {<br />
&nbsp;&nbsp;&nbsp;&nbsp;"legacy_plugins": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"mysql"<br />
&nbsp;&nbsp;&nbsp;&nbsp;]<br />
}</code></div></div><br />
启动服务器，控制台看到这行说明插件加载成功：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Loading plugin: mysql<br />
 &gt;&gt; plugin.mysql: R41-4 successfully loaded.</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第四章：创建数据库并连接数据库</h3><br />
<br />
插件装好了，接下来在脚本里建立连接，首先你要先使用 HeidiSQL 创建一个名为 openmp 的数据库。<br />
<br />
创建好之后，在pawn写以下代码<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
#include &lt;a_mysql&gt;&nbsp;&nbsp;&nbsp;&nbsp;// 引入 MySQL 插件头文件<br />
<br />
// 全局变量：保存连接句柄<br />
// 句柄相当于钥匙，后续所有操作都要带上它<br />
new MySQL:g_SQLHandle;<br />
<br />
public OnGameModeInit()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// mysql_connect("数据库地址", "用户名", "密码", "数据库名")<br />
&nbsp;&nbsp;&nbsp;&nbsp;g_SQLHandle = mysql_connect("127.0.0.1", "root", "password", "openmp");<br />
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↑ 127.0.0.1 = 本机，本地固定写这个<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 检查连接是否成功<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(g_SQLHandle == MYSQL_INVALID_HANDLE || mysql_errno(g_SQLHandle) != 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("[MySQL] 连接失败！请检查 MySQL 是否运行。");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 连不上数据库就关服，避免带着错误运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 这也是很多新手拿到开源图打开就闪退的原因<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 因为大部分服务器都是使用MySQL作为数据库<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 你没有正确搭建数据库环境，下面这行代码会自动关闭服务器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendRconCommand("exit");&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("[MySQL] 数据库连接成功！");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第五章：创建数据表</h3><br />
<br />
连接成功后，需要在数据库里建一张表来存玩家数据。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">什么是 SQL？</span><br />
<br />
SQL 是操作数据库专用的语言，每一条 SQL 语句就是给数据库下一道命令，其实你会发现SQL语句就像是说人话一样，教程的最后会展示一些实用便利的SQL语句示例。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_query(g_SQLHandle,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"CREATE TABLE IF NOT EXISTS `players` (&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`id`&nbsp;&nbsp;&nbsp;&nbsp;INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NOT NULL AUTO_INCREMENT,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`name`&nbsp;&nbsp;VARCHAR(24)&nbsp;&nbsp;NOT NULL UNIQUE,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`gold`&nbsp;&nbsp;INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT 0,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`level` INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT 1,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`skin`&nbsp;&nbsp;INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT 86,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PRIMARY KEY (`id`))", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 说明：<br />
&nbsp;&nbsp;&nbsp;&nbsp;// CREATE TABLE = 创建表<br />
&nbsp;&nbsp;&nbsp;&nbsp;// IF NOT EXISTS = 如果表不存在才创建，已存在就跳过<br />
&nbsp;&nbsp;&nbsp;&nbsp;// id&nbsp;&nbsp;&nbsp;&nbsp;- 整数，不能为空，自动递增（每插入一行自动+1，相当于每行的编号）<br />
&nbsp;&nbsp;&nbsp;&nbsp;// name&nbsp;&nbsp;- 最多24字符的字符串，不能为空，且不能重复（UNIQUE）<br />
&nbsp;&nbsp;&nbsp;&nbsp;// gold&nbsp;&nbsp;- 整数，不填时默认值是 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;// level - 整数，不填时默认值是 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;// skin&nbsp;&nbsp;- 整数，不填时默认值是 86<br />
&nbsp;&nbsp;&nbsp;&nbsp;// PRIMARY KEY(id) - 设 id 为主键，数据库用它来精确定位某一行<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("[MySQL] 数据表就绪！");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
执行完这段代码后，你的数据库里就有了一张这样结构的空表：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>players 表<br />
┌────┬──────┬──────┬───────┬──────┐<br />
│ id │ name │ gold │ level │ skin │<br />
├────┼──────┼──────┼───────┼──────┤<br />
│&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; │&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;│<br />
└────┴──────┴──────┴───────┴──────┘</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常用列类型速查</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">类型</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">适用场景</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">金币、等级、皮肤 ID</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">VARCHAR(n)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">最多 n 个字符的字符串</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">玩家名字、称号</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">FLOAT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">小数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">坐标、血量</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TEXT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">长文本（无长度限制）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">个人简介、日志</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TINYINT(1)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">0 或 1，常用作布尔值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">是否是管理员、是否封禁</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常用列约束速查</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">约束</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">NOT NULL</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不允许为空，插入时必须填这一列</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DEFAULT 值</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不填时使用的默认值</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">UNIQUE</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">该列的值在整张表里不能重复</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AUTO_INCREMENT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">自动递增，配合 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INT</code> 主键使用</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">PRIMARY KEY</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">主键，每行的唯一标识，一张表只能有一个</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">我需要背这些语句吗？</h4><br />
<br />
不需要，没有人会背这些，包括写了很多年代码的开发者，你只需要大概知道每种语句是干什么用的，要用的时候回来翻一下，或者直接百度搜 MySQL 创建表格语法，几秒钟就找到了，又或者直接可视化工具输出具体的SQL语句<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第六章：同步 vs 异步（非常重要）</h3><br />
<br />
在讲增删改查之前，必须先理解这个概念，否则你会做出卡服务器的代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">同步查询（mysql_query）—— 阻塞查询</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>mysql_query(g_SQLHandle, "SELECT * FROM players");<br />
// 同步查询会让服务器等待数据库返回结果，期间其他代码暂停<br />
// OnGameModeInit 是服务器刚启动时执行的，此时没有任何玩家在线<br />
// 有玩家在线时永远不要使用阻塞查询，除非你真的知道你在干什么</code></div></div><br />
就像你在餐厅点餐，服务员站在那里死等厨房做完，期间不接待任何其他桌。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>但新手不必害怕这个阻塞查询，阻塞过程可能才千分之一秒，也可能因特殊软件异常或你使用的是远程数据库导致的网络波动会持续更久，但安全意识很重要，只要记住在必要时仅在服务器初始化和启动时同步，其他地方异步即可</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">异步查询（mysql_tquery）—— 非阻塞查询</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>mysql_tquery(g_SQLHandle, "SELECT * FROM players", "我的回调函数", "i", playerid);<br />
// 把查询任务交给后台线程，然后立刻执行其他代码<br />
// 等查询完成后，会自动调用 "我的回调函数"</code></div></div><br />
就像你在餐厅点完餐，服务员给你一个号码牌，你的菜好了他会来找你，服务员继续招待其他桌。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第七章：INSERT — 插入（新增一行数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：玩家第一次进入服务器，在数据库里创建一条新的记录。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>INSERT INTO `players` (`name`, `gold`, `skin`) VALUES ('Tom', 100, 86)</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INSERT INTO</code> = 向某张表插入数据<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">players</code> = 表名<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(name, gold, skin)</code> = 要填写哪几列信息<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">VALUES (...)</code> = 信息对应的值<br />
</li>
</ul>
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">id</code> 不需要填，因为它是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AUTO_INCREMENT</code>，数据库会自动分配。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>InsertPlayer(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 使用 mysql_format 防止玩家名字里有单引号导致 SQL 出错（SQL 注入防护）<br />
&nbsp;&nbsp;&nbsp;&nbsp;// %e 是转义<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"INSERT INTO `players` (`name`, `gold`, `skin`) VALUES ('%e', 50, 86)",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 插入完成后调用 OnPlayerInserted，传入 playerid 告诉回调是哪个玩家<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerInserted", "i", playerid);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 数据正在创建...", name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
// mysql_tquery 完成后自动调用这里<br />
// mysql 会把sql语句的返回结果传入此回调中<br />
forward OnPlayerInserted(playerid);<br />
public OnPlayerInserted(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!IsPlayerConnected(playerid)) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// cache_insert_id() 返回刚刚插入的那行的 id<br />
&nbsp;&nbsp;&nbsp;&nbsp;new insertID = cache_insert_id();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(insertID &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %d 已创建，数据库 ID：%d", playerid, insertID);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第八章：SELECT — 查询（读取数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：玩家进入服务器，从数据库里读取他的金币、等级、皮肤。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT `gold`, `level`, `skin` FROM `players` WHERE `name` = 'Tom'</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SELECT</code> = 我要查询<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gold</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">level</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">skin</code> = 查这几列（用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">*</code> 代表查所有列）<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">FROM players</code> = 从 players 表里查<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">WHERE name = 'Tom'</code> = 条件：只要名字是 Tom 的那行<br />
</li>
</ul>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 存玩家数据的全局数组<br />
new g_Gold[MAX_PLAYERS];<br />
new g_Level[MAX_PLAYERS];<br />
new g_Skin[MAX_PLAYERS];<br />
<br />
LoadPlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT `gold`, `level`, `skin` FROM `players` WHERE `name` = '%e' LIMIT 1", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;// LIMIT 1 = 表示限制只查1行，名字是唯一的所以这样写更高效<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerDataLoaded", "is", playerid, name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
forward OnPlayerDataLoaded(playerid, const name[]);<br />
public OnPlayerDataLoaded(playerid, const name[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!IsPlayerConnected(playerid)) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 查询结果有几行<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(cache_num_rows() == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 没找到这个玩家，说明他是新玩家，去插入一条记录<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InsertPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 从结果的第 0 行（第一行）读取数据，填入全局数组<br />
&nbsp;&nbsp;&nbsp;&nbsp;// cache_get_value_name_int(行号, "列名", 存到哪个变量)<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "gold",&nbsp;&nbsp;g_Gold[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "level", g_Level[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "skin",&nbsp;&nbsp;g_Skin[playerid]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 数据加载完毕：金币=%d 等级=%d 皮肤=%d", name, g_Gold[playerid], g_Level[playerid], g_Skin[playerid]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 数据读好了，让玩家出生<br />
&nbsp;&nbsp;&nbsp;&nbsp;SpawnPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">读取不同类型数据的函数</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">函数</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">用途</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">cache_get_value_name_int(行, "列", 变量)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">读取整数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">cache_get_value_name_float(行, "列", 变量)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">读取浮点数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">cache_get_value_name(行, "列", 变量, 长度)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">读取字符串</td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第九章：UPDATE — 修改（更新数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：玩家下线时，把他当前的金币、等级、皮肤写回数据库。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>UPDATE `players` SET `gold` = 500, `level` = 3 WHERE `name` = 'Tom'</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">UPDATE players</code> = 更新 players 表<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SET gold = 500, level = 3</code> = 把这些列设置成新的值<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">WHERE name = 'Tom'</code> = 只改名字是 Tom 的那行<br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">WHERE 非常重要</span>：如果不写 WHERE，整张表所有行都会被修改！</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SavePlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[256];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"UPDATE `players` SET `gold` = %d, `level` = %d, `skin` = %d WHERE `name` = '%e'",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_Gold[playerid],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_Level[playerid],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_Skin[playerid],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 保存不需要读取回调结果，传空字符串 "" 表示不需要回调<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 数据已保存", name);<br />
}<br />
<br />
// 玩家下线时调用<br />
public OnPlayerDisconnect(playerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SavePlayerData(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第十章：DELETE — 删除（删除一行数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：把这个玩家的数据从数据库里彻底删除。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>DELETE FROM `players` WHERE `name` = 'Tom'</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DELETE FROM players</code> = 从 players 表里删除<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">WHERE name = 'Tom'</code> = 只删名字是 Tom 的那行<br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">同样注意 WHERE</span>：没有 WHERE 条件，整张表的数据全删光！</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>DeletePlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"DELETE FROM `players` WHERE `name` = '%e'",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerDataDelete", "s", name);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
forward OnPlayerDataDelete(const name[]);<br />
public OnPlayerDataDelete(const name[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 如果影响的行数大于0<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(cache_affected_rows() &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 的数据已删除", name);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第十一章：查询多行数据</h3><br />
<br />
前面的 SELECT 只查了一个玩家（一行），有时候你需要查多行，比如「排行榜」。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：查询金币最多的前 5 名玩家。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 5</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ORDER BY gold DESC</code> = 按 gold 列降序排列（DESC = 从大到小，ASC = 从小到大）<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT 5</code> = 只取前 5 行<br />
</li>
</ul>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowTopPlayers(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 5",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"OnTopPlayerLoaded",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"i", playerid<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
forward OnTopPlayerLoaded(playerid);<br />
public OnTopPlayerLoaded(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!IsPlayerConnected(playerid)) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new rows = cache_num_rows();&nbsp;&nbsp; // 获取返回了几行<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(rows == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "[排行榜] 暂无数据");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, 0xFFDD44FF, "=== 金币排行榜 ===");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;new gold;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 遍历每一行结果<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(new i = 0; i &lt; rows; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name(i, "name", name, sizeof(name));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(i, "gold", gold);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, 0xFFFFFFFF, "#%d %s — %d 金币", i + 1, name, gold);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第十二章：异步的安全防护措施</h3><br />
<br />
这一章讲的问题<span style="font-weight: bold;" class="mycode_b">在实际中极罕见发生</span>，但一旦发生就会造成数据写错玩家，值得了解并防范。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">问题是什么？</h4><br />
<br />
异步查询的特点是：<span style="font-weight: bold;" class="mycode_b">你发出查询，然后去做别的事，等数据库回来再处理结果。</span><br />
<br />
这中间有一段时间差，通常只有1毫秒（千分之一秒）不到。正常情况下没有任何问题。但考虑这个极端场景：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1. 玩家 海绵宝宝 连入服务器（ID = 5）<br />
2. 发出 SELECT 非阻塞查询，去数据库读 海绵宝宝 的数据<br />
3. 查询还没回来（1毫秒的空档）<br />
4. 玩家 海绵宝宝 突然断线了，此时ID 5 空出来了<br />
5. 另一个玩家 派大星 立刻连入，空出来 ID 5 就分配给了派大星<br />
6. 数据库查询回来了，把 海绵宝宝 的数据写进了 ID 5 的数组<br />
7. 结果：派大星 拿到了 海绵宝宝 的数据</code></div></div><br />
这个概率极其罕见——需要同一个玩家槽位在毫秒级内被复用，并且又刚好卡在发出查询 -&gt; 查询结果返回来 的这个过程内<br />
<br />
<span style="font-weight: bold;" class="mycode_b">但对于认真的服务器来说，防一下是好习惯。</span><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">解决思路：给每个玩家槽位标一个「版本号」</h4><br />
<br />
每次玩家连入或断开，版本号 +1。<br />
<br />
查询发出时记录当前版本号，查询回来时检查版本号是否还一致——不一致说明这个槽位已经换人了，直接丢弃结果。<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 全局：每个槽位的版本号<br />
new g_PlayerRace[MAX_PLAYERS];<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;g_PlayerRace[playerid]++;&nbsp;&nbsp; // 玩家连入，版本号 +1<br />
&nbsp;&nbsp;&nbsp;&nbsp;LoadPlayerData(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
public OnPlayerDisconnect(playerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SavePlayerData(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;g_PlayerRace[playerid]++;&nbsp;&nbsp; // 玩家断开，版本号 +1<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
发出查询时，把当前版本号一起传进回调参数：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>LoadPlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT `gold`,`level`,`skin` FROM `players` WHERE `name`='%e' LIMIT 1",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 把 race 一起传入回调，格式 "ii" = 两个整数<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerDataLoaded", "ii", playerid, g_PlayerRace[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
回调里第一件事就是核对版本号：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward OnPlayerDataLoaded(playerid, race);<br />
public OnPlayerDataLoaded(playerid, race)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 核对版本号<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 不一致说明这个 ID 已经换了别的玩家，直接丢弃<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(race != g_PlayerRace[playerid]) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 版本号一致，正常处理<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(cache_num_rows() == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InsertPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "gold",&nbsp;&nbsp;g_Gold[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "level", g_Level[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "skin",&nbsp;&nbsp;g_Skin[playerid]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;SpawnPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">这几行代码做了什么</h4><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>玩家 海绵宝宝 连入（ID=5）&nbsp;&nbsp;→ g_PlayerRace[5] = 1，查询携带 race=1 发出<br />
玩家 海绵宝宝 断线&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→ g_PlayerRace[5] = 2<br />
玩家 派大星 连入（ID=5）&nbsp;&nbsp;&nbsp;&nbsp;→ g_PlayerRace[5] = 3<br />
查询回来，race 1 ≠ g_PlayerRace[5] 3&nbsp;&nbsp;→ 丢弃，派大星不受影响</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">养成习惯，所有玩家异步回调都加上这个检查</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">附录：MySQL R41-4 完整函数列表</h3><br />
<br />
本教程只覆盖了最核心的几个函数。R41-4 还提供了更多功能，全部函数的说明和用法可以在官方 Wiki 查阅：<br />
<br />
<a href="https://github.com/pBlueG/SA-MP-MySQL/wiki" target="_blank" rel="noopener" class="mycode_url">https://github.com/pBlueG/SA-MP-MySQL/wiki</a><br />
<br />
遇到具体需求时，去 Wiki 查一下，通常几分钟就能找到你需要的。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">附录：MySQL 实用便利的查询语句示例</h3><br />
<br />
直接在数据库里做加减（不需要先读再写）<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>UPDATE `players` SET `gold` = `gold` + 100 WHERE `name` = 'Tom'</code></div></div><br />
玩家下线时保存数据，但不确定他的记录存不存在，与其先 SELECT 判断再决定 INSERT 还是 UPDATE，不如一句搞定<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>INSERT INTO `players` (`name`, `gold`, `level`)<br />
VALUES ('Tom', 100, 1)<br />
ON DUPLICATE KEY UPDATE `gold` = VALUES(`gold`), `level` = VALUES(`level`)</code></div></div><br />
LIMIT + OFFSET（分页）排行榜翻页时很有用，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OFFSET</code> 是跳过多少行，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT</code> 是取多少行：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>-- 第一页（第 1-10 名）<br />
SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 10 OFFSET 0<br />
<br />
-- 第二页（第 11-20 名）<br />
SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 10 OFFSET 10</code></div></div><br />
统计服务器总注册人数、某个帮派的成员数等：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT COUNT(*) AS `total` FROM `players`<br />
SELECT COUNT(*) AS `total` FROM `players` WHERE `faction` = 3</code></div></div><br />
SUM / MAX / MIN / AVG（计算相关语句）<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>-- 所有玩家总金币<br />
SELECT SUM(`gold`) AS `total_gold` FROM `players`<br />
<br />
-- 最高等级<br />
SELECT MAX(`level`) AS `max_level` FROM `players`<br />
<br />
-- 平均金币<br />
SELECT AVG(`gold`) AS `avg_gold` FROM `players`</code></div></div><br />
模糊搜索，管理员搜索玩家名字时很实用<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT `name`, `level` FROM `players` WHERE `name` LIKE '%Tom%'<br />
-- % 是通配符，匹配任意字符<br />
-- 'Tom%'&nbsp;&nbsp;= 以 Tom 开头<br />
-- '%Tom'&nbsp;&nbsp;= 以 Tom 结尾<br />
-- '%Tom%' = 包含 Tom</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">这里就不一一列举了，总之功能很强大很便利，这是文本保存带来不了的巨大优势</span>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">samp/openmp MySQL 数据库教程</h2><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">数据保存：读、查、改、删</h4><br />
<br />
<hr class="mycode_hr" />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>这篇教程只<span style="font-weight: bold;" class="mycode_b">教你用代码操作数据库里的数据</span>。<br />
不涉及登录注册系统，只讲最核心的数据库操作原理和用法。</blockquote>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第一章：数据库？</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">数据库在哪？</span><br />
<br />
你可以把数据库当成一个 <span style="font-weight: bold;" class="mycode_b">Excel 文件</span>，它就在你电脑硬盘上。<br />
<br />
这个 Excel 文件里有很多张表格，每张表格存某一类型的数据，比如玩家数据 载具数据 房屋数据：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>数据库（openmp）<br />
├── players 表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 存玩家数据<br />
│&nbsp;&nbsp; ├── id | name | gold | level | skin<br />
│&nbsp;&nbsp; ├──&nbsp;&nbsp;1 | Tom&nbsp;&nbsp;| 5000 |&nbsp;&nbsp;&nbsp;&nbsp;10 |&nbsp;&nbsp;287<br />
│&nbsp;&nbsp; └──&nbsp;&nbsp;2 | Jane | 2000 |&nbsp;&nbsp;&nbsp;&nbsp; 5 |&nbsp;&nbsp; 86<br />
│<br />
├── houses 表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ← 存房产数据<br />
│&nbsp;&nbsp; └── ...<br />
│<br />
└── vehicle 表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 存载具数据<br />
&nbsp;&nbsp;&nbsp;&nbsp;└── ...</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">为什么不用 .ini 文件或者 .txt 文件存？</span><br />
<br />
可以，但MySQL数据库的优势：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">高并发处理能力</span>：不会阻塞主线程，支持非阻塞/异步查询<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">速度快</span>：性能强劲，毫秒级返回结果，不需要历遍查找数据<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">安全</span>：数据安全可靠，也可以设置定时备份数据<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">灵活</span>：可以使用SQL语句执行各种复杂的数据库操作<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">维护管理</span>：可视化工具可直接管理、修改、备份数据<br />
</li>
</ul>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第二章：为什么要连接数据库？</h3><br />
<br />
数据库是一个<span style="font-weight: bold;" class="mycode_b">独立运行的软件</span>（MySQL），它和你的 open.mp 服务端是两个程序。<br />
<br />
就像你用 QQ 发消息，你要先登录QQ<span style="font-weight: bold;" class="mycode_b">连接</span>腾讯的服务器，才能使用它发消息。<br />
<br />
你的 Pawn 脚本要操作数据库，也需要先<span style="font-weight: bold;" class="mycode_b">建立连接</span>，告诉数据库：<br />
<ul class="mycode_list"><li>我是谁（用户名/密码）<br />
</li>
<li>我要操作哪个数据库<br />
</li>
</ul>
<br />
建立连接之后，你才能往里面读数据、写数据。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第三章：安装准备</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">3.1 在本地安装 MySQL</h4><br />
<br />
下载 MariaDB Server （80多mb）<br />
<br />
下载地址：<a href="https://mariadb.org/download/" target="_blank" rel="noopener" class="mycode_url">https://mariadb.org/download/</a><br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">安装过程有两点需要注意</h5><br />
<ul class="mycode_list"><li>在user settings步骤的时候需要你创建一个密码，这个密码你在后面连接的时候需要用到<br />
</li>
</ul>
<ul class="mycode_list"><li>确认TCP port是3306<br />
</li>
</ul>
<br />
MariaDB 安装包自带 HeidiSQL，安装完成之后你的桌面会有一个快捷方式：HeidiSQL，这是一个可视化数据库管理工具，不会操作的新手，网上也有非常多的视频教程更加直观，我就不多说了<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">3.2 下载 MySQL R41-4 插件</h4><br />
<br />
下载地址：<a href="https://github.com/pBlueG/SA-MP-MySQL/releases/tag/R41-4" target="_blank" rel="noopener" class="mycode_url">https://github.com/pBlueG/SA-MP-MySQL/re.../tag/R41-4</a><br />
<br />
解压后，把文件按下表复制到服务端对应位置：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">文件</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">复制到</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/mysql.dll</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">plugins/</code> 目录</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">libmariadb.dll</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端<span style="font-weight: bold;" class="mycode_b">根目录</span>（和 omp-server.exe 同级）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">log-core.dll</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端<span style="font-weight: bold;" class="mycode_b">根目录</span></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pawno/include/a_mysql.inc</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务端 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/include/</code> 目录</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">3.3 在 config.json 里加载插件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>"pawn": {<br />
&nbsp;&nbsp;&nbsp;&nbsp;"legacy_plugins": [<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"mysql"<br />
&nbsp;&nbsp;&nbsp;&nbsp;]<br />
}</code></div></div><br />
启动服务器，控制台看到这行说明插件加载成功：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Loading plugin: mysql<br />
 &gt;&gt; plugin.mysql: R41-4 successfully loaded.</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第四章：创建数据库并连接数据库</h3><br />
<br />
插件装好了，接下来在脚本里建立连接，首先你要先使用 HeidiSQL 创建一个名为 openmp 的数据库。<br />
<br />
创建好之后，在pawn写以下代码<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
#include &lt;a_mysql&gt;&nbsp;&nbsp;&nbsp;&nbsp;// 引入 MySQL 插件头文件<br />
<br />
// 全局变量：保存连接句柄<br />
// 句柄相当于钥匙，后续所有操作都要带上它<br />
new MySQL:g_SQLHandle;<br />
<br />
public OnGameModeInit()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// mysql_connect("数据库地址", "用户名", "密码", "数据库名")<br />
&nbsp;&nbsp;&nbsp;&nbsp;g_SQLHandle = mysql_connect("127.0.0.1", "root", "password", "openmp");<br />
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↑ 127.0.0.1 = 本机，本地固定写这个<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 检查连接是否成功<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(g_SQLHandle == MYSQL_INVALID_HANDLE || mysql_errno(g_SQLHandle) != 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("[MySQL] 连接失败！请检查 MySQL 是否运行。");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 连不上数据库就关服，避免带着错误运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 这也是很多新手拿到开源图打开就闪退的原因<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 因为大部分服务器都是使用MySQL作为数据库<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 你没有正确搭建数据库环境，下面这行代码会自动关闭服务器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendRconCommand("exit");&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("[MySQL] 数据库连接成功！");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第五章：创建数据表</h3><br />
<br />
连接成功后，需要在数据库里建一张表来存玩家数据。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">什么是 SQL？</span><br />
<br />
SQL 是操作数据库专用的语言，每一条 SQL 语句就是给数据库下一道命令，其实你会发现SQL语句就像是说人话一样，教程的最后会展示一些实用便利的SQL语句示例。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_query(g_SQLHandle,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"CREATE TABLE IF NOT EXISTS `players` (&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`id`&nbsp;&nbsp;&nbsp;&nbsp;INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NOT NULL AUTO_INCREMENT,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`name`&nbsp;&nbsp;VARCHAR(24)&nbsp;&nbsp;NOT NULL UNIQUE,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`gold`&nbsp;&nbsp;INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT 0,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`level` INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT 1,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`skin`&nbsp;&nbsp;INT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DEFAULT 86,&#92;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PRIMARY KEY (`id`))", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 说明：<br />
&nbsp;&nbsp;&nbsp;&nbsp;// CREATE TABLE = 创建表<br />
&nbsp;&nbsp;&nbsp;&nbsp;// IF NOT EXISTS = 如果表不存在才创建，已存在就跳过<br />
&nbsp;&nbsp;&nbsp;&nbsp;// id&nbsp;&nbsp;&nbsp;&nbsp;- 整数，不能为空，自动递增（每插入一行自动+1，相当于每行的编号）<br />
&nbsp;&nbsp;&nbsp;&nbsp;// name&nbsp;&nbsp;- 最多24字符的字符串，不能为空，且不能重复（UNIQUE）<br />
&nbsp;&nbsp;&nbsp;&nbsp;// gold&nbsp;&nbsp;- 整数，不填时默认值是 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;// level - 整数，不填时默认值是 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;// skin&nbsp;&nbsp;- 整数，不填时默认值是 86<br />
&nbsp;&nbsp;&nbsp;&nbsp;// PRIMARY KEY(id) - 设 id 为主键，数据库用它来精确定位某一行<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;print("[MySQL] 数据表就绪！");<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
执行完这段代码后，你的数据库里就有了一张这样结构的空表：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>players 表<br />
┌────┬──────┬──────┬───────┬──────┐<br />
│ id │ name │ gold │ level │ skin │<br />
├────┼──────┼──────┼───────┼──────┤<br />
│&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; │&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;│<br />
└────┴──────┴──────┴───────┴──────┘</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常用列类型速查</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">类型</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">适用场景</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">金币、等级、皮肤 ID</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">VARCHAR(n)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">最多 n 个字符的字符串</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">玩家名字、称号</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">FLOAT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">小数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">坐标、血量</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TEXT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">长文本（无长度限制）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">个人简介、日志</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">TINYINT(1)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">0 或 1，常用作布尔值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">是否是管理员、是否封禁</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常用列约束速查</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">约束</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">NOT NULL</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不允许为空，插入时必须填这一列</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DEFAULT 值</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不填时使用的默认值</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">UNIQUE</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">该列的值在整张表里不能重复</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AUTO_INCREMENT</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">自动递增，配合 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INT</code> 主键使用</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">PRIMARY KEY</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">主键，每行的唯一标识，一张表只能有一个</td>
  </tr>
</table>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">我需要背这些语句吗？</h4><br />
<br />
不需要，没有人会背这些，包括写了很多年代码的开发者，你只需要大概知道每种语句是干什么用的，要用的时候回来翻一下，或者直接百度搜 MySQL 创建表格语法，几秒钟就找到了，又或者直接可视化工具输出具体的SQL语句<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第六章：同步 vs 异步（非常重要）</h3><br />
<br />
在讲增删改查之前，必须先理解这个概念，否则你会做出卡服务器的代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">同步查询（mysql_query）—— 阻塞查询</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>mysql_query(g_SQLHandle, "SELECT * FROM players");<br />
// 同步查询会让服务器等待数据库返回结果，期间其他代码暂停<br />
// OnGameModeInit 是服务器刚启动时执行的，此时没有任何玩家在线<br />
// 有玩家在线时永远不要使用阻塞查询，除非你真的知道你在干什么</code></div></div><br />
就像你在餐厅点餐，服务员站在那里死等厨房做完，期间不接待任何其他桌。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>但新手不必害怕这个阻塞查询，阻塞过程可能才千分之一秒，也可能因特殊软件异常或你使用的是远程数据库导致的网络波动会持续更久，但安全意识很重要，只要记住在必要时仅在服务器初始化和启动时同步，其他地方异步即可</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">异步查询（mysql_tquery）—— 非阻塞查询</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>mysql_tquery(g_SQLHandle, "SELECT * FROM players", "我的回调函数", "i", playerid);<br />
// 把查询任务交给后台线程，然后立刻执行其他代码<br />
// 等查询完成后，会自动调用 "我的回调函数"</code></div></div><br />
就像你在餐厅点完餐，服务员给你一个号码牌，你的菜好了他会来找你，服务员继续招待其他桌。<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第七章：INSERT — 插入（新增一行数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：玩家第一次进入服务器，在数据库里创建一条新的记录。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>INSERT INTO `players` (`name`, `gold`, `skin`) VALUES ('Tom', 100, 86)</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INSERT INTO</code> = 向某张表插入数据<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">players</code> = 表名<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">(name, gold, skin)</code> = 要填写哪几列信息<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">VALUES (...)</code> = 信息对应的值<br />
</li>
</ul>
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">id</code> 不需要填，因为它是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AUTO_INCREMENT</code>，数据库会自动分配。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>InsertPlayer(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 使用 mysql_format 防止玩家名字里有单引号导致 SQL 出错（SQL 注入防护）<br />
&nbsp;&nbsp;&nbsp;&nbsp;// %e 是转义<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"INSERT INTO `players` (`name`, `gold`, `skin`) VALUES ('%e', 50, 86)",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 插入完成后调用 OnPlayerInserted，传入 playerid 告诉回调是哪个玩家<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerInserted", "i", playerid);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 数据正在创建...", name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
// mysql_tquery 完成后自动调用这里<br />
// mysql 会把sql语句的返回结果传入此回调中<br />
forward OnPlayerInserted(playerid);<br />
public OnPlayerInserted(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!IsPlayerConnected(playerid)) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// cache_insert_id() 返回刚刚插入的那行的 id<br />
&nbsp;&nbsp;&nbsp;&nbsp;new insertID = cache_insert_id();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(insertID &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %d 已创建，数据库 ID：%d", playerid, insertID);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第八章：SELECT — 查询（读取数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：玩家进入服务器，从数据库里读取他的金币、等级、皮肤。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT `gold`, `level`, `skin` FROM `players` WHERE `name` = 'Tom'</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SELECT</code> = 我要查询<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gold</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">level</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">skin</code> = 查这几列（用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">*</code> 代表查所有列）<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">FROM players</code> = 从 players 表里查<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">WHERE name = 'Tom'</code> = 条件：只要名字是 Tom 的那行<br />
</li>
</ul>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 存玩家数据的全局数组<br />
new g_Gold[MAX_PLAYERS];<br />
new g_Level[MAX_PLAYERS];<br />
new g_Skin[MAX_PLAYERS];<br />
<br />
LoadPlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT `gold`, `level`, `skin` FROM `players` WHERE `name` = '%e' LIMIT 1", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;// LIMIT 1 = 表示限制只查1行，名字是唯一的所以这样写更高效<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerDataLoaded", "is", playerid, name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
forward OnPlayerDataLoaded(playerid, const name[]);<br />
public OnPlayerDataLoaded(playerid, const name[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!IsPlayerConnected(playerid)) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 查询结果有几行<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(cache_num_rows() == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 没找到这个玩家，说明他是新玩家，去插入一条记录<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InsertPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 从结果的第 0 行（第一行）读取数据，填入全局数组<br />
&nbsp;&nbsp;&nbsp;&nbsp;// cache_get_value_name_int(行号, "列名", 存到哪个变量)<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "gold",&nbsp;&nbsp;g_Gold[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "level", g_Level[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "skin",&nbsp;&nbsp;g_Skin[playerid]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 数据加载完毕：金币=%d 等级=%d 皮肤=%d", name, g_Gold[playerid], g_Level[playerid], g_Skin[playerid]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 数据读好了，让玩家出生<br />
&nbsp;&nbsp;&nbsp;&nbsp;SpawnPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">读取不同类型数据的函数</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">函数</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">用途</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">cache_get_value_name_int(行, "列", 变量)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">读取整数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">cache_get_value_name_float(行, "列", 变量)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">读取浮点数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">cache_get_value_name(行, "列", 变量, 长度)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">读取字符串</td>
  </tr>
</table>
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第九章：UPDATE — 修改（更新数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：玩家下线时，把他当前的金币、等级、皮肤写回数据库。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>UPDATE `players` SET `gold` = 500, `level` = 3 WHERE `name` = 'Tom'</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">UPDATE players</code> = 更新 players 表<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SET gold = 500, level = 3</code> = 把这些列设置成新的值<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">WHERE name = 'Tom'</code> = 只改名字是 Tom 的那行<br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">WHERE 非常重要</span>：如果不写 WHERE，整张表所有行都会被修改！</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SavePlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[256];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"UPDATE `players` SET `gold` = %d, `level` = %d, `skin` = %d WHERE `name` = '%e'",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_Gold[playerid],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_Level[playerid],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_Skin[playerid],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 保存不需要读取回调结果，传空字符串 "" 表示不需要回调<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 数据已保存", name);<br />
}<br />
<br />
// 玩家下线时调用<br />
public OnPlayerDisconnect(playerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SavePlayerData(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第十章：DELETE — 删除（删除一行数据）</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：把这个玩家的数据从数据库里彻底删除。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>DELETE FROM `players` WHERE `name` = 'Tom'</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DELETE FROM players</code> = 从 players 表里删除<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">WHERE name = 'Tom'</code> = 只删名字是 Tom 的那行<br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">同样注意 WHERE</span>：没有 WHERE 条件，整张表的数据全删光！</blockquote>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>DeletePlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"DELETE FROM `players` WHERE `name` = '%e'",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerDataDelete", "s", name);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
forward OnPlayerDataDelete(const name[]);<br />
public OnPlayerDataDelete(const name[])<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 如果影响的行数大于0<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(cache_affected_rows() &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("[MySQL] 玩家 %s 的数据已删除", name);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第十一章：查询多行数据</h3><br />
<br />
前面的 SELECT 只查了一个玩家（一行），有时候你需要查多行，比如「排行榜」。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">场景</span>：查询金币最多的前 5 名玩家。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">SQL 语句解释</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 5</code></div></div><ul class="mycode_list"><li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ORDER BY gold DESC</code> = 按 gold 列降序排列（DESC = 从大到小，ASC = 从小到大）<br />
</li>
<li><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT 5</code> = 只取前 5 行<br />
</li>
</ul>
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 Pawn 里写</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>ShowTopPlayers(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 5",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"OnTopPlayerLoaded",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"i", playerid<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
forward OnTopPlayerLoaded(playerid);<br />
public OnTopPlayerLoaded(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!IsPlayerConnected(playerid)) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new rows = cache_num_rows();&nbsp;&nbsp; // 获取返回了几行<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(rows == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, -1, "[排行榜] 暂无数据");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, 0xFFDD44FF, "=== 金币排行榜 ===");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;new gold;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 遍历每一行结果<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(new i = 0; i &lt; rows; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name(i, "name", name, sizeof(name));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(i, "gold", gold);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendClientMessage(playerid, 0xFFFFFFFF, "#%d %s — %d 金币", i + 1, name, gold);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">第十二章：异步的安全防护措施</h3><br />
<br />
这一章讲的问题<span style="font-weight: bold;" class="mycode_b">在实际中极罕见发生</span>，但一旦发生就会造成数据写错玩家，值得了解并防范。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">问题是什么？</h4><br />
<br />
异步查询的特点是：<span style="font-weight: bold;" class="mycode_b">你发出查询，然后去做别的事，等数据库回来再处理结果。</span><br />
<br />
这中间有一段时间差，通常只有1毫秒（千分之一秒）不到。正常情况下没有任何问题。但考虑这个极端场景：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>1. 玩家 海绵宝宝 连入服务器（ID = 5）<br />
2. 发出 SELECT 非阻塞查询，去数据库读 海绵宝宝 的数据<br />
3. 查询还没回来（1毫秒的空档）<br />
4. 玩家 海绵宝宝 突然断线了，此时ID 5 空出来了<br />
5. 另一个玩家 派大星 立刻连入，空出来 ID 5 就分配给了派大星<br />
6. 数据库查询回来了，把 海绵宝宝 的数据写进了 ID 5 的数组<br />
7. 结果：派大星 拿到了 海绵宝宝 的数据</code></div></div><br />
这个概率极其罕见——需要同一个玩家槽位在毫秒级内被复用，并且又刚好卡在发出查询 -&gt; 查询结果返回来 的这个过程内<br />
<br />
<span style="font-weight: bold;" class="mycode_b">但对于认真的服务器来说，防一下是好习惯。</span><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">解决思路：给每个玩家槽位标一个「版本号」</h4><br />
<br />
每次玩家连入或断开，版本号 +1。<br />
<br />
查询发出时记录当前版本号，查询回来时检查版本号是否还一致——不一致说明这个槽位已经换人了，直接丢弃结果。<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 全局：每个槽位的版本号<br />
new g_PlayerRace[MAX_PLAYERS];<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;g_PlayerRace[playerid]++;&nbsp;&nbsp; // 玩家连入，版本号 +1<br />
&nbsp;&nbsp;&nbsp;&nbsp;LoadPlayerData(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}<br />
<br />
public OnPlayerDisconnect(playerid, reason)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;SavePlayerData(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;g_PlayerRace[playerid]++;&nbsp;&nbsp; // 玩家断开，版本号 +1<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
发出查询时，把当前版本号一起传进回调参数：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>LoadPlayerData(playerid)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;new name[MAX_PLAYER_NAME];<br />
&nbsp;&nbsp;&nbsp;&nbsp;GetPlayerName(playerid, name, sizeof(name));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;new query[128];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_format(g_SQLHandle, query, sizeof(query),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT `gold`,`level`,`skin` FROM `players` WHERE `name`='%e' LIMIT 1",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 把 race 一起传入回调，格式 "ii" = 两个整数<br />
&nbsp;&nbsp;&nbsp;&nbsp;mysql_tquery(g_SQLHandle, query, "OnPlayerDataLoaded", "ii", playerid, g_PlayerRace[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
回调里第一件事就是核对版本号：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward OnPlayerDataLoaded(playerid, race);<br />
public OnPlayerDataLoaded(playerid, race)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 核对版本号<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 不一致说明这个 ID 已经换了别的玩家，直接丢弃<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(race != g_PlayerRace[playerid]) return 0;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// 版本号一致，正常处理<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(cache_num_rows() == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InsertPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "gold",&nbsp;&nbsp;g_Gold[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "level", g_Level[playerid]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;cache_get_value_name_int(0, "skin",&nbsp;&nbsp;g_Skin[playerid]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;SpawnPlayer(playerid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">这几行代码做了什么</h4><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>玩家 海绵宝宝 连入（ID=5）&nbsp;&nbsp;→ g_PlayerRace[5] = 1，查询携带 race=1 发出<br />
玩家 海绵宝宝 断线&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→ g_PlayerRace[5] = 2<br />
玩家 派大星 连入（ID=5）&nbsp;&nbsp;&nbsp;&nbsp;→ g_PlayerRace[5] = 3<br />
查询回来，race 1 ≠ g_PlayerRace[5] 3&nbsp;&nbsp;→ 丢弃，派大星不受影响</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">养成习惯，所有玩家异步回调都加上这个检查</span><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">附录：MySQL R41-4 完整函数列表</h3><br />
<br />
本教程只覆盖了最核心的几个函数。R41-4 还提供了更多功能，全部函数的说明和用法可以在官方 Wiki 查阅：<br />
<br />
<a href="https://github.com/pBlueG/SA-MP-MySQL/wiki" target="_blank" rel="noopener" class="mycode_url">https://github.com/pBlueG/SA-MP-MySQL/wiki</a><br />
<br />
遇到具体需求时，去 Wiki 查一下，通常几分钟就能找到你需要的。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">附录：MySQL 实用便利的查询语句示例</h3><br />
<br />
直接在数据库里做加减（不需要先读再写）<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>UPDATE `players` SET `gold` = `gold` + 100 WHERE `name` = 'Tom'</code></div></div><br />
玩家下线时保存数据，但不确定他的记录存不存在，与其先 SELECT 判断再决定 INSERT 还是 UPDATE，不如一句搞定<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>INSERT INTO `players` (`name`, `gold`, `level`)<br />
VALUES ('Tom', 100, 1)<br />
ON DUPLICATE KEY UPDATE `gold` = VALUES(`gold`), `level` = VALUES(`level`)</code></div></div><br />
LIMIT + OFFSET（分页）排行榜翻页时很有用，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OFFSET</code> 是跳过多少行，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">LIMIT</code> 是取多少行：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>-- 第一页（第 1-10 名）<br />
SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 10 OFFSET 0<br />
<br />
-- 第二页（第 11-20 名）<br />
SELECT `name`, `gold` FROM `players` ORDER BY `gold` DESC LIMIT 10 OFFSET 10</code></div></div><br />
统计服务器总注册人数、某个帮派的成员数等：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT COUNT(*) AS `total` FROM `players`<br />
SELECT COUNT(*) AS `total` FROM `players` WHERE `faction` = 3</code></div></div><br />
SUM / MAX / MIN / AVG（计算相关语句）<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>-- 所有玩家总金币<br />
SELECT SUM(`gold`) AS `total_gold` FROM `players`<br />
<br />
-- 最高等级<br />
SELECT MAX(`level`) AS `max_level` FROM `players`<br />
<br />
-- 平均金币<br />
SELECT AVG(`gold`) AS `avg_gold` FROM `players`</code></div></div><br />
模糊搜索，管理员搜索玩家名字时很实用<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SELECT `name`, `level` FROM `players` WHERE `name` LIKE '%Tom%'<br />
-- % 是通配符，匹配任意字符<br />
-- 'Tom%'&nbsp;&nbsp;= 以 Tom 开头<br />
-- '%Tom'&nbsp;&nbsp;= 以 Tom 结尾<br />
-- '%Tom%' = 包含 Tom</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">这里就不一一列举了，总之功能很强大很便利，这是文本保存带来不了的巨大优势</span>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[零基础开发openmp/SAMP服务器基础教程 - 第三章(pawn新手入门终篇)]]></title>
			<link>https://open-mp.cn/showthread.php?tid=15</link>
			<pubDate>Fri, 20 Mar 2026 17:12:45 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=15</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">零基础开发openmp/SAMP服务器基础教程 - 第三章(pawn新手入门终篇)</h2><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>本篇是新手教程第二章的<span style="font-weight: bold;" class="mycode_b">基础巩固</span>部分，覆盖新手教程第二章中未涉及或一笔带过的语言细节。  <br />
建议在读完新手教程第二章、能跑起来第一个脚本之后，再来阅读本篇。</blockquote>
<br />
老实说，Pawn 和 openmp/samp 能做的事，远比这新手教程三章展示的多得多。更复杂的数据结构、更多的回调和函数、插件生态、性能优化……这些东西没有讲，也不可能全部讲完。剩下的路，要靠你自己走<br />
<br />
方法其实很简单：<span style="font-weight: bold;" class="mycode_b">想做一个功能，就去查它需要什么函数；看到别人的代码，就去读懂它在做什么。</span> 日积月累，你脑子里的「工具库」会越来越大，能做的事情也会越来越多。遇到看不懂的，查文档、搜索、问社区，这是每一个开发者每天都在做的事，你也不例外。<br />
<br />
官方文档：<a href="https://open.mp/docs" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs</a>  <br />
社区交流群：673335567<br />
<br />
后续仍然会更新更多教程，但不是pawn新手教程系列<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">#</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">章节</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#1-关键字变量声明修饰符" target="_blank" rel="noopener" class="mycode_url">关键字：变量声明修饰符</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#2-const--不可修改的变量" target="_blank" rel="noopener" class="mycode_url">const — 不可修改的变量</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">3</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#3-static--静态变量" target="_blank" rel="noopener" class="mycode_url">static — 静态变量</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#4-forward--函数前向声明" target="_blank" rel="noopener" class="mycode_url">forward — 函数前向声明</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">5</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#5-native--原生函数声明" target="_blank" rel="noopener" class="mycode_url">native — 原生函数声明</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">6</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#6-enum--枚举" target="_blank" rel="noopener" class="mycode_url">enum — 枚举</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">7</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#7-tag标签--类型系统" target="_blank" rel="noopener" class="mycode_url">Tag（标签）— 类型系统</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">8</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#8-编译指令-define" target="_blank" rel="noopener" class="mycode_url">编译指令 #define</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">9</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#9-编译指令-include" target="_blank" rel="noopener" class="mycode_url">编译指令 #include</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">10</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#10-编译指令-if--else--endif" target="_blank" rel="noopener" class="mycode_url">编译指令 #if / #else / #endif</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">11</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#11-编译指令-pragma" target="_blank" rel="noopener" class="mycode_url">编译指令 #pragma</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">12</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#12-运算符补充sizeof" target="_blank" rel="noopener" class="mycode_url">运算符补充：sizeof</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">13</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#13-运算符补充三目运算符-" target="_blank" rel="noopener" class="mycode_url">运算符补充：三目运算符 ?:</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#14-运算符补充位运算" target="_blank" rel="noopener" class="mycode_url">运算符补充：位运算</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">15</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#15-控制结构补充do-while" target="_blank" rel="noopener" class="mycode_url">控制结构补充：do-while</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">16</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#16-控制结构补充break-与-continue" target="_blank" rel="noopener" class="mycode_url">控制结构补充：break 与 continue</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">17</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#17-switch-进阶范围与列表匹配" target="_blank" rel="noopener" class="mycode_url">switch 进阶：范围与列表匹配</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">18</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#18-字符串函数" target="_blank" rel="noopener" class="mycode_url">字符串函数</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">19</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#19-玩家指令commands" target="_blank" rel="noopener" class="mycode_url">玩家指令（Commands）</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">20</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#20-sscanf--解析指令参数" target="_blank" rel="noopener" class="mycode_url">sscanf — 解析指令参数</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">21</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#21-printf-与-print--控制台输出" target="_blank" rel="noopener" class="mycode_url">printf 与 print — 控制台输出</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">22</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#22-代码组织include-拆分文件" target="_blank" rel="noopener" class="mycode_url">代码组织：#include 拆分文件</a></td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">1. 关键字：变量声明修饰符</h3><br />
<br />
在 Pawn 里，声明变量和函数时可以在前面加上<span style="font-weight: bold;" class="mycode_b">修饰关键字</span>，控制它们的可见性和行为。<br />
<br />
主教程只用了最基础的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code>，这里把所有修饰符都介绍清楚：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">关键字</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">用于</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">作用</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">变量</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">声明一个普通变量（最常用）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">变量</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">声明后不能被修改</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">变量/函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">限制作用域</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数/变量</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">未使用时不报警告</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">可被服务端直接调用（回调）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">前向声明，让编译器预先知道函数存在</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">声明由 C/C++ 实现的内置函数</td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">2. const — 不可修改的变量</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 声明的变量在初始化后<span style="font-weight: bold;" class="mycode_b">不能再被修改</span>，编译器会在你试图修改时报错。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>const MAX_LEVEL = 50;<br />
// MAX_LEVEL = 60;  ← 编译报错！不能修改 const 变量</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">const 与 #define 的区别</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MAX_A  50      // 编译时文本替换，不占内存，不带类型<br />
const  MAX_B = 50;    // 占内存，有类型，编译器会检查类型</code></div></div><br />
在 Pawn 里，绝大多数情况下用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 更普遍，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 更常见于：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数参数中的 const 数组：告诉编译器这个数组在函数内部不会被修改<br />
stock MyFunction(const string[])<br />
{<br />
    print(string);  // 只读，不修改<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">3. static — 静态变量</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 有两种用法：<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用法一：局部 static 变量（函数内）</h4><br />
<br />
普通局部变量每次调用函数时都会重置为 0，而 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 局部变量<span style="font-weight: bold;" class="mycode_b">只初始化一次，之后保留上次的值</span>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 普通局部变量：每次调用都从 0 开始<br />
CountNormal()<br />
{<br />
    new i = 0;<br />
    i++;<br />
    printf("普通：%d", i);  // 永远输出 1<br />
}<br />
// static 局部变量：值会在调用之间保留<br />
CountStatic()<br />
{<br />
    static iCount = 0;  // 只在第一次调用时初始化<br />
    iCount++;<br />
    printf("静态：%d", iCount);  // 第1次=1, 第2次=2, 第3次=3...<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用法二：全局 static 变量（文件私有）</h4><br />
<br />
在函数外部声明的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 全局变量，只能在<span style="font-weight: bold;" class="mycode_b">本文件</span>内访问，其他文件无法访问，同时还可以避免相同名称的变量冲突：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 只有本 .pwn 文件才能访问这个变量<br />
static g_Value;</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">新手建议</span>：入门阶段不用刻意区分，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 局部变量是最常用到的，记住「值会保留」这个特点就够了。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">4. forward — 函数前向声明</h3><br />
<br />
Pawn 编译器从上到下读取代码。如果函数 A 调用了函数 B，但 B 写在 A 的后面，编译器就会报错说找不到 B。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 告诉编译器：「这个函数存在，后面会定义它」。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">什么时候必须用 forward？</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. SetTimerEx 的目标函数</span>（最常见）<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 必须在使用前 forward 声明<br />
forward MyTimerFunc(playerid);<br />
// ... 某处调用 ...<br />
SetTimerEx("MyTimerFunc", 3000, false, "i", playerid);<br />
// 函数的实际执行逻辑<br />
public MyTimerFunc(playerid)<br />
{<br />
    SendClientMessage(playerid, -1, "3秒到了！");<br />
    return 1;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">2. 相互调用的函数</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward FuncB();  // 先声明 B<br />
FuncA()<br />
{<br />
    FuncB();  // 调用 B，编译器已经知道 B 存在了<br />
}<br />
FuncB()<br />
{<br />
    // ...<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">规则</span>：只要是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数且通过字符串名称调用的（比如 Timer），<span style="font-weight: bold;" class="mycode_b">都必须 forward</span>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">5. native — 原生函数声明</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code> 声明的函数是由服务端或插件用 C/C++ 实现的函数，不是在 Pawn 里定义的。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include &lt;open.mp&gt;</code> 已经帮你声明好了所有内置的 native 函数，所以你平时直接调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SendClientMessage</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CreateVehicle</code> 这些，底层都是 native。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">你通常不需要自己写 native 声明</span>，除非你在使用额外的插件，或者想给自定义函数加上 Pawno 的自动提示：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 声明一个插件提供的函数（例如 sscanf 插件）<br />
native sscanf(const str[], const format[], ...);<br />
// 利用 native 重命名内置函数（高级用法）<br />
native old_print = print;<br />
// 现在 print 不可用，改为用 old_print 调用</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">新手结论</span>：不需要手写 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code>，知道它是「C/C++ 实现的函数」就够了。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">6. enum — 枚举</h3><br />
<br />
枚举是定义<span style="font-weight: bold;" class="mycode_b">一组有名字的整数常量</span>的方式，让代码更有可读性。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法：替代一组 #define</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 不用枚举的写法（容易混乱）<br />
#define CLASS_PEASANT  0<br />
#define CLASS_KNIGHT    1<br />
#define CLASS_MERCHANT  2<br />
#define CLASS_FISHER    3<br />
// 用枚举（更整洁）<br />
enum E_CLASS<br />
{<br />
    CLASS_PEASANT,    // 自动赋值 0<br />
    CLASS_KNIGHT,    // 自动赋值 1<br />
    CLASS_MERCHANT,  // 自动赋值 2<br />
    CLASS_FISHER      // 自动赋值 3<br />
}<br />
new g_PlayerClass[MAX_PLAYERS];<br />
public OnPlayerSpawn(playerid)<br />
{<br />
    g_PlayerClass[playerid] = CLASS_KNIGHT;<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">高级用法：用枚举定义结构化数组（最强用法）</h4><br />
<br />
这是 SA-MP/open.mp 脚本中最常见的枚举用途，可以把多种数据整合在一个二维数组里：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 定义玩家数据的"字段"<br />
enum E_PLAYER_DATA<br />
{<br />
    PLAYER_GOLD,        // 金币<br />
    PLAYER_LEVEL,      // 等级<br />
    PLAYER_SKIN,        // 皮肤 ID<br />
    PLAYER_KILLS,      // 击杀数<br />
    PLAYER_DEATHS      // 死亡数<br />
}<br />
// 声明二维数组，第二维用枚举大小<br />
new g_PlayerData[MAX_PLAYERS][E_PLAYER_DATA];<br />
// 使用：用字段名代替数字下标，可读性极强<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_PlayerData[playerid][PLAYER_GOLD]  = 50;<br />
    g_PlayerData[playerid][PLAYER_LEVEL]  = 1;<br />
    g_PlayerData[playerid][PLAYER_SKIN]  = 86;<br />
    g_PlayerData[playerid][PLAYER_KILLS]  = 0;<br />
    g_PlayerData[playerid][PLAYER_DEATHS] = 0;<br />
    return 1;<br />
}<br />
// 读取<br />
public OnPlayerDeath(playerid, killerid, reason)<br />
{<br />
    g_PlayerData[playerid][PLAYER_DEATHS]++;<br />
    if(killerid != INVALID_PLAYER_ID)<br />
    {<br />
        g_PlayerData[killerid][PLAYER_KILLS]++;<br />
        g_PlayerData[killerid][PLAYER_GOLD] += 10;  // 击杀奖励 10 金<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>这种写法比单独维护 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">g_Gold[]</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">g_Level[]</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">g_Skin[]</code> 多个数组更整洁，是进阶脚本的标准写法。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">7. Tag（标签）— 类型系统</h3><br />
<br />
Pawn 是「弱类型」语言，所有变量本质上都是 32 位整数。  <br />
<span style="font-weight: bold;" class="mycode_b">Tag（标签）</span> 是 Pawn 对类型的模拟，让编译器在你混用不同「类型」时发出警告。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常见的内置 Tag</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">Tag</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">（无 tag）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">普通整数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new iScore = 0;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new Float:fX = 0.0;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">bool:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">布尔值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new bool:bAlive = true;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Text:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">TextDraw ID</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new Text:tdLogo;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">PlayerText:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">玩家 TextDraw</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new PlayerText:tdHUD;</code></td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Tag Mismatch 警告</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float:health;<br />
new score;<br />
score = health;  // 警告：tag mismatch！把 Float 赋给整数</code></div></div><br />
修复方法：用类型转换强制去除 tag：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>score = _:health;  // _: 去除 tag，变成普通整数再赋值（不推荐随意用）<br />
score = floatround(health);  // 正确做法：用转换函数</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">bool 类型</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new bool:g_IsAdmin[MAX_PLAYERS];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_IsAdmin[playerid] = false;  // 用 true/false，不用 0/1<br />
    return 1;<br />
}<br />
// 判断<br />
if(g_IsAdmin[playerid])<br />
{<br />
    SendClientMessage(playerid, -1, "你是管理员！");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">8. 编译指令 #define</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 是<span style="font-weight: bold;" class="mycode_b">预处理指令</span>，在代码编译前进行纯文本替换。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法：定义常量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MAX_GOLD    999<br />
#define SKIN_KNIGHT 287</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">带参数的宏（函数式宏）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 定义一个带参数的宏，%0 是第一个参数，%1 是第二个，以此类推<br />
#define IsValidPlayer(%0) ((%0) &gt;= 0 &amp;&amp; (%0) &lt; MAX_PLAYERS &amp;&amp; IsPlayerConnected(%0))<br />
// 使用：<br />
if(IsValidPlayer(playerid))<br />
{<br />
    SendClientMessage(playerid, -1, "有效的玩家");<br />
}<br />
// 实际展开为：<br />
// if(((playerid) &gt;= 0 &amp;&amp; (playerid) &lt; MAX_PLAYERS &amp;&amp; IsPlayerConnected(playerid)))</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">主教程用过的按键宏</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这两个就是带参数的宏<br />
#define PRESSED(%0)  (((newkeys) &amp; (%0)) &amp;&amp; !((oldkeys) &amp; (%0)))<br />
#define RELEASED(%0) (!((newkeys) &amp; (%0)) &amp;&amp; ((oldkeys) &amp; (%0)))</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">注意事项</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 宏是纯文本替换，不是函数，没有类型检查，要小心<br />
#define DOUBLE(%0)  %0 * 2<br />
new result = DOUBLE(3 + 4);<br />
// 展开为：3 + 4 * 2 = 11，不是 14！<br />
// 正确写法：<br />
#define DOUBLE(%0)  ((%0) * 2)  // 用括号包裹，避免运算符优先级问题</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">9. 编译指令 #include</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 把另一个文件的内容<span style="font-weight: bold;" class="mycode_b">插入到当前文件</span>，就像把那个文件的代码复制过来一样。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">两种写法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;      // 尖括号：在系统 include 目录（qawno/include/）查找<br />
#include "myfile"      // 引号：在当前目录查找</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常见的 include 文件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;      // open.mp 全量头文件（必须）<br />
// 常用插件头文件<br />
#include &lt;sscanf2&gt;      // 字符串解析（指令参数处理）<br />
#include &lt;Pawn.CMD&gt;      // 指令系统插件<br />
#include &lt;streamer&gt;      // 动态对象流送插件</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">自定义 .inc 文件</h4><br />
<br />
当脚本变大时，可以把部分代码拆分到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件里：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// shop.inc 文件里写商店相关的函数<br />
// 在主脚本里引入<br />
#include "shop"</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">注意事项</h4><br />
<br />
如果文件格式是<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code>可以直接写文件名，如果是其他格式比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.dat</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">txt</code> 则需要写文件格式<br />
<br />
比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include "myfile.pwn"</code><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">10. 编译指令 #if / #else / #endif</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 是<span style="font-weight: bold;" class="mycode_b">编译时的条件判断</span>，决定某段代码要不要被编译进去。  <br />
注意：这和运行时的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 不同，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 在编译阶段就生效。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常见用法：区分 GameMode 和 FilterScript</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 根据是否定义了 FILTERSCRIPT，决定编译哪个初始化函数<br />
#if defined FILTERSCRIPT<br />
    public OnFilterScriptInit()<br />
    {<br />
        print("FilterScript 加载！");<br />
        return 1;<br />
    }<br />
#else<br />
    public OnGameModeInit()<br />
    {<br />
        print("GameMode 加载！");<br />
        return 1;<br />
    }<br />
#endif</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用 #if 开关调试模式</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 在脚本顶部定义，需要调试时就定义它，发布时删掉<br />
#define DEBUG_MODE<br />
// 在代码中用 #if 检查<br />
#if defined DEBUG_MODE<br />
    print("[DEBUG] 服务器已以调试模式启动");<br />
#endif<br />
// 也可以在函数里用（但 #if 在函数内部也是编译时判断）<br />
// 示例中如果没有定义 DEBUG_MODE，则 #if - #endif 内的代码等于不存在，不会有任何开销<br />
public OnPlayerConnect(playerid)<br />
{<br />
    #if defined DEBUG_MODE<br />
        new name[MAX_PLAYER_NAME];<br />
        GetPlayerName(playerid, name, sizeof(name));<br />
        printf("[DEBUG] 玩家连入: %s (ID: %d)", name, playerid);<br />
    #endif<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">defined 运算符</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// defined 检查某个符号是否被 #define 过<br />
#if defined MY_CONSTANT<br />
    // MY_CONSTANT 存在时编译这段<br />
#else<br />
    // 不存在时编译这段<br />
#endif</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">11. 编译指令 #pragma</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma</code> 给编译器传递特殊指令，控制编译行为。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">最常用的几个</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 关闭 tab 缩进警告<br />
#pragma tabsize 0<br />
// 关闭某个编号的警告<br />
#pragma warning disable 200  // 关闭某个编号的警告<br />
// 标记某个变量为「可能不会被用到，不要报警告」<br />
new value;<br />
#pragma unused value</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">12. 运算符补充：sizeof</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sizeof</code> 返回数组的<span style="font-weight: bold;" class="mycode_b">元素数量</span>（不是字节数），是 Pawn 特有的运算符。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new arr[10];<br />
printf("%d", sizeof(arr));  // 输出 10<br />
new name[MAX_PLAYER_NAME];<br />
printf("%d", sizeof(name));  // 输出 MAX_PLAYER_NAME 的值（24）</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">为什么要用 sizeof？</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">避免硬编码数组大小</span>，让代码更安全：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new message[128];<br />
// 不好的写法：手动填 128，万一以后改了数组大小容易忘记改这里<br />
format(message, 128, "你好，%s", name);<br />
// 好的写法：用 sizeof 自动获取<br />
format(message, sizeof(message), "你好，%s", name);<br />
// 以后就算把 128 改成 256，这里也不需要动</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在函数参数里传 sizeof</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>GetPlayerName(playerid, name, sizeof(name));<br />
//                                ↑ 告诉函数数组有多大，防止越界</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">13. 运算符补充：三目运算符 ?:</h3><br />
<br />
三目运算符是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if/else</code> 的简写，适合简单的赋值判断：<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基本语法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 格式：条件 ? 成立时的值 : 不成立时的值<br />
new result = (mygold &gt; 100) ? 1 : 0;<br />
// 等同于：<br />
// if(mygold &gt; 100) result = 1;<br />
// else            result = 0;</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 根据玩家是否在线，获取名字<br />
new string[6];<br />
format(string, sizeof(string), "%s", IsPlayerConnected(targetid) ? "在线" : "离线");<br />
// 根据职业决定皮肤<br />
SetPlayerSkin(playerid, ((g_PlayerClass[playerid] == CLASS_KNIGHT) ? 287 : 86));<br />
// 嵌套三目<br />
new levelName[16];<br />
format(levelName, sizeof(levelName), "%s",<br />
    level &gt;= 10 ? "高级" :<br />
    level &gt;= 5  ? "中级" : "新手"<br />
);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">14. 运算符补充：位运算</h3><br />
<br />
位运算直接操作数字的二进制位，在 SA-MP/open.mp 中主要用于<span style="font-weight: bold;" class="mycode_b">按键检测</span>和<span style="font-weight: bold;" class="mycode_b">标志位</span>。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础位运算符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">名称</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&amp;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位与</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">两位都是 1 才得 1</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\|</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位或</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">任意一位是 1 就得 1</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">^</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位异或</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">两位不同才得 1</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">~</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位非</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">取反</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;&lt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左移</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">相当于乘以 2 的 n 次方</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&gt;&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">右移</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">相当于除以 2 的 n 次方</td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在按键检测中的应用</h4><br />
<br />
按键状态是一个整数，每一个「二进制位」代表一个按键是否被按下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)<br />
{<br />
    // &amp; 运算：检查某个按键位是否为 1（按下状态）<br />
    if(newkeys &amp; KEY_YES)<br />
    {<br />
        // KEY_YES 位是 1，说明 Y 键被按着<br />
    }<br />
    // PRESSED 宏就是用位运算实现的：<br />
    // PRESSED(KEY_YES) 展开为：<br />
    // ((newkeys &amp; KEY_YES) &amp;&amp; !(oldkeys &amp; KEY_YES))<br />
    // 意思是：现在按着 AND 之前没按 = 刚刚按下<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用位运算存储多个布尔标志</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 用一个整数存储多个开关状态（节省内存）<br />
#define FLAG_ADMIN    (1 &lt;&lt; 0)  // 二进制 0001<br />
#define FLAG_VIP      (1 &lt;&lt; 1)  // 二进制 0010<br />
#define FLAG_MUTED    (1 &lt;&lt; 2)  // 二进制 0100<br />
#define FLAG_JAILED  (1 &lt;&lt; 3)  // 二进制 1000<br />
new g_Flags[MAX_PLAYERS];<br />
// 设置标志（用 | 打开某位）<br />
g_Flags[playerid] |= FLAG_ADMIN;<br />
// 清除标志（用 &amp; 和 ~ 关闭某位）<br />
g_Flags[playerid] &amp;= ~FLAG_MUTED;<br />
// 检查标志（用 &amp; 检测某位）<br />
if(g_Flags[playerid] &amp; FLAG_ADMIN)<br />
{<br />
    SendClientMessage(playerid, -1, "你是管理员");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">15. 控制结构补充：do-while</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 的变体，区别是<span style="font-weight: bold;" class="mycode_b">先执行一次，再判断条件</span>。  <br />
即使条件一开始就是假的，循环体至少也会执行一次。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// while：先判断，可能一次都不执行<br />
while(false)<br />
{<br />
    print("永远不会执行");<br />
}<br />
// do-while：先执行，再判断，至少执行一次<br />
do<br />
{<br />
    print("至少执行一次！");<br />
}<br />
while(false);  // 注意：while 后面要加分号</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 寻找一个空的数据槽位（至少要进去看一次）<br />
new slot = 0;<br />
do<br />
{<br />
    if(g_SlotFree[slot])<br />
    {<br />
        break;  // 找到了，跳出<br />
    }<br />
    slot++;<br />
}<br />
while(slot &lt; MAX_SLOTS);</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">新手提示</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 在脚本里不太常用，了解即可。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">16. 控制结构补充：break 与 continue</h3><br />
<br />
这两个关键字用于控制循环的流程。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">break — 立即跳出循环</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 找到第一个死亡的玩家后停止循环<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
    if(!IsPlayerConnected(i)) continue;  // 跳过未连接的（见下）<br />
    new Float:health;<br />
    GetPlayerHealth(i, health);<br />
    if(health &lt;= 0.0)<br />
    {<br />
        printf("玩家 %d 已死亡", i);<br />
        break;  // 找到了就不用继续循环了<br />
    }<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">continue — 跳过本次，进入下一轮</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 给所有在线玩家发消息，跳过管理员<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
    if(!IsPlayerConnected(i)) continue;  // 没连接，跳过<br />
    if(g_Flags[i] &amp; FLAG_ADMIN) continue; // 是管理员，跳过<br />
    SendClientMessage(i, -1, "非管理员消息");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 switch 中不需要 break</h4><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>Pawn 的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 是<span style="font-weight: bold;" class="mycode_b">独立的，不会穿透</span>到下一个 case，这与 C 语言不同，不需要写 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">break</code>。</blockquote>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn：不会穿透，不需要 break<br />
switch(value)<br />
{<br />
    case 1: print("value 是 1");  // 执行后直接跳出 switch<br />
    case 2: print("value 是 2");<br />
    case 3: print("value 是 3");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">17. switch 进阶：范围与列表匹配</h3><br />
<br />
Pawn 的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 比 C 语言更强大，支持<span style="font-weight: bold;" class="mycode_b">范围</span>和<span style="font-weight: bold;" class="mycode_b">列表</span>匹配。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">列表匹配（多个值合并成一个 case）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new level = 3;<br />
switch(level)<br />
{<br />
    case 1, 2, 3:      // 匹配 1 或 2 或 3<br />
    {<br />
        SendClientMessage(playerid, -1, "初级段位");<br />
    }<br />
    case 4, 5, 6:      // 匹配 4 或 5 或 6<br />
    {<br />
        SendClientMessage(playerid, -1, "中级段位");<br />
    }<br />
    case 7, 8, 9, 10:<br />
    {<br />
        SendClientMessage(playerid, -1, "高级段位");<br />
    }<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">范围匹配（连续区间）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>switch(level)<br />
{<br />
    case 1 .. 3:    // 匹配 1 到 3（含两端）<br />
    {<br />
        SendClientMessage(playerid, -1, "初级段位");<br />
    }<br />
    case 4 .. 6:    // 匹配 4 到 6<br />
    {<br />
        SendClientMessage(playerid, -1, "中级段位");<br />
    }<br />
    case 7 .. 10:<br />
    {<br />
        SendClientMessage(playerid, -1, "高级段位");<br />
    }<br />
    default:<br />
    {<br />
        SendClientMessage(playerid, -1, "段位超出范围");<br />
    }<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">18. 字符串函数</h3><br />
<br />
Pawn 内置了很多处理字符串的函数，这里列出脚本开发中最常用的几个。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strlen — 获取字符串长度</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new name[MAX_PLAYER_NAME];<br />
GetPlayerName(playerid, name, sizeof(name));<br />
new len = strlen(name);<br />
printf("名字长度：%d", len);<br />
// 常用：检查输入是否为空<br />
if(strlen(inputtext) == 0)<br />
{<br />
    SendClientMessage(playerid, -1, "输入不能为空！");<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strcmp — 比较两个字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// strcmp(str1, str2, ignorecase, length)<br />
// 返回 0 = 相同，非 0 = 不同<br />
new input[32] = "hello";<br />
if(strcmp(input, "hello", true) == 0)  // true = 忽略大小写<br />
{<br />
    print("字符串匹配！");<br />
}<br />
// 常用简写（检查是否不同）<br />
if(strcmp(input, "admin"))<br />
{<br />
    // 不相同时执行（非 0 = true）<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strcat — 拼接字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new result[24] = "Hello, ";<br />
strcat(result, "World!");<br />
// result 现在是 "Hello, World!"</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strfind — 查找子字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[] = "Welcome to the server!";<br />
new pos = strfind(string, "server", true);  // 返回位置下标，找不到返回 -1<br />
if(pos != -1)<br />
{<br />
    printf("找到了 server，位置：%d", pos);  // 输出 15<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">字符串与数字互转</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 字符串 → 整数<br />
new string[] = "123";<br />
new number = strval(string);  // number = 123<br />
// 整数 → 字符串（用 format）<br />
new output[16];<br />
format(output, sizeof(output), "%d", number);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">19. 玩家指令（Commands）</h3><br />
<br />
玩家在聊天框输入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/指令名</code> 时触发 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerCommandText</code> 回调。  <br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">方法一：直接用 strcmp（基础做法）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Gold[MAX_PLAYERS] = {100, ...};<br />
public OnPlayerCommandText(playerid, cmdtext[])<br />
{<br />
    // cmdtext 是玩家输入的完整内容，例如 "/heal"<br />
    if(strcmp(cmdtext, "/heal", true) == 0)<br />
    {<br />
        SetPlayerHealth(playerid, 100.0);<br />
        SendClientMessage(playerid, -1, "血量已恢复！");<br />
        return 1;  // ← 一定要 return 1，表示指令已处理<br />
    }<br />
    if(strcmp(cmdtext, "/gold", true) == 0)<br />
    {<br />
        SendClientMessage(playerid, -1, "你现在有 %d 枚金币。", g_Gold[playerid]);<br />
        return 1;<br />
    }<br />
    // 没有匹配的指令：return 0 让服务器显示"未知指令"提示<br />
    return 0;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">方法二：用 Pawn.CMD 插件（推荐做法）</h4><br />
<br />
Pawn.CMD 是一个流行的指令处理插件，语法更简洁，性能更好：<br />
<br />
自行下载安装: <a href="https://github.com/katursis/Pawn.CMD" target="_blank" rel="noopener" class="mycode_url">https://github.com/katursis/Pawn.CMD</a><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;Pawn.CMD&gt;  // 需要安装 Pawn.CMD 插件<br />
// Pawn.CMD 的写法：CMD:指令名(playerid, params[])<br />
CMD:heal(playerid, params[])<br />
{<br />
    SetPlayerHealth(playerid, 100.0);<br />
    SendClientMessage(playerid, -1, "血量已恢复！");<br />
    return 1;<br />
}<br />
CMD:gold(playerid, params[])<br />
{<br />
    SendClientMessage(playerid, -1, "你现在有 %d 枚金币。", g_Gold[playerid]);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">指令权限检查</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>CMD:kick(playerid, params[])<br />
{<br />
    // 只有管理员才能用<br />
    if(!(g_Flags[playerid] &amp; FLAG_ADMIN))<br />
    {<br />
        SendClientMessage(playerid, -1, "你没有权限使用此指令！");<br />
        return 1;<br />
    }<br />
    // ... 踢人逻辑 ...<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">20. sscanf — 解析指令参数</h3><br />
<br />
当指令带参数时（例如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/kick 5</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/give 3 100</code>），需要从字符串里把参数提取出来。  <br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sscanf</code> 插件是处理这类问题的标准工具。<br />
<br />
自行下载安装: <a href="https://github.com/Y-Less/sscanf" target="_blank" rel="noopener" class="mycode_url">https://github.com/Y-Less/sscanf</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// sscanf(输入字符串, 格式, 变量1, 变量2, ...)<br />
// 返回 0 = 解析成功，非 0 = 解析失败（参数不够或格式不对）<br />
CMD:give(playerid, params[])<br />
{<br />
    new targetID, amount;<br />
    // 格式 "ii" = 两个整数<br />
    if(sscanf(params, "ii", targetID, amount))<br />
    {<br />
        SendClientMessage(playerid, -1, "用法：/give [玩家ID] [金币数]");<br />
        return 1;<br />
    }<br />
    if(!IsPlayerConnected(targetID))<br />
    {<br />
        SendClientMessage(playerid, -1, "该玩家不在线！");<br />
        return 1;<br />
    }<br />
    g_Gold[targetID] += amount;<br />
    SendClientMessage(playerid, -1, "向玩家 %d 赠送了 %d 枚金币。", targetID, amount);<br />
    SendClientMessage(targetID, -1, "管理员赠送了 %d 枚金币给你。", amount);<br />
    return 1;<br />
}<br />
CMD:skin(playerid, params[])<br />
{<br />
    new skinID;<br />
    if(sscanf(params, "i", skinID))<br />
    {<br />
        SendClientMessage(playerid, -1, "用法：/skin [皮肤ID]");<br />
        return 1;<br />
    }<br />
    SetPlayerSkin(playerid, skinID);<br />
    g_Skin[playerid] = skinID;<br />
    SendClientMessage(playerid, -1, "皮肤已更换为 %d。", skinID);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">sscanf 格式说明符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">格式符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">f</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">s</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串（到空格结束）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">s[32]</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">最大 32 字符的字符串</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">u</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">玩家名字或 ID（自动解析）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">p&lt;分隔符&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置分隔符，如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">p,</code> 用逗号分隔</td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">sscanf 相关文档说明</h4><br />
<br />
如何使用: <a href="https://github.com/Y-Less/sscanf?tab=readme-ov-file#use" target="_blank" rel="noopener" class="mycode_url">https://github.com/Y-Less/sscanf?tab=readme-ov-file#use</a><br />
格式说明符: <a href="https://github.com/Y-Less/sscanf?tab=readme-ov-file#specifiers" target="_blank" rel="noopener" class="mycode_url">https://github.com/Y-Less/sscanf?tab=rea...specifiers</a><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">21. printf 与 print — 控制台输出</h3><br />
<br />
这两个函数把内容输出到<span style="font-weight: bold;" class="mycode_b">服务器控制台窗口</span>，玩家看不到，只能在服务器后台终端看到。  <br />
常用于调试和记录日志。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">print — 输出纯文字</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>print("服务器启动了！");<br />
print("[DEBUG] 这是一条调试信息");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">printf — 带格式化输出</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new playerCounts = 0;<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
    if(IsPlayerConnected(i)) playerCounts++;<br />
printf("[服务器] 当前在线玩家：%d", playerCounts);<br />
printf("[DEBUG] 玩家 %d 的金币：%d", playerid, g_Gold[playerid]);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">格式符与 format 相同</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("整数：%d，浮点：%.2f，字符串：%s", 42, 3.14, "hello");<br />
// 输出：整数：42，浮点：3.14，字符串：hello</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">22. 代码组织：#include 拆分文件</h3><br />
<br />
当你的脚本越来越大，所有代码都写在一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件里会很难维护。 <br />
<br />
按<span style="font-weight: bold;" class="mycode_b">功能模块</span>拆分成多个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件，再在主文件里引入。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">比如</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>gamemodes/<br />
├── main.pwn            ← 主文件（只负责引入和框架）<br />
└── include/<br />
    ├── shop.inc        ← 商店系统<br />
    ├── npc.inc        ← NPC 系统<br />
    ├── vehicle.inc    ← 载具系统<br />
    └── commands.inc    ← 所有指令</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">主文件写法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// mian.pwn<br />
#include &lt;open.mp&gt;<br />
// 引入各功能模块<br />
#include "include/shop.inc"<br />
#include "include/npc.inc"<br />
#include "include/vehicle.inc"<br />
#include "include/commands.inc"<br />
// 主文件只写框架回调<br />
public OnGameModeInit()<br />
{<br />
    InitShop();      // 调用 shop.inc 里的初始化函数<br />
    InitNPCs();      // 调用 npc.inc 里的初始化函数<br />
    InitVehicles();  // 调用 vehicle.inc 里的初始化函数<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">shop.inc 示例</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 注意：这里不需要再 #include &lt;open.mp&gt;，主文件已经引入了<br />
// 商店相关的变量、函数、指令都写在这里<br />
InitShop()<br />
{<br />
    // 创建商店相关的 Pickup 等<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">进阶：ALS Hook 系统（让 .inc 自己挂载回调）</h4><br />
<br />
Pawn 不允许同一个回调定义两次，也就是说<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code> 等等这些回调只能有一个<br />
<br />
当模块越来越多，每次写新模块都要回去主文件里的各个回调中加入新模块的功能，容易忘记、切不容易维护管理。<br />
<br />
让每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件自己管理自己需要使用的回调，执行完自己的逻辑后再把控制权传给下一个模块，形成一条链。<br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">原理</h5><br />
<br />
<ol type="1" class="mycode_list"><li>我先把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> <span style="font-weight: bold;" class="mycode_b">重命名</span>成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">shop_OnGameModeInit</code>（用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 宏替换）<br />
</li>
<li>然后我自己写一个新的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code>，在里面先执行我的逻辑，再调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">shop_OnGameModeInit</code><br />
</li>
<li>下一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code>（比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">npc.inc</code>）接着同样操作，把我写的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> 再重命名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">npc_OnGameModeInit</code>，再写新的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code>...<br />
</li>
<li>最终形成一条调用链：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> → <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">npc_OnGameModeInit</code> → <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">shop_OnGameModeInit</code> → 主文件的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1</code><br />
</li>
</ol>
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// shop.inc 文件内部<br />
new g_ShopPickup;<br />
InitShop()<br />
{<br />
    g_ShopPickup = CreatePickup(1242, 2, 100.0, 200.0, 10.0, -1);<br />
    return 1;<br />
}<br />
public OnGameModeInit()<br />
{<br />
    InitShop();<br />
    #if defined shop_OnGameModeInit<br />
        return shop_OnGameModeInit();<br />
    #else<br />
        return 1;<br />
    #endif<br />
}<br />
#if defined _ALS_OnGameModeInit<br />
    #undef OnGameModeInit<br />
#else<br />
    #define _ALS_OnGameModeInit<br />
#endif<br />
#define OnGameModeInit shop_OnGameModeInit<br />
#if defined shop_OnGameModeInit<br />
    forward shop_OnGameModeInit();<br />
#endif</code></div></div><br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">有了 ALS 之后，主文件什么都不用写</h5><br />
<br />
只需要#include进去，干净利落<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
#include "include/shop.inc"    <br />
#include "include/npc.inc"    <br />
#include "include/vehicle.inc" <br />
public OnGameModeInit()<br />
{<br />
    return 1;<br />
}</code></div></div><hr class="mycode_hr" />]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">零基础开发openmp/SAMP服务器基础教程 - 第三章(pawn新手入门终篇)</h2><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>本篇是新手教程第二章的<span style="font-weight: bold;" class="mycode_b">基础巩固</span>部分，覆盖新手教程第二章中未涉及或一笔带过的语言细节。  <br />
建议在读完新手教程第二章、能跑起来第一个脚本之后，再来阅读本篇。</blockquote>
<br />
老实说，Pawn 和 openmp/samp 能做的事，远比这新手教程三章展示的多得多。更复杂的数据结构、更多的回调和函数、插件生态、性能优化……这些东西没有讲，也不可能全部讲完。剩下的路，要靠你自己走<br />
<br />
方法其实很简单：<span style="font-weight: bold;" class="mycode_b">想做一个功能，就去查它需要什么函数；看到别人的代码，就去读懂它在做什么。</span> 日积月累，你脑子里的「工具库」会越来越大，能做的事情也会越来越多。遇到看不懂的，查文档、搜索、问社区，这是每一个开发者每天都在做的事，你也不例外。<br />
<br />
官方文档：<a href="https://open.mp/docs" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs</a>  <br />
社区交流群：673335567<br />
<br />
后续仍然会更新更多教程，但不是pawn新手教程系列<br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">#</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">章节</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#1-关键字变量声明修饰符" target="_blank" rel="noopener" class="mycode_url">关键字：变量声明修饰符</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#2-const--不可修改的变量" target="_blank" rel="noopener" class="mycode_url">const — 不可修改的变量</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">3</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#3-static--静态变量" target="_blank" rel="noopener" class="mycode_url">static — 静态变量</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#4-forward--函数前向声明" target="_blank" rel="noopener" class="mycode_url">forward — 函数前向声明</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">5</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#5-native--原生函数声明" target="_blank" rel="noopener" class="mycode_url">native — 原生函数声明</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">6</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#6-enum--枚举" target="_blank" rel="noopener" class="mycode_url">enum — 枚举</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">7</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#7-tag标签--类型系统" target="_blank" rel="noopener" class="mycode_url">Tag（标签）— 类型系统</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">8</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#8-编译指令-define" target="_blank" rel="noopener" class="mycode_url">编译指令 #define</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">9</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#9-编译指令-include" target="_blank" rel="noopener" class="mycode_url">编译指令 #include</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">10</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#10-编译指令-if--else--endif" target="_blank" rel="noopener" class="mycode_url">编译指令 #if / #else / #endif</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">11</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#11-编译指令-pragma" target="_blank" rel="noopener" class="mycode_url">编译指令 #pragma</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">12</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#12-运算符补充sizeof" target="_blank" rel="noopener" class="mycode_url">运算符补充：sizeof</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">13</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#13-运算符补充三目运算符-" target="_blank" rel="noopener" class="mycode_url">运算符补充：三目运算符 ?:</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#14-运算符补充位运算" target="_blank" rel="noopener" class="mycode_url">运算符补充：位运算</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">15</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#15-控制结构补充do-while" target="_blank" rel="noopener" class="mycode_url">控制结构补充：do-while</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">16</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#16-控制结构补充break-与-continue" target="_blank" rel="noopener" class="mycode_url">控制结构补充：break 与 continue</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">17</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#17-switch-进阶范围与列表匹配" target="_blank" rel="noopener" class="mycode_url">switch 进阶：范围与列表匹配</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">18</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#18-字符串函数" target="_blank" rel="noopener" class="mycode_url">字符串函数</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">19</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#19-玩家指令commands" target="_blank" rel="noopener" class="mycode_url">玩家指令（Commands）</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">20</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#20-sscanf--解析指令参数" target="_blank" rel="noopener" class="mycode_url">sscanf — 解析指令参数</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">21</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#21-printf-与-print--控制台输出" target="_blank" rel="noopener" class="mycode_url">printf 与 print — 控制台输出</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">22</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#22-代码组织include-拆分文件" target="_blank" rel="noopener" class="mycode_url">代码组织：#include 拆分文件</a></td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">1. 关键字：变量声明修饰符</h3><br />
<br />
在 Pawn 里，声明变量和函数时可以在前面加上<span style="font-weight: bold;" class="mycode_b">修饰关键字</span>，控制它们的可见性和行为。<br />
<br />
主教程只用了最基础的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code>，这里把所有修饰符都介绍清楚：<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">关键字</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">用于</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">作用</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">变量</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">声明一个普通变量（最常用）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">变量</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">声明后不能被修改</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">变量/函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">限制作用域</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数/变量</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">未使用时不报警告</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">可被服务端直接调用（回调）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">前向声明，让编译器预先知道函数存在</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">声明由 C/C++ 实现的内置函数</td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">2. const — 不可修改的变量</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 声明的变量在初始化后<span style="font-weight: bold;" class="mycode_b">不能再被修改</span>，编译器会在你试图修改时报错。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>const MAX_LEVEL = 50;<br />
// MAX_LEVEL = 60;  ← 编译报错！不能修改 const 变量</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">const 与 #define 的区别</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MAX_A  50      // 编译时文本替换，不占内存，不带类型<br />
const  MAX_B = 50;    // 占内存，有类型，编译器会检查类型</code></div></div><br />
在 Pawn 里，绝大多数情况下用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 更普遍，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">const</code> 更常见于：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数参数中的 const 数组：告诉编译器这个数组在函数内部不会被修改<br />
stock MyFunction(const string[])<br />
{<br />
    print(string);  // 只读，不修改<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">3. static — 静态变量</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 有两种用法：<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用法一：局部 static 变量（函数内）</h4><br />
<br />
普通局部变量每次调用函数时都会重置为 0，而 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 局部变量<span style="font-weight: bold;" class="mycode_b">只初始化一次，之后保留上次的值</span>：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 普通局部变量：每次调用都从 0 开始<br />
CountNormal()<br />
{<br />
    new i = 0;<br />
    i++;<br />
    printf("普通：%d", i);  // 永远输出 1<br />
}<br />
// static 局部变量：值会在调用之间保留<br />
CountStatic()<br />
{<br />
    static iCount = 0;  // 只在第一次调用时初始化<br />
    iCount++;<br />
    printf("静态：%d", iCount);  // 第1次=1, 第2次=2, 第3次=3...<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用法二：全局 static 变量（文件私有）</h4><br />
<br />
在函数外部声明的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 全局变量，只能在<span style="font-weight: bold;" class="mycode_b">本文件</span>内访问，其他文件无法访问，同时还可以避免相同名称的变量冲突：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 只有本 .pwn 文件才能访问这个变量<br />
static g_Value;</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">新手建议</span>：入门阶段不用刻意区分，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static</code> 局部变量是最常用到的，记住「值会保留」这个特点就够了。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">4. forward — 函数前向声明</h3><br />
<br />
Pawn 编译器从上到下读取代码。如果函数 A 调用了函数 B，但 B 写在 A 的后面，编译器就会报错说找不到 B。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 告诉编译器：「这个函数存在，后面会定义它」。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">什么时候必须用 forward？</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. SetTimerEx 的目标函数</span>（最常见）<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 必须在使用前 forward 声明<br />
forward MyTimerFunc(playerid);<br />
// ... 某处调用 ...<br />
SetTimerEx("MyTimerFunc", 3000, false, "i", playerid);<br />
// 函数的实际执行逻辑<br />
public MyTimerFunc(playerid)<br />
{<br />
    SendClientMessage(playerid, -1, "3秒到了！");<br />
    return 1;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">2. 相互调用的函数</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward FuncB();  // 先声明 B<br />
FuncA()<br />
{<br />
    FuncB();  // 调用 B，编译器已经知道 B 存在了<br />
}<br />
FuncB()<br />
{<br />
    // ...<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">规则</span>：只要是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public</code> 函数且通过字符串名称调用的（比如 Timer），<span style="font-weight: bold;" class="mycode_b">都必须 forward</span>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">5. native — 原生函数声明</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code> 声明的函数是由服务端或插件用 C/C++ 实现的函数，不是在 Pawn 里定义的。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include &lt;open.mp&gt;</code> 已经帮你声明好了所有内置的 native 函数，所以你平时直接调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SendClientMessage</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">CreateVehicle</code> 这些，底层都是 native。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">你通常不需要自己写 native 声明</span>，除非你在使用额外的插件，或者想给自定义函数加上 Pawno 的自动提示：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 声明一个插件提供的函数（例如 sscanf 插件）<br />
native sscanf(const str[], const format[], ...);<br />
// 利用 native 重命名内置函数（高级用法）<br />
native old_print = print;<br />
// 现在 print 不可用，改为用 old_print 调用</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">新手结论</span>：不需要手写 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">native</code>，知道它是「C/C++ 实现的函数」就够了。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">6. enum — 枚举</h3><br />
<br />
枚举是定义<span style="font-weight: bold;" class="mycode_b">一组有名字的整数常量</span>的方式，让代码更有可读性。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法：替代一组 #define</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 不用枚举的写法（容易混乱）<br />
#define CLASS_PEASANT  0<br />
#define CLASS_KNIGHT    1<br />
#define CLASS_MERCHANT  2<br />
#define CLASS_FISHER    3<br />
// 用枚举（更整洁）<br />
enum E_CLASS<br />
{<br />
    CLASS_PEASANT,    // 自动赋值 0<br />
    CLASS_KNIGHT,    // 自动赋值 1<br />
    CLASS_MERCHANT,  // 自动赋值 2<br />
    CLASS_FISHER      // 自动赋值 3<br />
}<br />
new g_PlayerClass[MAX_PLAYERS];<br />
public OnPlayerSpawn(playerid)<br />
{<br />
    g_PlayerClass[playerid] = CLASS_KNIGHT;<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">高级用法：用枚举定义结构化数组（最强用法）</h4><br />
<br />
这是 SA-MP/open.mp 脚本中最常见的枚举用途，可以把多种数据整合在一个二维数组里：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 定义玩家数据的"字段"<br />
enum E_PLAYER_DATA<br />
{<br />
    PLAYER_GOLD,        // 金币<br />
    PLAYER_LEVEL,      // 等级<br />
    PLAYER_SKIN,        // 皮肤 ID<br />
    PLAYER_KILLS,      // 击杀数<br />
    PLAYER_DEATHS      // 死亡数<br />
}<br />
// 声明二维数组，第二维用枚举大小<br />
new g_PlayerData[MAX_PLAYERS][E_PLAYER_DATA];<br />
// 使用：用字段名代替数字下标，可读性极强<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_PlayerData[playerid][PLAYER_GOLD]  = 50;<br />
    g_PlayerData[playerid][PLAYER_LEVEL]  = 1;<br />
    g_PlayerData[playerid][PLAYER_SKIN]  = 86;<br />
    g_PlayerData[playerid][PLAYER_KILLS]  = 0;<br />
    g_PlayerData[playerid][PLAYER_DEATHS] = 0;<br />
    return 1;<br />
}<br />
// 读取<br />
public OnPlayerDeath(playerid, killerid, reason)<br />
{<br />
    g_PlayerData[playerid][PLAYER_DEATHS]++;<br />
    if(killerid != INVALID_PLAYER_ID)<br />
    {<br />
        g_PlayerData[killerid][PLAYER_KILLS]++;<br />
        g_PlayerData[killerid][PLAYER_GOLD] += 10;  // 击杀奖励 10 金<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>这种写法比单独维护 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">g_Gold[]</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">g_Level[]</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">g_Skin[]</code> 多个数组更整洁，是进阶脚本的标准写法。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">7. Tag（标签）— 类型系统</h3><br />
<br />
Pawn 是「弱类型」语言，所有变量本质上都是 32 位整数。  <br />
<span style="font-weight: bold;" class="mycode_b">Tag（标签）</span> 是 Pawn 对类型的模拟，让编译器在你混用不同「类型」时发出警告。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常见的内置 Tag</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">Tag</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">（无 tag）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">普通整数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new iScore = 0;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new Float:fX = 0.0;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">bool:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">布尔值</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new bool:bAlive = true;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Text:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">TextDraw ID</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new Text:tdLogo;</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">PlayerText:</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">玩家 TextDraw</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new PlayerText:tdHUD;</code></td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Tag Mismatch 警告</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float:health;<br />
new score;<br />
score = health;  // 警告：tag mismatch！把 Float 赋给整数</code></div></div><br />
修复方法：用类型转换强制去除 tag：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>score = _:health;  // _: 去除 tag，变成普通整数再赋值（不推荐随意用）<br />
score = floatround(health);  // 正确做法：用转换函数</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">bool 类型</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new bool:g_IsAdmin[MAX_PLAYERS];<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_IsAdmin[playerid] = false;  // 用 true/false，不用 0/1<br />
    return 1;<br />
}<br />
// 判断<br />
if(g_IsAdmin[playerid])<br />
{<br />
    SendClientMessage(playerid, -1, "你是管理员！");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">8. 编译指令 #define</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 是<span style="font-weight: bold;" class="mycode_b">预处理指令</span>，在代码编译前进行纯文本替换。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法：定义常量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define MAX_GOLD    999<br />
#define SKIN_KNIGHT 287</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">带参数的宏（函数式宏）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 定义一个带参数的宏，%0 是第一个参数，%1 是第二个，以此类推<br />
#define IsValidPlayer(%0) ((%0) &gt;= 0 &amp;&amp; (%0) &lt; MAX_PLAYERS &amp;&amp; IsPlayerConnected(%0))<br />
// 使用：<br />
if(IsValidPlayer(playerid))<br />
{<br />
    SendClientMessage(playerid, -1, "有效的玩家");<br />
}<br />
// 实际展开为：<br />
// if(((playerid) &gt;= 0 &amp;&amp; (playerid) &lt; MAX_PLAYERS &amp;&amp; IsPlayerConnected(playerid)))</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">主教程用过的按键宏</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这两个就是带参数的宏<br />
#define PRESSED(%0)  (((newkeys) &amp; (%0)) &amp;&amp; !((oldkeys) &amp; (%0)))<br />
#define RELEASED(%0) (!((newkeys) &amp; (%0)) &amp;&amp; ((oldkeys) &amp; (%0)))</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">注意事项</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 宏是纯文本替换，不是函数，没有类型检查，要小心<br />
#define DOUBLE(%0)  %0 * 2<br />
new result = DOUBLE(3 + 4);<br />
// 展开为：3 + 4 * 2 = 11，不是 14！<br />
// 正确写法：<br />
#define DOUBLE(%0)  ((%0) * 2)  // 用括号包裹，避免运算符优先级问题</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">9. 编译指令 #include</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include</code> 把另一个文件的内容<span style="font-weight: bold;" class="mycode_b">插入到当前文件</span>，就像把那个文件的代码复制过来一样。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">两种写法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;      // 尖括号：在系统 include 目录（qawno/include/）查找<br />
#include "myfile"      // 引号：在当前目录查找</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常见的 include 文件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;      // open.mp 全量头文件（必须）<br />
// 常用插件头文件<br />
#include &lt;sscanf2&gt;      // 字符串解析（指令参数处理）<br />
#include &lt;Pawn.CMD&gt;      // 指令系统插件<br />
#include &lt;streamer&gt;      // 动态对象流送插件</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">自定义 .inc 文件</h4><br />
<br />
当脚本变大时，可以把部分代码拆分到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件里：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// shop.inc 文件里写商店相关的函数<br />
// 在主脚本里引入<br />
#include "shop"</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">注意事项</h4><br />
<br />
如果文件格式是<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code>可以直接写文件名，如果是其他格式比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.dat</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">txt</code> 则需要写文件格式<br />
<br />
比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include "myfile.pwn"</code><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">10. 编译指令 #if / #else / #endif</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 是<span style="font-weight: bold;" class="mycode_b">编译时的条件判断</span>，决定某段代码要不要被编译进去。  <br />
注意：这和运行时的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if</code> 不同，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#if</code> 在编译阶段就生效。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常见用法：区分 GameMode 和 FilterScript</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 根据是否定义了 FILTERSCRIPT，决定编译哪个初始化函数<br />
#if defined FILTERSCRIPT<br />
    public OnFilterScriptInit()<br />
    {<br />
        print("FilterScript 加载！");<br />
        return 1;<br />
    }<br />
#else<br />
    public OnGameModeInit()<br />
    {<br />
        print("GameMode 加载！");<br />
        return 1;<br />
    }<br />
#endif</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用 #if 开关调试模式</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 在脚本顶部定义，需要调试时就定义它，发布时删掉<br />
#define DEBUG_MODE<br />
// 在代码中用 #if 检查<br />
#if defined DEBUG_MODE<br />
    print("[DEBUG] 服务器已以调试模式启动");<br />
#endif<br />
// 也可以在函数里用（但 #if 在函数内部也是编译时判断）<br />
// 示例中如果没有定义 DEBUG_MODE，则 #if - #endif 内的代码等于不存在，不会有任何开销<br />
public OnPlayerConnect(playerid)<br />
{<br />
    #if defined DEBUG_MODE<br />
        new name[MAX_PLAYER_NAME];<br />
        GetPlayerName(playerid, name, sizeof(name));<br />
        printf("[DEBUG] 玩家连入: %s (ID: %d)", name, playerid);<br />
    #endif<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">defined 运算符</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// defined 检查某个符号是否被 #define 过<br />
#if defined MY_CONSTANT<br />
    // MY_CONSTANT 存在时编译这段<br />
#else<br />
    // 不存在时编译这段<br />
#endif</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">11. 编译指令 #pragma</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#pragma</code> 给编译器传递特殊指令，控制编译行为。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">最常用的几个</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 关闭 tab 缩进警告<br />
#pragma tabsize 0<br />
// 关闭某个编号的警告<br />
#pragma warning disable 200  // 关闭某个编号的警告<br />
// 标记某个变量为「可能不会被用到，不要报警告」<br />
new value;<br />
#pragma unused value</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">12. 运算符补充：sizeof</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sizeof</code> 返回数组的<span style="font-weight: bold;" class="mycode_b">元素数量</span>（不是字节数），是 Pawn 特有的运算符。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new arr[10];<br />
printf("%d", sizeof(arr));  // 输出 10<br />
new name[MAX_PLAYER_NAME];<br />
printf("%d", sizeof(name));  // 输出 MAX_PLAYER_NAME 的值（24）</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">为什么要用 sizeof？</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">避免硬编码数组大小</span>，让代码更安全：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new message[128];<br />
// 不好的写法：手动填 128，万一以后改了数组大小容易忘记改这里<br />
format(message, 128, "你好，%s", name);<br />
// 好的写法：用 sizeof 自动获取<br />
format(message, sizeof(message), "你好，%s", name);<br />
// 以后就算把 128 改成 256，这里也不需要动</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在函数参数里传 sizeof</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>GetPlayerName(playerid, name, sizeof(name));<br />
//                                ↑ 告诉函数数组有多大，防止越界</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">13. 运算符补充：三目运算符 ?:</h3><br />
<br />
三目运算符是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if/else</code> 的简写，适合简单的赋值判断：<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基本语法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 格式：条件 ? 成立时的值 : 不成立时的值<br />
new result = (mygold &gt; 100) ? 1 : 0;<br />
// 等同于：<br />
// if(mygold &gt; 100) result = 1;<br />
// else            result = 0;</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 根据玩家是否在线，获取名字<br />
new string[6];<br />
format(string, sizeof(string), "%s", IsPlayerConnected(targetid) ? "在线" : "离线");<br />
// 根据职业决定皮肤<br />
SetPlayerSkin(playerid, ((g_PlayerClass[playerid] == CLASS_KNIGHT) ? 287 : 86));<br />
// 嵌套三目<br />
new levelName[16];<br />
format(levelName, sizeof(levelName), "%s",<br />
    level &gt;= 10 ? "高级" :<br />
    level &gt;= 5  ? "中级" : "新手"<br />
);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">14. 运算符补充：位运算</h3><br />
<br />
位运算直接操作数字的二进制位，在 SA-MP/open.mp 中主要用于<span style="font-weight: bold;" class="mycode_b">按键检测</span>和<span style="font-weight: bold;" class="mycode_b">标志位</span>。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础位运算符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">名称</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">说明</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&amp;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位与</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">两位都是 1 才得 1</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\|</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位或</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">任意一位是 1 就得 1</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">^</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位异或</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">两位不同才得 1</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">~</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">按位非</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">取反</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;&lt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">左移</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">相当于乘以 2 的 n 次方</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&gt;&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">右移</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">相当于除以 2 的 n 次方</td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在按键检测中的应用</h4><br />
<br />
按键状态是一个整数，每一个「二进制位」代表一个按键是否被按下：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)<br />
{<br />
    // &amp; 运算：检查某个按键位是否为 1（按下状态）<br />
    if(newkeys &amp; KEY_YES)<br />
    {<br />
        // KEY_YES 位是 1，说明 Y 键被按着<br />
    }<br />
    // PRESSED 宏就是用位运算实现的：<br />
    // PRESSED(KEY_YES) 展开为：<br />
    // ((newkeys &amp; KEY_YES) &amp;&amp; !(oldkeys &amp; KEY_YES))<br />
    // 意思是：现在按着 AND 之前没按 = 刚刚按下<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">用位运算存储多个布尔标志</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 用一个整数存储多个开关状态（节省内存）<br />
#define FLAG_ADMIN    (1 &lt;&lt; 0)  // 二进制 0001<br />
#define FLAG_VIP      (1 &lt;&lt; 1)  // 二进制 0010<br />
#define FLAG_MUTED    (1 &lt;&lt; 2)  // 二进制 0100<br />
#define FLAG_JAILED  (1 &lt;&lt; 3)  // 二进制 1000<br />
new g_Flags[MAX_PLAYERS];<br />
// 设置标志（用 | 打开某位）<br />
g_Flags[playerid] |= FLAG_ADMIN;<br />
// 清除标志（用 &amp; 和 ~ 关闭某位）<br />
g_Flags[playerid] &amp;= ~FLAG_MUTED;<br />
// 检查标志（用 &amp; 检测某位）<br />
if(g_Flags[playerid] &amp; FLAG_ADMIN)<br />
{<br />
    SendClientMessage(playerid, -1, "你是管理员");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">15. 控制结构补充：do-while</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 的变体，区别是<span style="font-weight: bold;" class="mycode_b">先执行一次，再判断条件</span>。  <br />
即使条件一开始就是假的，循环体至少也会执行一次。<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// while：先判断，可能一次都不执行<br />
while(false)<br />
{<br />
    print("永远不会执行");<br />
}<br />
// do-while：先执行，再判断，至少执行一次<br />
do<br />
{<br />
    print("至少执行一次！");<br />
}<br />
while(false);  // 注意：while 后面要加分号</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 寻找一个空的数据槽位（至少要进去看一次）<br />
new slot = 0;<br />
do<br />
{<br />
    if(g_SlotFree[slot])<br />
    {<br />
        break;  // 找到了，跳出<br />
    }<br />
    slot++;<br />
}<br />
while(slot &lt; MAX_SLOTS);</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">新手提示</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">do-while</code> 在脚本里不太常用，了解即可。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">16. 控制结构补充：break 与 continue</h3><br />
<br />
这两个关键字用于控制循环的流程。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">break — 立即跳出循环</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 找到第一个死亡的玩家后停止循环<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
    if(!IsPlayerConnected(i)) continue;  // 跳过未连接的（见下）<br />
    new Float:health;<br />
    GetPlayerHealth(i, health);<br />
    if(health &lt;= 0.0)<br />
    {<br />
        printf("玩家 %d 已死亡", i);<br />
        break;  // 找到了就不用继续循环了<br />
    }<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">continue — 跳过本次，进入下一轮</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 给所有在线玩家发消息，跳过管理员<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
    if(!IsPlayerConnected(i)) continue;  // 没连接，跳过<br />
    if(g_Flags[i] &amp; FLAG_ADMIN) continue; // 是管理员，跳过<br />
    SendClientMessage(i, -1, "非管理员消息");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在 switch 中不需要 break</h4><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>Pawn 的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 是<span style="font-weight: bold;" class="mycode_b">独立的，不会穿透</span>到下一个 case，这与 C 语言不同，不需要写 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">break</code>。</blockquote>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn：不会穿透，不需要 break<br />
switch(value)<br />
{<br />
    case 1: print("value 是 1");  // 执行后直接跳出 switch<br />
    case 2: print("value 是 2");<br />
    case 3: print("value 是 3");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">17. switch 进阶：范围与列表匹配</h3><br />
<br />
Pawn 的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 比 C 语言更强大，支持<span style="font-weight: bold;" class="mycode_b">范围</span>和<span style="font-weight: bold;" class="mycode_b">列表</span>匹配。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">列表匹配（多个值合并成一个 case）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new level = 3;<br />
switch(level)<br />
{<br />
    case 1, 2, 3:      // 匹配 1 或 2 或 3<br />
    {<br />
        SendClientMessage(playerid, -1, "初级段位");<br />
    }<br />
    case 4, 5, 6:      // 匹配 4 或 5 或 6<br />
    {<br />
        SendClientMessage(playerid, -1, "中级段位");<br />
    }<br />
    case 7, 8, 9, 10:<br />
    {<br />
        SendClientMessage(playerid, -1, "高级段位");<br />
    }<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">范围匹配（连续区间）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>switch(level)<br />
{<br />
    case 1 .. 3:    // 匹配 1 到 3（含两端）<br />
    {<br />
        SendClientMessage(playerid, -1, "初级段位");<br />
    }<br />
    case 4 .. 6:    // 匹配 4 到 6<br />
    {<br />
        SendClientMessage(playerid, -1, "中级段位");<br />
    }<br />
    case 7 .. 10:<br />
    {<br />
        SendClientMessage(playerid, -1, "高级段位");<br />
    }<br />
    default:<br />
    {<br />
        SendClientMessage(playerid, -1, "段位超出范围");<br />
    }<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">18. 字符串函数</h3><br />
<br />
Pawn 内置了很多处理字符串的函数，这里列出脚本开发中最常用的几个。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strlen — 获取字符串长度</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new name[MAX_PLAYER_NAME];<br />
GetPlayerName(playerid, name, sizeof(name));<br />
new len = strlen(name);<br />
printf("名字长度：%d", len);<br />
// 常用：检查输入是否为空<br />
if(strlen(inputtext) == 0)<br />
{<br />
    SendClientMessage(playerid, -1, "输入不能为空！");<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strcmp — 比较两个字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// strcmp(str1, str2, ignorecase, length)<br />
// 返回 0 = 相同，非 0 = 不同<br />
new input[32] = "hello";<br />
if(strcmp(input, "hello", true) == 0)  // true = 忽略大小写<br />
{<br />
    print("字符串匹配！");<br />
}<br />
// 常用简写（检查是否不同）<br />
if(strcmp(input, "admin"))<br />
{<br />
    // 不相同时执行（非 0 = true）<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strcat — 拼接字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new result[24] = "Hello, ";<br />
strcat(result, "World!");<br />
// result 现在是 "Hello, World!"</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">strfind — 查找子字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[] = "Welcome to the server!";<br />
new pos = strfind(string, "server", true);  // 返回位置下标，找不到返回 -1<br />
if(pos != -1)<br />
{<br />
    printf("找到了 server，位置：%d", pos);  // 输出 15<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">字符串与数字互转</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 字符串 → 整数<br />
new string[] = "123";<br />
new number = strval(string);  // number = 123<br />
// 整数 → 字符串（用 format）<br />
new output[16];<br />
format(output, sizeof(output), "%d", number);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">19. 玩家指令（Commands）</h3><br />
<br />
玩家在聊天框输入 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/指令名</code> 时触发 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerCommandText</code> 回调。  <br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">方法一：直接用 strcmp（基础做法）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Gold[MAX_PLAYERS] = {100, ...};<br />
public OnPlayerCommandText(playerid, cmdtext[])<br />
{<br />
    // cmdtext 是玩家输入的完整内容，例如 "/heal"<br />
    if(strcmp(cmdtext, "/heal", true) == 0)<br />
    {<br />
        SetPlayerHealth(playerid, 100.0);<br />
        SendClientMessage(playerid, -1, "血量已恢复！");<br />
        return 1;  // ← 一定要 return 1，表示指令已处理<br />
    }<br />
    if(strcmp(cmdtext, "/gold", true) == 0)<br />
    {<br />
        SendClientMessage(playerid, -1, "你现在有 %d 枚金币。", g_Gold[playerid]);<br />
        return 1;<br />
    }<br />
    // 没有匹配的指令：return 0 让服务器显示"未知指令"提示<br />
    return 0;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">方法二：用 Pawn.CMD 插件（推荐做法）</h4><br />
<br />
Pawn.CMD 是一个流行的指令处理插件，语法更简洁，性能更好：<br />
<br />
自行下载安装: <a href="https://github.com/katursis/Pawn.CMD" target="_blank" rel="noopener" class="mycode_url">https://github.com/katursis/Pawn.CMD</a><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;Pawn.CMD&gt;  // 需要安装 Pawn.CMD 插件<br />
// Pawn.CMD 的写法：CMD:指令名(playerid, params[])<br />
CMD:heal(playerid, params[])<br />
{<br />
    SetPlayerHealth(playerid, 100.0);<br />
    SendClientMessage(playerid, -1, "血量已恢复！");<br />
    return 1;<br />
}<br />
CMD:gold(playerid, params[])<br />
{<br />
    SendClientMessage(playerid, -1, "你现在有 %d 枚金币。", g_Gold[playerid]);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">指令权限检查</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>CMD:kick(playerid, params[])<br />
{<br />
    // 只有管理员才能用<br />
    if(!(g_Flags[playerid] &amp; FLAG_ADMIN))<br />
    {<br />
        SendClientMessage(playerid, -1, "你没有权限使用此指令！");<br />
        return 1;<br />
    }<br />
    // ... 踢人逻辑 ...<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">20. sscanf — 解析指令参数</h3><br />
<br />
当指令带参数时（例如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/kick 5</code> 或 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/give 3 100</code>），需要从字符串里把参数提取出来。  <br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">sscanf</code> 插件是处理这类问题的标准工具。<br />
<br />
自行下载安装: <a href="https://github.com/Y-Less/sscanf" target="_blank" rel="noopener" class="mycode_url">https://github.com/Y-Less/sscanf</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// sscanf(输入字符串, 格式, 变量1, 变量2, ...)<br />
// 返回 0 = 解析成功，非 0 = 解析失败（参数不够或格式不对）<br />
CMD:give(playerid, params[])<br />
{<br />
    new targetID, amount;<br />
    // 格式 "ii" = 两个整数<br />
    if(sscanf(params, "ii", targetID, amount))<br />
    {<br />
        SendClientMessage(playerid, -1, "用法：/give [玩家ID] [金币数]");<br />
        return 1;<br />
    }<br />
    if(!IsPlayerConnected(targetID))<br />
    {<br />
        SendClientMessage(playerid, -1, "该玩家不在线！");<br />
        return 1;<br />
    }<br />
    g_Gold[targetID] += amount;<br />
    SendClientMessage(playerid, -1, "向玩家 %d 赠送了 %d 枚金币。", targetID, amount);<br />
    SendClientMessage(targetID, -1, "管理员赠送了 %d 枚金币给你。", amount);<br />
    return 1;<br />
}<br />
CMD:skin(playerid, params[])<br />
{<br />
    new skinID;<br />
    if(sscanf(params, "i", skinID))<br />
    {<br />
        SendClientMessage(playerid, -1, "用法：/skin [皮肤ID]");<br />
        return 1;<br />
    }<br />
    SetPlayerSkin(playerid, skinID);<br />
    g_Skin[playerid] = skinID;<br />
    SendClientMessage(playerid, -1, "皮肤已更换为 %d。", skinID);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">sscanf 格式说明符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">格式符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">f</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">s</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串（到空格结束）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">s[32]</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">最大 32 字符的字符串</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">u</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">玩家名字或 ID（自动解析）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">p&lt;分隔符&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置分隔符，如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">p,</code> 用逗号分隔</td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">sscanf 相关文档说明</h4><br />
<br />
如何使用: <a href="https://github.com/Y-Less/sscanf?tab=readme-ov-file#use" target="_blank" rel="noopener" class="mycode_url">https://github.com/Y-Less/sscanf?tab=readme-ov-file#use</a><br />
格式说明符: <a href="https://github.com/Y-Less/sscanf?tab=readme-ov-file#specifiers" target="_blank" rel="noopener" class="mycode_url">https://github.com/Y-Less/sscanf?tab=rea...specifiers</a><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">21. printf 与 print — 控制台输出</h3><br />
<br />
这两个函数把内容输出到<span style="font-weight: bold;" class="mycode_b">服务器控制台窗口</span>，玩家看不到，只能在服务器后台终端看到。  <br />
常用于调试和记录日志。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">print — 输出纯文字</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>print("服务器启动了！");<br />
print("[DEBUG] 这是一条调试信息");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">printf — 带格式化输出</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new playerCounts = 0;<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
    if(IsPlayerConnected(i)) playerCounts++;<br />
printf("[服务器] 当前在线玩家：%d", playerCounts);<br />
printf("[DEBUG] 玩家 %d 的金币：%d", playerid, g_Gold[playerid]);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">格式符与 format 相同</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>printf("整数：%d，浮点：%.2f，字符串：%s", 42, 3.14, "hello");<br />
// 输出：整数：42，浮点：3.14，字符串：hello</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">22. 代码组织：#include 拆分文件</h3><br />
<br />
当你的脚本越来越大，所有代码都写在一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.pwn</code> 文件里会很难维护。 <br />
<br />
按<span style="font-weight: bold;" class="mycode_b">功能模块</span>拆分成多个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件，再在主文件里引入。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">比如</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>gamemodes/<br />
├── main.pwn            ← 主文件（只负责引入和框架）<br />
└── include/<br />
    ├── shop.inc        ← 商店系统<br />
    ├── npc.inc        ← NPC 系统<br />
    ├── vehicle.inc    ← 载具系统<br />
    └── commands.inc    ← 所有指令</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">主文件写法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// mian.pwn<br />
#include &lt;open.mp&gt;<br />
// 引入各功能模块<br />
#include "include/shop.inc"<br />
#include "include/npc.inc"<br />
#include "include/vehicle.inc"<br />
#include "include/commands.inc"<br />
// 主文件只写框架回调<br />
public OnGameModeInit()<br />
{<br />
    InitShop();      // 调用 shop.inc 里的初始化函数<br />
    InitNPCs();      // 调用 npc.inc 里的初始化函数<br />
    InitVehicles();  // 调用 vehicle.inc 里的初始化函数<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">shop.inc 示例</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 注意：这里不需要再 #include &lt;open.mp&gt;，主文件已经引入了<br />
// 商店相关的变量、函数、指令都写在这里<br />
InitShop()<br />
{<br />
    // 创建商店相关的 Pickup 等<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">进阶：ALS Hook 系统（让 .inc 自己挂载回调）</h4><br />
<br />
Pawn 不允许同一个回调定义两次，也就是说<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerDeath</code> 等等这些回调只能有一个<br />
<br />
当模块越来越多，每次写新模块都要回去主文件里的各个回调中加入新模块的功能，容易忘记、切不容易维护管理。<br />
<br />
让每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件自己管理自己需要使用的回调，执行完自己的逻辑后再把控制权传给下一个模块，形成一条链。<br />
<br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">原理</h5><br />
<br />
<ol type="1" class="mycode_list"><li>我先把 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> <span style="font-weight: bold;" class="mycode_b">重命名</span>成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">shop_OnGameModeInit</code>（用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define</code> 宏替换）<br />
</li>
<li>然后我自己写一个新的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code>，在里面先执行我的逻辑，再调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">shop_OnGameModeInit</code><br />
</li>
<li>下一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code>（比如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">npc.inc</code>）接着同样操作，把我写的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> 再重命名为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">npc_OnGameModeInit</code>，再写新的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code>...<br />
</li>
<li>最终形成一条调用链：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnGameModeInit</code> → <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">npc_OnGameModeInit</code> → <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">shop_OnGameModeInit</code> → 主文件的 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1</code><br />
</li>
</ol>
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// shop.inc 文件内部<br />
new g_ShopPickup;<br />
InitShop()<br />
{<br />
    g_ShopPickup = CreatePickup(1242, 2, 100.0, 200.0, 10.0, -1);<br />
    return 1;<br />
}<br />
public OnGameModeInit()<br />
{<br />
    InitShop();<br />
    #if defined shop_OnGameModeInit<br />
        return shop_OnGameModeInit();<br />
    #else<br />
        return 1;<br />
    #endif<br />
}<br />
#if defined _ALS_OnGameModeInit<br />
    #undef OnGameModeInit<br />
#else<br />
    #define _ALS_OnGameModeInit<br />
#endif<br />
#define OnGameModeInit shop_OnGameModeInit<br />
#if defined shop_OnGameModeInit<br />
    forward shop_OnGameModeInit();<br />
#endif</code></div></div><br />
<h5 style="font-size:1.05em;font-weight:bold;margin:10px 0 4px;color:#444;">有了 ALS 之后，主文件什么都不用写</h5><br />
<br />
只需要#include进去，干净利落<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
#include "include/shop.inc"    <br />
#include "include/npc.inc"    <br />
#include "include/vehicle.inc" <br />
public OnGameModeInit()<br />
{<br />
    return 1;<br />
}</code></div></div><hr class="mycode_hr" />]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[零基础开发openmp/SAMP服务器基础教程 - 第二章]]></title>
			<link>https://open-mp.cn/showthread.php?tid=14</link>
			<pubDate>Fri, 20 Mar 2026 13:22:57 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=14</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">零基础开发openmp/SAMP服务器基础教程 - 第二章</h2><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>本教程面向完全零基础的新手，每一节只讲一个知识点，循序渐进。</blockquote>
<blockquote class="mycode_quote"><cite>引用:</cite>本章节先以快速了解 Pawn 语言和 openmp 游戏实际应用为开端，让新手更快通过实际游戏表现获得反馈，以避免一开始就接触过多语法，建议阅读完本章节再开始第三章巩固进阶编程语言细节</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">#</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">章节</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#1-openmp-是什么" target="_blank" rel="noopener" class="mycode_url">open.mp 是什么</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#2-开启服务器" target="_blank" rel="noopener" class="mycode_url">开启服务器</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">3</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#3-第一个脚本" target="_blank" rel="noopener" class="mycode_url">第一个脚本</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#4-注释" target="_blank" rel="noopener" class="mycode_url">注释</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">5</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#5-变量" target="_blank" rel="noopener" class="mycode_url">变量</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">6</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#6-define" target="_blank" rel="noopener" class="mycode_url">define</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">7</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#7-字符串与-format" target="_blank" rel="noopener" class="mycode_url">字符串与 format</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">8</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#8-运算符" target="_blank" rel="noopener" class="mycode_url">运算符</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">9</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#9-if--else-判断" target="_blank" rel="noopener" class="mycode_url">if / else 判断</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">10</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#10-switch-多分支" target="_blank" rel="noopener" class="mycode_url">switch 多分支</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">11</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#11-for-循环" target="_blank" rel="noopener" class="mycode_url">for 循环</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">12</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#12-while-循环" target="_blank" rel="noopener" class="mycode_url">while 循环</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">13</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#13-函数" target="_blank" rel="noopener" class="mycode_url">函数</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#14-数组" target="_blank" rel="noopener" class="mycode_url">数组</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">15</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#15-回调函数callback" target="_blank" rel="noopener" class="mycode_url">回调函数（Callback）</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">16</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#16-sendclientmessage--发消息" target="_blank" rel="noopener" class="mycode_url">SendClientMessage — 发消息</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">17</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#17-gametext--屏幕大字" target="_blank" rel="noopener" class="mycode_url">GameText — 屏幕大字</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">18</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#18-textdraw--屏幕-ui" target="_blank" rel="noopener" class="mycode_url">TextDraw — 屏幕 UI</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">19</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#19-dialog--对话框" target="_blank" rel="noopener" class="mycode_url">Dialog — 对话框</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">20</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#20-pickup--拾取物" target="_blank" rel="noopener" class="mycode_url">Pickup — 拾取物</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">21</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#21-checkpoint--检查点" target="_blank" rel="noopener" class="mycode_url">Checkpoint — 检查点</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">22</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#22-vehicle--载具" target="_blank" rel="noopener" class="mycode_url">Vehicle — 载具</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">23</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#23-actor--npc" target="_blank" rel="noopener" class="mycode_url">Actor — NPC</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">24</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#24-timer--计时器" target="_blank" rel="noopener" class="mycode_url">Timer — 计时器</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">25</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#25-keys--按键检测" target="_blank" rel="noopener" class="mycode_url">Keys — 按键检测</a></td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">1. open.mp 是什么</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">open.mp</span>（open multiplayer）是一个全新的 侠盗猎车手：圣安地列斯 的多人游戏服务端，完全向下兼容 <span style="font-weight: bold;" class="mycode_b">SA-MP</span> 。<br />
<br />
你可以用 <span style="font-weight: bold;" class="mycode_b">Pawn 脚本语言</span> 来编写游戏服务器的逻辑，比如：<br />
<ul class="mycode_list"><li>玩家加入时显示欢迎消息<br />
</li>
<li>在地图上放置 NPC、载具、拾取物<br />
</li>
<li>制作商店、任务、角色扮演系统<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Pawn</span> 是一门类似 C 语言的脚本语言，语法简单，非常适合入门。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">open.mp vs SA-MP</span>：两者语法完全一样。open.mp 是活跃维护的现代版本。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">2. 开启服务器</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第一步：下载 open.mp 服务端</h4><br />
<br />
前往官网 <a href="https://www.open.mp" target="_blank" rel="noopener" class="mycode_url">https://www.open.mp</a> 下载最新版本，解压到任意文件夹。<br />
<br />
解压后你会看到这样的目录结构：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>components: open.mp 核心组件<br />
filterscripts: 服务器脚本文件（辅助脚本）<br />
gamemodes: 服务器游戏模式文件（主图）<br />
models: 服务器自定义模型（纹理 .txd .dff）<br />
plugins: 服务器插件文件（传统插件）<br />
qawno: Pawn 编辑器程序及包含文件<br />
scriptfiles: INI 配置文件及其他资源<br />
bans.json: 封禁列表文件<br />
config.json: 服务器配置文件<br />
omp-server.exe: open.mp 服务器主程序</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第二步：配置 config.json</h4><br />
<br />
打开 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">config.json</code>，找到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main_scripts</code> 这一行，改成你的主图名称 mygamemode<br />
<br />
根据需求设置端口 服务器名称 需要添加的插件 辅助脚本 修改高强度的rcon密码<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>{<br />
    "name": "我的服务器",<br />
    "network": {<br />
        "port": 7777<br />
    },<br />
    "max_bots": 0,<br />
    "max_players": 100,<br />
    "pawn": {<br />
        "main_scripts": [<br />
            "mygamemode 1"<br />
        ]<br />
    },<br />
    "rcon": {<br />
        "password": "changeme1"<br />
    },<br />
}</code></div></div><br />
关于config.json更多详情可查阅 <a href="https://open.mp/docs/server/config.json" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/server/config.json</a> 但几乎大部分设置保持默认即可<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第三步：打开 qawno 编辑器</h4><br />
<br />
双击 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/qawno.exe</code>，这就是你写代码和编译脚本的地方。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">提示</span>：推荐使用 VSCode，代码补全更强大。入门阶段用 qawno 就够了。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">3. 第一个脚本</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建脚本文件</h4><br />
<br />
在 qawno 中，点击菜单 <span style="font-weight: bold;" class="mycode_b">File → New Blank</span>，然后输入以下代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main(){}<br />
<br />
public OnGameModeInit()<br />
{<br />
    SetGameModeText("我的第一个open.mp服务器");<br />
    AddPlayerClass(1, 2495.3547, -1688.2319, 13.6774, 351.1646, WEAPON_M4, 500, WEAPON_KNIFE, 1, WEAPON_COLORT45, 100);<br />
&nbsp;&nbsp;&nbsp;&nbsp;AddStaticVehicle(522, 2493.7583, -1683.6482, 12.9099, 270.8069, -1, -1);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">保存并编译</h4><br />
<br />
点击 <span style="font-weight: bold;" class="mycode_b">File → Save</span>，保存为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">mygamemode.pwn</code>，保存到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gamemodes/</code> 目录下。<br />
<br />
然后按 <span style="font-weight: bold;" class="mycode_b">F5</span> 编译。<br />
<br />
编译成功后，在同目录会生成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">mygamemode.amx</code> 文件。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">启动服务器</h4><br />
<br />
双击 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">omp-server.exe</code>，就成功启动服务器了。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">代码解释</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">代码</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include &lt;open.mp&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">引入 open.mp 的所有函数，必须写在第一行</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public OnGameModeInit()</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务器启动时自动执行的函数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SetGameModeText("...")</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置服务器模式名称（显示在服务器列表）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AddPlayerClass(...)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在职业选择中添加一个职业 用于让玩家可以以自己选择的皮肤出生</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AddStaticVehicle(...)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在游戏模式中添加静态车辆（模型会预加载给玩家）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数结束，返回 1 表示成功</td>
  </tr>
</table>
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">规则</span>：每条语句末尾必须有 <span style="font-weight: bold;" class="mycode_b">分号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">;</code></span>，花括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code> 表示代码块的开始和结束。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">4. 注释</h3><br />
<br />
注释是写给人看的说明文字，<span style="font-weight: bold;" class="mycode_b">编译器会完全忽略它</span>，不影响程序运行。<br />
<br />
写注释的好处是以后回看代码时会轻松很多。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">单行注释</h4><br />
<br />
用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">//</code> 开头，从这里到行尾都是注释：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这是一行注释，不会被执行<br />
SetGameModeText("我的第一个open.mp服务器");  // 也可以写在代码后面</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">多行注释</h4><br />
<br />
用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/* ... */</code> 包裹，可以跨越多行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/*<br />
    这里是多行注释。<br />
    可以写很多行。<br />
    常用于说明。<br />
*/<br />
public OnGameModeInit()<br />
{<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">建议</span>：新手可以给每个函数写一行注释说明它的用途，给复杂逻辑写注释说明思路。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">5. 变量</h3><br />
<br />
变量是用来<span style="font-weight: bold;" class="mycode_b">存储数据</span>的容器，就像一个贴了标签的盒子。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明变量</h4><br />
<br />
用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 关键字声明变量：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myScore;       &nbsp;&nbsp;// 声明一个整数变量，初始值默认是 0<br />
new myScore = 10;    // 声明并赋初始值</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变量类型</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">整数（默认类型）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myAge = 25;<br />
new myGold = 100;<br />
new myScore = 0;</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">浮点数（小数）</span><br />
<br />
浮点数需要在变量名前加 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float:</code> 标签：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float:myHealth = 100.0;<br />
new Float:mySpeed  = 3.14;<br />
new Float:myX      = 1234.5; &nbsp;&nbsp;// 坐标通常是浮点数</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变量命名规范</h4><br />
<br />
变量名只能包含字母、数字、下划线，且不能以数字开头，推荐：g_ 前缀表示全局变量<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Score = 0;<br />
new g_Speed = 0.0;<br />
new g_Name[32];</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>这种前缀命名法不是强制要求，但能让代码更易读，虽然不是主流实践，但比较适用于pawn开发。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">全局变量 vs 局部变量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 全局变量：写在所有函数外面，整个脚本都能访问，g_ 前缀表示全局（global）<br />
new g_PlayerScore[MAX_PLAYERS];<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
    // 局部变量：写在函数内部，只在这个函数里有效，驼峰命名法‌（camelCase）：首词小写，后续大写<br />
    new defaultScore = 50;<br />
    g_PlayerScore[playerid] = defaultScore;<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">6. define</h3><br />
<br />
它本质上是一个文本替换符号，而不是一个真正的变量或常量，从使用效果看，它表现得像一个常量（运行过程中不能改变其数值），在编译时直接替换，不占用内存<br />
<br />
常量常用于替代魔法数字，使代码更具可读性和可维护性，在这篇教程中我们暂时称它为常量。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">定义常量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define SERVER_NAME   &nbsp;&nbsp;"我的第一个open.mp服务器"<br />
#define MAX_GOLD        999<br />
#define START_GOLD      50<br />
#define PI              3.14159</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">如何使用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()<br />
{<br />
    SetGameModeText(SERVER_NAME); &nbsp;&nbsp;// 等同于 SetGameModeText("我的第一个open.mp服务器");<br />
    return 1;<br />
}<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_Gold[playerid] = START_GOLD;  // 等同于 g_Gold[playerid] = 50;<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">规范</span>：全部大写，单词间用下划线分隔，例如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SKIN_NORMAL</code>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">7. 字符串与 format</h3><br />
<br />
字符串就是一段文字。在 Pawn 中，字符串用<span style="font-weight: bold;" class="mycode_b">字符数组</span>存储。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Name[32];               &nbsp;&nbsp;// 最多存 31 个字符（留一位给结束符）<br />
new g_Msg[128];               &nbsp;&nbsp;// 消息通常用 128 或 256<br />
new g_Name[MAX_PLAYER_NAME]; &nbsp;&nbsp;// 用内置常量，等同于 g_Name[24]</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">获取玩家名字</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Name[MAX_PLAYER_NAME];<br />
GetPlayerName(playerid, g_Name, sizeof(g_Name)); // sizeof(g_Name) 自动计算数组大小，不需要手动填数字</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">format — 格式化字符串</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code> 可以把变量的值拼进字符串里，类似其他语言的字符串模板：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[128];<br />
new name[MAX_PLAYER_NAME];<br />
new gold = 100;<br />
<br />
GetPlayerName(playerid, name, sizeof(name));<br />
<br />
format(string, sizeof(string), "你好，%s！你有 %d 枚金币。", name, gold);<br />
// 结果："你好，CJ！你有 100 枚金币。"</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">格式占位符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">占位符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%s</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"Hello, %s"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%d</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"金币：%d"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%f</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"血量：%.1f"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%i</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数（同 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%d</code>）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"等级：%i"</code></td>
  </tr>
</table>
<blockquote class="mycode_quote"><cite>引用:</cite><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%.1f</code> 表示保留 1 位小数，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%.2f</code> 保留 2 位，以此类推。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">8. 运算符</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">算术运算符</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a = 10;<br />
new b = 3;<br />
<br />
new add  = a + b; &nbsp;&nbsp;// 13  加<br />
new sub  = a - b; &nbsp;&nbsp;// 7 &nbsp;&nbsp;减<br />
new mul  = a * b; &nbsp;&nbsp;// 30  乘<br />
new div  = a / b; &nbsp;&nbsp;// 3 &nbsp;&nbsp;除（整数除法，舍去小数）<br />
new mod  = a % b; &nbsp;&nbsp;// 1 &nbsp;&nbsp;取余（10 除以 3 余 1）</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">快捷赋值</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 100;<br />
gold += 50; &nbsp;&nbsp;// 等同于 gold = 100 + 50  →  150<br />
gold -= 20; &nbsp;&nbsp;// 等同于 gold = 100 - 20  →  80<br />
gold *= 2;    // 等同于 gold = 100 * 2 &nbsp;&nbsp;→  200<br />
gold /= 4;    // 等同于 gold = 100 / 4 &nbsp;&nbsp;→  25</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">自增 / 自减</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new i = 0;<br />
i++;    // i 变成 1，等同于 i = i + 1<br />
i--;    // i 变成 0，等同于 i = i - 1</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">比较运算符（返回真/假）</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">==</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">等于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!=</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不等于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">大于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">小于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&gt;=</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">大于等于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;=</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">小于等于</td>
  </tr>
</table>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 100;<br />
<br />
if(gold == 100)  { /* 如果gold等于100 则成立 */ }<br />
if(gold &gt; 50)    { /* 如果gold大于50 则成立 */ }<br />
if(gold != 0)    { /* 如果gold不等于0 则成立 */ }</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">常见错误</span>：判断用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">==</code>（两个等号），赋值用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">=</code>（一个等号）。写成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if(gold = 100)</code> 是赋值，不是判断！</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">逻辑运算符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&amp;&amp;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">且（两个都成立）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gold &gt; 0 &amp;&amp; isAlive</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\|\|</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">或（任意一个成立）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">isAdmin \|\| isVIP</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">非（取反）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!IsPlayerConnected(i)</code></td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">9. if / else 判断</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if / else</code> 根据条件决定执行哪段代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 80;<br />
<br />
// 如果金币大于100<br />
if(gold &gt;= 100)<br />
{<br />
    SendClientMessage(playerid, 0xFFFF00FF, "金币充足，可以购买！");<br />
}<br />
// 否则<br />
else<br />
{<br />
    SendClientMessage(playerid, 0xFF4444FF, "金币不足！");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">if / else if / else</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myLevel = 5;<br />
<br />
if(myLevel &gt;= 10)<br />
{<br />
    SendClientMessage(playerid, -1, "你是高级玩家！");<br />
}<br />
else if(myLevel &gt;= 5)<br />
{<br />
    SendClientMessage(playerid, -1, "你是中级玩家。");<br />
}<br />
else<br />
{<br />
    SendClientMessage(playerid, -1, "你是新手。");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">10. switch 多分支</h3><br />
<br />
当你需要根据一个变量的<span style="font-weight: bold;" class="mycode_b">多个具体值</span>做不同处理时，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 比一堆 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 更清晰。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Class = 2;<br />
<br />
switch(g_Class)<br />
{<br />
    case 0:<br />
    {<br />
        SendClientMessage(playerid, -1, "你选择了：农民");<br />
        SetPlayerSkin(playerid, 86);<br />
    }<br />
    case 1:<br />
    {<br />
        SendClientMessage(playerid, -1, "你选择了：骑士");<br />
        SetPlayerSkin(playerid, 287);<br />
    }<br />
    case 2:<br />
    {<br />
        SendClientMessage(playerid, -1, "你选择了：商人");<br />
        SetPlayerSkin(playerid, 19);<br />
    }<br />
    default:<br />
    {<br />
        // 以上都不匹配时<br />
        SendClientMessage(playerid, -1, "未知职业");<br />
    }<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用：处理对话框响应</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])<br />
{<br />
    if(dialogid == DIALOG_SHOP)<br />
    {<br />
        if(!response) return 1; &nbsp;&nbsp;// 点了取消，不处理，等同于if(response == false)<br />
<br />
        switch(listitem)<br />
        {<br />
            case 0: SetPlayerSkin(playerid, 86); &nbsp;&nbsp;// 选择了对话框的第一个选项<br />
            case 1: SetPlayerSkin(playerid, 287);  // 选择了对话框的第二个选项<br />
            case 2: SetPlayerSkin(playerid, 19); &nbsp;&nbsp;// 选择了对话框的第三个选项<br />
        }<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 中每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 后面的值必须是<span style="font-weight: bold;" class="mycode_b">整数或常量</span>，不能是字符串或浮点数。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">11. for 循环</h3><br />
<br />
当你需要<span style="font-weight: bold;" class="mycode_b">重复执行</span>某段代码时，用循环。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code> 循环适合已知重复次数的场景。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础结构</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// &nbsp;&nbsp;初始值; 条件; 每次循环后执行<br />
for(new i = 0; i &lt; 5; i++)<br />
{<br />
    // 这里的代码会执行 5 次（i = 0, 1, 2, 3, 4）<br />
    print("循环中...(已循环%d次)", i + 1);<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">遍历所有在线玩家</h4><br />
<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 给所有在线玩家发送消息<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
    if(IsPlayerNPC(i) == false &amp;&amp; inGame[i] == true)<br />
    {<br />
        SendClientMessage(i, 0xFFFF00FF, "[公告] 比赛开始！");<br />
        GivePlayerWeapon(i, WEAPON_AK47, 1500);<br />
        SetPlayerPos(i, 0.0, 0.0, 2.5);<br />
        // 给所有玩家加金币<br />
        g_Gold[i] += 10;<br />
    }<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>但通常历遍玩家我们会选择foreach库，更高效。  <br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i &lt; MAX_PLAYERS</code> 不能写成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i &lt;= MAX_PLAYERS</code>，否则会越界。  <br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 是最大玩家数，有效的 playerid 是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0</code> 到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS - 1</code>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">12. while 循环</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 循环适合<span style="font-weight: bold;" class="mycode_b">不知道要循环多少次、只知道循环条件</span>的场景。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础结构</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new i = 0;<br />
while(i &lt; 5)<br />
{<br />
    print("执行中...");<br />
    i++;   &nbsp;&nbsp;// 一定要记得让条件向终止靠近，否则会导致无限死循环！<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">while vs for</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">场景</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">推荐</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">固定次数的重复（如遍历所有玩家）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">条件不满足就一直循环（如等待某个状态）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code></td>
  </tr>
</table>
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">警告</span>：循环体内一定要有让条件变化的语句，否则会进入<span style="font-weight: bold;" class="mycode_b">死循环</span>，导致服务器卡死。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">13. 函数</h3><br />
<br />
函数是把一段代码<span style="font-weight: bold;" class="mycode_b">打包起来命名</span>，方便重复调用，避免重复写同样的代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">定义函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数名(参数列表)<br />
// {<br />
//   &nbsp;&nbsp;代码内容<br />
//   &nbsp;&nbsp;return 返回值;<br />
// }<br />
<br />
GiveGold(playerid, amount)<br />
{<br />
    g_Gold[playerid] += amount;<br />
    SendClientMessage(playerid, 0xFFDD44FF, "你获得了金币！");<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">调用函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{<br />
    GiveGold(playerid, 50);    // 玩家连入时给 50 金币<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">带特定返回值的函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 检查玩家金币是否足够，返回 true（足够）或 false（不足）<br />
bool:HasEnoughGold(playerid, cost)<br />
{<br />
    if(g_Gold[playerid] &gt;= cost)<br />
    {<br />
        return true; &nbsp;&nbsp;// 足够<br />
    }<br />
    return false;     &nbsp;&nbsp;// 不足<br />
}<br />
<br />
// 使用：<br />
if(HasEnoughGold(playerid, 100) == true)<br />
{<br />
    SendClientMessage(playerid, -1, "可以购买！");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">不需要带任何返回值的函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>void:ResetGold(playerid)<br />
{<br />
    g_Gold[playerid] = 0;<br />
    SendClientMessage(playerid, 0xFFDD44FF, "你的金币被清空了");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">stock 函数</h4><br />
<br />
在 Pawn 中，如果你定义了函数但某些情况下没用到，编译器会发出警告。  <br />
加上 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 关键字可以消除这个警告：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock GetPlayerGold(playerid)<br />
{<br />
    return g_Gold[playerid];<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">原则</span>：把重复用到 3 次以上的代码封装成函数。函数名需要清晰描述它做什么，例如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GiveGold</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ShowShop</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">KickPlayer</code>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">14. 数组</h3><br />
<br />
数组是<span style="font-weight: bold;" class="mycode_b">一组同类型数据的集合</span>，用一个名字访问多个值。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明数组</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Scores[10];         &nbsp;&nbsp;// 存 10 个整数<br />
new Float:g_Positions[3]; &nbsp;&nbsp;// 存 3 个浮点数（X, Y, Z）<br />
new g_Name[MAX_PLAYER_NAME]; // 字符串本质也是字符数组</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">访问数组元素</h4><br />
<br />
数组下标从 <span style="font-weight: bold;" class="mycode_b">0</span> 开始：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Scores[5];<br />
<br />
g_Scores[0] = 100; &nbsp;&nbsp;// 第 1 个元素<br />
g_Scores[1] = 85;    // 第 2 个元素<br />
g_Scores[4] = 60;    // 第 5 个（最后一个）<br />
// g_Scores[5]  ← 越界！不能访问，会报错</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">最常见：每个玩家存一份数据</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 全局声明：每个玩家 ID 对应一个值<br />
new g_Gold[MAX_PLAYERS];<br />
new g_Level[MAX_PLAYERS];<br />
new g_Skin[MAX_PLAYERS];<br />
<br />
// 使用 playerid 作为下标访问对应玩家的数据<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_Gold[playerid]  = 50;<br />
    g_Level[playerid] = 1;<br />
    g_Skin[playerid]  = 86;<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">二维数组</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 存 5 个检查点的坐标（每个坐标有 X、Y、Z 三个值）<br />
new Float:g_CpPos[5][3] = {<br />
    {100.0, 200.0, 10.0}, &nbsp;&nbsp;// 检查点 0<br />
    {150.0, 220.0, 10.0}, &nbsp;&nbsp;// 检查点 1<br />
    {200.0, 240.0, 10.0}, &nbsp;&nbsp;// 检查点 2<br />
    {250.0, 260.0, 10.0}, &nbsp;&nbsp;// 检查点 3<br />
    {300.0, 280.0, 10.0}    // 检查点 4<br />
};<br />
<br />
// 访问检查点 2 的 Y 坐标：<br />
new Float:y = g_CpPos[2][1]; &nbsp;&nbsp;// 240.0</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">15. 回调函数（Callback）</h3><br />
<br />
回调函数是 open.mp <span style="font-weight: bold;" class="mycode_b">服务端自动调用</span>的特殊函数。<br />
<br />
你不需要手动调用它们，只需要在脚本里<span style="font-weight: bold;" class="mycode_b">定义</span>它们，当对应事件发生时，服务端会自动执行。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">规律</h4><br />
<br />
所有回调函数都以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public On</code> 开头：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()      // 服务器启动时<br />
public OnGameModeExit()      // 服务器关闭时<br />
public OnPlayerConnect()   &nbsp;&nbsp;// 玩家进入服务器时<br />
public OnPlayerDisconnect()  // 玩家离开服务器时<br />
public OnPlayerSpawn()     &nbsp;&nbsp;// 玩家出生时<br />
public OnPlayerDeath()     &nbsp;&nbsp;// 玩家死亡时<br />
public OnPlayerText()        // 玩家发送聊天消息时</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例：完整的玩家连入/断开流程</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{<br />
    new name[MAX_PLAYER_NAME];<br />
    GetPlayerName(playerid, name, sizeof(name));<br />
<br />
    SendClientMessageToAll(0x88FF88FF, "[服务器] %s 加入了游戏", name);<br />
    return 1;<br />
}<br />
<br />
public OnPlayerDisconnect(playerid, reason)<br />
{<br />
    // reason: 0=超时  1=主动退出  2=被踢<br />
    new name[MAX_PLAYER_NAME];<br />
    GetPlayerName(playerid, name, sizeof(name));<br />
<br />
    SendClientMessageToAll(0xAAAAAAFF, "[服务器] %s 离开了游戏", name);<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">返回值</span>：大多数回调函数返回 1 表示正常处理。返回 0 在某些回调里有特殊含义（如阻止某些行为）</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">16. SendClientMessage — 发消息</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SendClientMessage</code> 是向玩家的<span style="font-weight: bold;" class="mycode_b">聊天框</span>发送消息，是最基础的通知手段。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SendClientMessage</code> 支持中文，不支持 emoji 表情符号。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">语法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessage(playerid, color, "消息内容");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">颜色格式（RGBA）</h4><br />
<br />
颜色用 8 位十六进制数表示：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0xRRGGBBAA</code><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">参数</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">RR</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">红色分量（00~FF）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">GG</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">绿色分量（00~FF）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">BB</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">蓝色分量（00~FF）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">AA</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">透明度（FF = 完全不透明）</td>
  </tr>
</table>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessage(playerid, 0xFFFFFFFF, "白色消息");<br />
SendClientMessage(playerid, 0xFF4444FF, "红色消息");<br />
SendClientMessage(playerid, 0x44FF44FF, "绿色消息");<br />
SendClientMessage(playerid, 0xFFDD44FF, "金黄色消息");<br />
SendClientMessage(playerid, -1,       &nbsp;&nbsp;"也是白色（-1 是快捷写法）");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">颜色常量（推荐定义）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 在脚本顶部定义常用颜色<br />
#define COLOR_WHITE &nbsp;&nbsp;0xFFFFFFFF<br />
#define COLOR_RED   &nbsp;&nbsp;0xFF4444FF<br />
#define COLOR_GREEN &nbsp;&nbsp;0x44FF44FF<br />
#define COLOR_YELLOW  0xFFDD44FF<br />
#define COLOR_GRAY    0xAAAAAAFF<br />
<br />
// 使用时更直观<br />
SendClientMessage(playerid, COLOR_GREEN, "[商店] 购买成功！");<br />
SendClientMessage(playerid, COLOR_RED, &nbsp;&nbsp;"[商店] 金币不足！");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">发给所有玩家</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessageToAll(COLOR_YELLOW, "[公告] 服务器将在 5 分钟后重启。");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在消息里嵌入变量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessage(playerid, COLOR_GREEN, "[商店] 购买成功！剩余金币：%d 枚", g_Gold[playerid]);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">17. GameText — 屏幕大字</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GameText</code> 在玩家屏幕显示文字，会自动消失。  <br />
适合用于：重要事件提示、区域名称、倒计时。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：GameText <span style="font-weight: bold;" class="mycode_b">不支持中文</span>，只能写英文和符号。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">语法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>GameTextForPlayer(playerid, "文字内容", 持续毫秒, 样式);<br />
GameTextForAll("文字内容", 持续毫秒, 样式); &nbsp;&nbsp;// 对所有玩家显示</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">颜色标签</h4><br />
<br />
在文字中插入颜色标签改变颜色：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>~w~  白色      ~r~  红色      ~g~  绿色<br />
~b~  蓝色      ~y~  黄色      ~p~  紫色<br />
~n~  换行      ~h~  加亮</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">样式速查</h4><br />
<br />
<a href="https://open.mp/docs/scripting/resources/gametextstyles" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/gametextstyles</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 进入区域时提示<br />
GameTextForPlayer(playerid, "~y~Town Market", 3000, 3);<br />
<br />
// 组合颜色与换行<br />
GameTextForPlayer(playerid, "~g~Quest Complete!~n~~w~Reward: 100 Gold", 4000, 3);<br />
<br />
// 全服公告<br />
GameTextForAll("~r~Pirates~w~ are attacking!", 5000, 3);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">18. TextDraw — 屏幕 UI</h3><br />
<br />
TextDraw 是<span style="font-weight: bold;" class="mycode_b">固定显示在屏幕上</span>的文字，不像 GameText 那样会消失。  <br />
常用于：服务器 Logo、血量 HUD、分数显示。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">详细资料</h4><br />
<br />
<a href="https://open.mp/docs/scripting/resources/TextDraws" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/TextDraws</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建一个右上角 Logo</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">第一步：声明变量</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Text:g_MyText; &nbsp;&nbsp;// Text: 是 TextDraw 的类型标签</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">第二步：在 OnGameModeInit 里创建</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()<br />
{<br />
    // x, y坐标是基于640x480画布（与屏幕分辨率无关）<br />
    g_MyText = TextDrawCreate(240.0, 580.0, "Welcome to my OPEN.MP server");<br />
    return 1;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">第三步：在 OnPlayerSpawn 里显示给玩家</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerSpawn(playerid)<br />
{<br />
    TextDrawShowForPlayer(playerid, g_MyText);<br />
    return 1;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">玩家断开时隐藏</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerDisconnect(playerid, reason)<br />
{<br />
    TextDrawHideForPlayer(playerid, g_MyText);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">字体样式说明</h4><br />
<br />
<a href="https://open.mp/docs/scripting/functions/TextDrawFont" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/functions/TextDrawFont</a><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">19. Dialog — 对话框</h3><br />
<br />
Dialog 是弹出在玩家屏幕上的<span style="font-weight: bold;" class="mycode_b">交互窗口</span>，是最核心的 UI 交互方式。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">对话框类型</h4><br />
<br />
<a href="https://open.mp/docs/scripting/resources/dialogstyles" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/dialogstyles</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第一步：定义对话框 ID</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 每个对话框需要一个唯一 ID，用常量管理<br />
#define DIALOG_NULL 0<br />
#define DIALOG_LOGIN 1<br />
#define DIALOG_WELCOME 2<br />
#define DIALOG_WEAPONS 3</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 你也可以用枚举，他会自动分配ID，第一个是0 后面自动递增<br />
enum {<br />
    DIALOG_NULL,        // 0<br />
    DIALOG_LOGIN,     &nbsp;&nbsp;// 1<br />
    DIALOG_WELCOME,   &nbsp;&nbsp;// 2<br />
    DIALOG_WEAPONS      // 3<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第二步：显示对话框</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// ShowPlayerDialog(玩家ID, 对话框ID, 样式, 标题, 内容, 按钮1, 按钮2)<br />
// 对话框样式示例: DIALOG_STYLE_MSGBOX:<br />
ShowPlayerDialog(playerid, DIALOG_WELCOME, DIALOG_STYLE_MSGBOX, "提示", "你已进入服务器", "关闭", "");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_INPUT:<br />
ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_INPUT, "登录", "请在下方输入密码登陆服务器:", "登录", "取消");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_LIST:<br />
ShowPlayerDialog(playerid, DIALOG_WEAPONS, DIALOG_STYLE_LIST, "武器", "AK47&#92;nM4&#92;n狙击枪", "选择", "关闭");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_PASSWORD:<br />
ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "登录", "请在下方输入密码登陆服务器:", "登录", "取消");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_TABLIST:<br />
ShowPlayerDialog(playerid, DIALOG_WEAPONS, DIALOG_STYLE_TABLIST, "武器商店", "沙鹰&#92;t&#36;5000&#92;t100&#92;n短管散弹枪&#92;t&#36;5000&#92;t100&#92;n手枪&#92;t&#36;1000&#92;t50", "购买", "取消");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_TABLIST_HEADERS:<br />
ShowPlayerDialog(playerid, DIALOG_WEAPONS, DIALOG_STYLE_TABLIST_HEADERS, "武器商店", "武器&#92;t价格&#92;t弹药数量&#92;n沙鹰&#92;t&#36;5000&#92;t100&#92;n短管散弹枪&#92;t&#36;5000&#92;t100&#92;n手枪&#92;t&#36;1000&#92;t50", "购买", "取消");</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\n</code> 是换行符，在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DIALOG_STYLE_LIST</code> 里每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\n</code> 分隔一个选项。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第三步：处理玩家的响应</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])<br />
{<br />
    // response  = 1 点了左边按钮<br />
    //         &nbsp;&nbsp;= 0 点了右边按钮或按了 ESC<br />
    // listitem  = 玩家选的是第几行（从 0 开始）<br />
    // inputtext = 玩家输入的文字<br />
<br />
    if (dialogid == DIALOG_RULES)<br />
    {<br />
        if (response) // 如果玩家点击了左边的按钮<br />
        {<br />
            SendClientMessage(playerid, COLOR_GREEN, "你点击了左边的按钮!");<br />
        }<br />
        else // 否则(玩家点击了右边的按钮或按下ESC键)<br />
        {<br />
            SendClientMessage(playerid, COLOR_GREEN, "你点击了右边的按钮!");<br />
        }<br />
        return 1; // 返回停止后续代码的执行<br />
    }<br />
    return 0;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">20. Pickup — 拾取物</h3><br />
<br />
Pickup 是放在地图上的<span style="font-weight: bold;" class="mycode_b">可触发拾取物</span>，玩家走触碰到之后会自动触发，不需要按键。  <br />
常用于：金币、道具、任务触发点、商店入口。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建 Pickup</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_pickupGold; &nbsp;&nbsp;// 保存 pickup 的 ID，响应时用来判断<br />
<br />
public OnGameModeInit()<br />
{<br />
    // CreatePickup(模型ID, 类型, X, Y, Z, 虚拟世界)<br />
    // 类型 2 = 拾取后消失，15 秒后重生<br />
    g_pickupGold = CreatePickup(1274, 2, 2009.8658, 1220.0293, 10.8206, -1);<br />
    //                          ↑模型 ↑类型 &nbsp;&nbsp;↑坐标                   &nbsp;&nbsp;↑-1=所有世界可见<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常用模型 ID</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">模型 ID</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">外观</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1210</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">公文包</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1212</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">金钱</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1239</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">信息</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1240</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">爱心</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1273</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">绿色房子</td>
  </tr>
</table>
更多可查阅: <a href="https://open.mp/docs/scripting/resources/pickupids" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/pickupids</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">响应拾取事件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerPickUpPickup(playerid, pickupid)<br />
{<br />
    if(pickupid == g_pickupGold)<br />
    {<br />
        g_Gold[playerid] += 20;<br />
        SendClientMessage(playerid, COLOR_YELLOW, "捡到了金币！+20");<br />
        GameTextForPlayer(playerid, "~y~+20 Gold", 1500, 5);<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Pickup 类型说明</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">类型值</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">行为</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">0</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">无特殊属性，不可被拾取</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">永久存在 仅允许脚本控制</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">仅限车辆拾取，触发检查点音效后消失</td>
  </tr>
</table>
更多类型可查阅: <a href="https://open.mp/docs/scripting/resources/pickuptypes" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/pickuptypes</a><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">21. Checkpoint — 检查点</h3><br />
<br />
Checkpoint 是地图上的<span style="font-weight: bold;" class="mycode_b">红色发光圆柱区域</span>，玩家走进去自动触发。  <br />
常用于：任务目标点、区域进入触发、引导新玩家，每个玩家最多只能显示一个检查点。<br />
<br />
当玩家进入检查点时，会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerEnterCheckpoint</code> 回调<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">设置检查点</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 每个玩家同时只能有一个活动的 Checkpoint<br />
// SetPlayerCheckpoint(玩家ID, X, Y, Z, 检查点尺寸半径)<br />
SetPlayerCheckpoint(playerid, 1982.6150, -220.6680, -0.2432, 3.0);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">响应进入事件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerEnterCheckpoint(playerid)<br />
{<br />
    SendClientMessage(playerid, COLOR_GREEN, "到达目标地点！");<br />
<br />
    // 触发后通常需要清除，避免反复触发<br />
    DisablePlayerCheckpoint(playerid);<br />
<br />
    // 在这里做你想做的事，比如给与玩家金钱<br />
    GivePlayerMoney(playerid, 1000);<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">RaceCheckpoint — 比赛检查点</h4><br />
<br />
当玩家进入时，会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerEnterRaceCheckPoint</code> 回调<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SetPlayerRaceCheckpoint(玩家ID, 类型, 当前X,Y,Z, 下一目标X,Y,Z, 半径)<br />
SetPlayerRaceCheckpoint(playerid, CP_TYPE_GROUND_NORMAL, 644.3091, 1767.0223, 4.9970, 650.6734, 1812.0367, 4.9970, 3.0);<br />
<br />
public OnPlayerEnterRaceCheckpoint(playerid)<br />
{<br />
    DisablePlayerRaceCheckpoint(playerid);<br />
    SendClientMessage(playerid, COLOR_GREEN, "到达！");<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">22. Vehicle — 载具</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建载具</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// CreateVehicle(模型, X, Y, Z, 角度, 颜色1, 颜色2, 重生延迟秒)<br />
new vehicleid = CreateVehicle(411, 100.0, 200.0, 10.0, 90.0, -1, -1, 60);<br />
// -1 = 随机颜色，60 = 无人使用 60 秒后重生</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">让玩家进入载具</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// PutPlayerInVehicle(玩家ID, 载具ID, 座位)<br />
// 座位 0 = 驾驶座，1 = 副驾驶，2/3 = 后排<br />
PutPlayerInVehicle(playerid, vehicleid, 0);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">载具模型 ID</h4><br />
<br />
请查阅: <a href="https://open.mp/docs/scripting/resources/vehicleid" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/vehicleid</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">进出载具回调</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)<br />
{<br />
    // ispassenger: 0 = 驾驶座，1 = 乘客<br />
    if(!ispassenger)<br />
    {<br />
        SendClientMessage(playerid, COLOR_WHITE, "你正在进入载具的驾驶位。");<br />
    }<br />
    return 1;<br />
}<br />
<br />
public OnPlayerExitVehicle(playerid, vehicleid)<br />
{<br />
    SendClientMessage(playerid, COLOR_WHITE, "你正在离开载具");<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">23. Actor — NPC</h3><br />
<br />
Actor 是<span style="font-weight: bold;" class="mycode_b">站在世界里的静态 NPC 角色</span>，可以设置外观和动作动画，但不会移动，但功能有限<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建 Actor</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_ActorSmith; &nbsp;&nbsp;// 保存 actor ID<br />
<br />
public OnGameModeInit()<br />
{<br />
    // CreateActor(皮肤ID, X, Y, Z, 朝向角度)<br />
    g_ActorSmith = CreateActor(179, 316.1, -134.0, 999.6, 90.0);<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">给 Actor 播放动画</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// ApplyActorAnimation(actorID, 动画库, 动画名, 速度, 循环, lockX, lockY, 冻结, 时长)<br />
ApplyActorAnimation(g_ActorSmith, "DEALER", "shop_pay", 4.1, false, false, false, false, 0);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">玩家靠近时按键交互</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 工具函数：计算玩家到 Actor 的距离<br />
stock Float:DistToActor(playerid, actorid)<br />
{<br />
    new Float:px, Float:py, Float:pz;<br />
    new Float:ax, Float:ay, Float:az;<br />
    GetPlayerPos(playerid, px, py, pz);<br />
    GetActorPos(actorid, ax, ay, az);<br />
    return floatsqroot((px-ax)*(px-ax)+(py-ay)*(py-ay)+(pz-az)*(pz-az));<br />
}<br />
<br />
// 在按键回调里检测距离并触发对话<br />
public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)<br />
{<br />
    if(PRESSED(KEY_YES))<br />
    {<br />
        if(DistToActor(playerid, g_ActorSmith) &lt; 3.0)<br />
        {<br />
            ShowPlayerDialog(playerid, DIALOG_SMITH, DIALOG_STYLE_MSGBOX,<br />
                "[ 武器商人 ]",<br />
                "欢迎！我能为你提供精良的武器。",<br />
                "好的", ""<br />
            );<br />
        }<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">服务器关闭时清理</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeExit()<br />
{<br />
    DestroyActor(g_ActorSmith);<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">24. Timer — 计时器</h3><br />
<br />
Timer 用于<span style="font-weight: bold;" class="mycode_b">延迟执行</span>或<span style="font-weight: bold;" class="mycode_b">定期执行</span>某个函数，是实现游戏事件、冷却时间、倒计时的基础工具。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建计时器</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 一次性：2000 毫秒（2 秒）后执行，false = 不重复<br />
SetTimer("MyFunction", 2000, false);<br />
<br />
// 重复：每 5000 毫秒（5 秒）执行一次，true = 重复<br />
new g_Timer = SetTimer("MyRepeatFunc", 5000, true);<br />
<br />
// 停止计时器（需要提前保存它的 ID）<br />
KillTimer(g_Timer);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">带参数的计时器</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SetTimerEx("函数名", 间隔ms, 是否重复, "参数格式", 参数值...)<br />
SetTimerEx("SendDelayedMsg", 3000, false, "i", playerid);<br />
<br />
// 对应函数必须先用 forward 声明<br />
forward SendDelayedMsg(playerid);<br />
public SendDelayedMsg(playerid)<br />
{<br />
    if(!IsPlayerConnected(playerid)) return 0;<br />
    GameTextForPlayer(playerid, "~w~Welcome to~n~~y~Island Town!", 3000, 3);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">参数格式字符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">格式符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数（int）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">f</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数（float）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">s</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串</td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用：每 60 秒播报随机事件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_EventTimer;<br />
<br />
public OnGameModeInit()<br />
{<br />
    g_EventTimer = SetTimer("IslandEvent", 60000, true);<br />
    return 1;<br />
}<br />
<br />
public OnGameModeExit()<br />
{<br />
    KillTimer(g_EventTimer); &nbsp;&nbsp;// 服务器关闭时记得停止<br />
    return 1;<br />
}<br />
<br />
forward IslandEvent();<br />
public IslandEvent()<br />
{<br />
    switch(random(3))<br />
    {<br />
        case 0: SendClientMessageToAll(COLOR_ORANGE, "[小镇] 市集开放！来广场逛逛。");<br />
        case 1: SendClientMessageToAll(COLOR_RED,    "[小镇] 海湾发现海盗船！");<br />
        case 2: SendClientMessageToAll(COLOR_GREEN,  "[小镇] 今日好天气，渔获翻倍！");<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SetTimerEx</code> 的函数<span style="font-weight: bold;" class="mycode_b">必须</span>在使用前加 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 声明，否则编译会报错或运行异常。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">25. Keys — 按键检测</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerKeyStateChange</code> 在玩家<span style="font-weight: bold;" class="mycode_b">按下或松开按键</span>时触发，用于实现交互操作。<br />
<br />
官方文档: <a href="https://open.mp/docs/scripting/callbacks/OnPlayerKeyStateChange" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/callbacks...tateChange</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础宏定义</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 在脚本顶部定义这两个宏，后面判断按键时更方便<br />
#define PRESSED(%0)  (((newkeys) &amp; (%0)) &amp;&amp; !((oldkeys) &amp; (%0)))<br />
#define RELEASED(%0) (!((newkeys) &amp; (%0)) &amp;&amp; ((oldkeys) &amp; (%0)))</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)<br />
{<br />
    // PRESSED = 刚按下（本帧按着，上帧没按）<br />
    if(PRESSED(KEY_FIRE))<br />
    {<br />
        SendClientMessage(playerid, COLOR_WHITE, "你按了鼠标左键");<br />
    }<br />
<br />
    // RELEASED = 刚松开<br />
    if(RELEASED(KEY_FIRE))<br />
    {<br />
        SendClientMessage(playerid, COLOR_WHITE, "你松开了鼠标左键");<br />
    }<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">按键常量</h4><br />
<br />
请查阅: <a href="https://open.mp/docs/scripting/resources/keys" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/keys</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">完整交互示例：按 Y键 与 NPC 对话</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PRESSED(%0) (((newkeys) &amp; (%0)) &amp;&amp; !((oldkeys) &amp; (%0)))<br />
<br />
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)<br />
{<br />
    if(PRESSED(KEY_YES))<br />
    {<br />
        // 检查玩家是否靠近铁匠 NPC<br />
        if(DistToActor(playerid, g_ActorSmith) &lt; 3.0)<br />
        {<br />
            ShowPlayerDialog(playerid, DIALOG_SMITH, DIALOG_STYLE_MSGBOX,<br />
                "[ 武器商人 ]",<br />
                "你好，旅人！需要武器吗？",<br />
                "需要", "不了"<br />
            );<br />
        }<br />
    }<br />
    return 1;<br />
}</code></div></div>]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">零基础开发openmp/SAMP服务器基础教程 - 第二章</h2><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>本教程面向完全零基础的新手，每一节只讲一个知识点，循序渐进。</blockquote>
<blockquote class="mycode_quote"><cite>引用:</cite>本章节先以快速了解 Pawn 语言和 openmp 游戏实际应用为开端，让新手更快通过实际游戏表现获得反馈，以避免一开始就接触过多语法，建议阅读完本章节再开始第三章巩固进阶编程语言细节</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">目录</h3><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">#</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">章节</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#1-openmp-是什么" target="_blank" rel="noopener" class="mycode_url">open.mp 是什么</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">2</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#2-开启服务器" target="_blank" rel="noopener" class="mycode_url">开启服务器</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">3</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#3-第一个脚本" target="_blank" rel="noopener" class="mycode_url">第一个脚本</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">4</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#4-注释" target="_blank" rel="noopener" class="mycode_url">注释</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">5</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#5-变量" target="_blank" rel="noopener" class="mycode_url">变量</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">6</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#6-define" target="_blank" rel="noopener" class="mycode_url">define</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">7</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#7-字符串与-format" target="_blank" rel="noopener" class="mycode_url">字符串与 format</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">8</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#8-运算符" target="_blank" rel="noopener" class="mycode_url">运算符</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">9</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#9-if--else-判断" target="_blank" rel="noopener" class="mycode_url">if / else 判断</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">10</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#10-switch-多分支" target="_blank" rel="noopener" class="mycode_url">switch 多分支</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">11</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#11-for-循环" target="_blank" rel="noopener" class="mycode_url">for 循环</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">12</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#12-while-循环" target="_blank" rel="noopener" class="mycode_url">while 循环</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">13</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#13-函数" target="_blank" rel="noopener" class="mycode_url">函数</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#14-数组" target="_blank" rel="noopener" class="mycode_url">数组</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">15</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#15-回调函数callback" target="_blank" rel="noopener" class="mycode_url">回调函数（Callback）</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">16</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#16-sendclientmessage--发消息" target="_blank" rel="noopener" class="mycode_url">SendClientMessage — 发消息</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">17</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#17-gametext--屏幕大字" target="_blank" rel="noopener" class="mycode_url">GameText — 屏幕大字</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">18</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#18-textdraw--屏幕-ui" target="_blank" rel="noopener" class="mycode_url">TextDraw — 屏幕 UI</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">19</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#19-dialog--对话框" target="_blank" rel="noopener" class="mycode_url">Dialog — 对话框</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">20</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#20-pickup--拾取物" target="_blank" rel="noopener" class="mycode_url">Pickup — 拾取物</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">21</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#21-checkpoint--检查点" target="_blank" rel="noopener" class="mycode_url">Checkpoint — 检查点</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">22</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#22-vehicle--载具" target="_blank" rel="noopener" class="mycode_url">Vehicle — 载具</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">23</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#23-actor--npc" target="_blank" rel="noopener" class="mycode_url">Actor — NPC</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">24</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#24-timer--计时器" target="_blank" rel="noopener" class="mycode_url">Timer — 计时器</a></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">25</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><a href="http://#25-keys--按键检测" target="_blank" rel="noopener" class="mycode_url">Keys — 按键检测</a></td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">1. open.mp 是什么</h3><br />
<br />
<span style="font-weight: bold;" class="mycode_b">open.mp</span>（open multiplayer）是一个全新的 侠盗猎车手：圣安地列斯 的多人游戏服务端，完全向下兼容 <span style="font-weight: bold;" class="mycode_b">SA-MP</span> 。<br />
<br />
你可以用 <span style="font-weight: bold;" class="mycode_b">Pawn 脚本语言</span> 来编写游戏服务器的逻辑，比如：<br />
<ul class="mycode_list"><li>玩家加入时显示欢迎消息<br />
</li>
<li>在地图上放置 NPC、载具、拾取物<br />
</li>
<li>制作商店、任务、角色扮演系统<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Pawn</span> 是一门类似 C 语言的脚本语言，语法简单，非常适合入门。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">open.mp vs SA-MP</span>：两者语法完全一样。open.mp 是活跃维护的现代版本。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">2. 开启服务器</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第一步：下载 open.mp 服务端</h4><br />
<br />
前往官网 <a href="https://www.open.mp" target="_blank" rel="noopener" class="mycode_url">https://www.open.mp</a> 下载最新版本，解压到任意文件夹。<br />
<br />
解压后你会看到这样的目录结构：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>components: open.mp 核心组件<br />
filterscripts: 服务器脚本文件（辅助脚本）<br />
gamemodes: 服务器游戏模式文件（主图）<br />
models: 服务器自定义模型（纹理 .txd .dff）<br />
plugins: 服务器插件文件（传统插件）<br />
qawno: Pawn 编辑器程序及包含文件<br />
scriptfiles: INI 配置文件及其他资源<br />
bans.json: 封禁列表文件<br />
config.json: 服务器配置文件<br />
omp-server.exe: open.mp 服务器主程序</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第二步：配置 config.json</h4><br />
<br />
打开 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">config.json</code>，找到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main_scripts</code> 这一行，改成你的主图名称 mygamemode<br />
<br />
根据需求设置端口 服务器名称 需要添加的插件 辅助脚本 修改高强度的rcon密码<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>{<br />
    "name": "我的服务器",<br />
    "network": {<br />
        "port": 7777<br />
    },<br />
    "max_bots": 0,<br />
    "max_players": 100,<br />
    "pawn": {<br />
        "main_scripts": [<br />
            "mygamemode 1"<br />
        ]<br />
    },<br />
    "rcon": {<br />
        "password": "changeme1"<br />
    },<br />
}</code></div></div><br />
关于config.json更多详情可查阅 <a href="https://open.mp/docs/server/config.json" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/server/config.json</a> 但几乎大部分设置保持默认即可<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第三步：打开 qawno 编辑器</h4><br />
<br />
双击 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">qawno/qawno.exe</code>，这就是你写代码和编译脚本的地方。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">提示</span>：推荐使用 VSCode，代码补全更强大。入门阶段用 qawno 就够了。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">3. 第一个脚本</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建脚本文件</h4><br />
<br />
在 qawno 中，点击菜单 <span style="font-weight: bold;" class="mycode_b">File → New Blank</span>，然后输入以下代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
<br />
main(){}<br />
<br />
public OnGameModeInit()<br />
{<br />
    SetGameModeText("我的第一个open.mp服务器");<br />
    AddPlayerClass(1, 2495.3547, -1688.2319, 13.6774, 351.1646, WEAPON_M4, 500, WEAPON_KNIFE, 1, WEAPON_COLORT45, 100);<br />
&nbsp;&nbsp;&nbsp;&nbsp;AddStaticVehicle(522, 2493.7583, -1683.6482, 12.9099, 270.8069, -1, -1);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">保存并编译</h4><br />
<br />
点击 <span style="font-weight: bold;" class="mycode_b">File → Save</span>，保存为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">mygamemode.pwn</code>，保存到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gamemodes/</code> 目录下。<br />
<br />
然后按 <span style="font-weight: bold;" class="mycode_b">F5</span> 编译。<br />
<br />
编译成功后，在同目录会生成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">mygamemode.amx</code> 文件。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">启动服务器</h4><br />
<br />
双击 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">omp-server.exe</code>，就成功启动服务器了。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">代码解释</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">代码</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#include &lt;open.mp&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">引入 open.mp 的所有函数，必须写在第一行</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public OnGameModeInit()</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">服务器启动时自动执行的函数</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SetGameModeText("...")</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">设置服务器模式名称（显示在服务器列表）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AddPlayerClass(...)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在职业选择中添加一个职业 用于让玩家可以以自己选择的皮肤出生</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">AddStaticVehicle(...)</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">在游戏模式中添加静态车辆（模型会预加载给玩家）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">return 1;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">函数结束，返回 1 表示成功</td>
  </tr>
</table>
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">规则</span>：每条语句末尾必须有 <span style="font-weight: bold;" class="mycode_b">分号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">;</code></span>，花括号 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">{}</code> 表示代码块的开始和结束。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">4. 注释</h3><br />
<br />
注释是写给人看的说明文字，<span style="font-weight: bold;" class="mycode_b">编译器会完全忽略它</span>，不影响程序运行。<br />
<br />
写注释的好处是以后回看代码时会轻松很多。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">单行注释</h4><br />
<br />
用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">//</code> 开头，从这里到行尾都是注释：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 这是一行注释，不会被执行<br />
SetGameModeText("我的第一个open.mp服务器");  // 也可以写在代码后面</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">多行注释</h4><br />
<br />
用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">/* ... */</code> 包裹，可以跨越多行：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/*<br />
    这里是多行注释。<br />
    可以写很多行。<br />
    常用于说明。<br />
*/<br />
public OnGameModeInit()<br />
{<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">建议</span>：新手可以给每个函数写一行注释说明它的用途，给复杂逻辑写注释说明思路。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">5. 变量</h3><br />
<br />
变量是用来<span style="font-weight: bold;" class="mycode_b">存储数据</span>的容器，就像一个贴了标签的盒子。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明变量</h4><br />
<br />
用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new</code> 关键字声明变量：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myScore;       &nbsp;&nbsp;// 声明一个整数变量，初始值默认是 0<br />
new myScore = 10;    // 声明并赋初始值</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变量类型</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">整数（默认类型）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myAge = 25;<br />
new myGold = 100;<br />
new myScore = 0;</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">浮点数（小数）</span><br />
<br />
浮点数需要在变量名前加 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Float:</code> 标签：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Float:myHealth = 100.0;<br />
new Float:mySpeed  = 3.14;<br />
new Float:myX      = 1234.5; &nbsp;&nbsp;// 坐标通常是浮点数</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">变量命名规范</h4><br />
<br />
变量名只能包含字母、数字、下划线，且不能以数字开头，推荐：g_ 前缀表示全局变量<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Score = 0;<br />
new g_Speed = 0.0;<br />
new g_Name[32];</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>这种前缀命名法不是强制要求，但能让代码更易读，虽然不是主流实践，但比较适用于pawn开发。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">全局变量 vs 局部变量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 全局变量：写在所有函数外面，整个脚本都能访问，g_ 前缀表示全局（global）<br />
new g_PlayerScore[MAX_PLAYERS];<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
    // 局部变量：写在函数内部，只在这个函数里有效，驼峰命名法‌（camelCase）：首词小写，后续大写<br />
    new defaultScore = 50;<br />
    g_PlayerScore[playerid] = defaultScore;<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">6. define</h3><br />
<br />
它本质上是一个文本替换符号，而不是一个真正的变量或常量，从使用效果看，它表现得像一个常量（运行过程中不能改变其数值），在编译时直接替换，不占用内存<br />
<br />
常量常用于替代魔法数字，使代码更具可读性和可维护性，在这篇教程中我们暂时称它为常量。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">定义常量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define SERVER_NAME   &nbsp;&nbsp;"我的第一个open.mp服务器"<br />
#define MAX_GOLD        999<br />
#define START_GOLD      50<br />
#define PI              3.14159</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">如何使用</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()<br />
{<br />
    SetGameModeText(SERVER_NAME); &nbsp;&nbsp;// 等同于 SetGameModeText("我的第一个open.mp服务器");<br />
    return 1;<br />
}<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_Gold[playerid] = START_GOLD;  // 等同于 g_Gold[playerid] = 50;<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">规范</span>：全部大写，单词间用下划线分隔，例如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SKIN_NORMAL</code>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">7. 字符串与 format</h3><br />
<br />
字符串就是一段文字。在 Pawn 中，字符串用<span style="font-weight: bold;" class="mycode_b">字符数组</span>存储。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明字符串</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Name[32];               &nbsp;&nbsp;// 最多存 31 个字符（留一位给结束符）<br />
new g_Msg[128];               &nbsp;&nbsp;// 消息通常用 128 或 256<br />
new g_Name[MAX_PLAYER_NAME]; &nbsp;&nbsp;// 用内置常量，等同于 g_Name[24]</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">获取玩家名字</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Name[MAX_PLAYER_NAME];<br />
GetPlayerName(playerid, g_Name, sizeof(g_Name)); // sizeof(g_Name) 自动计算数组大小，不需要手动填数字</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">format — 格式化字符串</h4><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">format</code> 可以把变量的值拼进字符串里，类似其他语言的字符串模板：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new string[128];<br />
new name[MAX_PLAYER_NAME];<br />
new gold = 100;<br />
<br />
GetPlayerName(playerid, name, sizeof(name));<br />
<br />
format(string, sizeof(string), "你好，%s！你有 %d 枚金币。", name, gold);<br />
// 结果："你好，CJ！你有 100 枚金币。"</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">格式占位符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">占位符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%s</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"Hello, %s"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%d</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"金币：%d"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%f</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"血量：%.1f"</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%i</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数（同 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%d</code>）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">"等级：%i"</code></td>
  </tr>
</table>
<blockquote class="mycode_quote"><cite>引用:</cite><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%.1f</code> 表示保留 1 位小数，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">%.2f</code> 保留 2 位，以此类推。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">8. 运算符</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">算术运算符</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new a = 10;<br />
new b = 3;<br />
<br />
new add  = a + b; &nbsp;&nbsp;// 13  加<br />
new sub  = a - b; &nbsp;&nbsp;// 7 &nbsp;&nbsp;减<br />
new mul  = a * b; &nbsp;&nbsp;// 30  乘<br />
new div  = a / b; &nbsp;&nbsp;// 3 &nbsp;&nbsp;除（整数除法，舍去小数）<br />
new mod  = a % b; &nbsp;&nbsp;// 1 &nbsp;&nbsp;取余（10 除以 3 余 1）</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">快捷赋值</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 100;<br />
gold += 50; &nbsp;&nbsp;// 等同于 gold = 100 + 50  →  150<br />
gold -= 20; &nbsp;&nbsp;// 等同于 gold = 100 - 20  →  80<br />
gold *= 2;    // 等同于 gold = 100 * 2 &nbsp;&nbsp;→  200<br />
gold /= 4;    // 等同于 gold = 100 / 4 &nbsp;&nbsp;→  25</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">自增 / 自减</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new i = 0;<br />
i++;    // i 变成 1，等同于 i = i + 1<br />
i--;    // i 变成 0，等同于 i = i - 1</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">比较运算符（返回真/假）</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">==</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">等于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!=</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">不等于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&gt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">大于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">小于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&gt;=</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">大于等于</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&lt;=</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">小于等于</td>
  </tr>
</table>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 100;<br />
<br />
if(gold == 100)  { /* 如果gold等于100 则成立 */ }<br />
if(gold &gt; 50)    { /* 如果gold大于50 则成立 */ }<br />
if(gold != 0)    { /* 如果gold不等于0 则成立 */ }</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">常见错误</span>：判断用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">==</code>（两个等号），赋值用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">=</code>（一个等号）。写成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if(gold = 100)</code> 是赋值，不是判断！</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">逻辑运算符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">运算符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">示例</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">&amp;&amp;</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">且（两个都成立）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gold &gt; 0 &amp;&amp; isAlive</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\|\|</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">或（任意一个成立）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">isAdmin \|\| isVIP</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">非（取反）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">!IsPlayerConnected(i)</code></td>
  </tr>
</table>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">9. if / else 判断</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">if / else</code> 根据条件决定执行哪段代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new gold = 80;<br />
<br />
// 如果金币大于100<br />
if(gold &gt;= 100)<br />
{<br />
    SendClientMessage(playerid, 0xFFFF00FF, "金币充足，可以购买！");<br />
}<br />
// 否则<br />
else<br />
{<br />
    SendClientMessage(playerid, 0xFF4444FF, "金币不足！");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">if / else if / else</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new myLevel = 5;<br />
<br />
if(myLevel &gt;= 10)<br />
{<br />
    SendClientMessage(playerid, -1, "你是高级玩家！");<br />
}<br />
else if(myLevel &gt;= 5)<br />
{<br />
    SendClientMessage(playerid, -1, "你是中级玩家。");<br />
}<br />
else<br />
{<br />
    SendClientMessage(playerid, -1, "你是新手。");<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">10. switch 多分支</h3><br />
<br />
当你需要根据一个变量的<span style="font-weight: bold;" class="mycode_b">多个具体值</span>做不同处理时，<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 比一堆 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">else if</code> 更清晰。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Class = 2;<br />
<br />
switch(g_Class)<br />
{<br />
    case 0:<br />
    {<br />
        SendClientMessage(playerid, -1, "你选择了：农民");<br />
        SetPlayerSkin(playerid, 86);<br />
    }<br />
    case 1:<br />
    {<br />
        SendClientMessage(playerid, -1, "你选择了：骑士");<br />
        SetPlayerSkin(playerid, 287);<br />
    }<br />
    case 2:<br />
    {<br />
        SendClientMessage(playerid, -1, "你选择了：商人");<br />
        SetPlayerSkin(playerid, 19);<br />
    }<br />
    default:<br />
    {<br />
        // 以上都不匹配时<br />
        SendClientMessage(playerid, -1, "未知职业");<br />
    }<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用：处理对话框响应</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])<br />
{<br />
    if(dialogid == DIALOG_SHOP)<br />
    {<br />
        if(!response) return 1; &nbsp;&nbsp;// 点了取消，不处理，等同于if(response == false)<br />
<br />
        switch(listitem)<br />
        {<br />
            case 0: SetPlayerSkin(playerid, 86); &nbsp;&nbsp;// 选择了对话框的第一个选项<br />
            case 1: SetPlayerSkin(playerid, 287);  // 选择了对话框的第二个选项<br />
            case 2: SetPlayerSkin(playerid, 19); &nbsp;&nbsp;// 选择了对话框的第三个选项<br />
        }<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">switch</code> 中每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">case</code> 后面的值必须是<span style="font-weight: bold;" class="mycode_b">整数或常量</span>，不能是字符串或浮点数。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">11. for 循环</h3><br />
<br />
当你需要<span style="font-weight: bold;" class="mycode_b">重复执行</span>某段代码时，用循环。<br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code> 循环适合已知重复次数的场景。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础结构</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// &nbsp;&nbsp;初始值; 条件; 每次循环后执行<br />
for(new i = 0; i &lt; 5; i++)<br />
{<br />
    // 这里的代码会执行 5 次（i = 0, 1, 2, 3, 4）<br />
    print("循环中...(已循环%d次)", i + 1);<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">遍历所有在线玩家</h4><br />
<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 给所有在线玩家发送消息<br />
for(new i = 0; i &lt; MAX_PLAYERS; i++)<br />
{<br />
    if(IsPlayerNPC(i) == false &amp;&amp; inGame[i] == true)<br />
    {<br />
        SendClientMessage(i, 0xFFFF00FF, "[公告] 比赛开始！");<br />
        GivePlayerWeapon(i, WEAPON_AK47, 1500);<br />
        SetPlayerPos(i, 0.0, 0.0, 2.5);<br />
        // 给所有玩家加金币<br />
        g_Gold[i] += 10;<br />
    }<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite>但通常历遍玩家我们会选择foreach库，更高效。  <br />
<span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i &lt; MAX_PLAYERS</code> 不能写成 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i &lt;= MAX_PLAYERS</code>，否则会越界。  <br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS</code> 是最大玩家数，有效的 playerid 是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0</code> 到 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">MAX_PLAYERS - 1</code>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">12. while 循环</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code> 循环适合<span style="font-weight: bold;" class="mycode_b">不知道要循环多少次、只知道循环条件</span>的场景。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础结构</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new i = 0;<br />
while(i &lt; 5)<br />
{<br />
    print("执行中...");<br />
    i++;   &nbsp;&nbsp;// 一定要记得让条件向终止靠近，否则会导致无限死循环！<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">while vs for</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">场景</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">推荐</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">固定次数的重复（如遍历所有玩家）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">for</code></td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">条件不满足就一直循环（如等待某个状态）</td>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">while</code></td>
  </tr>
</table>
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">警告</span>：循环体内一定要有让条件变化的语句，否则会进入<span style="font-weight: bold;" class="mycode_b">死循环</span>，导致服务器卡死。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">13. 函数</h3><br />
<br />
函数是把一段代码<span style="font-weight: bold;" class="mycode_b">打包起来命名</span>，方便重复调用，避免重复写同样的代码。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">定义函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数名(参数列表)<br />
// {<br />
//   &nbsp;&nbsp;代码内容<br />
//   &nbsp;&nbsp;return 返回值;<br />
// }<br />
<br />
GiveGold(playerid, amount)<br />
{<br />
    g_Gold[playerid] += amount;<br />
    SendClientMessage(playerid, 0xFFDD44FF, "你获得了金币！");<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">调用函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{<br />
    GiveGold(playerid, 50);    // 玩家连入时给 50 金币<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">带特定返回值的函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 检查玩家金币是否足够，返回 true（足够）或 false（不足）<br />
bool:HasEnoughGold(playerid, cost)<br />
{<br />
    if(g_Gold[playerid] &gt;= cost)<br />
    {<br />
        return true; &nbsp;&nbsp;// 足够<br />
    }<br />
    return false;     &nbsp;&nbsp;// 不足<br />
}<br />
<br />
// 使用：<br />
if(HasEnoughGold(playerid, 100) == true)<br />
{<br />
    SendClientMessage(playerid, -1, "可以购买！");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">不需要带任何返回值的函数</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>void:ResetGold(playerid)<br />
{<br />
    g_Gold[playerid] = 0;<br />
    SendClientMessage(playerid, 0xFFDD44FF, "你的金币被清空了");<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">stock 函数</h4><br />
<br />
在 Pawn 中，如果你定义了函数但某些情况下没用到，编译器会发出警告。  <br />
加上 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">stock</code> 关键字可以消除这个警告：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>stock GetPlayerGold(playerid)<br />
{<br />
    return g_Gold[playerid];<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">原则</span>：把重复用到 3 次以上的代码封装成函数。函数名需要清晰描述它做什么，例如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GiveGold</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ShowShop</code>、<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">KickPlayer</code>。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">14. 数组</h3><br />
<br />
数组是<span style="font-weight: bold;" class="mycode_b">一组同类型数据的集合</span>，用一个名字访问多个值。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">声明数组</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Scores[10];         &nbsp;&nbsp;// 存 10 个整数<br />
new Float:g_Positions[3]; &nbsp;&nbsp;// 存 3 个浮点数（X, Y, Z）<br />
new g_Name[MAX_PLAYER_NAME]; // 字符串本质也是字符数组</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">访问数组元素</h4><br />
<br />
数组下标从 <span style="font-weight: bold;" class="mycode_b">0</span> 开始：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_Scores[5];<br />
<br />
g_Scores[0] = 100; &nbsp;&nbsp;// 第 1 个元素<br />
g_Scores[1] = 85;    // 第 2 个元素<br />
g_Scores[4] = 60;    // 第 5 个（最后一个）<br />
// g_Scores[5]  ← 越界！不能访问，会报错</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">最常见：每个玩家存一份数据</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 全局声明：每个玩家 ID 对应一个值<br />
new g_Gold[MAX_PLAYERS];<br />
new g_Level[MAX_PLAYERS];<br />
new g_Skin[MAX_PLAYERS];<br />
<br />
// 使用 playerid 作为下标访问对应玩家的数据<br />
public OnPlayerConnect(playerid)<br />
{<br />
    g_Gold[playerid]  = 50;<br />
    g_Level[playerid] = 1;<br />
    g_Skin[playerid]  = 86;<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">二维数组</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 存 5 个检查点的坐标（每个坐标有 X、Y、Z 三个值）<br />
new Float:g_CpPos[5][3] = {<br />
    {100.0, 200.0, 10.0}, &nbsp;&nbsp;// 检查点 0<br />
    {150.0, 220.0, 10.0}, &nbsp;&nbsp;// 检查点 1<br />
    {200.0, 240.0, 10.0}, &nbsp;&nbsp;// 检查点 2<br />
    {250.0, 260.0, 10.0}, &nbsp;&nbsp;// 检查点 3<br />
    {300.0, 280.0, 10.0}    // 检查点 4<br />
};<br />
<br />
// 访问检查点 2 的 Y 坐标：<br />
new Float:y = g_CpPos[2][1]; &nbsp;&nbsp;// 240.0</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">15. 回调函数（Callback）</h3><br />
<br />
回调函数是 open.mp <span style="font-weight: bold;" class="mycode_b">服务端自动调用</span>的特殊函数。<br />
<br />
你不需要手动调用它们，只需要在脚本里<span style="font-weight: bold;" class="mycode_b">定义</span>它们，当对应事件发生时，服务端会自动执行。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">规律</h4><br />
<br />
所有回调函数都以 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">public On</code> 开头：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()      // 服务器启动时<br />
public OnGameModeExit()      // 服务器关闭时<br />
public OnPlayerConnect()   &nbsp;&nbsp;// 玩家进入服务器时<br />
public OnPlayerDisconnect()  // 玩家离开服务器时<br />
public OnPlayerSpawn()     &nbsp;&nbsp;// 玩家出生时<br />
public OnPlayerDeath()     &nbsp;&nbsp;// 玩家死亡时<br />
public OnPlayerText()        // 玩家发送聊天消息时</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例：完整的玩家连入/断开流程</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerConnect(playerid)<br />
{<br />
    new name[MAX_PLAYER_NAME];<br />
    GetPlayerName(playerid, name, sizeof(name));<br />
<br />
    SendClientMessageToAll(0x88FF88FF, "[服务器] %s 加入了游戏", name);<br />
    return 1;<br />
}<br />
<br />
public OnPlayerDisconnect(playerid, reason)<br />
{<br />
    // reason: 0=超时  1=主动退出  2=被踢<br />
    new name[MAX_PLAYER_NAME];<br />
    GetPlayerName(playerid, name, sizeof(name));<br />
<br />
    SendClientMessageToAll(0xAAAAAAFF, "[服务器] %s 离开了游戏", name);<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">返回值</span>：大多数回调函数返回 1 表示正常处理。返回 0 在某些回调里有特殊含义（如阻止某些行为）</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">16. SendClientMessage — 发消息</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SendClientMessage</code> 是向玩家的<span style="font-weight: bold;" class="mycode_b">聊天框</span>发送消息，是最基础的通知手段。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SendClientMessage</code> 支持中文，不支持 emoji 表情符号。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">语法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessage(playerid, color, "消息内容");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">颜色格式（RGBA）</h4><br />
<br />
颜色用 8 位十六进制数表示：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">0xRRGGBBAA</code><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">参数</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">RR</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">红色分量（00~FF）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">GG</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">绿色分量（00~FF）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">BB</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">蓝色分量（00~FF）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">AA</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">透明度（FF = 完全不透明）</td>
  </tr>
</table>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessage(playerid, 0xFFFFFFFF, "白色消息");<br />
SendClientMessage(playerid, 0xFF4444FF, "红色消息");<br />
SendClientMessage(playerid, 0x44FF44FF, "绿色消息");<br />
SendClientMessage(playerid, 0xFFDD44FF, "金黄色消息");<br />
SendClientMessage(playerid, -1,       &nbsp;&nbsp;"也是白色（-1 是快捷写法）");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">颜色常量（推荐定义）</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 在脚本顶部定义常用颜色<br />
#define COLOR_WHITE &nbsp;&nbsp;0xFFFFFFFF<br />
#define COLOR_RED   &nbsp;&nbsp;0xFF4444FF<br />
#define COLOR_GREEN &nbsp;&nbsp;0x44FF44FF<br />
#define COLOR_YELLOW  0xFFDD44FF<br />
#define COLOR_GRAY    0xAAAAAAFF<br />
<br />
// 使用时更直观<br />
SendClientMessage(playerid, COLOR_GREEN, "[商店] 购买成功！");<br />
SendClientMessage(playerid, COLOR_RED, &nbsp;&nbsp;"[商店] 金币不足！");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">发给所有玩家</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessageToAll(COLOR_YELLOW, "[公告] 服务器将在 5 分钟后重启。");</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">在消息里嵌入变量</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>SendClientMessage(playerid, COLOR_GREEN, "[商店] 购买成功！剩余金币：%d 枚", g_Gold[playerid]);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">17. GameText — 屏幕大字</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">GameText</code> 在玩家屏幕显示文字，会自动消失。  <br />
适合用于：重要事件提示、区域名称、倒计时。<br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：GameText <span style="font-weight: bold;" class="mycode_b">不支持中文</span>，只能写英文和符号。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">语法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>GameTextForPlayer(playerid, "文字内容", 持续毫秒, 样式);<br />
GameTextForAll("文字内容", 持续毫秒, 样式); &nbsp;&nbsp;// 对所有玩家显示</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">颜色标签</h4><br />
<br />
在文字中插入颜色标签改变颜色：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>~w~  白色      ~r~  红色      ~g~  绿色<br />
~b~  蓝色      ~y~  黄色      ~p~  紫色<br />
~n~  换行      ~h~  加亮</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">样式速查</h4><br />
<br />
<a href="https://open.mp/docs/scripting/resources/gametextstyles" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/gametextstyles</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">示例</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 进入区域时提示<br />
GameTextForPlayer(playerid, "~y~Town Market", 3000, 3);<br />
<br />
// 组合颜色与换行<br />
GameTextForPlayer(playerid, "~g~Quest Complete!~n~~w~Reward: 100 Gold", 4000, 3);<br />
<br />
// 全服公告<br />
GameTextForAll("~r~Pirates~w~ are attacking!", 5000, 3);</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">18. TextDraw — 屏幕 UI</h3><br />
<br />
TextDraw 是<span style="font-weight: bold;" class="mycode_b">固定显示在屏幕上</span>的文字，不像 GameText 那样会消失。  <br />
常用于：服务器 Logo、血量 HUD、分数显示。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">详细资料</h4><br />
<br />
<a href="https://open.mp/docs/scripting/resources/TextDraws" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/TextDraws</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建一个右上角 Logo</h4><br />
<br />
<span style="font-weight: bold;" class="mycode_b">第一步：声明变量</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new Text:g_MyText; &nbsp;&nbsp;// Text: 是 TextDraw 的类型标签</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">第二步：在 OnGameModeInit 里创建</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeInit()<br />
{<br />
    // x, y坐标是基于640x480画布（与屏幕分辨率无关）<br />
    g_MyText = TextDrawCreate(240.0, 580.0, "Welcome to my OPEN.MP server");<br />
    return 1;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">第三步：在 OnPlayerSpawn 里显示给玩家</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerSpawn(playerid)<br />
{<br />
    TextDrawShowForPlayer(playerid, g_MyText);<br />
    return 1;<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">玩家断开时隐藏</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerDisconnect(playerid, reason)<br />
{<br />
    TextDrawHideForPlayer(playerid, g_MyText);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">字体样式说明</h4><br />
<br />
<a href="https://open.mp/docs/scripting/functions/TextDrawFont" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/functions/TextDrawFont</a><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">19. Dialog — 对话框</h3><br />
<br />
Dialog 是弹出在玩家屏幕上的<span style="font-weight: bold;" class="mycode_b">交互窗口</span>，是最核心的 UI 交互方式。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">对话框类型</h4><br />
<br />
<a href="https://open.mp/docs/scripting/resources/dialogstyles" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/dialogstyles</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第一步：定义对话框 ID</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 每个对话框需要一个唯一 ID，用常量管理<br />
#define DIALOG_NULL 0<br />
#define DIALOG_LOGIN 1<br />
#define DIALOG_WELCOME 2<br />
#define DIALOG_WEAPONS 3</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 你也可以用枚举，他会自动分配ID，第一个是0 后面自动递增<br />
enum {<br />
    DIALOG_NULL,        // 0<br />
    DIALOG_LOGIN,     &nbsp;&nbsp;// 1<br />
    DIALOG_WELCOME,   &nbsp;&nbsp;// 2<br />
    DIALOG_WEAPONS      // 3<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第二步：显示对话框</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// ShowPlayerDialog(玩家ID, 对话框ID, 样式, 标题, 内容, 按钮1, 按钮2)<br />
// 对话框样式示例: DIALOG_STYLE_MSGBOX:<br />
ShowPlayerDialog(playerid, DIALOG_WELCOME, DIALOG_STYLE_MSGBOX, "提示", "你已进入服务器", "关闭", "");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_INPUT:<br />
ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_INPUT, "登录", "请在下方输入密码登陆服务器:", "登录", "取消");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_LIST:<br />
ShowPlayerDialog(playerid, DIALOG_WEAPONS, DIALOG_STYLE_LIST, "武器", "AK47&#92;nM4&#92;n狙击枪", "选择", "关闭");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_PASSWORD:<br />
ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "登录", "请在下方输入密码登陆服务器:", "登录", "取消");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_TABLIST:<br />
ShowPlayerDialog(playerid, DIALOG_WEAPONS, DIALOG_STYLE_TABLIST, "武器商店", "沙鹰&#92;t&#36;5000&#92;t100&#92;n短管散弹枪&#92;t&#36;5000&#92;t100&#92;n手枪&#92;t&#36;1000&#92;t50", "购买", "取消");<br />
<br />
// 对话框样式示例: DIALOG_STYLE_TABLIST_HEADERS:<br />
ShowPlayerDialog(playerid, DIALOG_WEAPONS, DIALOG_STYLE_TABLIST_HEADERS, "武器商店", "武器&#92;t价格&#92;t弹药数量&#92;n沙鹰&#92;t&#36;5000&#92;t100&#92;n短管散弹枪&#92;t&#36;5000&#92;t100&#92;n手枪&#92;t&#36;1000&#92;t50", "购买", "取消");</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\n</code> 是换行符，在 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">DIALOG_STYLE_LIST</code> 里每个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">\n</code> 分隔一个选项。</blockquote>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">第三步：处理玩家的响应</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])<br />
{<br />
    // response  = 1 点了左边按钮<br />
    //         &nbsp;&nbsp;= 0 点了右边按钮或按了 ESC<br />
    // listitem  = 玩家选的是第几行（从 0 开始）<br />
    // inputtext = 玩家输入的文字<br />
<br />
    if (dialogid == DIALOG_RULES)<br />
    {<br />
        if (response) // 如果玩家点击了左边的按钮<br />
        {<br />
            SendClientMessage(playerid, COLOR_GREEN, "你点击了左边的按钮!");<br />
        }<br />
        else // 否则(玩家点击了右边的按钮或按下ESC键)<br />
        {<br />
            SendClientMessage(playerid, COLOR_GREEN, "你点击了右边的按钮!");<br />
        }<br />
        return 1; // 返回停止后续代码的执行<br />
    }<br />
    return 0;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">20. Pickup — 拾取物</h3><br />
<br />
Pickup 是放在地图上的<span style="font-weight: bold;" class="mycode_b">可触发拾取物</span>，玩家走触碰到之后会自动触发，不需要按键。  <br />
常用于：金币、道具、任务触发点、商店入口。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建 Pickup</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_pickupGold; &nbsp;&nbsp;// 保存 pickup 的 ID，响应时用来判断<br />
<br />
public OnGameModeInit()<br />
{<br />
    // CreatePickup(模型ID, 类型, X, Y, Z, 虚拟世界)<br />
    // 类型 2 = 拾取后消失，15 秒后重生<br />
    g_pickupGold = CreatePickup(1274, 2, 2009.8658, 1220.0293, 10.8206, -1);<br />
    //                          ↑模型 ↑类型 &nbsp;&nbsp;↑坐标                   &nbsp;&nbsp;↑-1=所有世界可见<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">常用模型 ID</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">模型 ID</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">外观</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1210</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">公文包</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1212</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">金钱</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1239</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">信息</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1240</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">爱心</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1273</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">绿色房子</td>
  </tr>
</table>
更多可查阅: <a href="https://open.mp/docs/scripting/resources/pickupids" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/pickupids</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">响应拾取事件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerPickUpPickup(playerid, pickupid)<br />
{<br />
    if(pickupid == g_pickupGold)<br />
    {<br />
        g_Gold[playerid] += 20;<br />
        SendClientMessage(playerid, COLOR_YELLOW, "捡到了金币！+20");<br />
        GameTextForPlayer(playerid, "~y~+20 Gold", 1500, 5);<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">Pickup 类型说明</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">类型值</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">行为</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">0</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">无特殊属性，不可被拾取</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">1</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">永久存在 仅允许脚本控制</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;">14</td>
    <td style="border:1px solid #ddd;padding:6px 10px;">仅限车辆拾取，触发检查点音效后消失</td>
  </tr>
</table>
更多类型可查阅: <a href="https://open.mp/docs/scripting/resources/pickuptypes" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/pickuptypes</a><br />
<br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">21. Checkpoint — 检查点</h3><br />
<br />
Checkpoint 是地图上的<span style="font-weight: bold;" class="mycode_b">红色发光圆柱区域</span>，玩家走进去自动触发。  <br />
常用于：任务目标点、区域进入触发、引导新玩家，每个玩家最多只能显示一个检查点。<br />
<br />
当玩家进入检查点时，会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerEnterCheckpoint</code> 回调<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">设置检查点</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 每个玩家同时只能有一个活动的 Checkpoint<br />
// SetPlayerCheckpoint(玩家ID, X, Y, Z, 检查点尺寸半径)<br />
SetPlayerCheckpoint(playerid, 1982.6150, -220.6680, -0.2432, 3.0);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">响应进入事件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerEnterCheckpoint(playerid)<br />
{<br />
    SendClientMessage(playerid, COLOR_GREEN, "到达目标地点！");<br />
<br />
    // 触发后通常需要清除，避免反复触发<br />
    DisablePlayerCheckpoint(playerid);<br />
<br />
    // 在这里做你想做的事，比如给与玩家金钱<br />
    GivePlayerMoney(playerid, 1000);<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">RaceCheckpoint — 比赛检查点</h4><br />
<br />
当玩家进入时，会调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerEnterRaceCheckPoint</code> 回调<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SetPlayerRaceCheckpoint(玩家ID, 类型, 当前X,Y,Z, 下一目标X,Y,Z, 半径)<br />
SetPlayerRaceCheckpoint(playerid, CP_TYPE_GROUND_NORMAL, 644.3091, 1767.0223, 4.9970, 650.6734, 1812.0367, 4.9970, 3.0);<br />
<br />
public OnPlayerEnterRaceCheckpoint(playerid)<br />
{<br />
    DisablePlayerRaceCheckpoint(playerid);<br />
    SendClientMessage(playerid, COLOR_GREEN, "到达！");<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">22. Vehicle — 载具</h3><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建载具</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// CreateVehicle(模型, X, Y, Z, 角度, 颜色1, 颜色2, 重生延迟秒)<br />
new vehicleid = CreateVehicle(411, 100.0, 200.0, 10.0, 90.0, -1, -1, 60);<br />
// -1 = 随机颜色，60 = 无人使用 60 秒后重生</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">让玩家进入载具</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// PutPlayerInVehicle(玩家ID, 载具ID, 座位)<br />
// 座位 0 = 驾驶座，1 = 副驾驶，2/3 = 后排<br />
PutPlayerInVehicle(playerid, vehicleid, 0);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">载具模型 ID</h4><br />
<br />
请查阅: <a href="https://open.mp/docs/scripting/resources/vehicleid" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/vehicleid</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">进出载具回调</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)<br />
{<br />
    // ispassenger: 0 = 驾驶座，1 = 乘客<br />
    if(!ispassenger)<br />
    {<br />
        SendClientMessage(playerid, COLOR_WHITE, "你正在进入载具的驾驶位。");<br />
    }<br />
    return 1;<br />
}<br />
<br />
public OnPlayerExitVehicle(playerid, vehicleid)<br />
{<br />
    SendClientMessage(playerid, COLOR_WHITE, "你正在离开载具");<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">23. Actor — NPC</h3><br />
<br />
Actor 是<span style="font-weight: bold;" class="mycode_b">站在世界里的静态 NPC 角色</span>，可以设置外观和动作动画，但不会移动，但功能有限<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建 Actor</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_ActorSmith; &nbsp;&nbsp;// 保存 actor ID<br />
<br />
public OnGameModeInit()<br />
{<br />
    // CreateActor(皮肤ID, X, Y, Z, 朝向角度)<br />
    g_ActorSmith = CreateActor(179, 316.1, -134.0, 999.6, 90.0);<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">给 Actor 播放动画</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// ApplyActorAnimation(actorID, 动画库, 动画名, 速度, 循环, lockX, lockY, 冻结, 时长)<br />
ApplyActorAnimation(g_ActorSmith, "DEALER", "shop_pay", 4.1, false, false, false, false, 0);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">玩家靠近时按键交互</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 工具函数：计算玩家到 Actor 的距离<br />
stock Float:DistToActor(playerid, actorid)<br />
{<br />
    new Float:px, Float:py, Float:pz;<br />
    new Float:ax, Float:ay, Float:az;<br />
    GetPlayerPos(playerid, px, py, pz);<br />
    GetActorPos(actorid, ax, ay, az);<br />
    return floatsqroot((px-ax)*(px-ax)+(py-ay)*(py-ay)+(pz-az)*(pz-az));<br />
}<br />
<br />
// 在按键回调里检测距离并触发对话<br />
public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)<br />
{<br />
    if(PRESSED(KEY_YES))<br />
    {<br />
        if(DistToActor(playerid, g_ActorSmith) &lt; 3.0)<br />
        {<br />
            ShowPlayerDialog(playerid, DIALOG_SMITH, DIALOG_STYLE_MSGBOX,<br />
                "[ 武器商人 ]",<br />
                "欢迎！我能为你提供精良的武器。",<br />
                "好的", ""<br />
            );<br />
        }<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">服务器关闭时清理</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnGameModeExit()<br />
{<br />
    DestroyActor(g_ActorSmith);<br />
    return 1;<br />
}</code></div></div><br />
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">24. Timer — 计时器</h3><br />
<br />
Timer 用于<span style="font-weight: bold;" class="mycode_b">延迟执行</span>或<span style="font-weight: bold;" class="mycode_b">定期执行</span>某个函数，是实现游戏事件、冷却时间、倒计时的基础工具。<br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">创建计时器</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 一次性：2000 毫秒（2 秒）后执行，false = 不重复<br />
SetTimer("MyFunction", 2000, false);<br />
<br />
// 重复：每 5000 毫秒（5 秒）执行一次，true = 重复<br />
new g_Timer = SetTimer("MyRepeatFunc", 5000, true);<br />
<br />
// 停止计时器（需要提前保存它的 ID）<br />
KillTimer(g_Timer);</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">带参数的计时器</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// SetTimerEx("函数名", 间隔ms, 是否重复, "参数格式", 参数值...)<br />
SetTimerEx("SendDelayedMsg", 3000, false, "i", playerid);<br />
<br />
// 对应函数必须先用 forward 声明<br />
forward SendDelayedMsg(playerid);<br />
public SendDelayedMsg(playerid)<br />
{<br />
    if(!IsPlayerConnected(playerid)) return 0;<br />
    GameTextForPlayer(playerid, "~w~Welcome to~n~~y~Island Town!", 3000, 3);<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">参数格式字符</h4><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
  <tr>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">格式符</th>
    <th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">含义</th>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">i</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">整数（int）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">f</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">浮点数（float）</td>
  </tr>
  <tr>
    <td style="border:1px solid #ddd;padding:6px 10px;"><code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">s</code></td>
    <td style="border:1px solid #ddd;padding:6px 10px;">字符串</td>
  </tr>
</table>
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">实际应用：每 60 秒播报随机事件</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new g_EventTimer;<br />
<br />
public OnGameModeInit()<br />
{<br />
    g_EventTimer = SetTimer("IslandEvent", 60000, true);<br />
    return 1;<br />
}<br />
<br />
public OnGameModeExit()<br />
{<br />
    KillTimer(g_EventTimer); &nbsp;&nbsp;// 服务器关闭时记得停止<br />
    return 1;<br />
}<br />
<br />
forward IslandEvent();<br />
public IslandEvent()<br />
{<br />
    switch(random(3))<br />
    {<br />
        case 0: SendClientMessageToAll(COLOR_ORANGE, "[小镇] 市集开放！来广场逛逛。");<br />
        case 1: SendClientMessageToAll(COLOR_RED,    "[小镇] 海湾发现海盗船！");<br />
        case 2: SendClientMessageToAll(COLOR_GREEN,  "[小镇] 今日好天气，渔获翻倍！");<br />
    }<br />
    return 1;<br />
}</code></div></div><br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意</span>：使用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">SetTimerEx</code> 的函数<span style="font-weight: bold;" class="mycode_b">必须</span>在使用前加 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">forward</code> 声明，否则编译会报错或运行异常。</blockquote>
<hr class="mycode_hr" />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">25. Keys — 按键检测</h3><br />
<br />
<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">OnPlayerKeyStateChange</code> 在玩家<span style="font-weight: bold;" class="mycode_b">按下或松开按键</span>时触发，用于实现交互操作。<br />
<br />
官方文档: <a href="https://open.mp/docs/scripting/callbacks/OnPlayerKeyStateChange" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/callbacks...tateChange</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础宏定义</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 在脚本顶部定义这两个宏，后面判断按键时更方便<br />
#define PRESSED(%0)  (((newkeys) &amp; (%0)) &amp;&amp; !((oldkeys) &amp; (%0)))<br />
#define RELEASED(%0) (!((newkeys) &amp; (%0)) &amp;&amp; ((oldkeys) &amp; (%0)))</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">基础用法</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)<br />
{<br />
    // PRESSED = 刚按下（本帧按着，上帧没按）<br />
    if(PRESSED(KEY_FIRE))<br />
    {<br />
        SendClientMessage(playerid, COLOR_WHITE, "你按了鼠标左键");<br />
    }<br />
<br />
    // RELEASED = 刚松开<br />
    if(RELEASED(KEY_FIRE))<br />
    {<br />
        SendClientMessage(playerid, COLOR_WHITE, "你松开了鼠标左键");<br />
    }<br />
<br />
    return 1;<br />
}</code></div></div><br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">按键常量</h4><br />
<br />
请查阅: <a href="https://open.mp/docs/scripting/resources/keys" target="_blank" rel="noopener" class="mycode_url">https://open.mp/docs/scripting/resources/keys</a><br />
<br />
<h4 style="font-size:1.15em;font-weight:bold;margin:12px 0 6px;">完整交互示例：按 Y键 与 NPC 对话</h4><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define PRESSED(%0) (((newkeys) &amp; (%0)) &amp;&amp; !((oldkeys) &amp; (%0)))<br />
<br />
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)<br />
{<br />
    if(PRESSED(KEY_YES))<br />
    {<br />
        // 检查玩家是否靠近铁匠 NPC<br />
        if(DistToActor(playerid, g_ActorSmith) &lt; 3.0)<br />
        {<br />
            ShowPlayerDialog(playerid, DIALOG_SMITH, DIALOG_STYLE_MSGBOX,<br />
                "[ 武器商人 ]",<br />
                "你好，旅人！需要武器吗？",<br />
                "需要", "不了"<br />
            );<br />
        }<br />
    }<br />
    return 1;<br />
}</code></div></div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[openmp/samp联机服务器插件开发 完全指南]]></title>
			<link>https://open-mp.cn/showthread.php?tid=13</link>
			<pubDate>Thu, 19 Mar 2026 22:28:53 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=13</guid>
			<description><![CDATA[<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">openmp/samp联机服务器插件开发 完全指南</span></span><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>从零开始，用 C++ 为 openmp 服务器开发自定义组件。<br />
<br />
本教程面向有 Pawn 脚本基础、想转 C++ 开发的 SAMP/openmp 服务器开发者。</blockquote>
<br />
本教程将教大家制作一个完整的查克拉系统简单插件实现<br />
<br />
为什么标题包含samp但是确实openmp类的教程，因为很多人搜索sa-mp，但sa-mp已经彻底消逝了，有许多遗留问题且不再维护更新，openmp是最优解，你应该使用openmp，而且它向下兼容samp（我指的是pawn层），开发过程基本一模一样<br />
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">目录</span><br />
<br />
<ol type="1" class="mycode_list"><li><a href="http://#1-环境搭建" target="_blank" rel="noopener" class="mycode_url">环境搭建</a><br />
</li>
<li><a href="http://#2-创建项目" target="_blank" rel="noopener" class="mycode_url">创建项目</a><br />
</li>
<li><a href="http://#3-最小可运行组件" target="_blank" rel="noopener" class="mycode_url">最小可运行组件</a><br />
</li>
<li><a href="http://#4-组件的生命周期" target="_blank" rel="noopener" class="mycode_url">组件的生命周期</a><br />
</li>
<li><a href="http://#5-创建自己的native函数" target="_blank" rel="noopener" class="mycode_url">创建自己的native函数</a><br />
</li>
<li><a href="http://#6-事件处理" target="_blank" rel="noopener" class="mycode_url">事件处理</a><br />
</li>
<li><a href="http://#7-玩家数据扩展" target="_blank" rel="noopener" class="mycode_url">玩家数据扩展</a><br />
</li>
<li><a href="http://#8-如何扫描amx的public" target="_blank" rel="noopener" class="mycode_url">如何扫描amx的public</a><br />
</li>
<li><a href="http://#9-完整示例" target="_blank" rel="noopener" class="mycode_url">完整示例</a><br />
</li>
</ol>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. 环境搭建</span><br />
<br />
这里将演示轻量级环境搭建，你只需要安装三样东西和 <a href="https://code.visualstudio.com/" target="_blank" rel="noopener" class="mycode_url">VSCode</a> 。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">1.1 安装工具</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Visual Studio Code</span>（代码编辑器）<br />
<br />
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener" class="mycode_url">https://code.visualstudio.com/</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Visual Studio Build Tools</span>（不是完整的 Visual Studio）<br />
<br />
这是微软的 C++ 编译器。你可以理解成pawn里的pawncc.exe，安装时只勾选「使用 C++ 的桌面开发」工作负载，其他全不选。<br />
<br />
下载：https://visualstudio.microsoft.com/visual-cpp-build-tools/<br />
<br />
<span style="font-weight: bold;" class="mycode_b">CMake</span><br />
<br />
构建系统，管理编译流程。<br />
<br />
下载：https://cmake.org/download/<br />
<br />
推荐下载 ZIP 版，解压到固定目录（如 D:\tools\cmake\），然后把 D:\tools\cmake\bin 加入系统 PATH 环境变量。干净利落，不想用了直接删文件夹。<br />
<br />
如果选 Installer 版，安装时勾选 "Add CMake to the system PATH"。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Git</span><br />
<br />
用于完整获取 open.mp SDK，以及后续各种开发所需的资源。<br />
<br />
下载：https://git-scm.com<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">1.2 VSCode 扩展</span><br />
<br />
打开 VSCode，安装以下扩展：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">C/C++</span>（Microsoft）--- 代码提示、语法高亮、调试<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">CMake Tools</span>（Microsoft）--- CMake 项目集成，一键编译<br />
</li>
</ul>
<br />
<span style="text-decoration: underline;" class="mycode_u">1.3 验证安装</span><br />
<br />
任意终端(比如 cmd)输入以下指令逐个验证是否安装配置成功：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>cmake --version    # 应该显示版本号<br />
git --version      # 应该显示版本号</code></div></div><br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. 创建项目</span><br />
<br />
<span style="text-decoration: underline;" class="mycode_u">2.1 初始化目录</span><br />
<br />
选一个你喜欢的位置，创建项目：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>新建文件夹 my-component<br />
在根目录新建 src 的文件夹<br />
在根目录新建 lib 的文件夹</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">2.2 添加 open.mp SDK 和相关依赖</span><br />
<br />
在lib文件夹内点击鼠标右键，选择 Open Git Bash here 并执行以下命令<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>git clone --recursive https://github.com/openmultiplayer/open.mp-sdk sdk<br />
git clone --recursive https://github.com/openmultiplayer/pawn-natives<br />
git clone --recursive https://github.com/openmultiplayer/compiler pawn</code></div></div><br />
等待获取完成，这会在lib文件夹内创建 sdk/ pawn/ pawn-natives/目录。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">2.3 创建 CMakeLists.txt</span><br />
<br />
在项目根目录创建 CMakeLists.txt 并复制以下内容粘贴进去：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>cmake_minimum_required(VERSION 3.19)<br />
project(my-component)<br />
<br />
set(CMAKE_CXX_STANDARD 17)<br />
set(CMAKE_CXX_STANDARD_REQUIRED ON)<br />
<br />
add_subdirectory(lib/sdk)<br />
<br />
add_library(&#36;{PROJECT_NAME} SHARED<br />
    src/main.cpp<br />
)<br />
<br />
# 解决库的兼容性问题<br />
add_definitions(<br />
    -DHAVE_STDINT_H=1<br />
    -DGLM_FORCE_SSE2=1<br />
    -DGLM_FORCE_QUAT_DATA_WXYZ=1<br />
    -DNOMINMAX=1<br />
    -Dnssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_NONSTD<br />
    -Dspan_CONFIG_SELECT_SPAN=span_SPAN_NONSTD<br />
    -DPAWN_CELL_SIZE=32 <br />
)<br />
<br />
target_include_directories(&#36;{PROJECT_NAME} PRIVATE<br />
    lib/<br />
    lib/pawn/source<br />
    lib/pawn/source/linux<br />
    lib/pawn-natives<br />
)<br />
<br />
target_link_libraries(&#36;{PROJECT_NAME} PRIVATE<br />
    OMP-SDK<br />
)</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">2.4 项目结构</span><br />
<br />
最终你的目录应该长这样：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>my-component/<br />
├── CMakeLists.txt      ← 构建配置<br />
├── lib/<br />
    ├── sdk/            ← open.mp SDK<br />
    ├── pawn-natives/ &nbsp;&nbsp;← 用于快速定义 PAWN 原生函数<br />
    └── pawn/         &nbsp;&nbsp;← 关联库<br />
└── src/<br />
    └── main.cpp        ← 你的代码</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">2.5 配置 VSCode</span><br />
<br />
用 VSCode 打开 my-component 文件夹。CMake Tools 扩展会自动检测到 CMakeLists.txt。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">选择编译器（Kit）：</span><br />
<br />
<ol type="1" class="mycode_list"><li>按 Ctrl+Shift+P，输入 CMake: Select a Kit<br />
</li>
<li>选择 Visual Studio 生成工具 2026 Release x86，如果没有这个选项，选择[扫描工具包]即可搜索。<br />
</li>
</ol>
<br />
<span style="font-weight: bold;" class="mycode_b">选择构建类型：</span><br />
<br />
<ol type="1" class="mycode_list"><li>按 Ctrl+Shift+P，输入 CMake: Select Variant<br />
</li>
<li>开发时选 Debug，发布时选 Release<br />
</li>
</ol>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意：</span> 如果你使用的是 CMake 4.x，可能会遇到旧版依赖的兼容性警告。在项目根目录创建 .vscode/settings.json：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>{<br />
    "cmake.configureArgs": [<br />
        "-DCMAKE_POLICY_VERSION_MINIMUM=3.10"<br />
    ]<br />
}</code></div></div></blockquote>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. 最小可运行组件</span><br />
<br />
创建 src/main.cpp，写入以下代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
<br />
class MyComponent final : public IComponent<br />
{<br />
private:<br />
    ICore* core_ = nullptr;<br />
<br />
public:<br />
    // 每个组件必须有一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成一个替换下面的ID<br />
    PROVIDE_UID(0x123456789ABCDEF0);<br />
<br />
    // 组件名称，显示在服务端加载日志里<br />
    StringView componentName() const override<br />
    {<br />
        return "MyComponent";<br />
    }<br />
    // 版本号<br />
    SemanticVersion componentVersion() const override<br />
    {<br />
        return SemanticVersion(1, 0, 0, 0);<br />
    }<br />
    // 组件加载时调用<br />
    void onLoad(ICore* c) override<br />
    {<br />
        core_ = c;<br />
        core_-&gt;printLn("Hello World!");<br />
    }<br />
<br />
    // 其他组件初始化完成后调用<br />
    void onInit(IComponentList* components) override {}<br />
<br />
    // 所有组件和脚本都就绪后调用<br />
    void onReady() override {}<br />
<br />
    // 其他组件卸载时调用<br />
    void onFree(IComponent* component) override {}<br />
<br />
    // 组件自身被释放<br />
    void free() override { delete this; }<br />
<br />
    // GMX（换图）时调用<br />
    void reset() override {}<br />
};<br />
<br />
// 组件入口点 —— 服务端通过这个宏发现并加载你的组件<br />
COMPONENT_ENTRY_POINT()<br />
{<br />
    return new MyComponent();<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">编译：</span><br />
<br />
按 F7（或 Ctrl+Shift+P → CMake: Build）。编译成功后，在 build/ 目录下会生成 my-component.dll。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">测试：</span><br />
<br />
把 .dll 复制到 open.mp 服务端的 components/ 目录，启动服务端，你应该能在控制台看到：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Loading component MyComponent.dll<br />
        Successfully loaded component MyComponent (1.0.0.0) with UID 123456789abcdef0<br />
<br />
Hello World!</code></div></div><br />
恭喜，你的第一个组件跑起来了。<br />
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. 组件的生命周期</span><br />
<br />
组件的函数按固定顺序调用。理解这个顺序非常重要：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>服务端启动<br />
  │<br />
  ├── onLoad(ICore*)         &nbsp;&nbsp;← 拿到核心接口<br />
  │<br />
  ├── onInit(IComponentList*)  ← 查询其他组件（如 IPawnComponent）<br />
  │<br />
  ├── onAmxLoad(IPawnScript&amp;)  ← Pawn 脚本加载，扫描 public 函数<br />
  │<br />
  ├── onReady()                ← 一切就绪，可以开始工作<br />
  │<br />
  │ &nbsp;&nbsp;... 服务器运行中 ...<br />
  │<br />
  ├── onAmxUnload(IPawnScript&amp;) ← Pawn 脚本卸载，清理相关数据<br />
  │<br />
  ├── onFree(IComponent*)      ← 组件卸载时<br />
  │<br />
  └── free()                 &nbsp;&nbsp;← 释放自身</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">关键点：</span><br />
<ul class="mycode_list"><li>onLoad 里只保存 ICore* 指针，不要访问其他组件（它们可能还没加载）<br />
</li>
<li>onInit 里通过 components-&gt;queryComponent&lt;IPawnComponent&gt;() 获取 Pawn 组件<br />
</li>
<li>onAmxLoad 是注册 native 函数和扫描 public 的地方<br />
</li>
</ul>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. 创建自己的native函数</span><br />
<br />
Native 函数让 Pawn 脚本能够调用你的 C++ 代码。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">5.1 基本概念</span><br />
<br />
在 Pawn 里写：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>native MyAdd(a, b);<br />
<br />
public OnGameModeInit()<br />
{<br />
    new a = 10, b = 20;<br />
    new result = MyAdd(a, b);<br />
    printf("%d + %d = %d", a, b, result);<br />
    return 1;<br />
}</code></div></div><br />
在 C++ 里你需要实现函数并注册到 AMX。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">5.2 使用 SCRIPT_API 宏（推荐）</span><br />
<br />
open.mp 提供了 SCRIPT_API 宏，自动处理参数的类型转换：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
#include &lt;Server/Components/Pawn/pawn.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_natives.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_impl.hpp&gt;<br />
<br />
SCRIPT_API(MyAdd, int(int a, int b))<br />
{<br />
    return a + b;<br />
}</code></div></div><br />
SCRIPT_API 的参数含义： - 第一个参数：函数名，必须和 Pawn 里的 native 名称完全一致 - 第二个参数：返回类型(参数列表)<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">5.3 注册时机</span><br />
<br />
在组件的 onAmxLoad 里调用 pawn_natives::AmxLoad，它会自动把所有 SCRIPT_API 定义的函数注册到 AMX：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>void onAmxLoad(IPawnScript&amp; script) override<br />
{<br />
    pawn_natives::AmxLoad(script.GetAMX());<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">5.4 完整的组件 + Native 示例</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
#include &lt;Server/Components/Pawn/pawn.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_natives.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_impl.hpp&gt;<br />
<br />
class MyComponent final : public IComponent, public PawnEventHandler<br />
{<br />
private:<br />
    ICore* core_ = nullptr;<br />
    IPawnComponent* pawn_ = nullptr;<br />
<br />
public:<br />
    // 每个组件必须有一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成一个替换下面的ID<br />
    PROVIDE_UID(0x123456789ABCDEF0);<br />
<br />
    StringView componentName() const override { return "MyComponent"; }<br />
    SemanticVersion componentVersion() const override { return SemanticVersion(1, 0, 0, 0); }<br />
<br />
    void onLoad(ICore* c) override<br />
    {<br />
        core_ = c;<br />
<br />
        // 初始化 AMX 查找表<br />
        setAmxLookups(core_);  <br />
    }<br />
<br />
    void onInit(IComponentList* components) override<br />
    {<br />
        pawn_ = components-&gt;queryComponent&lt;IPawnComponent&gt;();<br />
        if (pawn_)<br />
        {<br />
            setAmxFunctions(pawn_-&gt;getAmxFunctions());<br />
            setAmxLookups(components);<br />
            pawn_-&gt;getEventDispatcher().addEventHandler(this);<br />
        }<br />
    }<br />
<br />
    void onAmxLoad(IPawnScript&amp; script) override<br />
    {<br />
        pawn_natives::AmxLoad(script.GetAMX());<br />
    }<br />
<br />
    void onAmxUnload(IPawnScript&amp; script) override {}<br />
    void onReady() override {}<br />
    void onFree(IComponent* component) override {}<br />
    void free() override { delete this; }<br />
    void reset() override {}<br />
<br />
    ~MyComponent()<br />
    {<br />
        if (pawn_) pawn_-&gt;getEventDispatcher().removeEventHandler(this);<br />
    }<br />
};<br />
<br />
COMPONENT_ENTRY_POINT()<br />
{<br />
    return new MyComponent();<br />
}<br />
<br />
SCRIPT_API(MyAdd, int(int a, int b))<br />
{<br />
    return a + b;<br />
}</code></div></div><br />
重新编译插件并开启服务器，你就可以在控制台看到 10 + 20 = 30<br />
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. 事件处理</span><br />
<br />
open.mp 通过 EventHandler 接口分发事件。你的组件实现对应接口，注册到分发器，就能收到事件。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">6.1 常见的 EventHandler</span><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
<tr><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">接口</th><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">事件</th></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">PlayerConnectEventHandler</td><td style="border:1px solid #ddd;padding:6px 10px;">玩家连接/断开</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">PlayerTextEventHandler</td><td style="border:1px solid #ddd;padding:6px 10px;">玩家聊天/命令</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">PawnEventHandler</td><td style="border:1px solid #ddd;padding:6px 10px;">AMX 脚本加载/卸载</td></tr>
</table>
<br />
<span style="text-decoration: underline;" class="mycode_u">6.2 示例：监听玩家连接</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>class MyComponent final<br />
    : public IComponent<br />
    , public PawnEventHandler<br />
    , public PlayerConnectEventHandler  // 实现连接事件接口<br />
{<br />
    // ... 省略其他成员 ...<br />
<br />
    void onInit(IComponentList* components) override<br />
    {<br />
        // 注册 Pawn 事件<br />
        pawn_ = components-&gt;queryComponent&lt;IPawnComponent&gt;();<br />
        if (pawn_)<br />
        {<br />
            setAmxFunctions(pawn_-&gt;getAmxFunctions());<br />
            setAmxLookups(components);<br />
            pawn_-&gt;getEventDispatcher().addEventHandler(this);<br />
        }<br />
<br />
        // 注册玩家连接事件<br />
        core_-&gt;getPlayers().getPlayerConnectDispatcher().addEventHandler(this);<br />
    }<br />
    // 析构函数里注销<br />
    ~MyComponent()<br />
    {<br />
        if (pawn_)  pawn_-&gt;getEventDispatcher().removeEventHandler(this);<br />
        if (core_) core_-&gt;getPlayers().getPlayerConnectDispatcher().removeEventHandler(this);<br />
    }<br />
    // 玩家连接时调用<br />
    void onPlayerConnect(IPlayer&amp; player) override<br />
    {<br />
        core_-&gt;printLn("玩家 %d 进入了服务器!", player.getID());<br />
    }<br />
};</code></div></div><br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. 玩家数据扩展</span><br />
<br />
在 Pawn 里，你可能习惯用全局数组存储玩家数据：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new pScore[MAX_PLAYERS];<br />
new pLevel[MAX_PLAYERS];<br />
new bool:pLoggedIn[MAX_PLAYERS];</code></div></div><br />
在 open.mp 的 C++ 组件里，对应的机制是 <span style="font-weight: bold;" class="mycode_b">IExtension</span>。它把数据"挂"在玩家对象上。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">7.1 定义数据结构</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>struct PlayerEnergy final : IExtension<br />
{<br />
    // 每个 Extension 需要一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成<br />
    PROVIDE_EXT_UID(0xABCDEF1234567890);<br />
<br />
    // 你的自定义数据<br />
    int energy = 100;<br />
    int maxEnergy = 100;<br />
<br />
    void freeExtension() override { delete this; }<br />
    void reset() override<br />
    {<br />
        energy = 100;<br />
        maxEnergy = 100;<br />
    }<br />
};</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">7.2 在玩家连接时挂载</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>void onPlayerConnect(IPlayer&amp; player) override<br />
{<br />
    // 创建 PlayerEnergy 实例并挂到玩家身上<br />
    // 第二个参数 true 表示玩家断开时自动调用 freeExtension<br />
    player.addExtension(new PlayerEnergy(), true);<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">7.3 操作数据</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>auto* playerData = queryExtension&lt;PlayerEnergy&gt;(player);<br />
if (playerData)<br />
{<br />
    playerData-&gt;energy += 100;<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">7.4 为什么不用 std::unordered_map&lt;int, PlayerEnergy&gt;？</span><br />
<br />
你可以用，但 IExtension 有几个优势：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">生命周期自动管理</span>：玩家断开时 freeExtension 自动调用，不会忘记清理<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">GMX 自动重置</span>：换图时 reset 自动调用<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">数据跟着对象走</span>：不需要传 playerid 再去查 map，直接从 IPlayer&amp; 取<br />
</li>
</ul>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. 如何扫描amx的public</span><br />
<br />
这是反方向的交互：你的 C++ 组件主动调用 Pawn 脚本里定义的 public 函数。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">8.1 理解 AMX 虚拟机</span><br />
<br />
Pawn 脚本编译后是 .amx 文件，由 AMX 虚拟机执行。每个 public 函数在 AMX 里有一个编号（index）。要调用它，你需要：<br />
<br />
<ol type="1" class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">找到编号</span> --- 用 amx_FindPublic 或在 onAmxLoad 时扫描<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">压入参数</span> --- 用 amx_Push（整数）或 amx_PushString（字符串）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">执行</span> --- 用 amx_Exec<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">清理</span> --- 用 amx_Release 释放字符串内存<br />
</li>
</ol>
<br />
<span style="text-decoration: underline;" class="mycode_u">8.2 扫描 Public 函数</span><br />
<br />
假设 Pawn 里有：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward OnPlayerEnergyChange(playerid, oldEnergy, newEnergy);<br />
public OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
{<br />
    printf("玩家 %d 的查克拉发生了变化: %d -&gt; %d", playerid, oldEnergy, newEnergy);<br />
}</code></div></div><br />
在 onAmxLoad 时扫描它：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 保存 AMX 指针和 public index<br />
struct ScriptInfo<br />
{<br />
    AMX* amx = nullptr;<br />
    int onEnergyChange = -1;  // -1 表示该脚本里没有这个函数<br />
};<br />
<br />
std::vector&lt;ScriptInfo&gt; scripts_;<br />
<br />
void onAmxLoad(IPawnScript&amp; script) override<br />
{<br />
    pawn_natives::AmxLoad(script.GetAMX());<br />
<br />
    AMX* amx = script.GetAMX();<br />
    ScriptInfo info;<br />
    info.amx = amx;<br />
<br />
    // 方法一：按名称精确查找<br />
    amx_FindPublic(amx, "OnPlayerEnergyChange", &amp;info.onEnergyChange);<br />
    // 如果找到，info.onEnergyChange &gt;= 0<br />
    // 如果没找到，info.onEnergyChange 保持 -1<br />
<br />
    scripts_.push_back(info);<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">8.3 调用 Public 函数</span><br />
<br />
找到 index 后，就可以调用了。<span style="font-weight: bold;" class="mycode_b">AMX 是栈式虚拟机，参数要倒序压入。</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">调用无参数函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn 侧<br />
forward OnSomethingHappen();<br />
public OnSomethingHappen()<br />
{<br />
    print("damn!");<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// C++ 侧<br />
void callOnSomethingHappen(AMX* amx, int index)<br />
{<br />
    cell returnValue;<br />
    amx_Exec(amx, &amp;returnValue, index);<br />
    // returnValue 是 Pawn 函数的返回值<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">调用带整数参数的函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn 侧<br />
forward OnPlayerEnergyChange(playerid, oldEnergy, newEnergy);<br />
public OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
{<br />
    printf("玩家 %d 的查克拉发生了变化: %d -&gt; %d", playerid, oldEnergy, newEnergy);<br />
    return 1;<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// C++ 侧<br />
void callOnPlayerEnergyChange(AMX* amx, int index, int playerid, int oldEnergy, int newEnergy)<br />
{<br />
    // Pawn: OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
    // 倒序压栈<br />
    amx_Push(amx, newEnergy);<br />
    amx_Push(amx, oldEnergy);<br />
    amx_Push(amx, playerid);<br />
<br />
    cell returnValue;<br />
    amx_Exec(amx, &amp;returnValue, index);<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">调用带字符串参数的函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn 侧<br />
forward OnPlayerMessage(playerid, const message[]);<br />
public OnPlayerMessage(playerid, const message[])<br />
{<br />
    printf("Player %d: %s", playerid, message);<br />
    return 1;<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// C++ 侧<br />
void callMessage(AMX* amx, int index, int playerid, const char* message)<br />
{<br />
    cell addr_message;<br />
    amx_PushString(amx, &amp;addr_message, nullptr, message, 0, 0);<br />
    amx_Push(amx, playerid);<br />
<br />
    cell retval;<br />
    amx_Exec(amx, &amp;retval, index);<br />
<br />
    // 必须释放 addr_message 不然会导致内存泄漏<br />
    amx_Release(amx, addr_message);<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">8.4 AMX API 速查表</span><br />
<br />
可查阅：https://open.mp/docs/tutorials/PluginDevelopmentGuide#amx-functions<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
<tr><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">函数</th><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">用途</th></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_NumPublics(amx, &amp;count)</td><td style="border:1px solid #ddd;padding:6px 10px;">获取 public 函数数量</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_GetPublic(amx, index, name)</td><td style="border:1px solid #ddd;padding:6px 10px;">按 index 获取函数名</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_FindPublic(amx, name, &amp;index)</td><td style="border:1px solid #ddd;padding:6px 10px;">按名称查找 index</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_Push(amx, value)</td><td style="border:1px solid #ddd;padding:6px 10px;">压入整数参数</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_PushString(amx, &amp;addr, nullptr, str, 0, 0)</td><td style="border:1px solid #ddd;padding:6px 10px;">压入字符串参数</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_Exec(amx, &amp;retval, index)</td><td style="border:1px solid #ddd;padding:6px 10px;">执行 public 函数</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_Release(amx, addr)</td><td style="border:1px solid #ddd;padding:6px 10px;">释放 PushString 分配的内存</td></tr>
</table>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">9. 完整示例</span><br />
<br />
下面是一个完整的组件，包含上述所有概念。功能很简单：追踪玩家的"查克拉"，提供 native 函数给 Pawn 操作，并在查克拉变化时回调 Pawn。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">9.1 C++ 组件（src/main.cpp）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
#include &lt;Server/Components/Pawn/pawn.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_natives.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_impl.hpp&gt;<br />
<br />
#include &lt;vector&gt;<br />
#include &lt;string&gt;<br />
<br />
// 玩家数据扩展(查克拉)<br />
struct PlayerEnergy final : IExtension<br />
{<br />
    // 每个组件必须有一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成一个替换下面的ID<br />
    PROVIDE_EXT_UID(0x1A2B3C4D5E6F7890);<br />
<br />
    int energy = 100;<br />
    int maxEnergy = 100;<br />
<br />
    void freeExtension() override { delete this; }<br />
    void reset() override<br />
    {<br />
        energy = 100;<br />
        maxEnergy = 100;<br />
    }<br />
};<br />
<br />
// 组件主类<br />
class EnergyComponent final<br />
    : public IComponent<br />
    , public PawnEventHandler<br />
    , public PlayerConnectEventHandler<br />
{<br />
private:<br />
    ICore* core_ = nullptr;<br />
    IPawnComponent* pawn_ = nullptr;<br />
<br />
    // 保存 AMX 脚本中 OnPlayerEnergyChange 的 index<br />
    struct ScriptInfo<br />
    {<br />
        AMX* amx = nullptr;<br />
        int onEnergyChange = -1;<br />
    };<br />
    std::vector&lt;ScriptInfo&gt; scripts_;<br />
<br />
public:<br />
    PROVIDE_UID(0x9F8E7D6C5B4A3210);<br />
<br />
    StringView componentName() const override { return "EnergySystem"; }<br />
    SemanticVersion componentVersion() const override { return SemanticVersion(1, 0, 0, 0); }<br />
<br />
    void onLoad(ICore* c) override<br />
    {<br />
        core_ = c;<br />
        setAmxLookups(core_);<br />
        core_-&gt;printLn("[查克拉插件] 查克拉系统已加载.");<br />
    }<br />
<br />
    void onInit(IComponentList* components) override<br />
    {<br />
        pawn_ = components-&gt;queryComponent&lt;IPawnComponent&gt;();<br />
        if (pawn_)<br />
        {<br />
            setAmxFunctions(pawn_-&gt;getAmxFunctions());<br />
            setAmxLookups(components);<br />
            pawn_-&gt;getEventDispatcher().addEventHandler(this);<br />
        }<br />
        core_-&gt;getPlayers().getPlayerConnectDispatcher().addEventHandler(this);<br />
    }<br />
<br />
    // Pawn 事件 <br />
    void onAmxLoad(IPawnScript&amp; script) override<br />
    {<br />
        pawn_natives::AmxLoad(script.GetAMX());<br />
<br />
        // 扫描 Pawn 脚本中的回调函数<br />
        AMX* amx = script.GetAMX();<br />
        ScriptInfo info;<br />
        info.amx = amx;<br />
        amx_FindPublic(amx, "OnPlayerEnergyChange", &amp;info.onEnergyChange);<br />
        scripts_.push_back(info);<br />
    }<br />
<br />
    void onAmxUnload(IPawnScript&amp; script) override<br />
    {<br />
        AMX* amx = script.GetAMX();<br />
        scripts_.erase(<br />
            std::remove_if(scripts_.begin(), scripts_.end(), [amx](const ScriptInfo&amp; s) { return s.amx == amx; }), scripts_.end());<br />
    }<br />
<br />
    // 玩家事件 <br />
    void onPlayerConnect(IPlayer&amp; player) override<br />
    {<br />
        player.addExtension(new PlayerEnergy(), true);<br />
    }<br />
<br />
    // C++ 调用 Pawn 回调 <br />
    void callOnPlayerEnergyChange(int playerid, int oldEnergy, int newEnergy)<br />
    {<br />
        for (auto&amp; s : scripts_)<br />
        {<br />
            if (s.onEnergyChange &lt; 0)<br />
                continue;<br />
<br />
            // Pawn: OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
            // 倒序压栈<br />
            amx_Push(s.amx, newEnergy);<br />
            amx_Push(s.amx, oldEnergy);<br />
            amx_Push(s.amx, playerid);<br />
<br />
            cell retval;<br />
            amx_Exec(s.amx, &amp;retval, s.onEnergyChange);<br />
        }<br />
    }<br />
<br />
    // 生命周期 <br />
    void onReady() override {}<br />
    void onFree(IComponent* component) override<br />
    {<br />
        if (component == pawn_)<br />
        {<br />
            pawn_ = nullptr;<br />
            setAmxFunctions();<br />
            setAmxLookups();<br />
        }<br />
    }<br />
    void free() override { delete this; }<br />
    void reset() override {}<br />
<br />
    ~EnergyComponent()<br />
    {<br />
        if (pawn_) pawn_-&gt;getEventDispatcher().removeEventHandler(this);<br />
        if (core_) core_-&gt;getPlayers().getPlayerConnectDispatcher().removeEventHandler(this);<br />
    }<br />
};<br />
<br />
// 全局指针，给 SCRIPT_API 用<br />
static EnergyComponent* gComponent = nullptr;<br />
<br />
COMPONENT_ENTRY_POINT()<br />
{<br />
    gComponent = new EnergyComponent();<br />
    return gComponent;<br />
}<br />
<br />
// Native 函数<br />
// native GetPlayerEnergy(playerid);<br />
SCRIPT_API(GetPlayerEnergy, int(IPlayer&amp; player))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    return data ? data-&gt;energy : 0;<br />
}<br />
<br />
// native SetPlayerEnergy(playerid, energy);<br />
SCRIPT_API(SetPlayerEnergy, bool(IPlayer&amp; player, int energy))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    if (!data)<br />
        return false;<br />
<br />
    int oldEnergy = data-&gt;energy;<br />
    data-&gt;energy = (energy &gt; data-&gt;maxEnergy) ? data-&gt;maxEnergy : energy;<br />
<br />
    // 触发 Pawn 回调<br />
    if (data-&gt;energy != oldEnergy &amp;&amp; gComponent)<br />
        gComponent-&gt;callOnPlayerEnergyChange(player.getID(), oldEnergy, data-&gt;energy);<br />
<br />
    return true;<br />
}<br />
<br />
// native GetPlayerMaxEnergy(playerid);<br />
SCRIPT_API(GetPlayerMaxEnergy, int(IPlayer&amp; player))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    return data ? data-&gt;maxEnergy : 0;<br />
}<br />
<br />
// native SetPlayerMaxEnergy(playerid, maxEnergy);<br />
SCRIPT_API(SetPlayerMaxEnergy, bool(IPlayer&amp; player, int maxEnergy))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    if (!data)<br />
        return false;<br />
<br />
    data-&gt;maxEnergy = maxEnergy;<br />
    if (data-&gt;energy &gt; data-&gt;maxEnergy)<br />
        data-&gt;energy = data-&gt;maxEnergy;<br />
<br />
    return true;<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">9.2 Pawn Include 文件（energy.inc）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数声明<br />
native GetPlayerEnergy(playerid);<br />
native SetPlayerEnergy(playerid, energy);<br />
native GetPlayerMaxEnergy(playerid);<br />
native SetPlayerMaxEnergy(playerid, maxEnergy);<br />
<br />
// 回调声明<br />
forward OnPlayerEnergyChange(playerid, oldEnergy, newEnergy);</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">9.3 Pawn 测试脚本</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
#include "energy.inc"<br />
<br />
main() {}<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
    // 连接时默认 energy = 100<br />
    new energy = GetPlayerEnergy(playerid);<br />
    printf("[查克拉系统] Player %d 进入了服务器, 查克拉 = %d", playerid, energy);<br />
<br />
    // 设置为 50，会触发 OnPlayerEnergyChange<br />
    SetPlayerEnergy(playerid, 50);<br />
<br />
    return 1;<br />
}<br />
<br />
// C++ 组件在查克拉变化时回调这个函数<br />
public OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
{<br />
    printf("[回调] 玩家 %d 的查克拉发生了变化: %d -&gt; %d", playerid, oldEnergy, newEnergy);<br />
    return 1;<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">9.4 数据流向图</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>玩家连接<br />
  │<br />
  ├─ open.mp 触发 onPlayerConnect<br />
  │ &nbsp;&nbsp;└─ C++ 创建 PlayerEnergy, 挂到玩家对象上<br />
  │<br />
  ├─ Pawn OnPlayerConnect 被调用<br />
  │ &nbsp;&nbsp;└─ 调用 native SetPlayerEnergy(playerid, 50)<br />
  │        │<br />
  │        ├─ SCRIPT_API 自动解析 playerid → IPlayer&amp;<br />
  │        ├─ queryExtension&lt;PlayerEnergy&gt;(player) 取出数据<br />
  │        ├─ 修改 energy: 100 → 50<br />
  │        └─ callOnPlayerEnergyChange(playerid, 100, 50)<br />
  │           &nbsp;&nbsp;│<br />
  │           &nbsp;&nbsp;├─ amx_Push(amx, 50)       &nbsp;&nbsp;← newEnergy<br />
  │           &nbsp;&nbsp;├─ amx_Push(amx, 100)        ← oldEnergy<br />
  │           &nbsp;&nbsp;├─ amx_Push(amx, playerid)<br />
  │           &nbsp;&nbsp;└─ amx_Exec → 调用 Pawn 的 OnPlayerEnergyChange</code></div></div><br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">附录：资源</span><br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">c++学习网站</span>: <a href="https://www.w3school.com.cn/cpp/cpp_reference.asp" target="_blank" rel="noopener" class="mycode_url">https://www.w3school.com.cn/cpp/cpp_reference.asp</a><br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp SDK 仓库</span>：https://github.com/openmultiplayer/open.mp-sdk<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp 组件模板示例</span>：https://github.com/openmultiplayer/pawn-template<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp 完整组件模板示例</span>：https://github.com/openmultiplayer/full-template<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">使用组件实现的gamemode示例</span>：https://github.com/openmultiplayer/rivershell-cpp<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">UID 生成器</span>：https://open.mp/uid<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp 官方文档</span>：https://www.open.mp/docs<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">amx相关函数说明文档</span>：https://open.mp/docs/tutorials/PluginDevelopmentGuide#amx-functions<br />
</li>
</ul>
<br />
* * *]]></description>
			<content:encoded><![CDATA[<span style="text-decoration: underline;" class="mycode_u"><span style="font-weight: bold;" class="mycode_b">openmp/samp联机服务器插件开发 完全指南</span></span><br />
<br />
<blockquote class="mycode_quote"><cite>引用:</cite>从零开始，用 C++ 为 openmp 服务器开发自定义组件。<br />
<br />
本教程面向有 Pawn 脚本基础、想转 C++ 开发的 SAMP/openmp 服务器开发者。</blockquote>
<br />
本教程将教大家制作一个完整的查克拉系统简单插件实现<br />
<br />
为什么标题包含samp但是确实openmp类的教程，因为很多人搜索sa-mp，但sa-mp已经彻底消逝了，有许多遗留问题且不再维护更新，openmp是最优解，你应该使用openmp，而且它向下兼容samp（我指的是pawn层），开发过程基本一模一样<br />
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">目录</span><br />
<br />
<ol type="1" class="mycode_list"><li><a href="http://#1-环境搭建" target="_blank" rel="noopener" class="mycode_url">环境搭建</a><br />
</li>
<li><a href="http://#2-创建项目" target="_blank" rel="noopener" class="mycode_url">创建项目</a><br />
</li>
<li><a href="http://#3-最小可运行组件" target="_blank" rel="noopener" class="mycode_url">最小可运行组件</a><br />
</li>
<li><a href="http://#4-组件的生命周期" target="_blank" rel="noopener" class="mycode_url">组件的生命周期</a><br />
</li>
<li><a href="http://#5-创建自己的native函数" target="_blank" rel="noopener" class="mycode_url">创建自己的native函数</a><br />
</li>
<li><a href="http://#6-事件处理" target="_blank" rel="noopener" class="mycode_url">事件处理</a><br />
</li>
<li><a href="http://#7-玩家数据扩展" target="_blank" rel="noopener" class="mycode_url">玩家数据扩展</a><br />
</li>
<li><a href="http://#8-如何扫描amx的public" target="_blank" rel="noopener" class="mycode_url">如何扫描amx的public</a><br />
</li>
<li><a href="http://#9-完整示例" target="_blank" rel="noopener" class="mycode_url">完整示例</a><br />
</li>
</ol>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. 环境搭建</span><br />
<br />
这里将演示轻量级环境搭建，你只需要安装三样东西和 <a href="https://code.visualstudio.com/" target="_blank" rel="noopener" class="mycode_url">VSCode</a> 。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">1.1 安装工具</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Visual Studio Code</span>（代码编辑器）<br />
<br />
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener" class="mycode_url">https://code.visualstudio.com/</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Visual Studio Build Tools</span>（不是完整的 Visual Studio）<br />
<br />
这是微软的 C++ 编译器。你可以理解成pawn里的pawncc.exe，安装时只勾选「使用 C++ 的桌面开发」工作负载，其他全不选。<br />
<br />
下载：https://visualstudio.microsoft.com/visual-cpp-build-tools/<br />
<br />
<span style="font-weight: bold;" class="mycode_b">CMake</span><br />
<br />
构建系统，管理编译流程。<br />
<br />
下载：https://cmake.org/download/<br />
<br />
推荐下载 ZIP 版，解压到固定目录（如 D:\tools\cmake\），然后把 D:\tools\cmake\bin 加入系统 PATH 环境变量。干净利落，不想用了直接删文件夹。<br />
<br />
如果选 Installer 版，安装时勾选 "Add CMake to the system PATH"。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Git</span><br />
<br />
用于完整获取 open.mp SDK，以及后续各种开发所需的资源。<br />
<br />
下载：https://git-scm.com<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">1.2 VSCode 扩展</span><br />
<br />
打开 VSCode，安装以下扩展：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">C/C++</span>（Microsoft）--- 代码提示、语法高亮、调试<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">CMake Tools</span>（Microsoft）--- CMake 项目集成，一键编译<br />
</li>
</ul>
<br />
<span style="text-decoration: underline;" class="mycode_u">1.3 验证安装</span><br />
<br />
任意终端(比如 cmd)输入以下指令逐个验证是否安装配置成功：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>cmake --version    # 应该显示版本号<br />
git --version      # 应该显示版本号</code></div></div><br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. 创建项目</span><br />
<br />
<span style="text-decoration: underline;" class="mycode_u">2.1 初始化目录</span><br />
<br />
选一个你喜欢的位置，创建项目：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>新建文件夹 my-component<br />
在根目录新建 src 的文件夹<br />
在根目录新建 lib 的文件夹</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">2.2 添加 open.mp SDK 和相关依赖</span><br />
<br />
在lib文件夹内点击鼠标右键，选择 Open Git Bash here 并执行以下命令<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>git clone --recursive https://github.com/openmultiplayer/open.mp-sdk sdk<br />
git clone --recursive https://github.com/openmultiplayer/pawn-natives<br />
git clone --recursive https://github.com/openmultiplayer/compiler pawn</code></div></div><br />
等待获取完成，这会在lib文件夹内创建 sdk/ pawn/ pawn-natives/目录。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">2.3 创建 CMakeLists.txt</span><br />
<br />
在项目根目录创建 CMakeLists.txt 并复制以下内容粘贴进去：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>cmake_minimum_required(VERSION 3.19)<br />
project(my-component)<br />
<br />
set(CMAKE_CXX_STANDARD 17)<br />
set(CMAKE_CXX_STANDARD_REQUIRED ON)<br />
<br />
add_subdirectory(lib/sdk)<br />
<br />
add_library(&#36;{PROJECT_NAME} SHARED<br />
    src/main.cpp<br />
)<br />
<br />
# 解决库的兼容性问题<br />
add_definitions(<br />
    -DHAVE_STDINT_H=1<br />
    -DGLM_FORCE_SSE2=1<br />
    -DGLM_FORCE_QUAT_DATA_WXYZ=1<br />
    -DNOMINMAX=1<br />
    -Dnssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_NONSTD<br />
    -Dspan_CONFIG_SELECT_SPAN=span_SPAN_NONSTD<br />
    -DPAWN_CELL_SIZE=32 <br />
)<br />
<br />
target_include_directories(&#36;{PROJECT_NAME} PRIVATE<br />
    lib/<br />
    lib/pawn/source<br />
    lib/pawn/source/linux<br />
    lib/pawn-natives<br />
)<br />
<br />
target_link_libraries(&#36;{PROJECT_NAME} PRIVATE<br />
    OMP-SDK<br />
)</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">2.4 项目结构</span><br />
<br />
最终你的目录应该长这样：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>my-component/<br />
├── CMakeLists.txt      ← 构建配置<br />
├── lib/<br />
    ├── sdk/            ← open.mp SDK<br />
    ├── pawn-natives/ &nbsp;&nbsp;← 用于快速定义 PAWN 原生函数<br />
    └── pawn/         &nbsp;&nbsp;← 关联库<br />
└── src/<br />
    └── main.cpp        ← 你的代码</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">2.5 配置 VSCode</span><br />
<br />
用 VSCode 打开 my-component 文件夹。CMake Tools 扩展会自动检测到 CMakeLists.txt。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">选择编译器（Kit）：</span><br />
<br />
<ol type="1" class="mycode_list"><li>按 Ctrl+Shift+P，输入 CMake: Select a Kit<br />
</li>
<li>选择 Visual Studio 生成工具 2026 Release x86，如果没有这个选项，选择[扫描工具包]即可搜索。<br />
</li>
</ol>
<br />
<span style="font-weight: bold;" class="mycode_b">选择构建类型：</span><br />
<br />
<ol type="1" class="mycode_list"><li>按 Ctrl+Shift+P，输入 CMake: Select Variant<br />
</li>
<li>开发时选 Debug，发布时选 Release<br />
</li>
</ol>
<br />
<blockquote class="mycode_quote"><cite>引用:</cite><span style="font-weight: bold;" class="mycode_b">注意：</span> 如果你使用的是 CMake 4.x，可能会遇到旧版依赖的兼容性警告。在项目根目录创建 .vscode/settings.json：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>{<br />
    "cmake.configureArgs": [<br />
        "-DCMAKE_POLICY_VERSION_MINIMUM=3.10"<br />
    ]<br />
}</code></div></div></blockquote>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. 最小可运行组件</span><br />
<br />
创建 src/main.cpp，写入以下代码：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
<br />
class MyComponent final : public IComponent<br />
{<br />
private:<br />
    ICore* core_ = nullptr;<br />
<br />
public:<br />
    // 每个组件必须有一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成一个替换下面的ID<br />
    PROVIDE_UID(0x123456789ABCDEF0);<br />
<br />
    // 组件名称，显示在服务端加载日志里<br />
    StringView componentName() const override<br />
    {<br />
        return "MyComponent";<br />
    }<br />
    // 版本号<br />
    SemanticVersion componentVersion() const override<br />
    {<br />
        return SemanticVersion(1, 0, 0, 0);<br />
    }<br />
    // 组件加载时调用<br />
    void onLoad(ICore* c) override<br />
    {<br />
        core_ = c;<br />
        core_-&gt;printLn("Hello World!");<br />
    }<br />
<br />
    // 其他组件初始化完成后调用<br />
    void onInit(IComponentList* components) override {}<br />
<br />
    // 所有组件和脚本都就绪后调用<br />
    void onReady() override {}<br />
<br />
    // 其他组件卸载时调用<br />
    void onFree(IComponent* component) override {}<br />
<br />
    // 组件自身被释放<br />
    void free() override { delete this; }<br />
<br />
    // GMX（换图）时调用<br />
    void reset() override {}<br />
};<br />
<br />
// 组件入口点 —— 服务端通过这个宏发现并加载你的组件<br />
COMPONENT_ENTRY_POINT()<br />
{<br />
    return new MyComponent();<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">编译：</span><br />
<br />
按 F7（或 Ctrl+Shift+P → CMake: Build）。编译成功后，在 build/ 目录下会生成 my-component.dll。<br />
<br />
<span style="font-weight: bold;" class="mycode_b">测试：</span><br />
<br />
把 .dll 复制到 open.mp 服务端的 components/ 目录，启动服务端，你应该能在控制台看到：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>Loading component MyComponent.dll<br />
        Successfully loaded component MyComponent (1.0.0.0) with UID 123456789abcdef0<br />
<br />
Hello World!</code></div></div><br />
恭喜，你的第一个组件跑起来了。<br />
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. 组件的生命周期</span><br />
<br />
组件的函数按固定顺序调用。理解这个顺序非常重要：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>服务端启动<br />
  │<br />
  ├── onLoad(ICore*)         &nbsp;&nbsp;← 拿到核心接口<br />
  │<br />
  ├── onInit(IComponentList*)  ← 查询其他组件（如 IPawnComponent）<br />
  │<br />
  ├── onAmxLoad(IPawnScript&amp;)  ← Pawn 脚本加载，扫描 public 函数<br />
  │<br />
  ├── onReady()                ← 一切就绪，可以开始工作<br />
  │<br />
  │ &nbsp;&nbsp;... 服务器运行中 ...<br />
  │<br />
  ├── onAmxUnload(IPawnScript&amp;) ← Pawn 脚本卸载，清理相关数据<br />
  │<br />
  ├── onFree(IComponent*)      ← 组件卸载时<br />
  │<br />
  └── free()                 &nbsp;&nbsp;← 释放自身</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">关键点：</span><br />
<ul class="mycode_list"><li>onLoad 里只保存 ICore* 指针，不要访问其他组件（它们可能还没加载）<br />
</li>
<li>onInit 里通过 components-&gt;queryComponent&lt;IPawnComponent&gt;() 获取 Pawn 组件<br />
</li>
<li>onAmxLoad 是注册 native 函数和扫描 public 的地方<br />
</li>
</ul>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. 创建自己的native函数</span><br />
<br />
Native 函数让 Pawn 脚本能够调用你的 C++ 代码。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">5.1 基本概念</span><br />
<br />
在 Pawn 里写：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>native MyAdd(a, b);<br />
<br />
public OnGameModeInit()<br />
{<br />
    new a = 10, b = 20;<br />
    new result = MyAdd(a, b);<br />
    printf("%d + %d = %d", a, b, result);<br />
    return 1;<br />
}</code></div></div><br />
在 C++ 里你需要实现函数并注册到 AMX。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">5.2 使用 SCRIPT_API 宏（推荐）</span><br />
<br />
open.mp 提供了 SCRIPT_API 宏，自动处理参数的类型转换：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
#include &lt;Server/Components/Pawn/pawn.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_natives.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_impl.hpp&gt;<br />
<br />
SCRIPT_API(MyAdd, int(int a, int b))<br />
{<br />
    return a + b;<br />
}</code></div></div><br />
SCRIPT_API 的参数含义： - 第一个参数：函数名，必须和 Pawn 里的 native 名称完全一致 - 第二个参数：返回类型(参数列表)<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">5.3 注册时机</span><br />
<br />
在组件的 onAmxLoad 里调用 pawn_natives::AmxLoad，它会自动把所有 SCRIPT_API 定义的函数注册到 AMX：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>void onAmxLoad(IPawnScript&amp; script) override<br />
{<br />
    pawn_natives::AmxLoad(script.GetAMX());<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">5.4 完整的组件 + Native 示例</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
#include &lt;Server/Components/Pawn/pawn.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_natives.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_impl.hpp&gt;<br />
<br />
class MyComponent final : public IComponent, public PawnEventHandler<br />
{<br />
private:<br />
    ICore* core_ = nullptr;<br />
    IPawnComponent* pawn_ = nullptr;<br />
<br />
public:<br />
    // 每个组件必须有一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成一个替换下面的ID<br />
    PROVIDE_UID(0x123456789ABCDEF0);<br />
<br />
    StringView componentName() const override { return "MyComponent"; }<br />
    SemanticVersion componentVersion() const override { return SemanticVersion(1, 0, 0, 0); }<br />
<br />
    void onLoad(ICore* c) override<br />
    {<br />
        core_ = c;<br />
<br />
        // 初始化 AMX 查找表<br />
        setAmxLookups(core_);  <br />
    }<br />
<br />
    void onInit(IComponentList* components) override<br />
    {<br />
        pawn_ = components-&gt;queryComponent&lt;IPawnComponent&gt;();<br />
        if (pawn_)<br />
        {<br />
            setAmxFunctions(pawn_-&gt;getAmxFunctions());<br />
            setAmxLookups(components);<br />
            pawn_-&gt;getEventDispatcher().addEventHandler(this);<br />
        }<br />
    }<br />
<br />
    void onAmxLoad(IPawnScript&amp; script) override<br />
    {<br />
        pawn_natives::AmxLoad(script.GetAMX());<br />
    }<br />
<br />
    void onAmxUnload(IPawnScript&amp; script) override {}<br />
    void onReady() override {}<br />
    void onFree(IComponent* component) override {}<br />
    void free() override { delete this; }<br />
    void reset() override {}<br />
<br />
    ~MyComponent()<br />
    {<br />
        if (pawn_) pawn_-&gt;getEventDispatcher().removeEventHandler(this);<br />
    }<br />
};<br />
<br />
COMPONENT_ENTRY_POINT()<br />
{<br />
    return new MyComponent();<br />
}<br />
<br />
SCRIPT_API(MyAdd, int(int a, int b))<br />
{<br />
    return a + b;<br />
}</code></div></div><br />
重新编译插件并开启服务器，你就可以在控制台看到 10 + 20 = 30<br />
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. 事件处理</span><br />
<br />
open.mp 通过 EventHandler 接口分发事件。你的组件实现对应接口，注册到分发器，就能收到事件。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">6.1 常见的 EventHandler</span><br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
<tr><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">接口</th><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">事件</th></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">PlayerConnectEventHandler</td><td style="border:1px solid #ddd;padding:6px 10px;">玩家连接/断开</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">PlayerTextEventHandler</td><td style="border:1px solid #ddd;padding:6px 10px;">玩家聊天/命令</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">PawnEventHandler</td><td style="border:1px solid #ddd;padding:6px 10px;">AMX 脚本加载/卸载</td></tr>
</table>
<br />
<span style="text-decoration: underline;" class="mycode_u">6.2 示例：监听玩家连接</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>class MyComponent final<br />
    : public IComponent<br />
    , public PawnEventHandler<br />
    , public PlayerConnectEventHandler  // 实现连接事件接口<br />
{<br />
    // ... 省略其他成员 ...<br />
<br />
    void onInit(IComponentList* components) override<br />
    {<br />
        // 注册 Pawn 事件<br />
        pawn_ = components-&gt;queryComponent&lt;IPawnComponent&gt;();<br />
        if (pawn_)<br />
        {<br />
            setAmxFunctions(pawn_-&gt;getAmxFunctions());<br />
            setAmxLookups(components);<br />
            pawn_-&gt;getEventDispatcher().addEventHandler(this);<br />
        }<br />
<br />
        // 注册玩家连接事件<br />
        core_-&gt;getPlayers().getPlayerConnectDispatcher().addEventHandler(this);<br />
    }<br />
    // 析构函数里注销<br />
    ~MyComponent()<br />
    {<br />
        if (pawn_)  pawn_-&gt;getEventDispatcher().removeEventHandler(this);<br />
        if (core_) core_-&gt;getPlayers().getPlayerConnectDispatcher().removeEventHandler(this);<br />
    }<br />
    // 玩家连接时调用<br />
    void onPlayerConnect(IPlayer&amp; player) override<br />
    {<br />
        core_-&gt;printLn("玩家 %d 进入了服务器!", player.getID());<br />
    }<br />
};</code></div></div><br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. 玩家数据扩展</span><br />
<br />
在 Pawn 里，你可能习惯用全局数组存储玩家数据：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>new pScore[MAX_PLAYERS];<br />
new pLevel[MAX_PLAYERS];<br />
new bool:pLoggedIn[MAX_PLAYERS];</code></div></div><br />
在 open.mp 的 C++ 组件里，对应的机制是 <span style="font-weight: bold;" class="mycode_b">IExtension</span>。它把数据"挂"在玩家对象上。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">7.1 定义数据结构</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>struct PlayerEnergy final : IExtension<br />
{<br />
    // 每个 Extension 需要一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成<br />
    PROVIDE_EXT_UID(0xABCDEF1234567890);<br />
<br />
    // 你的自定义数据<br />
    int energy = 100;<br />
    int maxEnergy = 100;<br />
<br />
    void freeExtension() override { delete this; }<br />
    void reset() override<br />
    {<br />
        energy = 100;<br />
        maxEnergy = 100;<br />
    }<br />
};</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">7.2 在玩家连接时挂载</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>void onPlayerConnect(IPlayer&amp; player) override<br />
{<br />
    // 创建 PlayerEnergy 实例并挂到玩家身上<br />
    // 第二个参数 true 表示玩家断开时自动调用 freeExtension<br />
    player.addExtension(new PlayerEnergy(), true);<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">7.3 操作数据</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>auto* playerData = queryExtension&lt;PlayerEnergy&gt;(player);<br />
if (playerData)<br />
{<br />
    playerData-&gt;energy += 100;<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">7.4 为什么不用 std::unordered_map&lt;int, PlayerEnergy&gt;？</span><br />
<br />
你可以用，但 IExtension 有几个优势：<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">生命周期自动管理</span>：玩家断开时 freeExtension 自动调用，不会忘记清理<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">GMX 自动重置</span>：换图时 reset 自动调用<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">数据跟着对象走</span>：不需要传 playerid 再去查 map，直接从 IPlayer&amp; 取<br />
</li>
</ul>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. 如何扫描amx的public</span><br />
<br />
这是反方向的交互：你的 C++ 组件主动调用 Pawn 脚本里定义的 public 函数。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">8.1 理解 AMX 虚拟机</span><br />
<br />
Pawn 脚本编译后是 .amx 文件，由 AMX 虚拟机执行。每个 public 函数在 AMX 里有一个编号（index）。要调用它，你需要：<br />
<br />
<ol type="1" class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">找到编号</span> --- 用 amx_FindPublic 或在 onAmxLoad 时扫描<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">压入参数</span> --- 用 amx_Push（整数）或 amx_PushString（字符串）<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">执行</span> --- 用 amx_Exec<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">清理</span> --- 用 amx_Release 释放字符串内存<br />
</li>
</ol>
<br />
<span style="text-decoration: underline;" class="mycode_u">8.2 扫描 Public 函数</span><br />
<br />
假设 Pawn 里有：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>forward OnPlayerEnergyChange(playerid, oldEnergy, newEnergy);<br />
public OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
{<br />
    printf("玩家 %d 的查克拉发生了变化: %d -&gt; %d", playerid, oldEnergy, newEnergy);<br />
}</code></div></div><br />
在 onAmxLoad 时扫描它：<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 保存 AMX 指针和 public index<br />
struct ScriptInfo<br />
{<br />
    AMX* amx = nullptr;<br />
    int onEnergyChange = -1;  // -1 表示该脚本里没有这个函数<br />
};<br />
<br />
std::vector&lt;ScriptInfo&gt; scripts_;<br />
<br />
void onAmxLoad(IPawnScript&amp; script) override<br />
{<br />
    pawn_natives::AmxLoad(script.GetAMX());<br />
<br />
    AMX* amx = script.GetAMX();<br />
    ScriptInfo info;<br />
    info.amx = amx;<br />
<br />
    // 方法一：按名称精确查找<br />
    amx_FindPublic(amx, "OnPlayerEnergyChange", &amp;info.onEnergyChange);<br />
    // 如果找到，info.onEnergyChange &gt;= 0<br />
    // 如果没找到，info.onEnergyChange 保持 -1<br />
<br />
    scripts_.push_back(info);<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">8.3 调用 Public 函数</span><br />
<br />
找到 index 后，就可以调用了。<span style="font-weight: bold;" class="mycode_b">AMX 是栈式虚拟机，参数要倒序压入。</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">调用无参数函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn 侧<br />
forward OnSomethingHappen();<br />
public OnSomethingHappen()<br />
{<br />
    print("damn!");<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// C++ 侧<br />
void callOnSomethingHappen(AMX* amx, int index)<br />
{<br />
    cell returnValue;<br />
    amx_Exec(amx, &amp;returnValue, index);<br />
    // returnValue 是 Pawn 函数的返回值<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">调用带整数参数的函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn 侧<br />
forward OnPlayerEnergyChange(playerid, oldEnergy, newEnergy);<br />
public OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
{<br />
    printf("玩家 %d 的查克拉发生了变化: %d -&gt; %d", playerid, oldEnergy, newEnergy);<br />
    return 1;<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// C++ 侧<br />
void callOnPlayerEnergyChange(AMX* amx, int index, int playerid, int oldEnergy, int newEnergy)<br />
{<br />
    // Pawn: OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
    // 倒序压栈<br />
    amx_Push(amx, newEnergy);<br />
    amx_Push(amx, oldEnergy);<br />
    amx_Push(amx, playerid);<br />
<br />
    cell returnValue;<br />
    amx_Exec(amx, &amp;returnValue, index);<br />
}</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">调用带字符串参数的函数：</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// Pawn 侧<br />
forward OnPlayerMessage(playerid, const message[]);<br />
public OnPlayerMessage(playerid, const message[])<br />
{<br />
    printf("Player %d: %s", playerid, message);<br />
    return 1;<br />
}</code></div></div><br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// C++ 侧<br />
void callMessage(AMX* amx, int index, int playerid, const char* message)<br />
{<br />
    cell addr_message;<br />
    amx_PushString(amx, &amp;addr_message, nullptr, message, 0, 0);<br />
    amx_Push(amx, playerid);<br />
<br />
    cell retval;<br />
    amx_Exec(amx, &amp;retval, index);<br />
<br />
    // 必须释放 addr_message 不然会导致内存泄漏<br />
    amx_Release(amx, addr_message);<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">8.4 AMX API 速查表</span><br />
<br />
可查阅：https://open.mp/docs/tutorials/PluginDevelopmentGuide#amx-functions<br />
<br />
<table style="border-collapse:collapse;width:100%;margin:10px 0;">
<tr><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">函数</th><th style="background:#e8e8e8;border:1px solid #ccc;padding:7px 10px;text-align:left;font-weight:bold;">用途</th></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_NumPublics(amx, &amp;count)</td><td style="border:1px solid #ddd;padding:6px 10px;">获取 public 函数数量</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_GetPublic(amx, index, name)</td><td style="border:1px solid #ddd;padding:6px 10px;">按 index 获取函数名</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_FindPublic(amx, name, &amp;index)</td><td style="border:1px solid #ddd;padding:6px 10px;">按名称查找 index</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_Push(amx, value)</td><td style="border:1px solid #ddd;padding:6px 10px;">压入整数参数</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_PushString(amx, &amp;addr, nullptr, str, 0, 0)</td><td style="border:1px solid #ddd;padding:6px 10px;">压入字符串参数</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_Exec(amx, &amp;retval, index)</td><td style="border:1px solid #ddd;padding:6px 10px;">执行 public 函数</td></tr>
<tr><td style="border:1px solid #ddd;padding:6px 10px;">amx_Release(amx, addr)</td><td style="border:1px solid #ddd;padding:6px 10px;">释放 PushString 分配的内存</td></tr>
</table>
<br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">9. 完整示例</span><br />
<br />
下面是一个完整的组件，包含上述所有概念。功能很简单：追踪玩家的"查克拉"，提供 native 函数给 Pawn 操作，并在查克拉变化时回调 Pawn。<br />
<br />
<span style="text-decoration: underline;" class="mycode_u">9.1 C++ 组件（src/main.cpp）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;sdk.hpp&gt;<br />
#include &lt;Server/Components/Pawn/pawn.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_natives.hpp&gt;<br />
#include &lt;Server/Components/Pawn/Impl/pawn_impl.hpp&gt;<br />
<br />
#include &lt;vector&gt;<br />
#include &lt;string&gt;<br />
<br />
// 玩家数据扩展(查克拉)<br />
struct PlayerEnergy final : IExtension<br />
{<br />
    // 每个组件必须有一个全局唯一 ID<br />
    // 去 https://open.mp/uid 生成一个替换下面的ID<br />
    PROVIDE_EXT_UID(0x1A2B3C4D5E6F7890);<br />
<br />
    int energy = 100;<br />
    int maxEnergy = 100;<br />
<br />
    void freeExtension() override { delete this; }<br />
    void reset() override<br />
    {<br />
        energy = 100;<br />
        maxEnergy = 100;<br />
    }<br />
};<br />
<br />
// 组件主类<br />
class EnergyComponent final<br />
    : public IComponent<br />
    , public PawnEventHandler<br />
    , public PlayerConnectEventHandler<br />
{<br />
private:<br />
    ICore* core_ = nullptr;<br />
    IPawnComponent* pawn_ = nullptr;<br />
<br />
    // 保存 AMX 脚本中 OnPlayerEnergyChange 的 index<br />
    struct ScriptInfo<br />
    {<br />
        AMX* amx = nullptr;<br />
        int onEnergyChange = -1;<br />
    };<br />
    std::vector&lt;ScriptInfo&gt; scripts_;<br />
<br />
public:<br />
    PROVIDE_UID(0x9F8E7D6C5B4A3210);<br />
<br />
    StringView componentName() const override { return "EnergySystem"; }<br />
    SemanticVersion componentVersion() const override { return SemanticVersion(1, 0, 0, 0); }<br />
<br />
    void onLoad(ICore* c) override<br />
    {<br />
        core_ = c;<br />
        setAmxLookups(core_);<br />
        core_-&gt;printLn("[查克拉插件] 查克拉系统已加载.");<br />
    }<br />
<br />
    void onInit(IComponentList* components) override<br />
    {<br />
        pawn_ = components-&gt;queryComponent&lt;IPawnComponent&gt;();<br />
        if (pawn_)<br />
        {<br />
            setAmxFunctions(pawn_-&gt;getAmxFunctions());<br />
            setAmxLookups(components);<br />
            pawn_-&gt;getEventDispatcher().addEventHandler(this);<br />
        }<br />
        core_-&gt;getPlayers().getPlayerConnectDispatcher().addEventHandler(this);<br />
    }<br />
<br />
    // Pawn 事件 <br />
    void onAmxLoad(IPawnScript&amp; script) override<br />
    {<br />
        pawn_natives::AmxLoad(script.GetAMX());<br />
<br />
        // 扫描 Pawn 脚本中的回调函数<br />
        AMX* amx = script.GetAMX();<br />
        ScriptInfo info;<br />
        info.amx = amx;<br />
        amx_FindPublic(amx, "OnPlayerEnergyChange", &amp;info.onEnergyChange);<br />
        scripts_.push_back(info);<br />
    }<br />
<br />
    void onAmxUnload(IPawnScript&amp; script) override<br />
    {<br />
        AMX* amx = script.GetAMX();<br />
        scripts_.erase(<br />
            std::remove_if(scripts_.begin(), scripts_.end(), [amx](const ScriptInfo&amp; s) { return s.amx == amx; }), scripts_.end());<br />
    }<br />
<br />
    // 玩家事件 <br />
    void onPlayerConnect(IPlayer&amp; player) override<br />
    {<br />
        player.addExtension(new PlayerEnergy(), true);<br />
    }<br />
<br />
    // C++ 调用 Pawn 回调 <br />
    void callOnPlayerEnergyChange(int playerid, int oldEnergy, int newEnergy)<br />
    {<br />
        for (auto&amp; s : scripts_)<br />
        {<br />
            if (s.onEnergyChange &lt; 0)<br />
                continue;<br />
<br />
            // Pawn: OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
            // 倒序压栈<br />
            amx_Push(s.amx, newEnergy);<br />
            amx_Push(s.amx, oldEnergy);<br />
            amx_Push(s.amx, playerid);<br />
<br />
            cell retval;<br />
            amx_Exec(s.amx, &amp;retval, s.onEnergyChange);<br />
        }<br />
    }<br />
<br />
    // 生命周期 <br />
    void onReady() override {}<br />
    void onFree(IComponent* component) override<br />
    {<br />
        if (component == pawn_)<br />
        {<br />
            pawn_ = nullptr;<br />
            setAmxFunctions();<br />
            setAmxLookups();<br />
        }<br />
    }<br />
    void free() override { delete this; }<br />
    void reset() override {}<br />
<br />
    ~EnergyComponent()<br />
    {<br />
        if (pawn_) pawn_-&gt;getEventDispatcher().removeEventHandler(this);<br />
        if (core_) core_-&gt;getPlayers().getPlayerConnectDispatcher().removeEventHandler(this);<br />
    }<br />
};<br />
<br />
// 全局指针，给 SCRIPT_API 用<br />
static EnergyComponent* gComponent = nullptr;<br />
<br />
COMPONENT_ENTRY_POINT()<br />
{<br />
    gComponent = new EnergyComponent();<br />
    return gComponent;<br />
}<br />
<br />
// Native 函数<br />
// native GetPlayerEnergy(playerid);<br />
SCRIPT_API(GetPlayerEnergy, int(IPlayer&amp; player))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    return data ? data-&gt;energy : 0;<br />
}<br />
<br />
// native SetPlayerEnergy(playerid, energy);<br />
SCRIPT_API(SetPlayerEnergy, bool(IPlayer&amp; player, int energy))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    if (!data)<br />
        return false;<br />
<br />
    int oldEnergy = data-&gt;energy;<br />
    data-&gt;energy = (energy &gt; data-&gt;maxEnergy) ? data-&gt;maxEnergy : energy;<br />
<br />
    // 触发 Pawn 回调<br />
    if (data-&gt;energy != oldEnergy &amp;&amp; gComponent)<br />
        gComponent-&gt;callOnPlayerEnergyChange(player.getID(), oldEnergy, data-&gt;energy);<br />
<br />
    return true;<br />
}<br />
<br />
// native GetPlayerMaxEnergy(playerid);<br />
SCRIPT_API(GetPlayerMaxEnergy, int(IPlayer&amp; player))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    return data ? data-&gt;maxEnergy : 0;<br />
}<br />
<br />
// native SetPlayerMaxEnergy(playerid, maxEnergy);<br />
SCRIPT_API(SetPlayerMaxEnergy, bool(IPlayer&amp; player, int maxEnergy))<br />
{<br />
    auto* data = queryExtension&lt;PlayerEnergy&gt;(player);<br />
    if (!data)<br />
        return false;<br />
<br />
    data-&gt;maxEnergy = maxEnergy;<br />
    if (data-&gt;energy &gt; data-&gt;maxEnergy)<br />
        data-&gt;energy = data-&gt;maxEnergy;<br />
<br />
    return true;<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">9.2 Pawn Include 文件（energy.inc）</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 函数声明<br />
native GetPlayerEnergy(playerid);<br />
native SetPlayerEnergy(playerid, energy);<br />
native GetPlayerMaxEnergy(playerid);<br />
native SetPlayerMaxEnergy(playerid, maxEnergy);<br />
<br />
// 回调声明<br />
forward OnPlayerEnergyChange(playerid, oldEnergy, newEnergy);</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">9.3 Pawn 测试脚本</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#include &lt;open.mp&gt;<br />
#include "energy.inc"<br />
<br />
main() {}<br />
<br />
public OnPlayerConnect(playerid)<br />
{<br />
    // 连接时默认 energy = 100<br />
    new energy = GetPlayerEnergy(playerid);<br />
    printf("[查克拉系统] Player %d 进入了服务器, 查克拉 = %d", playerid, energy);<br />
<br />
    // 设置为 50，会触发 OnPlayerEnergyChange<br />
    SetPlayerEnergy(playerid, 50);<br />
<br />
    return 1;<br />
}<br />
<br />
// C++ 组件在查克拉变化时回调这个函数<br />
public OnPlayerEnergyChange(playerid, oldEnergy, newEnergy)<br />
{<br />
    printf("[回调] 玩家 %d 的查克拉发生了变化: %d -&gt; %d", playerid, oldEnergy, newEnergy);<br />
    return 1;<br />
}</code></div></div><br />
<span style="text-decoration: underline;" class="mycode_u">9.4 数据流向图</span><br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>玩家连接<br />
  │<br />
  ├─ open.mp 触发 onPlayerConnect<br />
  │ &nbsp;&nbsp;└─ C++ 创建 PlayerEnergy, 挂到玩家对象上<br />
  │<br />
  ├─ Pawn OnPlayerConnect 被调用<br />
  │ &nbsp;&nbsp;└─ 调用 native SetPlayerEnergy(playerid, 50)<br />
  │        │<br />
  │        ├─ SCRIPT_API 自动解析 playerid → IPlayer&amp;<br />
  │        ├─ queryExtension&lt;PlayerEnergy&gt;(player) 取出数据<br />
  │        ├─ 修改 energy: 100 → 50<br />
  │        └─ callOnPlayerEnergyChange(playerid, 100, 50)<br />
  │           &nbsp;&nbsp;│<br />
  │           &nbsp;&nbsp;├─ amx_Push(amx, 50)       &nbsp;&nbsp;← newEnergy<br />
  │           &nbsp;&nbsp;├─ amx_Push(amx, 100)        ← oldEnergy<br />
  │           &nbsp;&nbsp;├─ amx_Push(amx, playerid)<br />
  │           &nbsp;&nbsp;└─ amx_Exec → 调用 Pawn 的 OnPlayerEnergyChange</code></div></div><br />
* * *<br />
<br />
<span style="font-weight: bold;" class="mycode_b">附录：资源</span><br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">c++学习网站</span>: <a href="https://www.w3school.com.cn/cpp/cpp_reference.asp" target="_blank" rel="noopener" class="mycode_url">https://www.w3school.com.cn/cpp/cpp_reference.asp</a><br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp SDK 仓库</span>：https://github.com/openmultiplayer/open.mp-sdk<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp 组件模板示例</span>：https://github.com/openmultiplayer/pawn-template<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp 完整组件模板示例</span>：https://github.com/openmultiplayer/full-template<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">使用组件实现的gamemode示例</span>：https://github.com/openmultiplayer/rivershell-cpp<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">UID 生成器</span>：https://open.mp/uid<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">open.mp 官方文档</span>：https://www.open.mp/docs<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">amx相关函数说明文档</span>：https://open.mp/docs/tutorials/PluginDevelopmentGuide#amx-functions<br />
</li>
</ul>
<br />
* * *]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[教程] open.mp/sa-mp 服务器开发规范]]></title>
			<link>https://open-mp.cn/showthread.php?tid=6</link>
			<pubDate>Sat, 28 Feb 2026 11:55:21 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://open-mp.cn/member.php?action=profile&uid=3">小鸟unsigned</a>]]></dc:creator>
			<guid isPermaLink="false">https://open-mp.cn/showthread.php?tid=6</guid>
			<description><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">open.mp/sa-mp 服务器开发规范</h2><br />
<br />
为了避免开发者在服务器开发过程中，系统功能逐渐坍塌。本规范的引入，并非为了增加开发负担，而是为了建立一套对抗系统熵增的秩序，共同维护一个默认的社区标准和规范。<br />
<br />
本规范欢迎所有人提交 PR 或 Issue 进行改进。所有采纳的修改都将记入贡献者名单，共同维护 SA?MP/open.mp 中文开发社区的良好生态。规范的生命力在于持续迭代，而非一成不变。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">文件区分</h3><br />
<br />
其实文件夹怎么分没有铁打的标准，每个项目情况都不一样，但大致的思路都是差不多的<br />
<br />
先按“谁先用谁、谁依赖谁”排顺序，再按“这是游戏里的哪个系统”来分组，没必要一开始就搞得很复杂，先写着写着自然就知道哪里该拆了<br />
<br />
这里仅提供示范思路：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/Server<br />
  ├── gamemodes/<br />
  │    └── main.pwn         &nbsp;&nbsp;// 主文件，负责 #include 模块<br />
  │    └── locale/            // 如果你打算做多语言的话<br />
  │    └── utils/           &nbsp;&nbsp;// 自定义封装好的通用函数、工具（和 libraries 差不多）<br />
  │    └── core/              // 低层、必须先加载的核心系统（不依赖业务）<br />
  │    │ &nbsp;&nbsp;├── config/        // 配置相关 如 服务器名称 版本 规则 服务器设置<br />
  │    │ &nbsp;&nbsp;├── shared/        // 所有模块的“通用语言” 共享静态定义数据 用于校验 杜绝跨模块的变量污染<br />
  │    │ &nbsp;&nbsp;└── database/      // 数据库(如：MySQL) <br />
  │    ├── world/           &nbsp;&nbsp;// 游戏世界环境相关（地图、动态对象、时间等等）<br />
  │    └── modules/         &nbsp;&nbsp;// 所有功能模块存放处<br />
  │       &nbsp;&nbsp;├── players/      // 玩家模块<br />
  │       &nbsp;&nbsp;├── vehicles/   &nbsp;&nbsp;// 车辆模块<br />
  │       &nbsp;&nbsp;├── houses/     &nbsp;&nbsp;// 房屋模块<br />
  │       &nbsp;&nbsp;└── admin/        // 管理员模块<br />
  │    └── libraries/       &nbsp;&nbsp;// 第三方库 (如 mysql, sscanf等)<br />
  │    └── filterscripts/   &nbsp;&nbsp;// 可动态加载的独立功能（脚本玩法、工具之类的附加项内容）</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">模块间通信准则</h3><br />
<br />
模块之间严禁直接操作对方的 static 变量，必须通过 API<br />
<br />
如果 vehicles 模块需要获取玩家的某个状态，必须调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Player_GetSomeStatus(playerid)</code>，严禁直接读取 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gs_PlayerData</code><br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">命名规范</h3><br />
<ul class="mycode_list"><li>函数：PascalCase(所有单词首字母大写), 前缀是模块名 (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Player_Load(playerid)</code>)。<br />
</li>
<li>全局变量：<br />
</li>
<li>前缀 g_ 代表全局变量 (gobal) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new g_Var</code>;<br />
</li>
<li>前缀 gc_ 代表全局变量 (gobal const) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new const gc_Var</code>;<br />
</li>
<li>前缀 gs_ 代表全局静态变量（作用域仅在当前模块内） (gobal static) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static gs_Var</code>;<br />
</li>
<li>前缀 gsc_ 表示全局静态常数变量 (gobal static const) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static const gsc_Var</code>;<br />
</li>
<li>局部变量: 首单词小写, 后面单词首字母大写，或小写的缩写 (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new number, vehicleIndex, id, pos</code>)<br />
</li>
<li>常量/宏：大写 SNAKE_CASE (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define MAX_VEHICLES 2000</code>)。<br />
</li>
<li>文件：全小写，分割使用 '-' (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">player-main.inc、player-impl.inc</code>)；主文件 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main.pwn</code>。<br />
</li>
<li>枚举与数据结构规范: 采用 E<span style="font-style: italic;" class="mycode_i">MODULENAME</span>DATA 格式（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_PLAYER_DATA</code>），全大写，采用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_</code> 开头<br />
</li>
<li>枚举成员采用: 模块名<span style="font-style: italic;" class="mycode_i">字段名 全大写 SNAKE</span>CASE, 便于快速区分、选择、修改等等<br />
</li>
</ul>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 房屋模块<br />
enum E_HOUSE_DATA<br />
{<br />
    HOUSE_DBID,<br />
    HOUSE_OWNER[MAX_PLAYER_NAME],<br />
    Float:HOUSE_ENTRANCE_X,<br />
    Float:HOUSE_ENTRANCE_Y,<br />
    Float:HOUSE_ENTRANCE_Z,<br />
    bool:HOUSE_IS_LOCKED,<br />
    HOUSE_PRICE<br />
}<br />
static gs_HouseData[MAX_HOUSES][E_HOUSE_DATA];<br />
<br />
// 载具模块<br />
enum E_VEHICLE_DATA<br />
{<br />
    VEHICLE_DBID,<br />
    VEHICLE_MODEL,<br />
    Float:VEHICLE_HEALTH,<br />
    VEHICLE_OWNER_ID<br />
}<br />
static gs_VehicleData[MAX_VEHICLES][E_VEHICLE_DATA];</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">缩写准则</h3><br />
<br />
只允许通用缩写<br />
<br />
如：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ID (Identity)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Pos (Position)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Rot (Rotation)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Max/Min</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Msg (Message)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Cmd (Command)</code> 等等<br />
<br />
错误示例：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pLv</code>（到底是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Level</code> 还是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Leave</code>？）<br />
<br />
禁止：将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Owner</code> 缩写为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">O</code>, 将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Price</code> 缩写为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Pr</code>，禁止使用无意义缩写<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">包含守卫：</h3><br />
<br />
打开任何一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件，第一眼能看到“这个文件要放在哪里、依赖谁”，不用翻 main.pwn 的 include 列表猜顺序或者人工记忆顺序，长期维护更加直观清晰<br />
<br />
尤其是相同层级的脚本，由于相互之间可能存在依赖关系，比如房屋模块需要使用到玩家模块的信息(金钱等等)，包含守卫可以很好地理清关系，避免脚本运行时出现问题，在编译阶段完美规避问题的出现<br />
<br />
注意注释保持简短，别写成大段文档<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 防止重复包含 替换 SCRIPT_NAME 即可<br />
#if defined _INC_SCRIPT_NAME<br />
&nbsp;&nbsp;&nbsp;&nbsp;#endinput<br />
#endif<br />
#define _INC_SCRIPT_NAME<br />
<br />
// 模块之间的依赖说明<br />
#if !defined _INC_OTHER_SCRIPT_NAME<br />
&nbsp;&nbsp;&nbsp;&nbsp;#error 需要包含 other-script.inc.<br />
#endif<br />
<br />
// 环境约束 确保编译环境正确<br />
#if !defined _INC_open_mp<br />
&nbsp;&nbsp;&nbsp;&nbsp;#error 需要包含 open.mp.inc.<br />
#endif<br />
<br />
// 依赖项的显式校验 快速定位缺失依赖<br />
#tryinclude &lt;Pawn.RakNet&gt;<br />
#if !defined PAWNRAKNET_INC_<br />
    #error 需要使用 Pawn.RakNet 插件<br />
#endif<br />
<br />
// 插件版本与功能对齐<br />
#tryinclude &lt;streamer&gt;<br />
#if !defined Streamer_IncludeFileVersion<br />
    #error cannot read from file: "streamer.inc"<br />
#elseif Streamer_IncludeFileVersion != 0x296<br />
    #error 不兼容的 streamer 插件版本, 请使用 2.9.6 版本.<br />
#endif<br />
<br />
// 零开销的默认配置 可在后续代码中随时关闭或开启调试<br />
#if !defined SCR_DEBUG<br />
&nbsp;&nbsp;&nbsp;&nbsp;#define SCR_DEBUG false<br />
#endif<br />
<br />
// 或者这样<br />
#if SCR_DEBUG<br />
    #define DebugMessage(%1) printf("[Script Debug] " %1)<br />
    #define ErrorMessage(%1) printf("[Script Debug-Error] " %1)<br />
#else<br />
    #define DebugMessage(%1);<br />
    #define ErrorMessage(%1);<br />
#endif</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">ALS 钩子标准</h3><br />
<br />
用传统 ALS 钩子扩展回调/函数<br />
<br />
示例：回调钩子 (OnGameModeInit)<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 替换 SCR 即可<br />
public OnGameModeInit()<br />
{<br />
    #if defined SCR_OnGameModeInit<br />
        return SCR_OnGameModeInit();<br />
    #else<br />
        return 1;<br />
    #endif<br />
}<br />
#if defined _ALS_OnGameModeInit<br />
    #undef OnGameModeInit<br />
#else<br />
    #define _ALS_OnGameModeInit<br />
#endif<br />
#define OnGameModeInit SCR_OnGameModeInit<br />
#if defined SCR_OnGameModeInit<br />
    forward SCR_OnGameModeInit();<br />
#endif</code></div></div><br />
示例：stock 函数钩子 (SetPlayerScore)<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 替换 SCR 即可<br />
stock bool:SCR_SetPlayerScore(playerid, score)<br />
{<br />
    if(SetPlayerScore(playerid, score))<br />
    {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ......<br />
        return true;<br />
    }<br />
    return false;<br />
}<br />
#if defined _ALS_SetPlayerScore<br />
    #undef SetPlayerScore<br />
#else<br />
    #define _ALS_SetPlayerScore<br />
#endif<br />
#define SetPlayerScore SCR_SetPlayerScore</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">函数作用域规范</h3><br />
<br />
<ol type="1" class="mycode_list"><li>static stock (模块私有函数)<br />
</li>
</ol>
<ul class="mycode_list"><li>作用域仅在当前 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件中, 它只在内部使用<br />
</li>
<li>命名以 下划线 开头，采用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">_ModuleName_FunctionName</code> 格式（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">_House_CheckDistance</code>）<br />
</li>
</ul>
<br />
<ol type="1" class="mycode_list"><li>stock (模块公开接口)<br />
</li>
</ol>
<ul class="mycode_list"><li>定义：作用域全服务器, 命名采用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ModuleName_FunctionName</code> 格式<br />
</li>
</ul>
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define HOUSE_TAX_RATE 0.1<br />
<br />
// 只有本模块能用，外部无法使用，也不会冲突<br />
static stock _House_CalculateTax(houseid) <br />
{<br />
    return floatround(float(gs_HouseData[houseid][HOUSE_PRICE]) * HOUSE_TAX_RATE);<br />
}<br />
<br />
// 对外接口<br />
stock bool:House_GetTotalCost(houseid, &amp;cost)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(houseid &lt; 0 || houseid &gt;= MAX_HOUSES)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
<br />
    // 内部逻辑调用私有函数<br />
    cost = gs_HouseData[houseid][HOUSE_PRICE] + _House_CalculateTax(houseid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
}</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">注释标准</h3><br />
<br />
对于函数的说明注释使用 <a href="https://github.com/doxygen/doxygen" target="_blank" rel="noopener" class="mycode_url">Doxygen</a> 风格，直接关系到长期维护，至少包含 功能简述、参数、返回值、注意事项<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/**<br />
 * 获取玩家当前拥有的房产数量。<br />
 * @param playerid 玩家ID<br />
 * @return 房产数量，失败返回 -1<br />
 */<br />
stock Player_GetPropertyCount(playerid);</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">标签规范</h3><br />
<br />
用 enum + 宏定义标签，确保类型安全。<br />
<br />
示例：WEATHER<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum WEATHER:<br />
{<br />
    WEATHER_UNKNOWN = -1,<br />
    WEATHER_EXTRASUNNY_LA = 0,<br />
    WEATHER_SUNNY_LA,<br />
    WEATHER_EXTRASUNNY_SMOG_LA,<br />
    WEATHER_SUNNY_SMOG_LA,<br />
    WEATHER_CLOUDY_LA,<br />
    WEATHER_SUNNY_SF,<br />
&nbsp;&nbsp;&nbsp;&nbsp;...,<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
}</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">错误处理标准</h3><br />
<br />
规范：返回值语义化<br />
<br />
逻辑判断返回类型 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">bool</code>:<br />
<br />
成功返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ID ( &gt;= 0)</code>，失败返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INVALID_..._ID (-1)</code><br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">开源协议 (License)</h3><br />
<br />
本项目遵循 <a href="http://LICENSE" target="_blank" rel="noopener" class="mycode_url">MIT License</a> 协议。<br />
你可以自由地使用、修改和分发本规范。]]></description>
			<content:encoded><![CDATA[<h2 style="font-size:1.8em;font-weight:bold;border-bottom:2px solid #aaa;padding-bottom:5px;margin:20px 0 10px;">open.mp/sa-mp 服务器开发规范</h2><br />
<br />
为了避免开发者在服务器开发过程中，系统功能逐渐坍塌。本规范的引入，并非为了增加开发负担，而是为了建立一套对抗系统熵增的秩序，共同维护一个默认的社区标准和规范。<br />
<br />
本规范欢迎所有人提交 PR 或 Issue 进行改进。所有采纳的修改都将记入贡献者名单，共同维护 SA?MP/open.mp 中文开发社区的良好生态。规范的生命力在于持续迭代，而非一成不变。<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">文件区分</h3><br />
<br />
其实文件夹怎么分没有铁打的标准，每个项目情况都不一样，但大致的思路都是差不多的<br />
<br />
先按“谁先用谁、谁依赖谁”排顺序，再按“这是游戏里的哪个系统”来分组，没必要一开始就搞得很复杂，先写着写着自然就知道哪里该拆了<br />
<br />
这里仅提供示范思路：<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/Server<br />
  ├── gamemodes/<br />
  │    └── main.pwn         &nbsp;&nbsp;// 主文件，负责 #include 模块<br />
  │    └── locale/            // 如果你打算做多语言的话<br />
  │    └── utils/           &nbsp;&nbsp;// 自定义封装好的通用函数、工具（和 libraries 差不多）<br />
  │    └── core/              // 低层、必须先加载的核心系统（不依赖业务）<br />
  │    │ &nbsp;&nbsp;├── config/        // 配置相关 如 服务器名称 版本 规则 服务器设置<br />
  │    │ &nbsp;&nbsp;├── shared/        // 所有模块的“通用语言” 共享静态定义数据 用于校验 杜绝跨模块的变量污染<br />
  │    │ &nbsp;&nbsp;└── database/      // 数据库(如：MySQL) <br />
  │    ├── world/           &nbsp;&nbsp;// 游戏世界环境相关（地图、动态对象、时间等等）<br />
  │    └── modules/         &nbsp;&nbsp;// 所有功能模块存放处<br />
  │       &nbsp;&nbsp;├── players/      // 玩家模块<br />
  │       &nbsp;&nbsp;├── vehicles/   &nbsp;&nbsp;// 车辆模块<br />
  │       &nbsp;&nbsp;├── houses/     &nbsp;&nbsp;// 房屋模块<br />
  │       &nbsp;&nbsp;└── admin/        // 管理员模块<br />
  │    └── libraries/       &nbsp;&nbsp;// 第三方库 (如 mysql, sscanf等)<br />
  │    └── filterscripts/   &nbsp;&nbsp;// 可动态加载的独立功能（脚本玩法、工具之类的附加项内容）</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">模块间通信准则</h3><br />
<br />
模块之间严禁直接操作对方的 static 变量，必须通过 API<br />
<br />
如果 vehicles 模块需要获取玩家的某个状态，必须调用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Player_GetSomeStatus(playerid)</code>，严禁直接读取 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">gs_PlayerData</code><br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">命名规范</h3><br />
<ul class="mycode_list"><li>函数：PascalCase(所有单词首字母大写), 前缀是模块名 (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Player_Load(playerid)</code>)。<br />
</li>
<li>全局变量：<br />
</li>
<li>前缀 g_ 代表全局变量 (gobal) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new g_Var</code>;<br />
</li>
<li>前缀 gc_ 代表全局变量 (gobal const) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new const gc_Var</code>;<br />
</li>
<li>前缀 gs_ 代表全局静态变量（作用域仅在当前模块内） (gobal static) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static gs_Var</code>;<br />
</li>
<li>前缀 gsc_ 表示全局静态常数变量 (gobal static const) 比如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">static const gsc_Var</code>;<br />
</li>
<li>局部变量: 首单词小写, 后面单词首字母大写，或小写的缩写 (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">new number, vehicleIndex, id, pos</code>)<br />
</li>
<li>常量/宏：大写 SNAKE_CASE (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">#define MAX_VEHICLES 2000</code>)。<br />
</li>
<li>文件：全小写，分割使用 '-' (如: <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">player-main.inc、player-impl.inc</code>)；主文件 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">main.pwn</code>。<br />
</li>
<li>枚举与数据结构规范: 采用 E<span style="font-style: italic;" class="mycode_i">MODULENAME</span>DATA 格式（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_PLAYER_DATA</code>），全大写，采用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">E_</code> 开头<br />
</li>
<li>枚举成员采用: 模块名<span style="font-style: italic;" class="mycode_i">字段名 全大写 SNAKE</span>CASE, 便于快速区分、选择、修改等等<br />
</li>
</ul>
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 房屋模块<br />
enum E_HOUSE_DATA<br />
{<br />
    HOUSE_DBID,<br />
    HOUSE_OWNER[MAX_PLAYER_NAME],<br />
    Float:HOUSE_ENTRANCE_X,<br />
    Float:HOUSE_ENTRANCE_Y,<br />
    Float:HOUSE_ENTRANCE_Z,<br />
    bool:HOUSE_IS_LOCKED,<br />
    HOUSE_PRICE<br />
}<br />
static gs_HouseData[MAX_HOUSES][E_HOUSE_DATA];<br />
<br />
// 载具模块<br />
enum E_VEHICLE_DATA<br />
{<br />
    VEHICLE_DBID,<br />
    VEHICLE_MODEL,<br />
    Float:VEHICLE_HEALTH,<br />
    VEHICLE_OWNER_ID<br />
}<br />
static gs_VehicleData[MAX_VEHICLES][E_VEHICLE_DATA];</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">缩写准则</h3><br />
<br />
只允许通用缩写<br />
<br />
如：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ID (Identity)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Pos (Position)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Rot (Rotation)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Max/Min</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Msg (Message)</code>, <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Cmd (Command)</code> 等等<br />
<br />
错误示例：<code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">pLv</code>（到底是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Level</code> 还是 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Leave</code>？）<br />
<br />
禁止：将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Owner</code> 缩写为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">O</code>, 将 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Price</code> 缩写为 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">Pr</code>，禁止使用无意义缩写<br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">包含守卫：</h3><br />
<br />
打开任何一个 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件，第一眼能看到“这个文件要放在哪里、依赖谁”，不用翻 main.pwn 的 include 列表猜顺序或者人工记忆顺序，长期维护更加直观清晰<br />
<br />
尤其是相同层级的脚本，由于相互之间可能存在依赖关系，比如房屋模块需要使用到玩家模块的信息(金钱等等)，包含守卫可以很好地理清关系，避免脚本运行时出现问题，在编译阶段完美规避问题的出现<br />
<br />
注意注释保持简短，别写成大段文档<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 防止重复包含 替换 SCRIPT_NAME 即可<br />
#if defined _INC_SCRIPT_NAME<br />
&nbsp;&nbsp;&nbsp;&nbsp;#endinput<br />
#endif<br />
#define _INC_SCRIPT_NAME<br />
<br />
// 模块之间的依赖说明<br />
#if !defined _INC_OTHER_SCRIPT_NAME<br />
&nbsp;&nbsp;&nbsp;&nbsp;#error 需要包含 other-script.inc.<br />
#endif<br />
<br />
// 环境约束 确保编译环境正确<br />
#if !defined _INC_open_mp<br />
&nbsp;&nbsp;&nbsp;&nbsp;#error 需要包含 open.mp.inc.<br />
#endif<br />
<br />
// 依赖项的显式校验 快速定位缺失依赖<br />
#tryinclude &lt;Pawn.RakNet&gt;<br />
#if !defined PAWNRAKNET_INC_<br />
    #error 需要使用 Pawn.RakNet 插件<br />
#endif<br />
<br />
// 插件版本与功能对齐<br />
#tryinclude &lt;streamer&gt;<br />
#if !defined Streamer_IncludeFileVersion<br />
    #error cannot read from file: "streamer.inc"<br />
#elseif Streamer_IncludeFileVersion != 0x296<br />
    #error 不兼容的 streamer 插件版本, 请使用 2.9.6 版本.<br />
#endif<br />
<br />
// 零开销的默认配置 可在后续代码中随时关闭或开启调试<br />
#if !defined SCR_DEBUG<br />
&nbsp;&nbsp;&nbsp;&nbsp;#define SCR_DEBUG false<br />
#endif<br />
<br />
// 或者这样<br />
#if SCR_DEBUG<br />
    #define DebugMessage(%1) printf("[Script Debug] " %1)<br />
    #define ErrorMessage(%1) printf("[Script Debug-Error] " %1)<br />
#else<br />
    #define DebugMessage(%1);<br />
    #define ErrorMessage(%1);<br />
#endif</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">ALS 钩子标准</h3><br />
<br />
用传统 ALS 钩子扩展回调/函数<br />
<br />
示例：回调钩子 (OnGameModeInit)<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 替换 SCR 即可<br />
public OnGameModeInit()<br />
{<br />
    #if defined SCR_OnGameModeInit<br />
        return SCR_OnGameModeInit();<br />
    #else<br />
        return 1;<br />
    #endif<br />
}<br />
#if defined _ALS_OnGameModeInit<br />
    #undef OnGameModeInit<br />
#else<br />
    #define _ALS_OnGameModeInit<br />
#endif<br />
#define OnGameModeInit SCR_OnGameModeInit<br />
#if defined SCR_OnGameModeInit<br />
    forward SCR_OnGameModeInit();<br />
#endif</code></div></div><br />
示例：stock 函数钩子 (SetPlayerScore)<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>// 替换 SCR 即可<br />
stock bool:SCR_SetPlayerScore(playerid, score)<br />
{<br />
    if(SetPlayerScore(playerid, score))<br />
    {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ......<br />
        return true;<br />
    }<br />
    return false;<br />
}<br />
#if defined _ALS_SetPlayerScore<br />
    #undef SetPlayerScore<br />
#else<br />
    #define _ALS_SetPlayerScore<br />
#endif<br />
#define SetPlayerScore SCR_SetPlayerScore</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">函数作用域规范</h3><br />
<br />
<ol type="1" class="mycode_list"><li>static stock (模块私有函数)<br />
</li>
</ol>
<ul class="mycode_list"><li>作用域仅在当前 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">.inc</code> 文件中, 它只在内部使用<br />
</li>
<li>命名以 下划线 开头，采用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">_ModuleName_FunctionName</code> 格式（如 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">_House_CheckDistance</code>）<br />
</li>
</ul>
<br />
<ol type="1" class="mycode_list"><li>stock (模块公开接口)<br />
</li>
</ol>
<ul class="mycode_list"><li>定义：作用域全服务器, 命名采用 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ModuleName_FunctionName</code> 格式<br />
</li>
</ul>
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>#define HOUSE_TAX_RATE 0.1<br />
<br />
// 只有本模块能用，外部无法使用，也不会冲突<br />
static stock _House_CalculateTax(houseid) <br />
{<br />
    return floatround(float(gs_HouseData[houseid][HOUSE_PRICE]) * HOUSE_TAX_RATE);<br />
}<br />
<br />
// 对外接口<br />
stock bool:House_GetTotalCost(houseid, &amp;cost)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(houseid &lt; 0 || houseid &gt;= MAX_HOUSES)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
<br />
    // 内部逻辑调用私有函数<br />
    cost = gs_HouseData[houseid][HOUSE_PRICE] + _House_CalculateTax(houseid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
}</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">注释标准</h3><br />
<br />
对于函数的说明注释使用 <a href="https://github.com/doxygen/doxygen" target="_blank" rel="noopener" class="mycode_url">Doxygen</a> 风格，直接关系到长期维护，至少包含 功能简述、参数、返回值、注意事项<br />
<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>/**<br />
 * 获取玩家当前拥有的房产数量。<br />
 * @param playerid 玩家ID<br />
 * @return 房产数量，失败返回 -1<br />
 */<br />
stock Player_GetPropertyCount(playerid);</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">标签规范</h3><br />
<br />
用 enum + 宏定义标签，确保类型安全。<br />
<br />
示例：WEATHER<br />
<div class="codeblock"><div class="title">代码:</div><div class="body" dir="ltr"><code>enum WEATHER:<br />
{<br />
    WEATHER_UNKNOWN = -1,<br />
    WEATHER_EXTRASUNNY_LA = 0,<br />
    WEATHER_SUNNY_LA,<br />
    WEATHER_EXTRASUNNY_SMOG_LA,<br />
    WEATHER_SUNNY_SMOG_LA,<br />
    WEATHER_CLOUDY_LA,<br />
    WEATHER_SUNNY_SF,<br />
&nbsp;&nbsp;&nbsp;&nbsp;...,<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
}</code></div></div><br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">错误处理标准</h3><br />
<br />
规范：返回值语义化<br />
<br />
逻辑判断返回类型 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">bool</code>:<br />
<br />
成功返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">ID ( &gt;= 0)</code>，失败返回 <code style="background:#f0f0f0;border:1px solid #ddd;padding:1px 5px;border-radius:3px;font-family:Consolas,monospace;font-size:0.9em;">INVALID_..._ID (-1)</code><br />
<br />
<h3 style="font-size:1.4em;font-weight:bold;border-bottom:1px solid #ddd;padding-bottom:4px;margin:16px 0 8px;">开源协议 (License)</h3><br />
<br />
本项目遵循 <a href="http://LICENSE" target="_blank" rel="noopener" class="mycode_url">MIT License</a> 协议。<br />
你可以自由地使用、修改和分发本规范。]]></content:encoded>
		</item>
	</channel>
</rss>