<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alliedmods.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=CyberMind</id>
	<title>AlliedModders Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alliedmods.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=CyberMind"/>
	<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/Special:Contributions/CyberMind"/>
	<updated>2026-05-05T11:20:37Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.6</generator>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Natives_(SourceMod_Development)&amp;diff=4591</id>
		<title>Natives (SourceMod Development)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Natives_(SourceMod_Development)&amp;diff=4591"/>
		<updated>2007-06-06T05:19:18Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edits by PydPcp (Talk); changed back to last version by Damaged Soul&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Natives are functions which are available to plugins via Core itself, or a C++ extension.  They are called &amp;quot;natives&amp;quot; because they must be translated via a ''native interface''.  This article explains the various parameter passing conventions in SourcePawn, as well as how to use them in your own natives.&lt;br /&gt;
&lt;br /&gt;
To understand the contents of this article, you will need to read [[Writing_Extensions#Creating_Native_Functions|Creating Natives]], the Native section in the introductory article on creating extensions.&lt;br /&gt;
&lt;br /&gt;
In this article, &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; refers to the C/C++ data type, and &amp;lt;tt&amp;gt;Float&amp;lt;/tt&amp;gt; (note capital 'F') refers to the SourcePawn [[Tags (Scripting)|tag]].&lt;br /&gt;
&lt;br /&gt;
=By Value versus By Reference=&lt;br /&gt;
There are two ways to pass integers/Floats to native implementations.  They are ''by value'' (ByVal) and ''by reference'' (ByRef).  ByVal means that a copy of the value is passed to the native.  This is the default behaviour.  ByRef means a ''reference'' is passed to the native, and this reference points to the value.  Both will be explained below.&lt;br /&gt;
&lt;br /&gt;
Note that arrays and strings, as will be explained later, are always passed by reference.  This is because they are usually larger structures, and passing them ByVal would require copying their data, wasting CPU cycles.&lt;br /&gt;
&lt;br /&gt;
==By Value==&lt;br /&gt;
Passing by value is the default behaviour for primitive data types (integers, Floats, or any tag that's cell-based).  Data is treated normally as raw, copied input.  Observe the following native:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Returns the number decremented by one.&lt;br /&gt;
 *&lt;br /&gt;
 * @param num		Number to decrement.&lt;br /&gt;
 * @return		Decremented number.&lt;br /&gt;
 */&lt;br /&gt;
native Decrement(num);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
How would we use this native?  Since &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; is passed as a value, it cannot change in the native code.  This means we have to use the return value as such:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//Decrements a number 5 times&lt;br /&gt;
Example(num)&lt;br /&gt;
{&lt;br /&gt;
	num = Decrement(num);&lt;br /&gt;
	num = Decrement(num);&lt;br /&gt;
	num = Decrement(num);&lt;br /&gt;
	num = Decrement(num);&lt;br /&gt;
	num = Decrement(num);&lt;br /&gt;
	return num;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==By Reference==&lt;br /&gt;
Let's reuse the above example to use reference passing.  Observe the new native below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Subtracts one from the given number, by reference.&lt;br /&gt;
 *&lt;br /&gt;
 * @param num		Number to subtract, by reference.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native Decrement(&amp;amp;num);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the ampersand ('&amp;amp;') before the parameter name -- this specifies that it is passed by reference.  Now, let's see how this would look in our script:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;Example(num)&lt;br /&gt;
{&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	return num;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, &amp;lt;tt&amp;gt;Decrement&amp;lt;/tt&amp;gt; is acting on the &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; variable ''itself'', not a copy of it.  Thus, num will decrease 5 times.  In fact, scripts can even do this internally.  We can shorten the example even more:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;Example(&amp;amp;num)&lt;br /&gt;
{&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
	Decrement(num);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==When to use By Ref==&lt;br /&gt;
There is a misconception that passing by reference is always better then by value.  After all, copying data sounds excessive.  However, by value in SourcePawn only works on 32bit values, and thus copying the value is inherent to the processor, and trivial.&lt;br /&gt;
&lt;br /&gt;
On the other hand, passing by value is slightly more expensive.  First, the compiler has to generate a little extra code to compute the local address of the variable.  Second, the native code itself has to translate the local address to a ''real virtual address'' (native memory).&lt;br /&gt;
&lt;br /&gt;
It is a good idea to only use by reference when you need it.  A common usage is when you need to return more than one piece of data, and you can't fit it into the return value of your native or function.  In this case, by reference is ideal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Integers/Floats=&lt;br /&gt;
&lt;br /&gt;
==By Value==&lt;br /&gt;
Natives based purely on by-value floating point or integer input are generally the easiest to make.  Let's take a simple function which takes in a Float and an integer, and returns a Float:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Raises a number to an integer power.&lt;br /&gt;
 *&lt;br /&gt;
 * @param fNum		Base number (Float).&lt;br /&gt;
 * @param exp		Exponent (integer).&lt;br /&gt;
 * @return		Computed exponent result as a Float.&lt;br /&gt;
 */&lt;br /&gt;
native FloatIntPower(Float:fNum, exp);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An implementation of this native might look like:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
static cell_t sm_FloatIntPower(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	float f1 = sp_ctof(params[1]);&lt;br /&gt;
	int num = params[2];&lt;br /&gt;
	&lt;br /&gt;
	float result = (float)pow(f1, (double)f2);&lt;br /&gt;
	return sp_ftoc(result);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Integers, as we saw in the introduction, are accessed from the parameter stack normally.  Floats, however, must be ''reinterpret casted'' from a &amp;lt;tt&amp;gt;cell_t&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;.  Two inline functions are provided for this:&lt;br /&gt;
*&amp;lt;tt&amp;gt;sp_ctof&amp;lt;/tt&amp;gt;: Convert a &amp;lt;tt&amp;gt;cell_t&amp;lt;/tt&amp;gt; to a &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;sp_ftoc&amp;lt;/tt&amp;gt;: Convert a &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; to a &amp;lt;tt&amp;gt;cell_t&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==By Reference==&lt;br /&gt;
By reference is a little more tricky.  Let's first implement our &amp;lt;tt&amp;gt;Decrement&amp;lt;/tt&amp;gt; native from earlier.  A refresher:&lt;br /&gt;
&amp;lt;pawn&amp;gt;native Decrement(&amp;amp;num);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If we try to use our above code, &amp;lt;tt&amp;gt;params[1]&amp;lt;/tt&amp;gt; will no longer hold a value.  Instead, it holds a ''local address'' in the plugin.  We must use the &amp;lt;tt&amp;gt;LocalToPhysAddr&amp;lt;/tt&amp;gt; function to translate this.  It takes in a local address and returns back a physical pointer, which we can then modify.  This will modify the value in the script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_Decrement(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	cell_t *addr;&lt;br /&gt;
&lt;br /&gt;
	/* Translate the address. */&lt;br /&gt;
	pContext-&amp;gt;LocalToPhysAddr(params[1], &amp;amp;addr);&lt;br /&gt;
&lt;br /&gt;
	/* Decrement the number */&lt;br /&gt;
	*addr -= 1;&lt;br /&gt;
&lt;br /&gt;
	/* We have to return something, even if the plugin doesn't the value */&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: LocalToPhysAddr can return an error code.  For all practical purposes, this will never error, unless there is some memory or corruption issue, so checking it isn't necessary.''&lt;br /&gt;
&lt;br /&gt;
This works the same way for floats.  Let's say we change our native to this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Decrements a Float by an integer, and stores the result by reference.&lt;br /&gt;
 *&lt;br /&gt;
 * @param fNum		Float number to decrement (by ref).&lt;br /&gt;
 * @param decamt	Amount to decrement by.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native Decrement(&amp;amp;Float:fNum, decamt);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example is fairly contrived -- our native simply performs a subtract operation.  But let's look at the implementation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_Decrement(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	cell_t *addr;&lt;br /&gt;
&lt;br /&gt;
	/* Translate the address. */&lt;br /&gt;
	pContext-&amp;gt;LocalToPhysAddr(params[1], &amp;amp;addr);&lt;br /&gt;
&lt;br /&gt;
	/* Get the value */&lt;br /&gt;
	float val = sp_ctof(*addr);&lt;br /&gt;
	/* Decrement */&lt;br /&gt;
	val -= params[2];&lt;br /&gt;
	/* Store back */&lt;br /&gt;
	*addr = sp_ftoc(val);&lt;br /&gt;
&lt;br /&gt;
	/* We have to return something, even if the plugin doesn't the value */&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that even though the first parameter was passed by reference, the second was not, and is accessed normally.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Arrays=&lt;br /&gt;
&lt;br /&gt;
==Basic Arrays==&lt;br /&gt;
Arrays are always passed by reference.  The first example is an array which contains a list of numbers to sum.  Observe the native:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Averages an array of numbers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param array		Array of numbers to average.&lt;br /&gt;
 * @param num		Number of slots in the array.&lt;br /&gt;
 * @return		Average number as a Float.&lt;br /&gt;
 */&lt;br /&gt;
native Float:Average(array[], num);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usage might look like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;Example()&lt;br /&gt;
{&lt;br /&gt;
	new numbers[5] = {5, 6, 1, 3, 8};&lt;br /&gt;
	return Average(numbers, 5);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The implementation, like the by ref examples above, requires &amp;lt;tt&amp;gt;LocalToPhysAddr&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_Average(IPluginContext *pContext, cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	cell_t *array;&lt;br /&gt;
	float sum = 0.0f, average;&lt;br /&gt;
&lt;br /&gt;
	if (params[2] &amp;lt; 1)&lt;br /&gt;
	{&lt;br /&gt;
		/* 0 works without sp_ftoc() */&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	pContext-&amp;gt;LocalToPhysAddr(params[1], &amp;amp;array);&lt;br /&gt;
	for (cell_t i=0; i&amp;lt;params[2]; i++)&lt;br /&gt;
	{&lt;br /&gt;
		sum += array[i];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	average = sum / params[2];&lt;br /&gt;
&lt;br /&gt;
	return sp_ftoc(average);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Float Arrays==&lt;br /&gt;
This works similarly for Float arrays.  Let's take Vectors an example, with the following native:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Adds two vectors together.&lt;br /&gt;
 *&lt;br /&gt;
 * @param r	Array to store the result in.&lt;br /&gt;
 * @param v1	First vector to add.&lt;br /&gt;
 * @param v2	Second vector to add.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native AddVectors(Float:r[3], const Float:v1[3], const Float:v2[3]);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The implementation is straightforward:&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_AddVectors(IPluginContext *pContext, cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	cell_t *v1, *v2;&lt;br /&gt;
	float result[3];&lt;br /&gt;
	&lt;br /&gt;
	pContext-&amp;gt;LocalToPhysAddr(params[2], &amp;amp;v1);&lt;br /&gt;
	pContext-&amp;gt;LocalToPhysAddr(params[3], &amp;amp;v2);&lt;br /&gt;
&lt;br /&gt;
	result[0] = sp_ctof(v1[0]) + sp_ctof(v2[0]);&lt;br /&gt;
	result[1] = sp_ctof(v1[1]) + sp_ctof(v2[1]);&lt;br /&gt;
	result[2] = sp_ctof(v1[2]) + sp_ctof(v2[2]);&lt;br /&gt;
&lt;br /&gt;
	cell_t *r;&lt;br /&gt;
	pContext-&amp;gt;LocalToPhysAddr(params[1], &amp;amp;r);&lt;br /&gt;
	r[0] = sp_ftoc(result[0]);&lt;br /&gt;
	r[1] = sp_ftoc(result[1]);&lt;br /&gt;
	r[2] = sp_ftoc(result[2]);&lt;br /&gt;
	&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only store the result after we have computed the input, rather than store directly.  This is a bit more work, but is good practice in case users re-use data inputs, and risk overwriting inputs as they are written.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Float:origin[3];&lt;br /&gt;
AddVectors(origin, origin, origin);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Strings=&lt;br /&gt;
Strings are just like arrays, in that they are passed by reference.  The only difference is that each character is stored in a byte, not a 32bit &amp;lt;tt&amp;gt;cell_t&amp;lt;/tt&amp;gt;.  However, to make coding a bit easier for you, the coder, there are separate functions.&lt;br /&gt;
*&amp;lt;tt&amp;gt;LocalToString&amp;lt;/tt&amp;gt;: Converts a local address to a physical string address.&lt;br /&gt;
*&amp;lt;tt&amp;gt;StringToLocal&amp;lt;/tt&amp;gt;: Copies a physical string into a local address buffer.&lt;br /&gt;
*&amp;lt;tt&amp;gt;StringToLocalUTF8&amp;lt;/tt&amp;gt;: Same as &amp;lt;tt&amp;gt;StringToLocal&amp;lt;/tt&amp;gt;, but only copies the maximum amount possible without cutting off any multi byte characters.&lt;br /&gt;
&lt;br /&gt;
First, let's take an easy example: the infamous strlen.&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Returns the length of a string.&lt;br /&gt;
 * &lt;br /&gt;
 * @param string	String to calculate.&lt;br /&gt;
 * @return		Number of bytes in the string.&lt;br /&gt;
 */&lt;br /&gt;
native strlen(const String:string[]);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementation:&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_StrLen(IPluginContext *pContext, cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	char *str;&lt;br /&gt;
	pContext-&amp;gt;LocalToString(params[1], &amp;amp;str);&lt;br /&gt;
	return strlen(str);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, let's say we want to modify the string.  There is an important note here: since the string is passed by reference, when you modify the string, it is also modified in the plugin.  This is a huge difference from AMX Mod X, where strings were essentially by value in most cases, and you had to copy results back.&lt;br /&gt;
&lt;br /&gt;
Thus, if we wanted to copy a new result into &amp;lt;tt&amp;gt;str&amp;lt;/tt&amp;gt; in the above implementation, it would be very easy.  If we were implementing &amp;lt;tt&amp;gt;strcpy()&amp;lt;/tt&amp;gt;, we would have to use &amp;lt;tt&amp;gt;memmove()&amp;lt;/tt&amp;gt; to make sure there are no overlaps.  Let's do this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Copies one string onto another.&lt;br /&gt;
 *&lt;br /&gt;
 * @param dest		Destination buffer to copy to.&lt;br /&gt;
 * @param length	Maximum length of the buffer.&lt;br /&gt;
 * @param source	Source to copy from.&lt;br /&gt;
 * @noreturn&lt;br /&gt;
 */&lt;br /&gt;
native StringCopy(String:dest[], length, const String:source);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Implementation using &amp;lt;tt&amp;gt;memmove&amp;lt;/tt&amp;gt; for safety:&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_StringCopy(IPluginContext *pContext, cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	char *dest, *src;&lt;br /&gt;
	size_t len;&lt;br /&gt;
&lt;br /&gt;
	pContext-&amp;gt;LocalToString(params[1], &amp;amp;dest);&lt;br /&gt;
	pContext-&amp;gt;LocalToString(params[3], &amp;amp;src);&lt;br /&gt;
	&lt;br /&gt;
	/* Perform bounds checking */&lt;br /&gt;
	len = strlen(src);&lt;br /&gt;
	if (len &amp;gt;= params[2])&lt;br /&gt;
	{&lt;br /&gt;
		len = params[2] - 1;&lt;br /&gt;
	} else {&lt;br /&gt;
		len = params[2];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* Copy */&lt;br /&gt;
	memmove(dest, src, len);&lt;br /&gt;
&lt;br /&gt;
	dest[len] = '\0';&lt;br /&gt;
&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can also use &amp;lt;tt&amp;gt;StringToLocal&amp;lt;/tt&amp;gt;, which would requires a temporary buffer for the original string:&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t sm_StringCopy(IPluginContext *pContext, cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	char *src;&lt;br /&gt;
	char buffer[2048];&lt;br /&gt;
	size_t len;&lt;br /&gt;
&lt;br /&gt;
	pContext-&amp;gt;LocalToString(params[3], &amp;amp;src);&lt;br /&gt;
	&lt;br /&gt;
	snprintf(buffer, sizeof(buffer), &amp;quot;%s&amp;quot;, src);&lt;br /&gt;
	pContext-&amp;gt;StringToLocal(params[1], params[2], src);&lt;br /&gt;
&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Generally, you will be using &amp;lt;tt&amp;gt;StringToLocal&amp;lt;/tt&amp;gt; for setting strings from outside sources, because it calculates addresses and overflows for you.  However, you must make sure that you are not overwriting memory as you are reading it, or else programmers who are using certain types of array slicing may find themselves getting unexpected results.&lt;br /&gt;
&lt;br /&gt;
=Advanced=&lt;br /&gt;
==Default Arguments==&lt;br /&gt;
Any type of parameter can have a default argument.  For example, here is a native where every argument has a default parameter:&lt;br /&gt;
&amp;lt;pawn&amp;gt;native RandomStuff(a=0, Float:b=1.0f, &amp;amp;c=0, const String:d[]=&amp;quot;&amp;quot;, e[3] = {0,1,2});&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that even by reference parameters can have default arguments, as shown above.  This does not change the code; it just means the address will contain the default value.  &lt;br /&gt;
&lt;br /&gt;
Scripts can force default values.  Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;native RandomStuff(a, b, c=0, d=0);&lt;br /&gt;
&lt;br /&gt;
Example()&lt;br /&gt;
{&lt;br /&gt;
	RandomStuff(1, 2, _, d);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The underscore ('_') means &amp;quot;use the default value for this argument.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==Variable Arguments==&lt;br /&gt;
Variable arguments means any number of arguments can be passed.  An example of this looks like:&lt;br /&gt;
&amp;lt;pawn&amp;gt;native FormatText(const String:format[], {Float,String,_}:...);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;{Float,Handle_}:&amp;lt;/tt&amp;gt; is a multi-tag specifier that means any extra parameters must be either a &amp;lt;tt&amp;gt;Float&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, or have no tag at all.  The &amp;lt;tt&amp;gt;...&amp;lt;/tt&amp;gt; characters mean any number of parameters can follow.&lt;br /&gt;
&lt;br /&gt;
'''There is one important note about variable arguments.  They are always passed by reference.'''  This means if you have a function which supports variable arguments, and an integer is passed, you will need to use &amp;lt;tt&amp;gt;LocalToPhysAddr&amp;lt;/tt&amp;gt; as required with by reference parameters.  &lt;br /&gt;
&lt;br /&gt;
==Argument Counts/Backwards Compatibility==&lt;br /&gt;
In native handlers, the &amp;lt;tt&amp;gt;params&amp;lt;/tt&amp;gt; array has a 0th index which stores the number of parameters it contains.  This is useful for both Default Arguments and Variable Arguments.  &lt;br /&gt;
&lt;br /&gt;
For example, consider the following native:&lt;br /&gt;
&amp;lt;pawn&amp;gt;native DoSomething(index);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's say that this native exists in plugins for six months.  After that, you decide to add a new parameter.  You want two conditions to be true after you release this update:&lt;br /&gt;
*Old plugins in binary form should still work on newer installations.&lt;br /&gt;
*Old plugins should still compile fine on the new API.&lt;br /&gt;
&lt;br /&gt;
The second condition is solved by using default arguments.  You should choose a value that will mimic the old functionality of the native.&lt;br /&gt;
&amp;lt;pawn&amp;gt;native DoSomething(index, newparam = 0);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, when changing the implementation, you should detect whether &amp;lt;tt&amp;gt;params[0]&amp;lt;/tt&amp;gt; contains ''one parameter'' or ''two parameters''.  If it only contains one, you know to use the old version.  If it contains two, you know to use the later version and accept the second parameter.&lt;br /&gt;
&lt;br /&gt;
Similarly, you can use the &amp;lt;tt&amp;gt;params[0]&amp;lt;/tt&amp;gt; count to detect how many arguments were passed to a variable argument native.  This is used primarily in [[Format Class Functions (SourceMod Scripting)|Format Class Functions]] for parameter-count validation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Throwing Errors/Invoking the Debugger=&lt;br /&gt;
Often, you will write a native and realize that you need to tell the plugin that a serious error has occurred.  A good example of this is if you are writing a function which requires a player index, but that index is beyond the reasonable bounds for the maximum players in the server.&lt;br /&gt;
&lt;br /&gt;
In this case, it is a good idea to throw a ''runtime error''.  This is an error that halts the plugin and invokes a call trace from the debugger.  The halt is not permanent, but it does break the execution flow of the current callback.&lt;br /&gt;
&lt;br /&gt;
There are two ways to throw a native error: &amp;lt;tt&amp;gt;ThrowNativeErrorEx()&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;ThrowNativeError()&amp;lt;/tt&amp;gt;.  The former lets you specify a detailed error code from &amp;lt;tt&amp;gt;sp_vm_types.h&amp;lt;/tt&amp;gt;.  The latter is a helper function for generic errors, and it returns 0, allowing you to return with the function itself.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;static cell_t GetPlayerFrags(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	if (params[1] &amp;lt; 0 || params[1] &amp;gt; maxplayers)&lt;br /&gt;
	{&lt;br /&gt;
		return pContext-&amp;gt;ThrowNativeError(&amp;quot;Invalid client index: %d&amp;quot;, params[1]);&lt;br /&gt;
	}&lt;br /&gt;
	/* ... rest of code ... */&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don't worry about including extra information, such as your native name or the module name.  The debugger knows all of this information and will decide what to print to the user.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Handles_(SourceMod_Scripting)&amp;diff=4490</id>
		<title>Handles (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Handles_(SourceMod_Scripting)&amp;diff=4490"/>
		<updated>2007-05-02T01:14:16Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Handles are a special data type used in [[SourceMod Scripting]].  They represent a single internal and unique object.  For example, there are &amp;quot;File&amp;quot; Handles for files, and &amp;quot;Menu&amp;quot; Handles for menus, but they are both encapsulated under the &amp;quot;Handle&amp;quot; [[Tags (SourceMod Scripting)|tag]].&lt;br /&gt;
&lt;br /&gt;
Handles are more than &amp;quot;pointers&amp;quot; from C or C++ because they have a ''reference count''.  This means that the number of copies floating around in memory is tracked.  The actual internal object is not destroyed until each copy is also destroyed.&lt;br /&gt;
&lt;br /&gt;
Since SourcePawn does not have [[Garbage Collection]], Handles are a special way of intelligently allowing plugins and SourceMod to manage their own memory.&lt;br /&gt;
&lt;br /&gt;
For more information on using Handles in the SourceMod API, see [[Handle API (SourceMod)]].&lt;br /&gt;
&lt;br /&gt;
=Opening Handles=&lt;br /&gt;
Opening a Handle is usually done implicitly by a native function.  For example, OpenDirectory opens a new Handle which is used in other Directory natives.  This associates a ''type'' with the Handle.  Trying to use a Directory Handle with any other non-Directory native will cause an error (HandleError_Type), because Handles are type checked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Handle:hndl = OpenDirectory(&amp;quot;addons/sourcemod/configs&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Closing Handles=&lt;br /&gt;
==Basic operation==&lt;br /&gt;
Closing a Handle means seeing if the internal object can be removed from memory.  For example, if a plugin creates an SQL connection, closing the Handle means closing and destroying the connection.  This is almost always done using the CloseHandle() native function.&lt;br /&gt;
&lt;br /&gt;
==When to close==&lt;br /&gt;
When a plugin unloads, all of its Handles are automatically destroyed.  This does not mean, however, that closing Handles is optional.  Consider the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;stock bool:IsFileInFolder(const String:path[], const String:file[])&lt;br /&gt;
{&lt;br /&gt;
	new String:path[PLATFORM_MAX_PATH];&lt;br /&gt;
	new FileType:type;&lt;br /&gt;
&lt;br /&gt;
	new Handle:dir = OpenDirectory(path);&lt;br /&gt;
	if (dir == INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	while (ReadDirEntry(dir, path, sizeof(path), type))&lt;br /&gt;
	{&lt;br /&gt;
		if (type == FileType_File &amp;amp;&amp;amp; StrEqual(path, file))&lt;br /&gt;
		{&lt;br /&gt;
			return true;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	CloseHandle(dir);&lt;br /&gt;
&lt;br /&gt;
	return false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function searches a directory for a single file.  If this function were to omit the call to CloseHandle, it would [[Memory Leak|leak memory]] every time it was called, and eventually the script would fill up with a large number of lingering Handles that were left open.&lt;br /&gt;
&lt;br /&gt;
So, when do you close Handles?  There are generally two rules of thumb to go by:&lt;br /&gt;
*If the native uses terminology such as &amp;quot;Opens a [...]&amp;quot; or &amp;quot;Creates a [...]&amp;quot; or gives explicit directions for closing.&lt;br /&gt;
*If the Handle represents a temporary object or piece of information, and you will no longer be using it.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you will be closing Handles.  Check the Handle Type documentation at the end of this page.&lt;br /&gt;
&lt;br /&gt;
==When you can't close==&lt;br /&gt;
There are a few Handle types that cannot be closed.  The major one is the Handle which identifies a plugin.  Plugins cannot unload themselves, and thus destroying their own Handles is not allowed.&lt;br /&gt;
&lt;br /&gt;
Furthermore, a script cannot close a Handle that is owned by another plugin.  This is for protection against API mistakes and accidental errors.  For example, if a Handle is shared between two plugins, one accidental free could invalidate a Handle unexpectedly.  To allow the sharing of Handles, see [[#Cloning Handles|Cloning Handles]].&lt;br /&gt;
&lt;br /&gt;
==Reference counters==&lt;br /&gt;
Closing Handles does not always destroy the internal data.  This is the case when Handles are [[#Cloning Handles|cloned]].  Each clone adds a ''reference count'' to the Handle, and closing each clone removes one reference count.  The original object is only actually destroyed once the Handle has no more reference counters.  &lt;br /&gt;
&lt;br /&gt;
=Cloning Handles=&lt;br /&gt;
As briefly described earlier, there is a problem when scripts try to share Handles.  Imagine this scenario:&lt;br /&gt;
*Plugin 'A' creates a Handle.&lt;br /&gt;
*Plugin 'B' received the Handle.&lt;br /&gt;
*Plugin 'A' is unloaded, and the Handle is destroyed.&lt;br /&gt;
*Plugin 'B' tries to use the Handle.&lt;br /&gt;
&lt;br /&gt;
To prevent this, the CloneHandle native is provided.  This function returns a ''new'' Handle that is a &amp;quot;copy&amp;quot; of the original.  While their values won't be equal, they contain the same internal data.  The data itself will not be destroyed until each copy and the original are closed with CloseHandle.  It does not matter what order they are freed in, however, each Handle can only be freed once.&lt;br /&gt;
&lt;br /&gt;
There are two ways of cloning.  A plugin can either clone a Handle itself, and become the owner, or it can explicitly set a new owner.  The difference is one of API design.  Example of the former:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Handle:g_hSQL;&lt;br /&gt;
/**&lt;br /&gt;
 * The other plugin calling this function must pass his ID in,&lt;br /&gt;
 * but doesn't have to call CloneHandle()&lt;br /&gt;
 */&lt;br /&gt;
public Handle:GetGlobalSQL(Handle:otherPlugin)&lt;br /&gt;
{&lt;br /&gt;
   return CloneHandle(g_hSQL, otherPlugin);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This code would appear in the other plugin&lt;br /&gt;
 */&lt;br /&gt;
new Handle:sql = GetGlobalSQL(myself);&lt;br /&gt;
/* ... */&lt;br /&gt;
CloseHandle(sql);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of the latter:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Handle:g_hSQL;&lt;br /&gt;
/**&lt;br /&gt;
 * The calling plugin must call CloneHandle() himself.&lt;br /&gt;
 */&lt;br /&gt;
public Handle:GetGlobalSQL()&lt;br /&gt;
{&lt;br /&gt;
   return g_hSQL;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This code would appear in the other plugin&lt;br /&gt;
 */&lt;br /&gt;
new Handle:sql = GetGlobalSQL();&lt;br /&gt;
if (sql != INVALID_HANDLE)&lt;br /&gt;
{&lt;br /&gt;
   sql = CloneHandle(sql);&lt;br /&gt;
}&lt;br /&gt;
CloseHandle(sql);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Handle Types=&lt;br /&gt;
The following is a list of the known Handle types provided by SourceMod and some documentation on each.&lt;br /&gt;
==BitBuffers==&lt;br /&gt;
{{HandleType|bf_read or bf_write|Only if explicitly stated|Only if it can also be closed|Core|bitbuffer.inc}}&lt;br /&gt;
&lt;br /&gt;
There are four types of BitBuffer Handles.  They are separated into ''bf_write'' (writable buffer) and ''bf_read'' (readable buffer).  These are directly abstracted from their Half-Life 2 counterpart.  Internally, there are separate Handle types for each; certain functions will use BitBuffer handles that cannot be freed.&lt;br /&gt;
&lt;br /&gt;
==ConVars==&lt;br /&gt;
{{HandleType|ConVar|No|No|Core|console.inc}}&lt;br /&gt;
&lt;br /&gt;
ConVar Handles are primarily used for getting and setting a console variable's value. They cannot be cloned nor deleted since they exist until SourceMod is shut down.&lt;br /&gt;
&lt;br /&gt;
==Directories==&lt;br /&gt;
{{HandleType|Directory|Yes|Yes|Core|files.inc}}&lt;br /&gt;
&lt;br /&gt;
Directory Handles are used for opening and enumerating the contents of a directory (folder) on the filesystem.&lt;br /&gt;
&lt;br /&gt;
==Database Drivers==&lt;br /&gt;
{{HandleType|DBDriver|Yes|No|Core|dbi.inc}}&lt;br /&gt;
&lt;br /&gt;
DBDriver Handles contain information about a database driver.  They must be closed so your plugin does not have any dependencies lingering on the database driver.&lt;br /&gt;
&lt;br /&gt;
==Database Queries==&lt;br /&gt;
{{HandleType|IQuery|Yes|No|Core|dbi.inc}}&lt;br /&gt;
&lt;br /&gt;
Database Queries wrap an &amp;lt;tt&amp;gt;IQuery&amp;lt;/tt&amp;gt; pointer for database queries.  Closing a query frees its resources, including any prepared statement information and any result sets.&lt;br /&gt;
&lt;br /&gt;
==Databases==&lt;br /&gt;
{{HandleType|IDatabase|Yes|Yes|Core|dbi.inc}}&lt;br /&gt;
&lt;br /&gt;
Database Handles wrap an &amp;lt;tt&amp;gt;IDatabase&amp;lt;/tt&amp;gt; pointer for database connections.  Closing these disconnects the database and frees any related resources.&lt;br /&gt;
&lt;br /&gt;
==Events==&lt;br /&gt;
{{HandleType|Event|No|No|Core|events.inc}}&lt;br /&gt;
&lt;br /&gt;
Event Handles are used for getting and setting data in Half-Life 2 game events as well as for firing them. They can only be closed using CancelCreatedEvent() if the event was not fired for some reason.&lt;br /&gt;
&lt;br /&gt;
==Files==&lt;br /&gt;
{{HandleType|File|Yes|Yes|Core|files.inc}}&lt;br /&gt;
&lt;br /&gt;
File Handles are used for opening, reading from, writing to, and creating to files on the file system.&lt;br /&gt;
&lt;br /&gt;
==Forwards==&lt;br /&gt;
{{HandleType|Forward|Yes|Only if explicitly stated|Core|functions.inc}}&lt;br /&gt;
&lt;br /&gt;
Forward Handles are primarily used when calling functions inside a forward container. There are two types of forwards: global and private. Only private forwards can be cloned.&lt;br /&gt;
&lt;br /&gt;
==KeyValues==&lt;br /&gt;
{{HandleType|KeyValues|Yes|No|Core|keyvalues.inc}}&lt;br /&gt;
&lt;br /&gt;
KeyValues Handles abstract the Valve data type &amp;lt;tt&amp;gt;KeyValues&amp;lt;/tt&amp;gt;, which are tree-based, recursive key to value mapping structures, often used to enumerate properties or configuration file directives.&lt;br /&gt;
&lt;br /&gt;
==Plugins==&lt;br /&gt;
{{HandleType|Plugin|No|No|Core|sourcemod.inc}}&lt;br /&gt;
&lt;br /&gt;
Plugin Handles are used for the unique identification of a Plugin.  They are owned by Core and cannot be cloned or closed by any other plugin or extension.  However, plugins can use Handles for certain natives which enumerate or retrieve information on plugins.  &lt;br /&gt;
&lt;br /&gt;
Plugin Handles should not be cached globally, as plugins can become unloaded, and the Handle will be invalid.&lt;br /&gt;
&lt;br /&gt;
==Plugin Iterators==&lt;br /&gt;
{{HandleType|PluginIter|Yes|No|Core|sourcemod.inc}}&lt;br /&gt;
&lt;br /&gt;
Plugin Iterators allow you to walk over a list of plugins.  They are intended for temporary use only.&lt;br /&gt;
&lt;br /&gt;
==SMC Parsers==&lt;br /&gt;
{{HandleType|SMC Parser|Yes|No|Core|textparse.inc}}&lt;br /&gt;
&lt;br /&gt;
SMC Parsers are Handles which contain a set of functions for hooking parse events in an SMC file.  See more in [[SMC Parsing (SourceMod Scripting)]].  Since they directly reference functions in a plugin, they cannot be cloned.&lt;br /&gt;
&lt;br /&gt;
==Timers==&lt;br /&gt;
{{HandleType|Timer|Yes|No|Core|timers.inc}}&lt;br /&gt;
&lt;br /&gt;
Timers are temporary Handles which are automatically closed on any of the following events:&lt;br /&gt;
*The timer ends (via Plugin_Stop or being a one-time timer that is finished)&lt;br /&gt;
*The timer is killed via &amp;lt;tt&amp;gt;KillTimer&amp;lt;/tt&amp;gt;&lt;br /&gt;
*The timer is closed via &amp;lt;tt&amp;gt;CloseHandle&amp;lt;/tt&amp;gt;&lt;br /&gt;
*The timer's parent plugin unloads&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Development]][[Category:SourceMod Scripting]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=4481</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=4481"/>
		<updated>2007-04-30T04:57:24Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: /* Simple Values */ typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:LoadStuff(Handle:timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
DoMessage()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, PrintMsg, _, TIMER_REPEAT)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:PrintMsg(Handle:timer)&lt;br /&gt;
{&lt;br /&gt;
	static NumPrinted = 0&lt;br /&gt;
	if (NumPrinted++ &amp;gt;= 5)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;)&lt;br /&gt;
		NumPrinted = 0&lt;br /&gt;
&lt;br /&gt;
		return Plugin_Stop&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define MAX_PLAYERS 256&lt;br /&gt;
&lt;br /&gt;
new Handle:WelcomeTimers[MAX_PLAYERS+1]&lt;br /&gt;
&lt;br /&gt;
public OnClientPutInServer(client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnClientDisconnect(client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client])&lt;br /&gt;
		WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:WelcomePlayer(Handle:timer, client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;)&lt;br /&gt;
	WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define MAX_PLAYERS 256&lt;br /&gt;
&lt;br /&gt;
new Handle:WelcomeTimers[MAX_PLAYERS+1]&lt;br /&gt;
&lt;br /&gt;
public OnClientPutInServer(client)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:pack&lt;br /&gt;
	WelcomeTimers[client] = CreateDataTimer(15.0, WelcomePlayer, pack)&lt;br /&gt;
	WritePackCell(pack, client)&lt;br /&gt;
	WritePackString(pack, &amp;quot;Welcome to the server!&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnClientDisconnect(client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client])&lt;br /&gt;
		WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:WelcomePlayer(Handle:timer, Handle:pack)&lt;br /&gt;
{&lt;br /&gt;
	decl String:str[128]&lt;br /&gt;
	new client&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	ResetPack(pack)&lt;br /&gt;
	client = ReadPackCell(pack)&lt;br /&gt;
	ReadPackString(pack, str, sizeof(str))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str)&lt;br /&gt;
	WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=4480</id>
		<title>Timers (SourceMod Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Timers_(SourceMod_Scripting)&amp;diff=4480"/>
		<updated>2007-04-30T04:57:16Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: /* Data Packs */ fixed typo in timer function name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timers in [[SourceMod]] are timed events that occur once or repeatedly at a given interval.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Timers allow you to set an interval, a function to use as the event callback, and an optional Handle to pass through the callback.  This is useful for saving data asynchronously.&lt;br /&gt;
&lt;br /&gt;
All timer functions are in &amp;lt;tt&amp;gt;plugins/include/timers.inc&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
=Basic Usage=&lt;br /&gt;
==One-Time Timers==&lt;br /&gt;
One-time timers are timers that only execute once.  An example of a one-time timer might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public OnPluginStart()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(5.0, LoadStuff)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:LoadStuff(Handle:timer)&lt;br /&gt;
{&lt;br /&gt;
	PrintToServer(&amp;quot;Loading stuff!&amp;quot;)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code will print &amp;quot;Loading stuff!&amp;quot; to the server console five seconds after the map loads.  The return value has no meaning for one-time timers.&lt;br /&gt;
&lt;br /&gt;
==Repeatable Timers==&lt;br /&gt;
Repeatable timers execute infinitely many times, once every interval.  Based on the return value, they either continue or cancel.&lt;br /&gt;
&lt;br /&gt;
For example, say you want to display a message five times, once every three seconds:&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
DoMessage()&lt;br /&gt;
{&lt;br /&gt;
	CreateTimer(3.0, PrintMsg, _, TIMER_REPEAT)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:PrintMsg(Handle:timer)&lt;br /&gt;
{&lt;br /&gt;
	static NumPrinted = 0&lt;br /&gt;
	if (NumPrinted++ &amp;gt;= 5)&lt;br /&gt;
	{&lt;br /&gt;
		PrintToServer(&amp;quot;Warning! This is a message.&amp;quot;)&lt;br /&gt;
		NumPrinted = 0&lt;br /&gt;
&lt;br /&gt;
		return Plugin_Stop&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return Plugin_Continue&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; stops the timer, and &amp;lt;tt&amp;gt;Plugin_Continue&amp;lt;/tt&amp;gt; allows it to continue repeating.&lt;br /&gt;
&lt;br /&gt;
=Passing Data=&lt;br /&gt;
==Simple Values==&lt;br /&gt;
As mentioned earlier, timers let you pass values on to the callback function.  This value can be any type.  For example, let's say we want to print a message to a player fifteen seconds after they connect.  However, we want to cancel the timer if the player disconnects.  Implementing this is very easy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define MAX_PLAYERS 256&lt;br /&gt;
&lt;br /&gt;
new Handle:WelcomeTimers[MAX_PLAYERS+1]&lt;br /&gt;
&lt;br /&gt;
public OnClientPutInServer(client)&lt;br /&gt;
{&lt;br /&gt;
	WelcomeTimers[client] = CreateTimer(15.0, WelcomePlayer, client)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnClientDisconnect(client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client])&lt;br /&gt;
		WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:WelcomeTimer(Handle:timer, client)&lt;br /&gt;
{&lt;br /&gt;
	PrintToConsole(client, &amp;quot;Welcome to the server!&amp;quot;)&lt;br /&gt;
	WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Handles==&lt;br /&gt;
If you want to pass a Handle as a value, you have the option of using &amp;lt;tt&amp;gt;TIMER_HNDL_CLOSE&amp;lt;/tt&amp;gt;, which will automatically call &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; for you once the timer dies.  &lt;br /&gt;
&lt;br /&gt;
==Data Packs==&lt;br /&gt;
Data packs are packable structures that can be used to hold asynchronous data (data that must be saved and unpacked for later).  They are especially useful for timers, and thus there exists a helper function, called &amp;lt;tt&amp;gt;CreateDataTimer()&amp;lt;/tt&amp;gt;, which creates a timer using a data pack handle.  The handle is created and closed automatically for you.&lt;br /&gt;
&lt;br /&gt;
The above example could be rewritten as:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define MAX_PLAYERS 256&lt;br /&gt;
&lt;br /&gt;
new Handle:WelcomeTimers[MAX_PLAYERS+1]&lt;br /&gt;
&lt;br /&gt;
public OnClientPutInServer(client)&lt;br /&gt;
{&lt;br /&gt;
	new Handle:pack&lt;br /&gt;
	WelcomeTimers[client] = CreateDataTimer(15.0, WelcomePlayer, pack)&lt;br /&gt;
	WritePackCell(pack, client)&lt;br /&gt;
	WritePackString(pack, &amp;quot;Welcome to the server!&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public OnClientDisconnect(client)&lt;br /&gt;
{&lt;br /&gt;
	if (WelcomeTimers[client] != INVALID_HANDLE)&lt;br /&gt;
	{&lt;br /&gt;
		KillTimer(WelcomeTimers[client])&lt;br /&gt;
		WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Action:WelcomePlayer(Handle:timer, Handle:pack)&lt;br /&gt;
{&lt;br /&gt;
	decl String:str[128]&lt;br /&gt;
	new client&lt;br /&gt;
&lt;br /&gt;
	/* Set to the beginning and unpack it */&lt;br /&gt;
	ResetPack(pack)&lt;br /&gt;
	client = ReadPackCell(pack)&lt;br /&gt;
	ReadPackString(pack, str, sizeof(str))&lt;br /&gt;
&lt;br /&gt;
	PrintToConsole(client, &amp;quot;%s&amp;quot;, str)&lt;br /&gt;
	WelcomeTimers[client] = INVALID_HANDLE&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Notes=&lt;br /&gt;
==Accuracy==&lt;br /&gt;
The smallest possible interval is 0.1 seconds.  Timers have high precision (floating point) but low accuracy, as the current time is based on the in-game tick count, not the system clock.  This has two implications:&lt;br /&gt;
*If the server is paused (not ticking), timers will not run.&lt;br /&gt;
*The server will not always tick at an exact interval.  &lt;br /&gt;
&lt;br /&gt;
For example, a 1.234 second interval timer starting from time &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt; might not tick until &amp;lt;tt&amp;gt;t+1.242&amp;lt;/tt&amp;gt; at a tickrate of 66 ticks per second.&lt;br /&gt;
&lt;br /&gt;
==Timer Death==&lt;br /&gt;
All timers are guaranteed to die either by:&lt;br /&gt;
*&amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; being called (or on plugin unload);&lt;br /&gt;
*&amp;lt;tt&amp;gt;KillTimer()&amp;lt;/tt&amp;gt; being called;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Plugin_Stop&amp;lt;/tt&amp;gt; being returned from a repeatable timer;&lt;br /&gt;
*&amp;lt;tt&amp;gt;TriggerTimer()&amp;lt;/tt&amp;gt; being called on a one-time timer;&lt;br /&gt;
*Execution of a one-time timer finishes.&lt;br /&gt;
&lt;br /&gt;
When a timer dies, if &amp;lt;tt&amp;gt;TIMER_HNDL_CLOSE&amp;lt;/tt&amp;gt; is set, the Handle will always be closed with the permissions that &amp;lt;tt&amp;gt;CloseHandle()&amp;lt;/tt&amp;gt; uses by default.  Since timers cannot be cloned, there should be no ownership issues.&lt;br /&gt;
&lt;br /&gt;
==Changing Intervals==&lt;br /&gt;
The interval of a timer cannot be changed as of this writing.  The timer must be killed and a new one created.&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Unlike [[AMX Mod X]]'s &amp;lt;tt&amp;gt;set_task&amp;lt;/tt&amp;gt; function, you cannot pass arrays using &amp;lt;tt&amp;gt;CreateTimer&amp;lt;/tt&amp;gt;.  To accomplish this, you should use the data pack functionality explained above.&lt;br /&gt;
&lt;br /&gt;
Similarly, there are no flags for counted repeats (non-infinite loops) or timers based on the map start or end.  These must be done manually.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod Scripting]]&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=User:CyberMind&amp;diff=3957</id>
		<title>User:CyberMind</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=User:CyberMind&amp;diff=3957"/>
		<updated>2007-03-02T02:09:39Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: /* WebMod */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=About Me=&lt;br /&gt;
I am a [[User:BAILOPAN|BAILOPAN]] groupie. I am on IRC [http://cybermind.user.stfunoob.com/misc/mirctimer.png too much].&lt;br /&gt;
&lt;br /&gt;
=Gaming Projects=&lt;br /&gt;
*[http://www.q3mm.org/ QMM] (Quake3 MultiMod) - a Metamod-like system for Quake 3-based games&lt;br /&gt;
*[http://qmm.planetquake.gamespy.com/forums/viewtopic.php?t=52 Stripper] QMM plugin - Dynamic map entity addition/removal&lt;br /&gt;
*[http://qmm.planetquake.gamespy.com/forums/viewtopic.php?t=53 RocketMod] QMM plugin - Gameplay modification plugin&lt;br /&gt;
*[http://www.phpua.com/ phpua_mm] [[Metamod]] plugin (co-author, lead developer) - Provides real-time game information for web-based phpUA software&lt;br /&gt;
*[http://logd.sourceforge.net/weaptfc/ WeapTFC] [[Metamod]] plugin - Class-based TFC weapon restrictions&lt;br /&gt;
&lt;br /&gt;
=Other Projects=&lt;br /&gt;
*[http://finop.sourceforge.net/ FinOP] IRC Bot - Modular IRC bot that has gone through far too many core rewrites; still not done; very inactive&lt;br /&gt;
*[http://quala.sourceforge.net/ Quala] Extension Language - Scripting language based off of the Quake3 Virtual Machine format. Currently undeveloped and inactive.&lt;br /&gt;
&lt;br /&gt;
=Contributions=&lt;br /&gt;
I enjoy pointing out answers via pictorial depictions. See [http://www.sourcemod.net/forums/viewtopic.php?p=27600#27600 here], [http://www.amxmodx.org/forums/viewtopic.php?p=182749&amp;amp;#182749 here], and [http://www.amxmodx.org/forums/viewtopic.php?p=204502&amp;amp;#204502 here].&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Since I don't know [[AMX_Mod_X|AMX Mod X]] plugin API to save my life, I typically only help out when questions are related to Pawn programming in general.&lt;br /&gt;
&lt;br /&gt;
==SourceMM==&lt;br /&gt;
I know a little bit more in the [[SourceMM]] plugin API department, despite not owning [[Half-Life_2|Half-Life 2]], and sometimes help out on the [[SourceMod]] forums. I also have moderate-to-advanced C/C++ knowledge and minor asm knowledge and sometimes help with general coding questions.&lt;br /&gt;
&lt;br /&gt;
==Pawn/AMX==&lt;br /&gt;
A while ago, I set out to get Visual Basic 6 to load and execute AMX files. My goal was to run AdminMod plugins in a pseudo-server environment, and I got as far as properly loading the files and handling natives, but I only coded around 3 or 4 of all of available AdminMod natives. The AMX version has undoubtedly changed by then, but the code is available [http://cybermind.user.stfunoob.com/vbamx/ here] to view. Note the included amx.h file has been changed and must be used in recompiling AdminMod's amx_admin.dll. Yes, I am aware my malloc/free implementation could have been better, but I was not as awesome back then as I am now.&lt;br /&gt;
&lt;br /&gt;
==WebMod==&lt;br /&gt;
I [http://secunia.com/advisories/14302/ defeated it] in hand-to-hand combat.&lt;br /&gt;
And then I [http://secunia.com/advisories/24346/ judo-chopped] it.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=User:CyberMind&amp;diff=3956</id>
		<title>User:CyberMind</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=User:CyberMind&amp;diff=3956"/>
		<updated>2007-03-02T02:07:26Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: /* WebMod */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=About Me=&lt;br /&gt;
I am a [[User:BAILOPAN|BAILOPAN]] groupie. I am on IRC [http://cybermind.user.stfunoob.com/misc/mirctimer.png too much].&lt;br /&gt;
&lt;br /&gt;
=Gaming Projects=&lt;br /&gt;
*[http://www.q3mm.org/ QMM] (Quake3 MultiMod) - a Metamod-like system for Quake 3-based games&lt;br /&gt;
*[http://qmm.planetquake.gamespy.com/forums/viewtopic.php?t=52 Stripper] QMM plugin - Dynamic map entity addition/removal&lt;br /&gt;
*[http://qmm.planetquake.gamespy.com/forums/viewtopic.php?t=53 RocketMod] QMM plugin - Gameplay modification plugin&lt;br /&gt;
*[http://www.phpua.com/ phpua_mm] [[Metamod]] plugin (co-author, lead developer) - Provides real-time game information for web-based phpUA software&lt;br /&gt;
*[http://logd.sourceforge.net/weaptfc/ WeapTFC] [[Metamod]] plugin - Class-based TFC weapon restrictions&lt;br /&gt;
&lt;br /&gt;
=Other Projects=&lt;br /&gt;
*[http://finop.sourceforge.net/ FinOP] IRC Bot - Modular IRC bot that has gone through far too many core rewrites; still not done; very inactive&lt;br /&gt;
*[http://quala.sourceforge.net/ Quala] Extension Language - Scripting language based off of the Quake3 Virtual Machine format. Currently undeveloped and inactive.&lt;br /&gt;
&lt;br /&gt;
=Contributions=&lt;br /&gt;
I enjoy pointing out answers via pictorial depictions. See [http://www.sourcemod.net/forums/viewtopic.php?p=27600#27600 here], [http://www.amxmodx.org/forums/viewtopic.php?p=182749&amp;amp;#182749 here], and [http://www.amxmodx.org/forums/viewtopic.php?p=204502&amp;amp;#204502 here].&lt;br /&gt;
&lt;br /&gt;
==AMX Mod X==&lt;br /&gt;
Since I don't know [[AMX_Mod_X|AMX Mod X]] plugin API to save my life, I typically only help out when questions are related to Pawn programming in general.&lt;br /&gt;
&lt;br /&gt;
==SourceMM==&lt;br /&gt;
I know a little bit more in the [[SourceMM]] plugin API department, despite not owning [[Half-Life_2|Half-Life 2]], and sometimes help out on the [[SourceMod]] forums. I also have moderate-to-advanced C/C++ knowledge and minor asm knowledge and sometimes help with general coding questions.&lt;br /&gt;
&lt;br /&gt;
==Pawn/AMX==&lt;br /&gt;
A while ago, I set out to get Visual Basic 6 to load and execute AMX files. My goal was to run AdminMod plugins in a pseudo-server environment, and I got as far as properly loading the files and handling natives, but I only coded around 3 or 4 of all of available AdminMod natives. The AMX version has undoubtedly changed by then, but the code is available [http://cybermind.user.stfunoob.com/vbamx/ here] to view. Note the included amx.h file has been changed and must be used in recompiling AdminMod's amx_admin.dll. Yes, I am aware my malloc/free implementation could have been better, but I was not as awesome back then as I am now.&lt;br /&gt;
&lt;br /&gt;
==WebMod==&lt;br /&gt;
I [http://secunia.com/advisories/14302/ defeated it] in hand-to-hand combat.&lt;br /&gt;
And then I [url=http://secunia.com/advisories/24346/]judo-chopped[/url] it.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Using_New_Menu_System&amp;diff=3862</id>
		<title>Ru Using New Menu System</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Using_New_Menu_System&amp;diff=3862"/>
		<updated>2007-01-23T00:21:55Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: added russian category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
= Введение =&lt;br /&gt;
Это статья поможет вам разобраться в новой системе меню.&lt;br /&gt;
&lt;br /&gt;
== Урок по созданию меню ==&lt;br /&gt;
Давайте попробуем воспользоваться новой системмой меню. Мы пройдем через этоу простую инструкцию и создадим простое голосование смены карты.&lt;br /&gt;
&lt;br /&gt;
=== Заголовочные файлы ===&lt;br /&gt;
Как обычно мы начинаем с добавления необходимых заголовочных файлов&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Глобальные переменные ===&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
new g_Menu;	// Переменная обработки главного меню&lt;br /&gt;
new g_Votes[3];	// Сохраняем голосования Да как 1, No как 2&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тут мы создали 2 глобальные переменные. Одна содержит указатель вашего меню, другая хранит резуьтаты голосования. Голоса 'Да' будут сохранены в g_Votes[1] ,а 'Нет' будет сохранена в g_Votes[2].&lt;br /&gt;
&lt;br /&gt;
=== Регистрируем Плагин и Меню ===&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	// Регистрируем ваш плагин&lt;br /&gt;
	register_plugin(&amp;quot;Vote Menu&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Freecode&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Регистрируем меню смены карты&lt;br /&gt;
	g_Menu = menu_create(&amp;quot;Change Level?&amp;quot;,&amp;quot;menu_handle&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	register_clcmd(&amp;quot;amx_startvote&amp;quot;,&amp;quot;startvote&amp;quot;,ADMIN_CFG,&amp;quot;Gaben&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Теперь нам надо создать наше меню&lt;br /&gt;
	build_menu();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lets break this down. &lt;br /&gt;
&lt;br /&gt;
*Регистрирует ваш плагин&lt;br /&gt;
&amp;lt;pawn&amp;gt;register_plugin(&amp;quot;Vote Menu&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Freecode&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*g_Menu - Указатель на ваше меню. Это будет установлено после вызова menu_create.&lt;br /&gt;
&amp;lt;pawn&amp;gt;g_Menu = menu_create(&amp;quot;Change Level?&amp;quot;,&amp;quot;menu_handle&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
//menu_create ( title[], handler[], ml=0 )&lt;br /&gt;
//title[] - Заголовок меню&lt;br /&gt;
//handler[] - Эта функция будет вызвана когда будет нажата клавиша в вашем меню.&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Мы добавили эту команду. Она начинает ваше голосование.&lt;br /&gt;
&amp;lt;pawn&amp;gt;register_clcmd(&amp;quot;amx_startvote&amp;quot;,&amp;quot;startvote&amp;quot;,ADMIN_CFG,&amp;quot;Gaben&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Это вызов функции. build_menu() функция создает ваше меню.&lt;br /&gt;
&amp;lt;pawn&amp;gt;build_menu();&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Создение меню ===&lt;br /&gt;
Конструирование заключается в добавлении пунктов в ваше меню. Прежде чем начали добавлять пункты, мы должны взглянуть на &lt;br /&gt;
menu_additem .&lt;br /&gt;
&amp;lt;pawn&amp;gt;menu_additem ( menu, const name[], const command[], paccess=0, callback=-1 )&amp;lt;/pawn&amp;gt;&lt;br /&gt;
* menu - указатель на меню. Это указывает menu_additem меню к которому нужно добавить пункты.&lt;br /&gt;
* const name[] - имя пункта меню. Это то что будет показано в меню.&lt;br /&gt;
* const command[] - информация пункта меню.&lt;br /&gt;
&lt;br /&gt;
Теперь давайте приступим к созданию нашего меню. Как уже говорилось, это простое голосование смены карты. Так что нам надо всего 2 пункта меню. А именно &amp;quot;Да&amp;quot; и &amp;quot;Нет&amp;quot;.&lt;br /&gt;
&amp;lt;pawn&amp;gt;build_menu()&lt;br /&gt;
{&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;Yes&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;No&amp;quot;, &amp;quot;2&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	menu_setprop(g_Menu, MPROP_PERPAGE, 0);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Примечание&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Как вы можете видеть вместо command[] я указал числа. Это необходимо для более простой идентификации пунктов меню.&lt;br /&gt;
** Я так-же добавил menu_setprop. Это говорит нашему меню что оно не имеет страниц. Для дополнительной информации смотрите в amxconst.inc&lt;br /&gt;
&lt;br /&gt;
=== Показывает меню голосования ===&lt;br /&gt;
Для того что-бы показать меню мы должны использовать menu_display.&lt;br /&gt;
&amp;lt;pawn&amp;gt;menu_display ( id, menu, page )&amp;lt;/pawn&amp;gt;&lt;br /&gt;
* id - id пользователя которому надо показать это меню.&lt;br /&gt;
* menu - тут указываем хэндл меню которое показываем пользователю.&lt;br /&gt;
* page - какая страница (номер страницы меню) с которой начинаем. Страницы меню начинаются с 0.&lt;br /&gt;
&lt;br /&gt;
Ok теперь посмотрим на наш код.&lt;br /&gt;
&amp;lt;pawn&amp;gt;public startvote(id)&lt;br /&gt;
{&lt;br /&gt;
	for(new i = 0; i &amp;lt; 33; i++)&lt;br /&gt;
	{&lt;br /&gt;
		if( is_user_alive(i) )&lt;br /&gt;
		{&lt;br /&gt;
			menu_display(i, g_Menu, 0);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Примечание:&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Используем цыкл для прохождения по всем игрокам и показываем меню тем кто живой.&lt;br /&gt;
&lt;br /&gt;
=== Обработка выборов меню ===&lt;br /&gt;
Последний этап заключается в обработке выбора меню. Это делается через функцию обработки.&lt;br /&gt;
Она вызывается каждый раз когда пользователь сделал выбор.&lt;br /&gt;
Вот  &amp;lt;b&amp;gt;3&amp;lt;/b&amp;gt; переменные которые передаются в функцию.&lt;br /&gt;
* id - id пользователя&lt;br /&gt;
* menu - открытое меню у пользователя&lt;br /&gt;
* item - тут выбор пункта меню пользователем&lt;br /&gt;
&lt;br /&gt;
Далее мы объявляем несколько специальных переменных таких как меню выхода.&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define MENU_EXIT	-3&lt;br /&gt;
#define	MENU_BACK	-2&lt;br /&gt;
#define MENU_MORE	-1&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь нам надо проверить если пункт меню выбран и он не является специальной переменной&lt;br /&gt;
&amp;lt;pawn&amp;gt;if( item &amp;lt; 0 ) return PLUGIN_CONTINUE;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующим шагом мы получаем информацию о выбранном пункте меню. Все что мы ищем это номер пункта меню. (Да = 1, Нет = 2).&lt;br /&gt;
Для этого надо использовать menu_item_getinfo.&lt;br /&gt;
&amp;lt;pawn&amp;gt;menu_item_getinfo ( menu, item, &amp;amp;access, command[], cmdlen, name[]=&amp;quot;&amp;quot;, namelen=0, &amp;amp;callback )&amp;lt;/pawn&amp;gt;&lt;br /&gt;
* menu - меню в котором находится пункт меню.&lt;br /&gt;
* item - the item itself&lt;br /&gt;
* &amp;amp;access - (edit)&lt;br /&gt;
* command[] - (edit)(это то где сохраняются идентификационные номера меню)&lt;br /&gt;
* cmdlen - размер command[]&lt;br /&gt;
* name[] - имя пункта меню&lt;br /&gt;
* namelen - размер name[]&lt;br /&gt;
* &amp;amp;callback - (edit)&lt;br /&gt;
&lt;br /&gt;
После того как мы получили информацию о пуектах меню, надо взять из command[] номера выбранных меню(это должно быть 1 или 2). &lt;br /&gt;
Теперь надо добавить в g_Votes теми голосами что были сделаны.&lt;br /&gt;
Вот как завершонная функция должна выглядеть:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public menu_handle(id, menu, item)&lt;br /&gt;
{&lt;br /&gt;
	if( item &amp;lt; 0 ) return PLUGIN_CONTINUE;&lt;br /&gt;
	&lt;br /&gt;
	// Get item info&lt;br /&gt;
	new cmd[3];&lt;br /&gt;
	new access, callback;&lt;br /&gt;
	&lt;br /&gt;
	menu_item_getinfo(menu, item, access, cmd,2,_,_, callback);&lt;br /&gt;
	&lt;br /&gt;
	new iChoice = str_to_num(cmd);&lt;br /&gt;
	&lt;br /&gt;
	g_Votes[iChoice]++;&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Завершение ===&lt;br /&gt;
Это конец. Вы завершили Урок по созданию меню. Используя новую систему меню можно создать более удобное управление.&lt;br /&gt;
В следующем уроке вы увидите более сложную систему меню которая будет использовать callbacks, уничтожение меню и создание.&lt;br /&gt;
Вот код который должен получится посли всех действий.&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new g_Menu;	// Переменная обработки главного меню&lt;br /&gt;
new g_Votes[3];	// Сохраняем голосования Да как 1, No как 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	// Регистрируем ваш плагин&lt;br /&gt;
	register_plugin(&amp;quot;Vote Menu&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Freecode&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Регистрируем меню смены карты&lt;br /&gt;
	g_Menu = menu_create(&amp;quot;Change Level?&amp;quot;,&amp;quot;menu_handle&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	register_clcmd(&amp;quot;amx_startvote&amp;quot;,&amp;quot;startvote&amp;quot;,ADMIN_CFG,&amp;quot;Gaben&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Теперь нам надо создать наше меню&lt;br /&gt;
	build_menu();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
build_menu()&lt;br /&gt;
{&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;Yes&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;No&amp;quot;, &amp;quot;2&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	menu_setprop(g_Menu, MPROP_PERPAGE, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public startvote(id)&lt;br /&gt;
{&lt;br /&gt;
	for(new i = 0; i &amp;lt; 33; i++)&lt;br /&gt;
	{&lt;br /&gt;
		if( is_user_alive(i) )&lt;br /&gt;
		{&lt;br /&gt;
			menu_display(i, g_Menu, 0);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public menu_handle(id, menu, item)&lt;br /&gt;
{&lt;br /&gt;
	if( item &amp;lt; 0 ) return PLUGIN_CONTINUE;&lt;br /&gt;
	&lt;br /&gt;
	// Получаем информацию о пункте&lt;br /&gt;
	new cmd[3];&lt;br /&gt;
	new access, callback;&lt;br /&gt;
	&lt;br /&gt;
	menu_item_getinfo(menu, item, access, cmd,2,_,_, callback);&lt;br /&gt;
	&lt;br /&gt;
	new iChoice = str_to_num(cmd);&lt;br /&gt;
	&lt;br /&gt;
	g_Votes[iChoice]++;&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Commands_(AMX_Mod_X)&amp;diff=3861</id>
		<title>Ru Commands (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Commands_(AMX_Mod_X)&amp;diff=3861"/>
		<updated>2007-01-23T00:21:40Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: added russian category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
[[Category:Ru:Documentation (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
= Выбор языка =&lt;br /&gt;
&lt;br /&gt;
Смотреть эту страницу на:&lt;br /&gt;
&lt;br /&gt;
* [[Commands_%28AMX_Mod_X%29|English]]&lt;br /&gt;
* [[ru:Commands_%28AMX_Mod_X%29|Russian]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
Консольные команды вводятся в консоли как:&lt;br /&gt;
&amp;lt;pre&amp;gt;amx_&amp;lt;command&amp;gt; &amp;lt;option1&amp;gt; &amp;lt;option2&amp;gt; [option3]&amp;lt;/pre&amp;gt;&lt;br /&gt;
Обязательные оции показаны с &amp;lt;&amp;gt;, не обязательные параметры показаны с []. Символы &amp;lt;&amp;gt; и [] в действительности вводить не нужно.&lt;br /&gt;
&lt;br /&gt;
Чтобы увидеть справку во время игры, введите в консоли следующее:&lt;br /&gt;
&amp;lt;pre&amp;gt;amx_help&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Команды админа=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Формат&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_kick&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; [причина]A&lt;br /&gt;
| ADMIN_KICK&lt;br /&gt;
| Кикнуть игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_ban&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; &amp;lt;время&amp;gt; [причина]&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Забанить игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_banip&lt;br /&gt;
| &amp;lt;authid или ip&amp;gt; &amp;lt;минуты&amp;gt; [причина]&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Забанить игрока по IP.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_addban&lt;br /&gt;
| &amp;lt;authid или ip&amp;gt; &amp;lt;минуты&amp;gt; [причина]&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Добавить бан в бансписок.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_unban&lt;br /&gt;
| &amp;lt;authid или ip&amp;gt;&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Разбанить игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_slay&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt;&lt;br /&gt;
| ADMIN_SLAY&lt;br /&gt;
| Убивает игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_slap&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; [повреждение]&lt;br /&gt;
| ADMIN_SLAY&lt;br /&gt;
| Бьет игрока с силой указанной в переменной.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_leave&lt;br /&gt;
| &amp;lt;tag&amp;gt; [тег1] [тег2] [тег3]&lt;br /&gt;
| ADMIN_KICK&lt;br /&gt;
| Кикать всех игроков которые не имеют один из тегов.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_pause&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_CVAR&lt;br /&gt;
| Устанавливает паузу в игре или снимает её.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_who&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_ADMIN&lt;br /&gt;
| Выводит список текущих клиентов сервера, с указанием различных деталей, таких как уровень доступа и др.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cvar&lt;br /&gt;
| &amp;lt;cvar&amp;gt; [value]&lt;br /&gt;
| ADMIN_CVAR&lt;br /&gt;
| Устанавливает или показывает cvar переменную.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_map&lt;br /&gt;
| &amp;lt;имя карты&amp;gt;&lt;br /&gt;
| ADMIN_MAP&lt;br /&gt;
| Меняет карту.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_nick&lt;br /&gt;
| &amp;lt;name or #userid&amp;gt; &amp;lt;новое имя&amp;gt;&lt;br /&gt;
| ADMIN_LEVEL_A&lt;br /&gt;
| Меняет имя пользователя (на самом деле запускает команду name удаленно на консоли пользователя - не работает если у пользователя прописано alias name)&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cfg&lt;br /&gt;
| &amp;lt;имя файла&amp;gt;&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Загружает на стороне сервера конфигурационный файл.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_rcon&lt;br /&gt;
| &amp;lt;командная строка&amp;gt;&lt;br /&gt;
| ADMIN_RCON&lt;br /&gt;
| Запускает консольную команду на стороне сервера.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_showrcon&lt;br /&gt;
| &amp;lt;командная строка&amp;gt;&lt;br /&gt;
| ADMIN_RCON&lt;br /&gt;
| Запускает консольную команду на стороне сервера с возвратом ответа от сервера.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_plugins&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_ADMIN&lt;br /&gt;
| Список всех загруженых плагинов.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_modules&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_ADMIN&lt;br /&gt;
| Список всех загруженых модулей.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды чата=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Формат&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_say&lt;br /&gt;
| &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем игрокам через обычный чат.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_chat&lt;br /&gt;
| &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем администраторам через обычный чат.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_psay&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Послать личное сообщение игроку.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_tsay&lt;br /&gt;
| &amp;lt;цвет&amp;gt; &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем игрокам. Сообщение показывается слевой стороны в игре.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_csay&lt;br /&gt;
| &amp;lt;цвет&amp;gt; &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем игрокам. Сообщение показывается в центре экрана.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды голосования=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Формат&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_votemap&lt;br /&gt;
| &amp;lt;карта&amp;gt; [карта] [карта] [карта]&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает голосование за карту.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_votekick&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt;&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает голосование за то чтобы кикнуть игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_voteban&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt;&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает голосование за то чтобы забанить игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_vote&lt;br /&gt;
| &amp;lt;Вопрос&amp;gt; &amp;lt;ответ1&amp;gt; &amp;lt;ответ2&amp;gt;&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает произвольное голосование.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cancelvote  	 &lt;br /&gt;
| &lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Отменяет последнее голосование которое находится в прогрессе.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды статистики=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /hp&lt;br /&gt;
| Показывает информацию о вашем убийце.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /statsme&lt;br /&gt;
| Показывает вашу статистику.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /stats&lt;br /&gt;
| Показывает статистику других игроков.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /top15&lt;br /&gt;
| Показывает рейтинг лучших 15 игроков.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /rank&lt;br /&gt;
| Показывает ваш рейтинг на сервере.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды чата=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say nextmap&lt;br /&gt;
| Показывает следующую карту в mapcycle.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say timeleft&lt;br /&gt;
| Показывает сколько времени осталось до смены карты.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say thetime&lt;br /&gt;
| Показывает текущее время.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды меню=&lt;br /&gt;
{{qnotice|ACCESS_LEVEL_A не является &amp;quot;a&amp;quot;, это &amp;quot;m&amp;quot;.  Смотрите [[Adding Admins (AMX Mod X)#Access Levels|Уровни доступа]].}}&lt;br /&gt;
&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amxmodmenu&lt;br /&gt;
| ADMIN_MENU&lt;br /&gt;
| Показывает главное AMX Mod X меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cvarmenu&lt;br /&gt;
| ADMIN_CVAR&lt;br /&gt;
| Показывает CVAR меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_mapmenu&lt;br /&gt;
| ADMIN_MAP&lt;br /&gt;
| Показывает меню смены карт.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_votemapmenu&lt;br /&gt;
| ADMIN_MAP&lt;br /&gt;
| Показывает меню голосований.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_kickmenu&lt;br /&gt;
| ADMIN_KICK&lt;br /&gt;
| Показывает kick меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_banmenu&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Показывает ban меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_slapmenu&lt;br /&gt;
| ADMIN_SLAY&lt;br /&gt;
| Показывает slap/slay меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_teammenu&lt;br /&gt;
| ADMIN_LEVEL_A&lt;br /&gt;
| Показывает меню смены команд.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_clcmdmenu&lt;br /&gt;
| ADMIN_LEVEL_A&lt;br /&gt;
| Показывает меню клиентских команд.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_restmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Показывает меню оружейного огранчения.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_teleportmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Показывает меню телепорта.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_pausecfgmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Меню установки плагинов в паузу или снятие паузы.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_statscfgmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Показывает меню настроек статистики.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команда Конфига=&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Команда:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | amx_pausecfg&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Формат: &lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | &amp;lt;команда&amp;gt; [имя]&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Доступ:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | ADMIN_CFG&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Описание:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | Установить в паузу плагин.&amp;lt;br /&amp;gt;&lt;br /&gt;
Список команд:&amp;lt;br /&amp;gt;&lt;br /&gt;
*off - Установить паузу на всех плагинах которые не в списке.&lt;br /&gt;
*on - Снять паузу со всех плагинов.&lt;br /&gt;
*stop &amp;lt;файл&amp;gt; - Остановить плагин.&lt;br /&gt;
*pause &amp;lt;файл&amp;gt; - Установть в паузу плагин.&lt;br /&gt;
*enable &amp;lt;файл&amp;gt; - Включить плагин.&lt;br /&gt;
*save - Сохранить список остановленных плагинов.&lt;br /&gt;
*clear - Очистить список остановленных плагинов.&lt;br /&gt;
*list [id] - Список плагинов.&lt;br /&gt;
*add &amp;lt;заголовок&amp;gt; - Пометить плагин как не устанавливаемый в паузу.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Команда&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | amx_statscfg&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Формат: &lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | &amp;lt;команда&amp;gt; [параметры]&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Доступ:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | ADMIN_CFG&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Описание:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | Изменение настроек статистики.&amp;lt;br /&amp;gt;&lt;br /&gt;
Список команд:&amp;lt;br /&amp;gt;&lt;br /&gt;
*on &amp;lt;переменная&amp;gt; - Включить выбранную опцию.&lt;br /&gt;
*off &amp;lt;переменная&amp;gt; - Выключить выбранную опцию.&lt;br /&gt;
*save - Сохранить конфигурацию статистики.&lt;br /&gt;
*load - Загрузить конфигурацию статистики.&lt;br /&gt;
*list [id] - Список статусов статистики.&lt;br /&gt;
*add &amp;lt;имя&amp;gt; &amp;lt;переменная&amp;gt; - Добавить переменную статистики в список.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды RCON=&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Команда:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | amxx&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Формат: &lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | &amp;lt;команда&amp;gt; [параметры]&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Доступ:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Описание:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | Список доступных команд:&amp;lt;br /&amp;gt;&lt;br /&gt;
*amxx version - Показать версию AMX Mod X;&lt;br /&gt;
*amxx modules - Показать список модулей;&lt;br /&gt;
*amxx plugins - Показать список плагинов;&lt;br /&gt;
*amxx gpl - Показать GNU General Public Лицензию;&lt;br /&gt;
*amxx cvars - Показать AMX Mod X зарегистрированные CVARs;&lt;br /&gt;
*amxx cmds - Показать AMX Mod X зарегистрированные команды;&lt;br /&gt;
*amxx pause &amp;lt;plugin&amp;gt; - Приостановить плагин;&lt;br /&gt;
*amxx unpause &amp;lt;plugin&amp;gt; - Возобновить работу приостановленного плагина.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Button_constants_(AMX_Mod_X)&amp;diff=3860</id>
		<title>Ru Button constants (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Button_constants_(AMX_Mod_X)&amp;diff=3860"/>
		<updated>2007-01-23T00:21:28Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
=Кнопочные константы=&lt;br /&gt;
&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Button constants (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
=Использование=&lt;br /&gt;
&lt;br /&gt;
Кнопочные константы обычно используются для того, чтобы &amp;quot;поймать&amp;quot; момент, когда игрок пытается совершить какое-либо действие, нажимая на кнопки, &amp;quot;привязанные&amp;quot; к таким командам, как +attack, +use и так далее. Метод используется потому, что HL &amp;quot;движок&amp;quot;  не может &amp;quot;поймать&amp;quot; +/-команды стандартным регистрированием, если их реализация выполнена в самом движке.&lt;br /&gt;
&lt;br /&gt;
Например, это будет работать:&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;+explode&amp;quot;,&amp;quot;explode&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
А это - нет:&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;+attack&amp;quot;,&amp;quot;hook_attack&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Константы=&lt;br /&gt;
&lt;br /&gt;
Полный список всех констант вы можете найти [http://amxmodx.org/funcwiki.php?go=module&amp;amp;id=3#const_buttons здесь].&lt;br /&gt;
&lt;br /&gt;
=Реализация=&lt;br /&gt;
&lt;br /&gt;
Вот, например, один из вариантов, как оперделить, нажимает ли игрок кнопку атаки или нет:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	if(entity_get_int(id, EV_INT_BUTTON) &amp;amp; IN_ATTACK)&lt;br /&gt;
	{&lt;br /&gt;
		// do something&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что используется битовый оператор &amp;amp;, в отличии от логического оператора &amp;amp;&amp;amp;. Оператор &amp;amp; проверяет, содержится ли бит после оператора в бите до него, т.е. в данном случае проверяется, есть ли среди нажатых кнопок игрока кнопка IN_ATTACK.&lt;br /&gt;
&lt;br /&gt;
Чтобы заставить игрока эмулировать нажатие кнопки, можно поступить следующим образом:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	entity_set_int(id,EV_INT_button,entity_get_int(id,EV_INT_button) | IN_ATTACK);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Этот пример будет выставлять флаг кнопки &amp;quot;атака&amp;quot; в положение &amp;quot;ВКЛ&amp;quot; каждый раз, когда рендерится entity игрока. Т.е. мы получаем все кнопки, нажатые в данный момент, и как бы прибавляем кнопку атаки.&lt;br /&gt;
&lt;br /&gt;
Чтобы &amp;quot;поймать&amp;quot; кнопки игрока, а потом &amp;quot;вычесть&amp;quot; какую либо кнопку, можно использовать следующий метод:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	entity_set_int(id,EV_INT_button,entity_get_int(id,EV_INT_button) &amp;amp; ~IN_ATTACK);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например, клиент прыгает (IN_JUMP) и атакует (IN_ATTACK) одновременно, функция entity_get_int(id,EV_INT_button) будет возвращать бит сумму IN_ATTACK и IN_JUMP. Используя конструкцию &amp;amp; ~БИТ мы как бы удаляем конкретное значение бита, в данном случае IN_ATTACK. Таким образом, в итоге получим только IN_JUMP.&lt;br /&gt;
&lt;br /&gt;
=Замечания=&lt;br /&gt;
&lt;br /&gt;
Важно понимать, что нажатие какой-либо кнопки не всегда означает, что в это время происходит конкретное действие. Например, если выстрелить из пистолета и не отпускать кнопку атаки - пуля вылетит, атака закончится и не возобновится, т.к. пистолет не является автоматическим оружием, но, т.к. кнопка все еще будет нажата, то, используя вышеприведенный метод, мы получим активное состояние кнопки IN_ATTACK, хотя атаки как таковой в данный момент не осуществляется.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Более наглядный пример с прыжком. Представьте, что вы прыгнули и, не отпуская кнопки прыжка, опустились на землю. Второго прыжка не произойдет, т.к. для этого нужно отпустить кнопку и нажать ее снова. Таким образом, нажатая кнопка прыжка не говорит о том, что в данный момент вы находитесь в состоянии прыжка. Как уже было отмечено, это относится и к другим кнопкам. Поэтому, в подавляющем большинстве случаев вы не должны делать проверку на наличие нажатой кнопки, если хотите определить, совершает ли игрок соответствующее действие или нет, для этого существуют другие методы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
По большому счету метод, описанный в данной статье, может быть эффективен только для блокировки или эмуляции атаки, хотя для этого есть еще более эффективные методы. Описанный метод не может быть применим к блокировке подавляющего большинства кнопок: для этого существуют другие методы ''(TODO: указать здесь ссылку на эти методы)''.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Configuring_AMX_Mod_X&amp;diff=3859</id>
		<title>Ru Configuring AMX Mod X</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Configuring_AMX_Mod_X&amp;diff=3859"/>
		<updated>2007-01-23T00:21:18Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
[[Category:Ru:Documentation (AMX Mod X)]]&lt;br /&gt;
Данная статья переведена не полностью.&lt;br /&gt;
&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Configuring AMX Mod X]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Плагины=&lt;br /&gt;
==Установка==&lt;br /&gt;
Иногда плагины могут иметь свои собственные инструкции, если они требуют особенной установки. Однако данная статья поможет освоить основы установки плагинов.&lt;br /&gt;
#Следуйте всем указаниям, которые дает автор плагина. Если плагин требует дополнительных шагов или специальных файлов, убедитесь, что вы имеете их в правильном месте и порядке.&lt;br /&gt;
#Если вам был предоставлен .sma файл вместо .amxx, вам следует откомпилировать плагин самим. Для более детальной информации смотрите [[Ru:Compiling Plugins (AMX Mod X)]].&lt;br /&gt;
#Поместите .amxx файл в addons/amxmodx/plugins директорию.&lt;br /&gt;
#Добавьте имя плагина в addons\amxmodx\configs\plugins.ini. Например: &amp;lt;pre&amp;gt;myplugin.amxx&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Смените карту или перезапустите сервер. Если при загрузке сообщается о каких-либо ошибках, смотрите [[Troubleshooting AMX Mod X#Plugins|Troubleshooting AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
==Удаление==&lt;br /&gt;
#Удалите запись из addons\amxmodx\configs\plugins.ini или добавьте в начале строки точку с запятой.&lt;br /&gt;
#Также можно удалить все файлы, связанные с отключаемым плагином.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Intro_to_AMX_Mod_X_Scripting&amp;diff=3858</id>
		<title>Ru Intro to AMX Mod X Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Intro_to_AMX_Mod_X_Scripting&amp;diff=3858"/>
		<updated>2007-01-23T00:21:11Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: added russian category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
[[Category:Russian]]&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Intro to AMX Mod X Scripting]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Введение в AMX Mod X скриптинг=&lt;br /&gt;
Это руководство позволит разобраться в основах скриптинга [[AMX Mod X]] плагинов.&lt;br /&gt;
&lt;br /&gt;
=Обзор=&lt;br /&gt;
&lt;br /&gt;
Значит, вы хотите создать плагин? Вы должны иметь хорошее представление о том, как работает [[Pawn]], скриптинг язык, который используется для написания [[AMX Mod X]] плагинов. Поэтому в первую очередь настоятельно рекомендуется ознакомиться с фундаментальными основами [[Pawn]] и [[AMX Mod X]] скриптинга: [[Ru:Fundamental Basics of AMX Mod X Scripting]]. Желательно читать данную статью, сидя за компьютером с текстовым редактором и [[Pawn]] компилятором под рукой - хорошее подспорье для эффективного обучения. Конечно же, вы не будете сразу писать большие плагины типа WC3, Matrix Mod и CSDM, но все же статья даст вам &amp;quot;толчок&amp;quot; в мир моддинга [[AMX Mod X]]. Хороший редактор с поддержкой [[Pawn]] - это AMXX-Studio, который можно найти в секции [http://www.amxmodx.org/downloads.php AMX Mod X downloads].&lt;br /&gt;
&lt;br /&gt;
Вам необходимо знать, как компилировать плагины. Обратитесь к секции [[Ru:Compiling Plugins (AMX Mod X)]] для ознакомления. Также, чтобы проверить и отладить ваш плагин, вы должны знать, как устанавливать плагины. Для этого обратитесь к секции [[Ru:Configuring AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
&lt;br /&gt;
AMX Mod X плагин может иметь четыре главных типа функций. Первый - &amp;quot;public&amp;quot; функция. Это означает, что функция доступна для AMX Mod X &amp;quot;движка&amp;quot;. Второй тип - &amp;quot;native&amp;quot; функция, которая располагается в модуле или в ядре AMX Mod X. Третий тип - обычные пользовательские функции, которые прописываются без каких-либо специальных атрибутов. Четвертый тип - это &amp;quot;forward&amp;quot; функция, которая вызывается каждый раз, когда происходит какое-то определенное событие (forward функция также является и public). AMX Mod X плагин должен начинаться с функции, инициализирующей плагин:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//Это делает возможным использование функций AMX Mod X ядра&lt;br /&gt;
//Это &amp;quot;влаживает&amp;quot; native &amp;quot;определители&amp;quot;(заголовки) из includes\amxmodx.inc&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//Объявляем три строковых переменных&lt;br /&gt;
new PLUGIN[]=&amp;quot;AMXX Demo&amp;quot;&lt;br /&gt;
new AUTHOR[]=&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
new VERSION[]=&amp;quot;1.00&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//Это public функция.&lt;br /&gt;
//Необходимо инициализировать ваш скрипт для AMX Mod X.&lt;br /&gt;
//Эта функция не содержит параметров, вызывается сразу после загрузки карты.&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     //Это функция, которая &amp;quot;берет&amp;quot; три строки.&lt;br /&gt;
     //Она регистрирует ваш плагин в AMX Mod X и присваивает некоторую основную информацию.&lt;br /&gt;
     register_plugin(PLUGIN, VERSION, AUTHOR)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Попробуйте откомпилировать скрипт, приведенный выше. Он будет очень мал, т.к. не делает ничего особенного. Однако, если вы загрузите этот скрипт и напишите &amp;quot;amxx plugins&amp;quot; в серверной консоли, вы должны увидеть новую запись в листе плагинов.&lt;br /&gt;
&lt;br /&gt;
=Создание админ-комманд=&lt;br /&gt;
&lt;br /&gt;
AMX Mod X предоставляет возможность простого добавления консольных админ-команд. Каждая команда &amp;quot;регистрируется&amp;quot; как консольная команда. При регистрировании команды вы должны указать четыре свойства: имя консольной команды; функцию, которая будет вызываться при использовании команды; уровень доступа, необходимый для использования команды; короткое описание команды.&lt;br /&gt;
&lt;br /&gt;
Для демонстрации давайте сделаем плагин, который позволит вам изменить количество жизней игрока на сервере с помощью команды &amp;quot;amx_hp&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Для начала нам понадобится сделать две вещи: первая - нам нужно зарегистрировать команду в консоли. Т.к. мы &amp;quot;привязываем&amp;quot; команду к public функции, мы должны убедиться, что функция существует.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmisc&amp;gt; //Это содержит некоторые полезные функции&lt;br /&gt;
#include &amp;lt;fun&amp;gt;     //Это содержит функцию для изменения жизней&lt;br /&gt;
&lt;br /&gt;
new PLUGIN[]=&amp;quot;Change Health&amp;quot;&lt;br /&gt;
new AUTHOR[]=&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
new VERSION[]=&amp;quot;1.00&amp;quot;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     register_plugin(PLUGIN, VERSION, AUTHOR)&lt;br /&gt;
     register_concmd(&amp;quot;amx_hp&amp;quot;, &amp;quot;cmd_hp&amp;quot;, ADMIN_SLAY, &amp;quot;&amp;lt;target&amp;gt; &amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первая новая функция - это &amp;quot;register_concmd&amp;quot;, которая берет четыре параметра. Первый - название команды, которую необходимо набрать в консоли. Второй - название public функции, которая будет контролировать команду. Третий - уровень доступа, который необходим для вашей команды. И последний - строка, описывающая, как использовать вашу команду.&lt;br /&gt;
&lt;br /&gt;
Далее мы создаем public функцию для контроля amx_hp команды. Обратите внимание, что мы даем ей три параметра. Эти параметры будут содержать специальные данные, когда команду будет использована. id будет содержать индекс(номер) игрока, который запустил команду, level будет содержать уровень доступа команды (вы должны сами осуществить проверку уровня доступа), cid будет содержать внутренний индекс(номер) команды.&lt;br /&gt;
&lt;br /&gt;
Также обратите внимание на PLUGIN_HANDLED. Существует два главных return значения. PLUGIN_CONTINUE как бы означает &amp;quot;продолжить с нормальным выполнением&amp;quot;, PLUGIN_HANDLED означает &amp;quot;блокировать дальнейшее выполнение&amp;quot;. Разница сложно уловима, но важна. К примеру, если вы делаете &amp;quot;привязку&amp;quot; к своей команде, вы не должны возвращать PLUGIN_CONTINUE. Но если вы возвращаете PLUGIN_HANDLED, при привязанной &amp;quot;say&amp;quot; команде, это полностью заблокирует say-текст. Вы должны быть внимательны с тем, что вы выбираете для возврата в различных ситуациях. Однако, многие вещи &amp;quot;безразличны&amp;quot; к возвращаемому значению. Например, таймеры(tasks), события(events) и другие вещи, с которыми вы встретитесь позже.&lt;br /&gt;
&lt;br /&gt;
Итак, как же мы убедимся, что данный пользователь - это админ, который имеет ADMIN_SLAY уровень доступа?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     if (!cmd_access(id, level, cid, 3))&lt;br /&gt;
        return PLUGIN_HANDLED&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
cmd_access() функция проверит информацию команды (пользователя, уровень доступа и индекс) и проверяет две вещи: что пользователь имеет доступ, и что было дано минимальное количество параметров. Мы указали три, потому что команда будет выглядеть как: amx_hp &amp;lt;target&amp;gt; &amp;lt;amount&amp;gt;, и в действительности сама команда также считается как параметр. Если cmd_access откажет, мы сразу прекращаем выполнение команды.&lt;br /&gt;
&lt;br /&gt;
Следующее, что нужно решить: мы должны взять два параметра и преобразовать их. &amp;quot;amount&amp;quot; параметр прост - мы просто конвертируем его из строки в число. Другой же параметр будет по сложнее, т.к. мы хотим иметь возможность указывать на три различных типа людей:&lt;br /&gt;
&lt;br /&gt;
* @CT или @T - (контр-террористы или террористы)&lt;br /&gt;
* @ALL - (все)&lt;br /&gt;
* &amp;lt;target&amp;gt; - частичное имя игрока&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     if (!cmd_access(id, level, cid, 3))&lt;br /&gt;
        return PLUGIN_HANDLED&lt;br /&gt;
&lt;br /&gt;
     new Arg1[24]&lt;br /&gt;
     new Arg2[4]&lt;br /&gt;
&lt;br /&gt;
     //Берем аргументы команды из консоли&lt;br /&gt;
     read_argv(1, Arg1, 23)&lt;br /&gt;
     read_argv(2, Arg2, 3)&lt;br /&gt;
&lt;br /&gt;
     //Конвертируем количество жизней из строки в число&lt;br /&gt;
     new Health = str_to_num(Arg2)&lt;br /&gt;
&lt;br /&gt;
     //Является ли первый символ @ символом?&lt;br /&gt;
     if (Arg1[0] == '@')&lt;br /&gt;
     {&lt;br /&gt;
          new Team = 0&lt;br /&gt;
          //Проверяем, какая команда была указана.&lt;br /&gt;
          //Заметьте, что мы начинаем с [1]&lt;br /&gt;
          // это означает, что @ не входит&lt;br /&gt;
          if (equali(Arg1[1], &amp;quot;CT&amp;quot;))&lt;br /&gt;
          {&lt;br /&gt;
               Team = 2&lt;br /&gt;
          } else if (equali(Arg1[1], &amp;quot;T&amp;quot;)) {&lt;br /&gt;
               Team = 1&lt;br /&gt;
          }&lt;br /&gt;
          new players[32], num&lt;br /&gt;
          //Эта функция заполнит players[32] переменную&lt;br /&gt;
          // верными индексами игроков. num будет содержать количество&lt;br /&gt;
          // игроков, которые действительны.&lt;br /&gt;
          get_players(players, num)&lt;br /&gt;
          new i&lt;br /&gt;
          for (i=0; i&amp;lt;num; i++)&lt;br /&gt;
          {&lt;br /&gt;
               if (!Team)&lt;br /&gt;
               {&lt;br /&gt;
                    //Устанавливаем количество жизней этого игрока&lt;br /&gt;
                    set_user_health(players[i], Health)&lt;br /&gt;
               } else {&lt;br /&gt;
                    if (get_user_team(players[i]) == Team)&lt;br /&gt;
                    {&lt;br /&gt;
                         set_user_health(players[i], Health)&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
          }&lt;br /&gt;
     } else {&lt;br /&gt;
          //находит индекс игрока, который соответствует части указанного имени&lt;br /&gt;
          //1 означает, что игрок с &amp;quot;иммунитетом&amp;quot; не будет учтен&lt;br /&gt;
          new player = cmd_target(id, Arg1, 1)&lt;br /&gt;
          if (!player)&lt;br /&gt;
          {&lt;br /&gt;
               //это напечатает сообщение пользователю, который запускал команду&lt;br /&gt;
               //Формат для этой команды называется &amp;quot;format()&amp;quot; стиль,&lt;br /&gt;
               // где первая строка форматирует сообщение соответственно&lt;br /&gt;
               // любому количеству следующих параметров:&lt;br /&gt;
               //  %s означает строка&lt;br /&gt;
               //  %d или %i означает целое число&lt;br /&gt;
               //  %f означает дробное число&lt;br /&gt;
               // поэтому &amp;quot;Privet %s, mne %d let&amp;quot; будет требовать&lt;br /&gt;
               //  чтобы следовали параметры строки и целого числа&lt;br /&gt;
               console_print(id, &amp;quot;Izvinite, igrok %s ne mojet bit naiden ili ispol'zovan v kachestve ob'ekta!&amp;quot;, Arg1)&lt;br /&gt;
               return PLUGIN_HANDLED&lt;br /&gt;
          } else {&lt;br /&gt;
               set_user_health(player, Health)&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, наша финальная версия amx_hp плагина будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;fun&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new PLUGIN[]=&amp;quot;Change Health&amp;quot;&lt;br /&gt;
new AUTHOR[]=&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
new VERSION[]=&amp;quot;1.00&amp;quot;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     register_plugin(PLUGIN, VERSION, AUTHOR)&lt;br /&gt;
     register_concmd(&amp;quot;amx_hp&amp;quot;, &amp;quot;cmd_hp&amp;quot;, ADMIN_SLAY, &amp;quot;&amp;lt;target&amp;gt; &amp;lt;hp&amp;gt;&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     if (!cmd_access(id, level, cid, 3))&lt;br /&gt;
        return PLUGIN_HANDLED&lt;br /&gt;
&lt;br /&gt;
     new Arg1[24]&lt;br /&gt;
     new Arg2[4]&lt;br /&gt;
&lt;br /&gt;
     //Берем аргументы команды из консоли&lt;br /&gt;
     read_argv(1, Arg1, 23)&lt;br /&gt;
     read_argv(2, Arg2, 3)&lt;br /&gt;
&lt;br /&gt;
     //Конвертируем количество жизней из строки в число&lt;br /&gt;
     new Health = str_to_num(Arg2)&lt;br /&gt;
&lt;br /&gt;
     //Является ли первый символ @ символом?&lt;br /&gt;
     if (Arg1[0] == '@')&lt;br /&gt;
     {&lt;br /&gt;
          new Team = 0&lt;br /&gt;
          if (equali(Arg1[1], &amp;quot;CT&amp;quot;))&lt;br /&gt;
          {&lt;br /&gt;
               Team = 2&lt;br /&gt;
          } else if (equali(Arg1[1], &amp;quot;T&amp;quot;)) {&lt;br /&gt;
               Team = 1&lt;br /&gt;
          }&lt;br /&gt;
          new players[32], num&lt;br /&gt;
          get_players(players, num)&lt;br /&gt;
          new i&lt;br /&gt;
          for (i=0; i&amp;lt;num; i++)&lt;br /&gt;
          {&lt;br /&gt;
               if (!Team)&lt;br /&gt;
               {&lt;br /&gt;
                    set_user_health(players[i], Health)&lt;br /&gt;
               } else {&lt;br /&gt;
                    if (get_user_team(players[i]) == Team)&lt;br /&gt;
                    {&lt;br /&gt;
                         set_user_health(players[i], Health)&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
          }&lt;br /&gt;
     } else {&lt;br /&gt;
          new player = cmd_target(id, Arg1, 1)&lt;br /&gt;
          if (!player)&lt;br /&gt;
          {&lt;br /&gt;
               console_print(id, &amp;quot;Izvinite, igrok %s ne mojet bit naiden ili ispol'zovan v kachestve ob'ekta!&amp;quot;, Arg1)&lt;br /&gt;
               return PLUGIN_HANDLED&lt;br /&gt;
          } else {&lt;br /&gt;
               set_user_health(player, Health)&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Консольные переменные=&lt;br /&gt;
&lt;br /&gt;
CVar - это консольная переменная. Существуют клиентские и серверные CVar'ы. К примеру, &amp;quot;mp_startmoney&amp;quot; - Counter-Strike серверная CVar, содержащая число, указывающее, сколько денег дается игрокам, когда они заходят на сервер. Вы можете создавать свои серверные CVar'ы путем их регистрирования. Давайте создадим свою amx_startmoney CVar.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;cstrike&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     register_plugin(&amp;quot;CVAR Test&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
     //регистрируем amx_startmoney CVar&lt;br /&gt;
     // и устанавливаем для нее значение по умолчанию 500&lt;br /&gt;
     register_cvar(&amp;quot;amx_startmoney&amp;quot;, &amp;quot;500&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//это вызывается, когда клиент заходит непосредственно на сервер&lt;br /&gt;
public client_putinserver(id)&lt;br /&gt;
{&lt;br /&gt;
     if (get_cvar_num(&amp;quot;amx_startmoney&amp;quot;) &amp;gt; 0)&lt;br /&gt;
     {&lt;br /&gt;
          cs_set_user_money(id, get_cvar_num(&amp;quot;amx_startmoney&amp;quot;))&lt;br /&gt;
     } else {&lt;br /&gt;
          cs_set_user_money(id, get_cvar_num(&amp;quot;mp_startmoney&amp;quot;))&lt;br /&gt;
     }&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вы можете устанавливать дробные, целые или строковые значения как для своих CVar, так и для любых других.&lt;br /&gt;
&lt;br /&gt;
=Дополнительно=&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать больше о скриптинге для AMX Mod X вам следует взглянуть на native прототипы в описаниях функий или в *.inc файлах (&amp;quot;инклудах&amp;quot;). Инклуды по большому счету придерживаются двух форматов. Они имеют название в соответствии с модулем или определенным предназначением. _const добавляется, если они содержат предопределенные числа или списки. _stocks добавляется, если они содержат &amp;quot;помогающие&amp;quot; или полезные &amp;quot;функции-обертки&amp;quot;. Помните, что stocks компилируются только, если вы используете их, поэтому без опаски можно &amp;quot;включать&amp;quot; файлы, содержащие большое количество stocks.&lt;br /&gt;
&lt;br /&gt;
Вы также можете посетить [http://amxmodx.ucoz.ru/forum/ Форум] и задать вопросы или найти больше информации.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Fundamental_Basics_of_AMX_Mod_X_Scripting&amp;diff=3857</id>
		<title>Ru:Fundamental Basics of AMX Mod X Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Fundamental_Basics_of_AMX_Mod_X_Scripting&amp;diff=3857"/>
		<updated>2007-01-23T00:20:43Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: added russian category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
=Фундаментальные основы AMX Mod X скриптинга=&lt;br /&gt;
&lt;br /&gt;
Данная статья не дает готовых &amp;quot;рецептов&amp;quot; по [[AMX Mod X]] скриптингу, но раскрывает его фундаментальные основы. Это и типы данных, и прототипы функций и многое другое, без знания чего невозможно писать AMX Mod X плагины.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
&lt;br /&gt;
Прежде чем начинать писать AMX Mod X плагины, в первую очередь необходимо разобраться в основах [[Pawn]].&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Pawn – это скриптовый язык, созданный компанией ITB CompuPhase. Ранее Pawn назывался Small, но с версии 3.0 языку было решено дать более характерное название. Т.к. &amp;quot;pawn&amp;quot; в переводе с английского языка означает &amp;quot;пешка&amp;quot;, можно догадаться, что основной характерной чертой данного языка является простота.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Если вы владеете английским языком, рекомендуется ознакомиться с полным руководством по Pawn - [http://www.compuphase.com/pawn/pawn-lang.pdf Pawn The Language].&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Код плагина представляет собой текст (как правило, заключенный в файл типа *.sma), включающий множество элементов языка: комментарии, переменные, функции и др. Поэтому для оформления кода потребуется текстовый редактор. Из простейших можно выделить, например, Microsoft Notepad. Также существует AMXX-Studio – специализированый редактор для AMX Mod X плагинов, позволяющий максимально эффективно работать в соответствующей среде. Последняя версия данного редактора может быть найдена в секции [http://www.amxmodx.org/downloads.php downloads] официального сайта AMX Mod X.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Чтобы позволить AMX Mod X выполнять код, файл с кодом необходимо откомпилировать с помощью компилятора AMXXPC (AMX Mod X Pawn Compiler). Операция компилирования преобразовывает набор текстовых инструкций в последовательность инструкций абстрактной машины (от англ. abstract machine), она же AMX, а также интерпретатор (от англ. interpreter).&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Откомпилированый код обычно помещается в файл типа *.amxx, имеющий двоичный формат. Такой файл называют AMX Mod X плагином (от англ. plugin).&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Для ознакомления с инструкциями по компилированию и установке плагинов смотрите [[Ru:Compiling Plugins (AMX Mod X)]] и [[Ru:Configuring AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Pawn=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Уровни кода==&lt;br /&gt;
&lt;br /&gt;
В основе любого кода лежит уровневая структура. Причиной этому является нелинейность инструкций.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.н. &amp;quot;нулевой уровень&amp;quot; или &amp;quot;глобальное пространство&amp;quot; является неотъемлемой частью любого кода. Как только вы приступаете к написанию нового кода, вы оказываетесь в его глобальном пространстве. Оно же в свою очередь будет включать в себя пространства с более низкими уровнями.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Обычно глобальное пространство содержит всю общую информацию, которая может потребоваться в ходе выполнения кода пространствам более низкого уровня. Примером такой информации могут служить общие константы, переменные, списки, макросы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Комментарии==&lt;br /&gt;
&lt;br /&gt;
Комментарий – это, как правило, текст информативного характера. Например, чтобы дать описание плагину можно использовать многострочный комментарий:&amp;lt;pawn&amp;gt;/* здесь вы помещаете&lt;br /&gt;
необходимую информацию */&amp;lt;/pawn&amp;gt;Как видно из примера, многострочный комментарий ограничивается символами /* и */, отмечающими начало и конец комментария соответственно. Недопустимо открывать последующий комментарий, не закрыв при этом предыдущий.&lt;br /&gt;
&amp;lt;BR&amp;gt;Примером однострочного комментария может быть:&amp;lt;pawn&amp;gt;/* ваш комментарий */&amp;lt;/pawn&amp;gt;Хотя, можно упростить конструкцию:&amp;lt;pawn&amp;gt;// ваш комментарий&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Как видно из последнего примера, комментарий начинается с двойного симовола обратного слеша //. Заканчивается такой комментарий вместе с концом текущей строки, поэтому не требует закрывающих символов. Такие комментарии могут быть только однострочными. Не обязательно комментарий должен начинаться с новой строки. Например, /* ... */ комментарий может быть расположен непосредственно в самом коде.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.к. комментарии не считаются кодом, они исключаются из обработки. Данная особенность позволяет при необходимости исключать части кода путем комментирования, что может быть использовано, например, при отладке кода.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Типы данных==&lt;br /&gt;
&lt;br /&gt;
Технически основой всех типов данных в Pawn является т.н. &amp;quot;cell&amp;quot; – ячейка памяти, состоящая из последовательности определенного количества бит. Количество бит в такой ячейке постоянно для определенной платформы. Так для 32х битной платформы оно будет составлять 32, а для 64х битной – 64.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.к. технически все данные не имеют отличия, для обозначения их типа применяются т.н. &amp;quot;тэги&amp;quot;. Если при создании переменной тэг не указан, то переменная является целым числом:&amp;lt;pawn&amp;gt;new ivar // создана целочисленная переменная с именем &amp;quot;ivar&amp;quot;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Если при создании переменной ей не присваивается какое-либо конкретное значение, то переменная будет равна нулю. Таким образом, вышеприведенный пример технически соответствует:&amp;lt;pawn&amp;gt;new ivar = 0&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы создать дробную переменную, необходимо использовать тэг &amp;quot;Float&amp;quot;:&amp;lt;pawn&amp;gt;new Float:fvar&amp;lt;/pawn&amp;gt;Переменная fvar также будет равна нулю, но ввиду соответствия типу данных это будет 0.0, т.е. технический аналог примера будет:&amp;lt;pawn&amp;gt;new Float:fvar = 0.0&amp;lt;/pawn&amp;gt;Таким образом, мы обеспечиваем типовое соответствие &amp;quot;левой&amp;quot; и &amp;quot;правой&amp;quot; части.&lt;br /&gt;
&amp;lt;BR&amp;gt;Одним из особых типов данных является т.н. &amp;quot;булевые&amp;quot; переменные, которые технически могут иметь только два значение, логически интерпретируемые как &amp;quot;истина&amp;quot; и &amp;quot;ложь&amp;quot; (true и false). Чтобы создать булевую переменную, необходимо использовать тэг &amp;quot;bool&amp;quot;:&amp;lt;pawn&amp;gt;new bool:bvar&amp;lt;/pawn&amp;gt;Т.к. численно false является нулем, то технический аналог примера будет выглядеть как:&amp;lt;pawn&amp;gt;new bool:bvar = false&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Примечание: чтобы запретить изменение значения переменной, необходимо использовать атрибут const, например:&amp;lt;pawn&amp;gt;new const var = 1&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Pawn также позволяет создавать массивы данных, представляющие собой набор значений определенного типа. Так примером простого массива, содержащего два целочисленных значения будет:&amp;lt;pawn&amp;gt;new array[2]&amp;lt;/pawn&amp;gt;Технически данный пример выглядит следующим образом:&amp;lt;pawn&amp;gt;new array[2] = {0, 0}&amp;lt;/pawn&amp;gt;Технические аналоги для Float и bool массивов выглядят как:&amp;lt;pawn&amp;gt;new Float:farray[2] = {0.0, 0.0}&lt;br /&gt;
new bool:barray[2] = {false, false}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Также существует особый тип данных, называемый &amp;quot;строка&amp;quot;, технически являющийся массивом целых чисел. Каждое целое число в строковом массиве соответствует числовому ASCII коду символа. Например, код 32 соответствует пробелу. Таким образом,&amp;lt;pawn&amp;gt;new string[3] = {'h', 'i', '^0'}&amp;lt;/pawn&amp;gt;является символьным представлением строкового массива&amp;lt;pawn&amp;gt;new string[3] = &amp;quot;hi&amp;quot;&amp;lt;/pawn&amp;gt;Обратите внимание на наличие специального символа '^0'. Это обязательный элемент строки, указывающий на ее окончание (численно равен нулю).&lt;br /&gt;
&amp;lt;BR&amp;gt;Также Pawn поддерживает многоуровневые массивы, например:&amp;lt;pawn&amp;gt;new multiarray[2][2]&amp;lt;/pawn&amp;gt;Технически такой массив равен:&amp;lt;pawn&amp;gt;new multiarray[2][2] = {{0, 0}, {0, 0}}&amp;lt;/pawn&amp;gt;Максимальное количество уровней массива равно 3.&lt;br /&gt;
&amp;lt;BR&amp;gt;Для любого явно заданного массива его размер может не указываться, например:&amp;lt;pawn&amp;gt;new array[] = {1, 2, 3} // размер массива равен 3&lt;br /&gt;
new string[] = &amp;quot;hello&amp;quot; // размер массива равен 6, т.к. помимо 5 символов также включает в себя символ окончания строки '^0'&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы инициализировать все элементы массива каким-либо конкретным значением, можно использовать символ троеточия ..., например:&amp;lt;pawn&amp;gt;new bool:is_active[16] = {true, ...}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Прекомпиляция==&lt;br /&gt;
&lt;br /&gt;
На начальной стадии компилирования Pawn компилятор обрабатывает т.н. &amp;quot;статическую&amp;quot; часть кода. К ней можно отнести директивы, глобальные константы, списки и др.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Директивы являются специальными инструкциями компилятора. Одна из самых широко используемых директив – это &amp;quot;include&amp;quot;. Пример ее использования может быть следующим:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&amp;lt;/pawn&amp;gt;Директива как бы &amp;quot;влаживает&amp;quot; содержимое указанного файла в текущую позицию. В данном случае указывается файл amxmodx.inc, который обычно расположен в amxmodx\scripting\include директории, и декларирует основные AMX Mod X функции.&lt;br /&gt;
&amp;lt;BR&amp;gt;Другая директива, позволяющая конструировать т.н. &amp;quot;макросы&amp;quot;, имеет название &amp;quot;define&amp;quot;. Макрос удобен тем, что способен заменять простые блоки кода. Один из простейших макросов – это т.н. &amp;quot;макроконстанта&amp;quot;, например:&amp;lt;pawn&amp;gt;#define VALUE 1&amp;lt;/pawn&amp;gt;В названиях макросов принято использовать буквы только верхнего регистра.&lt;br /&gt;
&amp;lt;BR&amp;gt;Нетехническим аналогом вышеприведенной макроконстанты является т.н. &amp;quot;глобальная константа&amp;quot;:&amp;lt;pawn&amp;gt;stock const value = 1&amp;lt;/pawn&amp;gt;stock атрибут позволяет не включать константу в плагин, если она не используется в коде.&lt;br /&gt;
&amp;lt;BR&amp;gt;Т.н. &amp;quot;список&amp;quot; – это набор нумерованных элементов определенного типа. Например:&amp;lt;pawn&amp;gt;enum {zero, one, two} // соответствует 0, 1, 2&lt;br /&gt;
enum {elem1 = 1, elem2, elem3} // соответствует 1, 2, 3&lt;br /&gt;
enum steeps {steep1 = 10, steep2 = 20} // соответствует 10, 20&amp;lt;/pawn&amp;gt;Тип списка (в вышеприведенном примере типом списка является steeps) – необязательный атрибут, по сути является тэгом, указывающим тип элементов, поэтому следующий пример является верным:&amp;lt;pawn&amp;gt;new steeps:steep = steep2&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Функции==&lt;br /&gt;
&lt;br /&gt;
Существует несколько типов функций.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.н. &amp;quot;обычная&amp;quot; – обычно т.н. &amp;quot;вспомогательная&amp;quot; функция; может быть вызвана непосредственно только другими функциями данного плагина; не может быть вызвана непосредственно AMX Mod X либо его модулями.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;public – обычно функция, вызываемая непосредственно AMX Mod X либо его модулями; может быть также вызвана непосредственно другими функциями данного плагина.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;native – функция, имеющая т.н. &amp;quot;глобальный&amp;quot; характер; может быть вызвана AMX Mod X плагинами.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;forward - функция, имеющая т.н. &amp;quot;глобальный&amp;quot; характер; при наличии в плагине public функции с соответствующим именем функция будет вызываться AMX Mod X или его модулями.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;stock – обычно функция, состоящая в т.н. &amp;quot;библиотеке&amp;quot; функций; не включается в плагин, если не используется в коде.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;В общем виде заголовок, а также прототип любой функции условно выглядит следующим образом (символами треуголных скобок &amp;lt;&amp;gt; ограничены обязательные элементы, символами квадратных скобок [] ограничены необязательные элементы, которые могут быть опущены в определенных случаях):&amp;lt;pawn&amp;gt;[type] [tag]:&amp;lt;name&amp;gt;([[param1], [param2], ..., [paramN]])&amp;lt;/pawn&amp;gt;, где&lt;br /&gt;
[type] – соответствует типу функции (для обычной функции тип не указывается).&lt;br /&gt;
&amp;lt;BR&amp;gt;[tag] – соответствует типу данных возвращаемого результата функции.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;name&amp;gt; - соответствует имени функции&lt;br /&gt;
&amp;lt;BR&amp;gt;([...]) – соответствует набору параметров функции; количество параметров может быть от нуля (параметры отсутствуют) до N, где N – целое положительное число.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;За заголовком функции следует т.н. &amp;quot;тело&amp;quot; функции, ограниченное символами фигурных скобок {}. Таким образом, примером простейшей функции является:&amp;lt;pawn&amp;gt;function()&lt;br /&gt;
{&lt;br /&gt;
	// это пустое тело функции, имеющей имя &amp;quot;function&amp;quot;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;Технически данная функция не выполняет никаких действий, т.к. в своем теле содержит только комментарий. Обратите внимание, что комментарий как бы сдвинут вправо относительно заголовка функции. В данном случае функция инициализирует новый уровень кода. Каждый уровень кода в целях удобочитаемости принято оформлять с соответствующим отступом. Чем более низкий уровень кода, тем больший отступ он будет иметь. Обычно в качестве отступа принято использовать символ табуляции, т.к. многие редакторы позволяют задавать видимую ширину табулированого отступа.&lt;br /&gt;
&amp;lt;BR&amp;gt;Существует два способа передачи параметров функции. Т.н. &amp;quot;основной&amp;quot; способ заключается в том, что при передаче данные дублируются путем создания соответствующих копий в памяти. Т.н. способ передачи параметров &amp;quot;по ссылке&amp;quot; (от англ. by reference) состоит в том, что данные передаются &amp;quot;как есть&amp;quot;, т.е. их дублирования не осуществляется, что позволяет функции изменять оригинальные данные непосредственно.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Для параметров функции все типы массивов, в том числе и строковые, могут передаваться исключительно по ссылке. Передача остальных данных по умолчанию осуществляется основным способом. Чтобы произвести передачу параметра функции по ссылке, в заголовке функции перед параметром необходимо добавлять символ амперсанда &amp;amp;, например:&amp;lt;pawn&amp;gt;function(&amp;amp;Float:fparam)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Параметры функции могут иметь значения по умолчанию, например:&amp;lt;pawn&amp;gt;function(param = 1)&amp;lt;/pawn&amp;gt;Таким образом, чтобы вызвать данную функцию с параметром по умолчанию, параметр можно не указывать:&amp;lt;pawn&amp;gt;function()&amp;lt;/pawn&amp;gt;Также в таких случаях можно использовать символ подчеркивания _:&amp;lt;pawn&amp;gt;function(_)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы запретить функции изменение передаваемых данных, необходимо использовать атрибут const, например:&amp;lt;pawn&amp;gt;function(const array[])&amp;lt;/pawn&amp;gt;Таким образом, можно утверждать, что в данном случае целью функции не является изменение данных массива, чего нельзя утверждать о следующей функции:&amp;lt;pawn&amp;gt;swaparray(array[2])&amp;lt;/pawn&amp;gt;Исходя из названия функции, типа параметра, его размера и отсутствия запрета на изменение, можно сделать предположение о том, что данная функция меняет элементы массива местами.&lt;br /&gt;
&amp;lt;BR&amp;gt;Важным свойством функции является способность возвращать результат, значение которого имеет определенный тип, например:&amp;lt;pawn&amp;gt;bool:is_true()&lt;br /&gt;
{&lt;br /&gt;
	return true&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы указать допустимые типы параметра функции, в заголовке функции перед параметром необходимо добавлять конструкцию, которая условно выглядит как {tag1, tag2, ..., tagN}:, т.е. представляет собой набор тэгов, количество которых может быть от одного до N, где N – целое положительное число, например:&amp;lt;pawn&amp;gt;get_integer({bool, _}:value)&lt;br /&gt;
{&lt;br /&gt;
	return _:value // возвращается значение типа &amp;quot;целое число&amp;quot;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;Смысл вышеприведенной функции заключается в том, что она принимает параметр как типа &amp;quot;целое число&amp;quot;, так и булевого типа, в результате возвращая значение параметра в числовой форме.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=AMX Mod X=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Функции==&lt;br /&gt;
&lt;br /&gt;
При написании AMX Mod X плагинов важно уметь понимать назначение и принцип действия AMX Mod X функций.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Прототипы функций, а также используемые ими константы и списки заключены в файлы типа *.inc, т.н. &amp;quot;инклуды&amp;quot; (от англ. include), которые обычно расположены в amxmodx\scripting\include директории.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Иногда одни инклуды включают в себя другие. Так основные AMX Mod X функции (т.н. функции AMX Mod X &amp;quot;ядра&amp;quot;) продекларированы в файле amxmodx.inc, который также включает векторные и другие инклуды, декларирующие функции, константы и списки, также имеющие непосредственное отношение к AMX Mod X ядру.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Одной из основных функций AMX Mod X является forward функция plugin_init. Если в коде плагина имеется public функция plugin_init, она будет вызвана AMX Mod X после загрузки карты на сервере. Обычно в plugin_init регистрируют сам плагин, его команды, переменные и т.п.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Плагин регистрируют с помощью native функции register_plugin. Т.к. прототип register_plugin соответствует:&amp;lt;pawn&amp;gt;native register_plugin(const plugin_name[], const version[], const author[])&amp;lt;/pawn&amp;gt;, можно понять, что в качестве параметров функция принимает три строковых массива, соответствующих названию плагина, номеру его версии и автору плагина.&lt;br /&gt;
&amp;lt;BR&amp;gt;Итак, примером простого AMX Mod X плагина является:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Test&amp;quot;, &amp;quot;0.1&amp;quot;, &amp;quot;VEN&amp;quot;)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;По сути данный плагин не выполняет каких-либо действий, но регистрирует себя в AMX Mod X с указанными данными.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Системы функционирования==&lt;br /&gt;
&lt;br /&gt;
AMX Mod X предоставляет большое количество определенных систем функционирования. Так одна из основных систем – это система контроля уровней доступа. Здесь имеют место соответствующие функции, например get_user_flags, а также константы стандартных уровней доступа типа ADMIN_*.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Система регистрирования и контроля консольных команд также &amp;quot;пересекается&amp;quot; с системой контроля уровней доступа и использует такие функции, как например register_concmd и cmd_access.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Также существует множество других систем, среди которых имеется система регистрирования и контроля серверных консольных переменных (англ.: Server CVars), клиентских меню и др.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Как правило, системы регистрирования используют т.н. &amp;quot;handle&amp;quot; (или &amp;quot;hook&amp;quot;) функции, которые вызываются системой в необходимый момент.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Так после регистрирования консольной команды &amp;quot;action&amp;quot;:&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;action&amp;quot;, &amp;quot;action_handler&amp;quot;)&amp;lt;/pawn&amp;gt;при исполнении данной команды из консоли сервера или клиента система попытается найти и выполнить public функцию action_handler.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Система строкового форматирования==&lt;br /&gt;
&lt;br /&gt;
Многие AMX Mod X функции используют систему строкового форматирования. Например, это все *_print функции.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Такие функции принимают практически неограниченное количество параметров, которые используются при форматировании соответствующей строковой конструкции. Для наглядности рассмотрим пример:&amp;lt;pawn&amp;gt;server_print(&amp;quot;Formatted string: %d %f %s %c&amp;quot;, 1, 1.234567, &amp;quot;hello&amp;quot;, '!')&amp;lt;/pawn&amp;gt;Функция server_print отформатирует строковую конструкцию &amp;quot;Formatted string: %d %f %s %c&amp;quot;, используя переданные параметры, и выведет в серверной консоли строку:&amp;lt;pawn&amp;gt;Formatted string: 1 1.234567 hello !&amp;lt;/pawn&amp;gt;Таким образом, %d, %f, %s, %c – специальные элементы, используемые для форматирования целого числа, дробного числа, строки и символа соответственно.&lt;br /&gt;
&amp;lt;BR&amp;gt;Опасно при использовании функций, поддерживающих форматирование, передавать строковую переменную непосредственно в параметр строковой конструкции, например:&amp;lt;pawn&amp;gt;server_print(string)&amp;lt;/pawn&amp;gt;Безопасный вариант выглядит, следующим образом:&amp;lt;pawn&amp;gt;server_print(&amp;quot;%s&amp;quot;, string)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Т.к. символ процента % является, т.н. &amp;quot;специальным символом&amp;quot;, для его форматирования в строковой конструкции необходимо использовать двойной символ процента %%, например:&amp;lt;pawn&amp;gt; server_print(&amp;quot;This is a single symbol of percent: %%&amp;quot;)&amp;lt;/pawn&amp;gt;выведет в серверной консоли:&amp;lt;pawn&amp;gt; This is a single symbol of percent: %&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Также существует т.н. &amp;quot;контрольный символ&amp;quot; (от англ. control character), позволяющий использовать т.н. &amp;quot;специальные символы форматирования&amp;quot;. Контрольным символом по умолчанию является символ ^, который может быть изменен директивой pragma ctrlchar, например:&amp;lt;pawn&amp;gt;#pragma ctrlchar '\'&amp;lt;/pawn&amp;gt;изменит контрольный символ на \.&lt;br /&gt;
&amp;lt;BR&amp;gt;Примеры некоторых специальных символов форматирования приведены ниже:&lt;br /&gt;
&amp;lt;BR&amp;gt;^t – табуляция&lt;br /&gt;
&amp;lt;BR&amp;gt;^n – новая строка&lt;br /&gt;
&amp;lt;BR&amp;gt;^xHH – символ, представленный в шестнадцатиричном формате, где HH – двойное число, представленное в шестнадцатиричном формате&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Compiling_Plugins_(AMX_Mod_X)&amp;diff=3856</id>
		<title>Ru Compiling Plugins (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Compiling_Plugins_(AMX_Mod_X)&amp;diff=3856"/>
		<updated>2007-01-23T00:20:32Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: added russian category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Compiling Plugins (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Компилирование плагинов=&lt;br /&gt;
&lt;br /&gt;
Эта статья описывает, как компилировать [[AMX Mod X]] плагины из [[Ru:source code|исходного кода]] (.sma).&lt;br /&gt;
&lt;br /&gt;
Для всех случаев вы должны поместить .sma файл в директорию addons/amxmodx/scripting.&lt;br /&gt;
&lt;br /&gt;
=Windows=&lt;br /&gt;
&lt;br /&gt;
==Метод перетаскивания==&lt;br /&gt;
#Перетащите .sma файл на &amp;quot;compile.exe&amp;quot;.&lt;br /&gt;
#Откомпилированный .amxx файл будет находиться в директории compiled.&lt;br /&gt;
&lt;br /&gt;
==Компилирование всех плагинов==&lt;br /&gt;
#Дважды щелкните на compile.exe, чтобы откомпилировать все плагины и поместить их в директорию compiled.&lt;br /&gt;
==Командная строка==&lt;br /&gt;
#Зайдите в &amp;quot;Пуск&amp;quot;, &amp;quot;Выполнить&amp;quot;, введите &amp;quot;cmd&amp;quot;, нажмите Ok.&lt;br /&gt;
#Используйте cd, чтобы сменить директорию, например: &amp;lt;pre&amp;gt;cd c:\hlserver\cstrike\addons\amxmodx\scripting&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Используйте amxxpc, чтобы откомпилировать плагин: &amp;lt;pre&amp;gt;amxxpc.exe myplugin.sma&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Откомпилированный плагин будет в этой же директории.&lt;br /&gt;
&lt;br /&gt;
=Linux=&lt;br /&gt;
&lt;br /&gt;
Сперва перейдите в scripting директорию в вашей оболочке следующим образом: &amp;lt;pre&amp;gt;cd addons/amxmodx/scripting&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Компилирование всех плагинов==&lt;br /&gt;
#Запустите скрипт compile.sh одним из способов: &amp;lt;pre&amp;gt;sh compile.sh&amp;lt;/pre&amp;gt; or &amp;lt;pre&amp;gt;chmod +x compile.sh&lt;br /&gt;
        ./compile.sh&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Компилирование одиночного плагина==&lt;br /&gt;
#Запустите amxxpc, например: &amp;lt;pre&amp;gt;./amxxpc myplugin.sma&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Откомпилированный плагин будет в этой же директории.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3854</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3854"/>
		<updated>2007-01-22T22:43:01Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;br /&gt;
::AMWiki needs to have an &amp;quot;Ru&amp;quot; namespace added (and perhaps an &amp;quot;No&amp;quot; namespace) in order for Template:LangaugeSwitch to work as desired. [http://meta.wikimedia.org/wiki/Help:Custom_namespaces Here] are MediaWiki instructions for how to add it. Also all the old Talk:Ru:blah pages will have to be moved over to Ru_talk if you decide to use that for the Ru namespace talk pages. --[[User:CyberMind|cybermind]] 12:15, 22 January 2007 (CST)&lt;br /&gt;
:::I've renamed all the Ru: pages so that when the namespace is added, the pages will not become inaccessible (I will move them to the new namespace once it is created). I also added a new template, LanguageHelpSwitch which will be used where the namespace for the English version of the page is Help: but the Russian is just Ru: (like Help:Editing vs Ru:Editing). --[[User:CyberMind|cybermind]] 12:27, 22 January 2007 (CST)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[http://wiki.amxmodx.org/index.php/Category:Ru:Scripting_%28AMX_Mod_X%29 Category:Ru:Scripting (AMX Mod X)] contain broken links. What is the best to do here? Should i create Category:Ru Scripting (AMX Mod X) and relink related articles here?&lt;br /&gt;
:They should all work now. The Category names can stay Ru: since you can't have any other category namespaces other than Category, so Category:Ru: would be like a sub-namespace sort of. Also, once the Ru namespace is made, the Ru articles will be moved back to Ru:Whatever which will make them active in the Ru namespace (right now, there is no Ru namespace, that was just a part of those articles' titles). Once that happens, the LanguageSwitch (and LanguageHelpSwitch) templates will work perfectly. For now, nothing else should be modified and we should wait for the namespaces to be created before we figure out what else needs to be changed. --[[User:CyberMind|cybermind]] 16:42, 22 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3853</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3853"/>
		<updated>2007-01-22T22:42:10Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;br /&gt;
::AMWiki needs to have an &amp;quot;Ru&amp;quot; namespace added (and perhaps an &amp;quot;No&amp;quot; namespace) in order for Template:LangaugeSwitch to work as desired. [http://meta.wikimedia.org/wiki/Help:Custom_namespaces Here] are MediaWiki instructions for how to add it. Also all the old Talk:Ru:blah pages will have to be moved over to Ru_talk if you decide to use that for the Ru namespace talk pages. --[[User:CyberMind|cybermind]] 12:15, 22 January 2007 (CST)&lt;br /&gt;
:::I've renamed all the Ru: pages so that when the namespace is added, the pages will not become inaccessible (I will move them to the new namespace once it is created). I also added a new template, LanguageHelpSwitch which will be used where the namespace for the English version of the page is Help: but the Russian is just Ru: (like Help:Editing vs Ru:Editing). --[[User:CyberMind|cybermind]] 12:27, 22 January 2007 (CST)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[http://wiki.amxmodx.org/index.php/Category:Ru:Scripting_%28AMX_Mod_X%29 Category:Ru:Scripting (AMX Mod X)] contain broken links. What is the best to do here? Should i create Category:Ru Scripting (AMX Mod X) and relink related articles here?&lt;br /&gt;
:They should all work now. The Category names can stay Ru: since you can't have any other category namespaces other than Category, so Category:Ru: would be like a sub-namespace sort of. Also, once the Ru namespace is made, the Ru articles will be moved back to Ru:Whatever which will make them active in the Ru namespace (right now, there is no Ru namespace, that was just a part of those articles' titles). Once that happens, the LanguageSwitch (and LanguageHelpSwitch) templates will work perfectly. --[[User:CyberMind|cybermind]] 16:42, 22 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3844</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3844"/>
		<updated>2007-01-22T18:29:36Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;br /&gt;
::AMWiki needs to have an &amp;quot;Ru&amp;quot; namespace added (and perhaps an &amp;quot;No&amp;quot; namespace) in order for Template:LangaugeSwitch to work as desired. [http://meta.wikimedia.org/wiki/Help:Custom_namespaces Here] are MediaWiki instructions for how to add it. Also all the old Talk:Ru:blah pages will have to be moved over to Ru_talk if you decide to use that for the Ru namespace talk pages. --[[User:CyberMind|cybermind]] 12:15, 22 January 2007 (CST)&lt;br /&gt;
:::I've renamed all the Ru: pages so that when the namespace is added, the pages will not become inaccessible (I will move them to the new namespace once it is created). I also added a new template, LanguageHelpSwitch which will be used where the namespace for the English version of the page is Help: but the Russian is just Ru: (like Help:Editing vs Ru:Editing). --[[User:CyberMind|cybermind]] 12:27, 22 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3843</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3843"/>
		<updated>2007-01-22T18:27:13Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;br /&gt;
::AMWiki needs to have an &amp;quot;Ru&amp;quot; namespace added (and perhaps an &amp;quot;No&amp;quot; namespace) in order for Template:LangaugeSwitch to work as desired. [http://meta.wikimedia.org/wiki/Help:Custom_namespaces Here] are MediaWiki instructions for how to add it. Also all the old Talk:Ru:blah pages will have to be moved over to Ru_talk if you decide to use that for the Ru namespace talk pages. --[[User:CyberMind|cybermind]] 12:15, 22 January 2007 (CST)&lt;br /&gt;
::I've renamed all the Ru: pages so that when the namespace is added, the pages will not become inaccessible. I also added a new template, LanguageHelpSwitch which will be used where the namespace for the English version of the page is Help: but the Russian is just Ru: (like Help:Editing vs Ru:Editing). --[[User:CyberMind|cybermind]] 12:27, 22 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Template:LanguageHelpSwitch&amp;diff=3842</id>
		<title>Template:LanguageHelpSwitch</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Template:LanguageHelpSwitch&amp;diff=3842"/>
		<updated>2007-01-22T18:25:18Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;table width=&amp;quot;100%&amp;quot; style=&amp;quot;border: 1px solid #AAAAAA; background-color: #EEEEEE&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td width=&amp;quot;80%&amp;quot;&amp;gt;&lt;br /&gt;
'''View this page in:'''&lt;br /&gt;
&amp;amp;nbsp;[[Help:{{PAGENAME}}|English]]&lt;br /&gt;
&amp;amp;nbsp;[[Ru:{{PAGENAME}}|Russian]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&amp;lt;td width=&amp;quot;20%&amp;quot; align=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Help:Editing&amp;diff=3841</id>
		<title>Help:Editing</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Help:Editing&amp;diff=3841"/>
		<updated>2007-01-22T18:25:03Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LanguageHelpSwitch}}&lt;br /&gt;
To read more about editing a wiki, see the MediaWiki editing documentation here: [http://meta.wikimedia.org/wiki/Help:Editing MediaWiki Editing]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Configuring_AMX_Mod_X&amp;diff=3839</id>
		<title>Ru Configuring AMX Mod X</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Configuring_AMX_Mod_X&amp;diff=3839"/>
		<updated>2007-01-22T18:21:27Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Configuring AMX Mod X moved to Ru Configuring AMX Mod X&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Documentation (AMX Mod X)]]&lt;br /&gt;
Данная статья переведена не полностью.&lt;br /&gt;
&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Configuring AMX Mod X]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Плагины=&lt;br /&gt;
==Установка==&lt;br /&gt;
Иногда плагины могут иметь свои собственные инструкции, если они требуют особенной установки. Однако данная статья поможет освоить основы установки плагинов.&lt;br /&gt;
#Следуйте всем указаниям, которые дает автор плагина. Если плагин требует дополнительных шагов или специальных файлов, убедитесь, что вы имеете их в правильном месте и порядке.&lt;br /&gt;
#Если вам был предоставлен .sma файл вместо .amxx, вам следует откомпилировать плагин самим. Для более детальной информации смотрите [[Ru:Compiling Plugins (AMX Mod X)]].&lt;br /&gt;
#Поместите .amxx файл в addons/amxmodx/plugins директорию.&lt;br /&gt;
#Добавьте имя плагина в addons\amxmodx\configs\plugins.ini. Например: &amp;lt;pre&amp;gt;myplugin.amxx&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Смените карту или перезапустите сервер. Если при загрузке сообщается о каких-либо ошибках, смотрите [[Troubleshooting AMX Mod X#Plugins|Troubleshooting AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
==Удаление==&lt;br /&gt;
#Удалите запись из addons\amxmodx\configs\plugins.ini или добавьте в начале строки точку с запятой.&lt;br /&gt;
#Также можно удалить все файлы, связанные с отключаемым плагином.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Scripting_(AMX_Mod_X)&amp;diff=3837</id>
		<title>Ru Scripting (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Scripting_(AMX_Mod_X)&amp;diff=3837"/>
		<updated>2007-01-22T18:20:57Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Scripting (AMX Mod X) moved to Ru Scripting (AMX Mod X)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]] &lt;br /&gt;
[[AMX Mod X]] позволяет расширить функциональность игры с помощью плагинов. Перейдите в категорию [http://wiki.amxmodx.org/index.php/Category:Ru:Scripting_%28AMX_Mod_X%29 Ru:Scripting (AMX Mod X)], чтобы просмотреть список некторых статей, которые помогут вам разработать свои (или доработать чужие) плагины, используя язык [[Pawn]] (известный ранее как [[Small]]).&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Editing&amp;diff=3835</id>
		<title>Ru Editing</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Editing&amp;diff=3835"/>
		<updated>2007-01-22T18:20:50Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Editing moved to Ru Editing&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
Чтобы узнать больше о том, как редактировать wiki-страницы, посетите страницу Википедии [http://ru.wikipedia.org/wiki/Википедия:Как_править_статьи Как править статьи].&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Commands_(AMX_Mod_X)&amp;diff=3833</id>
		<title>Ru Commands (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Commands_(AMX_Mod_X)&amp;diff=3833"/>
		<updated>2007-01-22T18:20:43Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Commands (AMX Mod X) moved to Ru Commands (AMX Mod X)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Documentation (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
= Выбор языка =&lt;br /&gt;
&lt;br /&gt;
Смотреть эту страницу на:&lt;br /&gt;
&lt;br /&gt;
* [[Commands_%28AMX_Mod_X%29|English]]&lt;br /&gt;
* [[ru:Commands_%28AMX_Mod_X%29|Russian]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
Консольные команды вводятся в консоли как:&lt;br /&gt;
&amp;lt;pre&amp;gt;amx_&amp;lt;command&amp;gt; &amp;lt;option1&amp;gt; &amp;lt;option2&amp;gt; [option3]&amp;lt;/pre&amp;gt;&lt;br /&gt;
Обязательные оции показаны с &amp;lt;&amp;gt;, не обязательные параметры показаны с []. Символы &amp;lt;&amp;gt; и [] в действительности вводить не нужно.&lt;br /&gt;
&lt;br /&gt;
Чтобы увидеть справку во время игры, введите в консоли следующее:&lt;br /&gt;
&amp;lt;pre&amp;gt;amx_help&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Команды админа=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Формат&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_kick&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; [причина]A&lt;br /&gt;
| ADMIN_KICK&lt;br /&gt;
| Кикнуть игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_ban&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; &amp;lt;время&amp;gt; [причина]&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Забанить игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_banip&lt;br /&gt;
| &amp;lt;authid или ip&amp;gt; &amp;lt;минуты&amp;gt; [причина]&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Забанить игрока по IP.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_addban&lt;br /&gt;
| &amp;lt;authid или ip&amp;gt; &amp;lt;минуты&amp;gt; [причина]&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Добавить бан в бансписок.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_unban&lt;br /&gt;
| &amp;lt;authid или ip&amp;gt;&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Разбанить игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_slay&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt;&lt;br /&gt;
| ADMIN_SLAY&lt;br /&gt;
| Убивает игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_slap&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; [повреждение]&lt;br /&gt;
| ADMIN_SLAY&lt;br /&gt;
| Бьет игрока с силой указанной в переменной.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_leave&lt;br /&gt;
| &amp;lt;tag&amp;gt; [тег1] [тег2] [тег3]&lt;br /&gt;
| ADMIN_KICK&lt;br /&gt;
| Кикать всех игроков которые не имеют один из тегов.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_pause&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_CVAR&lt;br /&gt;
| Устанавливает паузу в игре или снимает её.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_who&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_ADMIN&lt;br /&gt;
| Выводит список текущих клиентов сервера, с указанием различных деталей, таких как уровень доступа и др.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cvar&lt;br /&gt;
| &amp;lt;cvar&amp;gt; [value]&lt;br /&gt;
| ADMIN_CVAR&lt;br /&gt;
| Устанавливает или показывает cvar переменную.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_map&lt;br /&gt;
| &amp;lt;имя карты&amp;gt;&lt;br /&gt;
| ADMIN_MAP&lt;br /&gt;
| Меняет карту.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_nick&lt;br /&gt;
| &amp;lt;name or #userid&amp;gt; &amp;lt;новое имя&amp;gt;&lt;br /&gt;
| ADMIN_LEVEL_A&lt;br /&gt;
| Меняет имя пользователя (на самом деле запускает команду name удаленно на консоли пользователя - не работает если у пользователя прописано alias name)&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cfg&lt;br /&gt;
| &amp;lt;имя файла&amp;gt;&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Загружает на стороне сервера конфигурационный файл.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_rcon&lt;br /&gt;
| &amp;lt;командная строка&amp;gt;&lt;br /&gt;
| ADMIN_RCON&lt;br /&gt;
| Запускает консольную команду на стороне сервера.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_showrcon&lt;br /&gt;
| &amp;lt;командная строка&amp;gt;&lt;br /&gt;
| ADMIN_RCON&lt;br /&gt;
| Запускает консольную команду на стороне сервера с возвратом ответа от сервера.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_plugins&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_ADMIN&lt;br /&gt;
| Список всех загруженых плагинов.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_modules&lt;br /&gt;
| &lt;br /&gt;
| ADMIN_ADMIN&lt;br /&gt;
| Список всех загруженых модулей.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды чата=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Формат&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_say&lt;br /&gt;
| &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем игрокам через обычный чат.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_chat&lt;br /&gt;
| &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем администраторам через обычный чат.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_psay&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt; &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Послать личное сообщение игроку.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_tsay&lt;br /&gt;
| &amp;lt;цвет&amp;gt; &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем игрокам. Сообщение показывается слевой стороны в игре.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_csay&lt;br /&gt;
| &amp;lt;цвет&amp;gt; &amp;lt;сообщение&amp;gt;&lt;br /&gt;
| ADMIN_CHAT&lt;br /&gt;
| Посылает сообщение всем игрокам. Сообщение показывается в центре экрана.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды голосования=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Формат&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_votemap&lt;br /&gt;
| &amp;lt;карта&amp;gt; [карта] [карта] [карта]&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает голосование за карту.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_votekick&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt;&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает голосование за то чтобы кикнуть игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_voteban&lt;br /&gt;
| &amp;lt;name или #userid&amp;gt;&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает голосование за то чтобы забанить игрока.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_vote&lt;br /&gt;
| &amp;lt;Вопрос&amp;gt; &amp;lt;ответ1&amp;gt; &amp;lt;ответ2&amp;gt;&lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Начинает произвольное голосование.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cancelvote  	 &lt;br /&gt;
| &lt;br /&gt;
| ADMIN_VOTE&lt;br /&gt;
| Отменяет последнее голосование которое находится в прогрессе.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды статистики=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /hp&lt;br /&gt;
| Показывает информацию о вашем убийце.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /statsme&lt;br /&gt;
| Показывает вашу статистику.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /stats&lt;br /&gt;
| Показывает статистику других игроков.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /top15&lt;br /&gt;
| Показывает рейтинг лучших 15 игроков.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say /rank&lt;br /&gt;
| Показывает ваш рейтинг на сервере.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды чата=&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say nextmap&lt;br /&gt;
| Показывает следующую карту в mapcycle.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say timeleft&lt;br /&gt;
| Показывает сколько времени осталось до смены карты.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| say thetime&lt;br /&gt;
| Показывает текущее время.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды меню=&lt;br /&gt;
{{qnotice|ACCESS_LEVEL_A не является &amp;quot;a&amp;quot;, это &amp;quot;m&amp;quot;.  Смотрите [[Adding Admins (AMX Mod X)#Access Levels|Уровни доступа]].}}&lt;br /&gt;
&lt;br /&gt;
:{|&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Команда&lt;br /&gt;
| Доступ&lt;br /&gt;
| Описание&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amxmodmenu&lt;br /&gt;
| ADMIN_MENU&lt;br /&gt;
| Показывает главное AMX Mod X меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_cvarmenu&lt;br /&gt;
| ADMIN_CVAR&lt;br /&gt;
| Показывает CVAR меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_mapmenu&lt;br /&gt;
| ADMIN_MAP&lt;br /&gt;
| Показывает меню смены карт.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_votemapmenu&lt;br /&gt;
| ADMIN_MAP&lt;br /&gt;
| Показывает меню голосований.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_kickmenu&lt;br /&gt;
| ADMIN_KICK&lt;br /&gt;
| Показывает kick меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_banmenu&lt;br /&gt;
| ADMIN_BAN&lt;br /&gt;
| Показывает ban меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_slapmenu&lt;br /&gt;
| ADMIN_SLAY&lt;br /&gt;
| Показывает slap/slay меню.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_teammenu&lt;br /&gt;
| ADMIN_LEVEL_A&lt;br /&gt;
| Показывает меню смены команд.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_clcmdmenu&lt;br /&gt;
| ADMIN_LEVEL_A&lt;br /&gt;
| Показывает меню клиентских команд.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_restmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Показывает меню оружейного огранчения.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_teleportmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Показывает меню телепорта.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_pausecfgmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Меню установки плагинов в паузу или снятие паузы.&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| amx_statscfgmenu&lt;br /&gt;
| ADMIN_CFG&lt;br /&gt;
| Показывает меню настроек статистики.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команда Конфига=&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Команда:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | amx_pausecfg&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Формат: &lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | &amp;lt;команда&amp;gt; [имя]&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Доступ:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | ADMIN_CFG&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Описание:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | Установить в паузу плагин.&amp;lt;br /&amp;gt;&lt;br /&gt;
Список команд:&amp;lt;br /&amp;gt;&lt;br /&gt;
*off - Установить паузу на всех плагинах которые не в списке.&lt;br /&gt;
*on - Снять паузу со всех плагинов.&lt;br /&gt;
*stop &amp;lt;файл&amp;gt; - Остановить плагин.&lt;br /&gt;
*pause &amp;lt;файл&amp;gt; - Установть в паузу плагин.&lt;br /&gt;
*enable &amp;lt;файл&amp;gt; - Включить плагин.&lt;br /&gt;
*save - Сохранить список остановленных плагинов.&lt;br /&gt;
*clear - Очистить список остановленных плагинов.&lt;br /&gt;
*list [id] - Список плагинов.&lt;br /&gt;
*add &amp;lt;заголовок&amp;gt; - Пометить плагин как не устанавливаемый в паузу.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Команда&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | amx_statscfg&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Формат: &lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | &amp;lt;команда&amp;gt; [параметры]&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Доступ:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | ADMIN_CFG&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Описание:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | Изменение настроек статистики.&amp;lt;br /&amp;gt;&lt;br /&gt;
Список команд:&amp;lt;br /&amp;gt;&lt;br /&gt;
*on &amp;lt;переменная&amp;gt; - Включить выбранную опцию.&lt;br /&gt;
*off &amp;lt;переменная&amp;gt; - Выключить выбранную опцию.&lt;br /&gt;
*save - Сохранить конфигурацию статистики.&lt;br /&gt;
*load - Загрузить конфигурацию статистики.&lt;br /&gt;
*list [id] - Список статусов статистики.&lt;br /&gt;
*add &amp;lt;имя&amp;gt; &amp;lt;переменная&amp;gt; - Добавить переменную статистики в список.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Команды RCON=&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Команда:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | amxx&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Формат: &lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | &amp;lt;команда&amp;gt; [параметры]&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Доступ:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| class=&amp;quot;t2th&amp;quot; | Описание:&lt;br /&gt;
| class=&amp;quot;t2td&amp;quot; | Список доступных команд:&amp;lt;br /&amp;gt;&lt;br /&gt;
*amxx version - Показать версию AMX Mod X;&lt;br /&gt;
*amxx modules - Показать список модулей;&lt;br /&gt;
*amxx plugins - Показать список плагинов;&lt;br /&gt;
*amxx gpl - Показать GNU General Public Лицензию;&lt;br /&gt;
*amxx cvars - Показать AMX Mod X зарегистрированные CVARs;&lt;br /&gt;
*amxx cmds - Показать AMX Mod X зарегистрированные команды;&lt;br /&gt;
*amxx pause &amp;lt;plugin&amp;gt; - Приостановить плагин;&lt;br /&gt;
*amxx unpause &amp;lt;plugin&amp;gt; - Возобновить работу приостановленного плагина.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Intro_to_AMX_Mod_X_Scripting&amp;diff=3831</id>
		<title>Ru Intro to AMX Mod X Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Intro_to_AMX_Mod_X_Scripting&amp;diff=3831"/>
		<updated>2007-01-22T18:20:33Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Intro to AMX Mod X Scripting moved to Ru Intro to AMX Mod X Scripting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Intro to AMX Mod X Scripting]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Введение в AMX Mod X скриптинг=&lt;br /&gt;
Это руководство позволит разобраться в основах скриптинга [[AMX Mod X]] плагинов.&lt;br /&gt;
&lt;br /&gt;
=Обзор=&lt;br /&gt;
&lt;br /&gt;
Значит, вы хотите создать плагин? Вы должны иметь хорошее представление о том, как работает [[Pawn]], скриптинг язык, который используется для написания [[AMX Mod X]] плагинов. Поэтому в первую очередь настоятельно рекомендуется ознакомиться с фундаментальными основами [[Pawn]] и [[AMX Mod X]] скриптинга: [[Ru:Fundamental Basics of AMX Mod X Scripting]]. Желательно читать данную статью, сидя за компьютером с текстовым редактором и [[Pawn]] компилятором под рукой - хорошее подспорье для эффективного обучения. Конечно же, вы не будете сразу писать большие плагины типа WC3, Matrix Mod и CSDM, но все же статья даст вам &amp;quot;толчок&amp;quot; в мир моддинга [[AMX Mod X]]. Хороший редактор с поддержкой [[Pawn]] - это AMXX-Studio, который можно найти в секции [http://www.amxmodx.org/downloads.php AMX Mod X downloads].&lt;br /&gt;
&lt;br /&gt;
Вам необходимо знать, как компилировать плагины. Обратитесь к секции [[Ru:Compiling Plugins (AMX Mod X)]] для ознакомления. Также, чтобы проверить и отладить ваш плагин, вы должны знать, как устанавливать плагины. Для этого обратитесь к секции [[Ru:Configuring AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
&lt;br /&gt;
AMX Mod X плагин может иметь четыре главных типа функций. Первый - &amp;quot;public&amp;quot; функция. Это означает, что функция доступна для AMX Mod X &amp;quot;движка&amp;quot;. Второй тип - &amp;quot;native&amp;quot; функция, которая располагается в модуле или в ядре AMX Mod X. Третий тип - обычные пользовательские функции, которые прописываются без каких-либо специальных атрибутов. Четвертый тип - это &amp;quot;forward&amp;quot; функция, которая вызывается каждый раз, когда происходит какое-то определенное событие (forward функция также является и public). AMX Mod X плагин должен начинаться с функции, инициализирующей плагин:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;//Это делает возможным использование функций AMX Mod X ядра&lt;br /&gt;
//Это &amp;quot;влаживает&amp;quot; native &amp;quot;определители&amp;quot;(заголовки) из includes\amxmodx.inc&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//Объявляем три строковых переменных&lt;br /&gt;
new PLUGIN[]=&amp;quot;AMXX Demo&amp;quot;&lt;br /&gt;
new AUTHOR[]=&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
new VERSION[]=&amp;quot;1.00&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//Это public функция.&lt;br /&gt;
//Необходимо инициализировать ваш скрипт для AMX Mod X.&lt;br /&gt;
//Эта функция не содержит параметров, вызывается сразу после загрузки карты.&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     //Это функция, которая &amp;quot;берет&amp;quot; три строки.&lt;br /&gt;
     //Она регистрирует ваш плагин в AMX Mod X и присваивает некоторую основную информацию.&lt;br /&gt;
     register_plugin(PLUGIN, VERSION, AUTHOR)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Попробуйте откомпилировать скрипт, приведенный выше. Он будет очень мал, т.к. не делает ничего особенного. Однако, если вы загрузите этот скрипт и напишите &amp;quot;amxx plugins&amp;quot; в серверной консоли, вы должны увидеть новую запись в листе плагинов.&lt;br /&gt;
&lt;br /&gt;
=Создание админ-комманд=&lt;br /&gt;
&lt;br /&gt;
AMX Mod X предоставляет возможность простого добавления консольных админ-команд. Каждая команда &amp;quot;регистрируется&amp;quot; как консольная команда. При регистрировании команды вы должны указать четыре свойства: имя консольной команды; функцию, которая будет вызываться при использовании команды; уровень доступа, необходимый для использования команды; короткое описание команды.&lt;br /&gt;
&lt;br /&gt;
Для демонстрации давайте сделаем плагин, который позволит вам изменить количество жизней игрока на сервере с помощью команды &amp;quot;amx_hp&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Для начала нам понадобится сделать две вещи: первая - нам нужно зарегистрировать команду в консоли. Т.к. мы &amp;quot;привязываем&amp;quot; команду к public функции, мы должны убедиться, что функция существует.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmisc&amp;gt; //Это содержит некоторые полезные функции&lt;br /&gt;
#include &amp;lt;fun&amp;gt;     //Это содержит функцию для изменения жизней&lt;br /&gt;
&lt;br /&gt;
new PLUGIN[]=&amp;quot;Change Health&amp;quot;&lt;br /&gt;
new AUTHOR[]=&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
new VERSION[]=&amp;quot;1.00&amp;quot;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     register_plugin(PLUGIN, VERSION, AUTHOR)&lt;br /&gt;
     register_concmd(&amp;quot;amx_hp&amp;quot;, &amp;quot;cmd_hp&amp;quot;, ADMIN_SLAY, &amp;quot;&amp;lt;target&amp;gt; &amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первая новая функция - это &amp;quot;register_concmd&amp;quot;, которая берет четыре параметра. Первый - название команды, которую необходимо набрать в консоли. Второй - название public функции, которая будет контролировать команду. Третий - уровень доступа, который необходим для вашей команды. И последний - строка, описывающая, как использовать вашу команду.&lt;br /&gt;
&lt;br /&gt;
Далее мы создаем public функцию для контроля amx_hp команды. Обратите внимание, что мы даем ей три параметра. Эти параметры будут содержать специальные данные, когда команду будет использована. id будет содержать индекс(номер) игрока, который запустил команду, level будет содержать уровень доступа команды (вы должны сами осуществить проверку уровня доступа), cid будет содержать внутренний индекс(номер) команды.&lt;br /&gt;
&lt;br /&gt;
Также обратите внимание на PLUGIN_HANDLED. Существует два главных return значения. PLUGIN_CONTINUE как бы означает &amp;quot;продолжить с нормальным выполнением&amp;quot;, PLUGIN_HANDLED означает &amp;quot;блокировать дальнейшее выполнение&amp;quot;. Разница сложно уловима, но важна. К примеру, если вы делаете &amp;quot;привязку&amp;quot; к своей команде, вы не должны возвращать PLUGIN_CONTINUE. Но если вы возвращаете PLUGIN_HANDLED, при привязанной &amp;quot;say&amp;quot; команде, это полностью заблокирует say-текст. Вы должны быть внимательны с тем, что вы выбираете для возврата в различных ситуациях. Однако, многие вещи &amp;quot;безразличны&amp;quot; к возвращаемому значению. Например, таймеры(tasks), события(events) и другие вещи, с которыми вы встретитесь позже.&lt;br /&gt;
&lt;br /&gt;
Итак, как же мы убедимся, что данный пользователь - это админ, который имеет ADMIN_SLAY уровень доступа?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     if (!cmd_access(id, level, cid, 3))&lt;br /&gt;
        return PLUGIN_HANDLED&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
cmd_access() функция проверит информацию команды (пользователя, уровень доступа и индекс) и проверяет две вещи: что пользователь имеет доступ, и что было дано минимальное количество параметров. Мы указали три, потому что команда будет выглядеть как: amx_hp &amp;lt;target&amp;gt; &amp;lt;amount&amp;gt;, и в действительности сама команда также считается как параметр. Если cmd_access откажет, мы сразу прекращаем выполнение команды.&lt;br /&gt;
&lt;br /&gt;
Следующее, что нужно решить: мы должны взять два параметра и преобразовать их. &amp;quot;amount&amp;quot; параметр прост - мы просто конвертируем его из строки в число. Другой же параметр будет по сложнее, т.к. мы хотим иметь возможность указывать на три различных типа людей:&lt;br /&gt;
&lt;br /&gt;
* @CT или @T - (контр-террористы или террористы)&lt;br /&gt;
* @ALL - (все)&lt;br /&gt;
* &amp;lt;target&amp;gt; - частичное имя игрока&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     if (!cmd_access(id, level, cid, 3))&lt;br /&gt;
        return PLUGIN_HANDLED&lt;br /&gt;
&lt;br /&gt;
     new Arg1[24]&lt;br /&gt;
     new Arg2[4]&lt;br /&gt;
&lt;br /&gt;
     //Берем аргументы команды из консоли&lt;br /&gt;
     read_argv(1, Arg1, 23)&lt;br /&gt;
     read_argv(2, Arg2, 3)&lt;br /&gt;
&lt;br /&gt;
     //Конвертируем количество жизней из строки в число&lt;br /&gt;
     new Health = str_to_num(Arg2)&lt;br /&gt;
&lt;br /&gt;
     //Является ли первый символ @ символом?&lt;br /&gt;
     if (Arg1[0] == '@')&lt;br /&gt;
     {&lt;br /&gt;
          new Team = 0&lt;br /&gt;
          //Проверяем, какая команда была указана.&lt;br /&gt;
          //Заметьте, что мы начинаем с [1]&lt;br /&gt;
          // это означает, что @ не входит&lt;br /&gt;
          if (equali(Arg1[1], &amp;quot;CT&amp;quot;))&lt;br /&gt;
          {&lt;br /&gt;
               Team = 2&lt;br /&gt;
          } else if (equali(Arg1[1], &amp;quot;T&amp;quot;)) {&lt;br /&gt;
               Team = 1&lt;br /&gt;
          }&lt;br /&gt;
          new players[32], num&lt;br /&gt;
          //Эта функция заполнит players[32] переменную&lt;br /&gt;
          // верными индексами игроков. num будет содержать количество&lt;br /&gt;
          // игроков, которые действительны.&lt;br /&gt;
          get_players(players, num)&lt;br /&gt;
          new i&lt;br /&gt;
          for (i=0; i&amp;lt;num; i++)&lt;br /&gt;
          {&lt;br /&gt;
               if (!Team)&lt;br /&gt;
               {&lt;br /&gt;
                    //Устанавливаем количество жизней этого игрока&lt;br /&gt;
                    set_user_health(players[i], Health)&lt;br /&gt;
               } else {&lt;br /&gt;
                    if (get_user_team(players[i]) == Team)&lt;br /&gt;
                    {&lt;br /&gt;
                         set_user_health(players[i], Health)&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
          }&lt;br /&gt;
     } else {&lt;br /&gt;
          //находит индекс игрока, который соответствует части указанного имени&lt;br /&gt;
          //1 означает, что игрок с &amp;quot;иммунитетом&amp;quot; не будет учтен&lt;br /&gt;
          new player = cmd_target(id, Arg1, 1)&lt;br /&gt;
          if (!player)&lt;br /&gt;
          {&lt;br /&gt;
               //это напечатает сообщение пользователю, который запускал команду&lt;br /&gt;
               //Формат для этой команды называется &amp;quot;format()&amp;quot; стиль,&lt;br /&gt;
               // где первая строка форматирует сообщение соответственно&lt;br /&gt;
               // любому количеству следующих параметров:&lt;br /&gt;
               //  %s означает строка&lt;br /&gt;
               //  %d или %i означает целое число&lt;br /&gt;
               //  %f означает дробное число&lt;br /&gt;
               // поэтому &amp;quot;Privet %s, mne %d let&amp;quot; будет требовать&lt;br /&gt;
               //  чтобы следовали параметры строки и целого числа&lt;br /&gt;
               console_print(id, &amp;quot;Izvinite, igrok %s ne mojet bit naiden ili ispol'zovan v kachestve ob'ekta!&amp;quot;, Arg1)&lt;br /&gt;
               return PLUGIN_HANDLED&lt;br /&gt;
          } else {&lt;br /&gt;
               set_user_health(player, Health)&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, наша финальная версия amx_hp плагина будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;fun&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new PLUGIN[]=&amp;quot;Change Health&amp;quot;&lt;br /&gt;
new AUTHOR[]=&amp;quot;BAILOPAN&amp;quot;&lt;br /&gt;
new VERSION[]=&amp;quot;1.00&amp;quot;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     register_plugin(PLUGIN, VERSION, AUTHOR)&lt;br /&gt;
     register_concmd(&amp;quot;amx_hp&amp;quot;, &amp;quot;cmd_hp&amp;quot;, ADMIN_SLAY, &amp;quot;&amp;lt;target&amp;gt; &amp;lt;hp&amp;gt;&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public cmd_hp(id, level, cid)&lt;br /&gt;
{&lt;br /&gt;
     if (!cmd_access(id, level, cid, 3))&lt;br /&gt;
        return PLUGIN_HANDLED&lt;br /&gt;
&lt;br /&gt;
     new Arg1[24]&lt;br /&gt;
     new Arg2[4]&lt;br /&gt;
&lt;br /&gt;
     //Берем аргументы команды из консоли&lt;br /&gt;
     read_argv(1, Arg1, 23)&lt;br /&gt;
     read_argv(2, Arg2, 3)&lt;br /&gt;
&lt;br /&gt;
     //Конвертируем количество жизней из строки в число&lt;br /&gt;
     new Health = str_to_num(Arg2)&lt;br /&gt;
&lt;br /&gt;
     //Является ли первый символ @ символом?&lt;br /&gt;
     if (Arg1[0] == '@')&lt;br /&gt;
     {&lt;br /&gt;
          new Team = 0&lt;br /&gt;
          if (equali(Arg1[1], &amp;quot;CT&amp;quot;))&lt;br /&gt;
          {&lt;br /&gt;
               Team = 2&lt;br /&gt;
          } else if (equali(Arg1[1], &amp;quot;T&amp;quot;)) {&lt;br /&gt;
               Team = 1&lt;br /&gt;
          }&lt;br /&gt;
          new players[32], num&lt;br /&gt;
          get_players(players, num)&lt;br /&gt;
          new i&lt;br /&gt;
          for (i=0; i&amp;lt;num; i++)&lt;br /&gt;
          {&lt;br /&gt;
               if (!Team)&lt;br /&gt;
               {&lt;br /&gt;
                    set_user_health(players[i], Health)&lt;br /&gt;
               } else {&lt;br /&gt;
                    if (get_user_team(players[i]) == Team)&lt;br /&gt;
                    {&lt;br /&gt;
                         set_user_health(players[i], Health)&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
          }&lt;br /&gt;
     } else {&lt;br /&gt;
          new player = cmd_target(id, Arg1, 1)&lt;br /&gt;
          if (!player)&lt;br /&gt;
          {&lt;br /&gt;
               console_print(id, &amp;quot;Izvinite, igrok %s ne mojet bit naiden ili ispol'zovan v kachestve ob'ekta!&amp;quot;, Arg1)&lt;br /&gt;
               return PLUGIN_HANDLED&lt;br /&gt;
          } else {&lt;br /&gt;
               set_user_health(player, Health)&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     return PLUGIN_HANDLED&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Консольные переменные=&lt;br /&gt;
&lt;br /&gt;
CVar - это консольная переменная. Существуют клиентские и серверные CVar'ы. К примеру, &amp;quot;mp_startmoney&amp;quot; - Counter-Strike серверная CVar, содержащая число, указывающее, сколько денег дается игрокам, когда они заходят на сервер. Вы можете создавать свои серверные CVar'ы путем их регистрирования. Давайте создадим свою amx_startmoney CVar.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;cstrike&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
     register_plugin(&amp;quot;CVAR Test&amp;quot;, &amp;quot;1.0&amp;quot;, &amp;quot;BAILOPAN&amp;quot;)&lt;br /&gt;
     //регистрируем amx_startmoney CVar&lt;br /&gt;
     // и устанавливаем для нее значение по умолчанию 500&lt;br /&gt;
     register_cvar(&amp;quot;amx_startmoney&amp;quot;, &amp;quot;500&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//это вызывается, когда клиент заходит непосредственно на сервер&lt;br /&gt;
public client_putinserver(id)&lt;br /&gt;
{&lt;br /&gt;
     if (get_cvar_num(&amp;quot;amx_startmoney&amp;quot;) &amp;gt; 0)&lt;br /&gt;
     {&lt;br /&gt;
          cs_set_user_money(id, get_cvar_num(&amp;quot;amx_startmoney&amp;quot;))&lt;br /&gt;
     } else {&lt;br /&gt;
          cs_set_user_money(id, get_cvar_num(&amp;quot;mp_startmoney&amp;quot;))&lt;br /&gt;
     }&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вы можете устанавливать дробные, целые или строковые значения как для своих CVar, так и для любых других.&lt;br /&gt;
&lt;br /&gt;
=Дополнительно=&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать больше о скриптинге для AMX Mod X вам следует взглянуть на native прототипы в описаниях функий или в *.inc файлах (&amp;quot;инклудах&amp;quot;). Инклуды по большому счету придерживаются двух форматов. Они имеют название в соответствии с модулем или определенным предназначением. _const добавляется, если они содержат предопределенные числа или списки. _stocks добавляется, если они содержат &amp;quot;помогающие&amp;quot; или полезные &amp;quot;функции-обертки&amp;quot;. Помните, что stocks компилируются только, если вы используете их, поэтому без опаски можно &amp;quot;включать&amp;quot; файлы, содержащие большое количество stocks.&lt;br /&gt;
&lt;br /&gt;
Вы также можете посетить [http://amxmodx.ucoz.ru/forum/ Форум] и задать вопросы или найти больше информации.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Ru_Button_constants_(AMX_Mod_X)&amp;diff=3827</id>
		<title>Talk:Ru Button constants (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Ru_Button_constants_(AMX_Mod_X)&amp;diff=3827"/>
		<updated>2007-01-22T18:19:22Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Talk:Ru:Button constants (AMX Mod X) moved to Talk:Ru Button constants (AMX Mod X)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[User:Slogic|Slogic]]: Теперь понятно, почему я +use не мог поймать =)&lt;br /&gt;
&lt;br /&gt;
== reply ==&lt;br /&gt;
&lt;br /&gt;
Сам момент исполнения +use с помощью описанного метода &amp;quot;поймать&amp;quot; можно, но нельзя &amp;quot;поймать&amp;quot; т.н. момент самого использования (pfnUse) --[[User:VEN|VEN]] 10:30, 12 December 2006 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Button_constants_(AMX_Mod_X)&amp;diff=3825</id>
		<title>Ru Button constants (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Button_constants_(AMX_Mod_X)&amp;diff=3825"/>
		<updated>2007-01-22T18:19:21Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Button constants (AMX Mod X) moved to Ru Button constants (AMX Mod X)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
=Кнопочные константы=&lt;br /&gt;
&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Button constants (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
=Использование=&lt;br /&gt;
&lt;br /&gt;
Кнопочные константы обычно используются для того, чтобы &amp;quot;поймать&amp;quot; момент, когда игрок пытается совершить какое-либо действие, нажимая на кнопки, &amp;quot;привязанные&amp;quot; к таким командам, как +attack, +use и так далее. Метод используется потому, что HL &amp;quot;движок&amp;quot;  не может &amp;quot;поймать&amp;quot; +/-команды стандартным регистрированием, если их реализация выполнена в самом движке.&lt;br /&gt;
&lt;br /&gt;
Например, это будет работать:&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;+explode&amp;quot;,&amp;quot;explode&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
А это - нет:&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;+attack&amp;quot;,&amp;quot;hook_attack&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Константы=&lt;br /&gt;
&lt;br /&gt;
Полный список всех констант вы можете найти [http://amxmodx.org/funcwiki.php?go=module&amp;amp;id=3#const_buttons здесь].&lt;br /&gt;
&lt;br /&gt;
=Реализация=&lt;br /&gt;
&lt;br /&gt;
Вот, например, один из вариантов, как оперделить, нажимает ли игрок кнопку атаки или нет:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	if(entity_get_int(id, EV_INT_BUTTON) &amp;amp; IN_ATTACK)&lt;br /&gt;
	{&lt;br /&gt;
		// do something&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что используется битовый оператор &amp;amp;, в отличии от логического оператора &amp;amp;&amp;amp;. Оператор &amp;amp; проверяет, содержится ли бит после оператора в бите до него, т.е. в данном случае проверяется, есть ли среди нажатых кнопок игрока кнопка IN_ATTACK.&lt;br /&gt;
&lt;br /&gt;
Чтобы заставить игрока эмулировать нажатие кнопки, можно поступить следующим образом:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	entity_set_int(id,EV_INT_button,entity_get_int(id,EV_INT_button) | IN_ATTACK);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Этот пример будет выставлять флаг кнопки &amp;quot;атака&amp;quot; в положение &amp;quot;ВКЛ&amp;quot; каждый раз, когда рендерится entity игрока. Т.е. мы получаем все кнопки, нажатые в данный момент, и как бы прибавляем кнопку атаки.&lt;br /&gt;
&lt;br /&gt;
Чтобы &amp;quot;поймать&amp;quot; кнопки игрока, а потом &amp;quot;вычесть&amp;quot; какую либо кнопку, можно использовать следующий метод:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
#include &amp;lt;engine&amp;gt;&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Attack Test&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Hawk552&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public client_PreThink(id)&lt;br /&gt;
{&lt;br /&gt;
	entity_set_int(id,EV_INT_button,entity_get_int(id,EV_INT_button) &amp;amp; ~IN_ATTACK);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например, клиент прыгает (IN_JUMP) и атакует (IN_ATTACK) одновременно, функция entity_get_int(id,EV_INT_button) будет возвращать бит сумму IN_ATTACK и IN_JUMP. Используя конструкцию &amp;amp; ~БИТ мы как бы удаляем конкретное значение бита, в данном случае IN_ATTACK. Таким образом, в итоге получим только IN_JUMP.&lt;br /&gt;
&lt;br /&gt;
=Замечания=&lt;br /&gt;
&lt;br /&gt;
Важно понимать, что нажатие какой-либо кнопки не всегда означает, что в это время происходит конкретное действие. Например, если выстрелить из пистолета и не отпускать кнопку атаки - пуля вылетит, атака закончится и не возобновится, т.к. пистолет не является автоматическим оружием, но, т.к. кнопка все еще будет нажата, то, используя вышеприведенный метод, мы получим активное состояние кнопки IN_ATTACK, хотя атаки как таковой в данный момент не осуществляется.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Более наглядный пример с прыжком. Представьте, что вы прыгнули и, не отпуская кнопки прыжка, опустились на землю. Второго прыжка не произойдет, т.к. для этого нужно отпустить кнопку и нажать ее снова. Таким образом, нажатая кнопка прыжка не говорит о том, что в данный момент вы находитесь в состоянии прыжка. Как уже было отмечено, это относится и к другим кнопкам. Поэтому, в подавляющем большинстве случаев вы не должны делать проверку на наличие нажатой кнопки, если хотите определить, совершает ли игрок соответствующее действие или нет, для этого существуют другие методы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
По большому счету метод, описанный в данной статье, может быть эффективен только для блокировки или эмуляции атаки, хотя для этого есть еще более эффективные методы. Описанный метод не может быть применим к блокировке подавляющего большинства кнопок: для этого существуют другие методы ''(TODO: указать здесь ссылку на эти методы)''.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Using_New_Menu_System&amp;diff=3823</id>
		<title>Ru Using New Menu System</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Using_New_Menu_System&amp;diff=3823"/>
		<updated>2007-01-22T18:19:02Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Using New Menu System moved to Ru Using New Menu System&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
= Введение =&lt;br /&gt;
Это статья поможет вам разобраться в новой системе меню.&lt;br /&gt;
&lt;br /&gt;
== Урок по созданию меню ==&lt;br /&gt;
Давайте попробуем воспользоваться новой системмой меню. Мы пройдем через этоу простую инструкцию и создадим простое голосование смены карты.&lt;br /&gt;
&lt;br /&gt;
=== Заголовочные файлы ===&lt;br /&gt;
Как обычно мы начинаем с добавления необходимых заголовочных файлов&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Глобальные переменные ===&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
new g_Menu;	// Переменная обработки главного меню&lt;br /&gt;
new g_Votes[3];	// Сохраняем голосования Да как 1, No как 2&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тут мы создали 2 глобальные переменные. Одна содержит указатель вашего меню, другая хранит резуьтаты голосования. Голоса 'Да' будут сохранены в g_Votes[1] ,а 'Нет' будет сохранена в g_Votes[2].&lt;br /&gt;
&lt;br /&gt;
=== Регистрируем Плагин и Меню ===&lt;br /&gt;
&amp;lt;pawn&amp;gt;&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	// Регистрируем ваш плагин&lt;br /&gt;
	register_plugin(&amp;quot;Vote Menu&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Freecode&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Регистрируем меню смены карты&lt;br /&gt;
	g_Menu = menu_create(&amp;quot;Change Level?&amp;quot;,&amp;quot;menu_handle&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	register_clcmd(&amp;quot;amx_startvote&amp;quot;,&amp;quot;startvote&amp;quot;,ADMIN_CFG,&amp;quot;Gaben&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Теперь нам надо создать наше меню&lt;br /&gt;
	build_menu();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lets break this down. &lt;br /&gt;
&lt;br /&gt;
*Регистрирует ваш плагин&lt;br /&gt;
&amp;lt;pawn&amp;gt;register_plugin(&amp;quot;Vote Menu&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Freecode&amp;quot;);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*g_Menu - Указатель на ваше меню. Это будет установлено после вызова menu_create.&lt;br /&gt;
&amp;lt;pawn&amp;gt;g_Menu = menu_create(&amp;quot;Change Level?&amp;quot;,&amp;quot;menu_handle&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
//menu_create ( title[], handler[], ml=0 )&lt;br /&gt;
//title[] - Заголовок меню&lt;br /&gt;
//handler[] - Эта функция будет вызвана когда будет нажата клавиша в вашем меню.&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Мы добавили эту команду. Она начинает ваше голосование.&lt;br /&gt;
&amp;lt;pawn&amp;gt;register_clcmd(&amp;quot;amx_startvote&amp;quot;,&amp;quot;startvote&amp;quot;,ADMIN_CFG,&amp;quot;Gaben&amp;quot;);&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Это вызов функции. build_menu() функция создает ваше меню.&lt;br /&gt;
&amp;lt;pawn&amp;gt;build_menu();&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Создение меню ===&lt;br /&gt;
Конструирование заключается в добавлении пунктов в ваше меню. Прежде чем начали добавлять пункты, мы должны взглянуть на &lt;br /&gt;
menu_additem .&lt;br /&gt;
&amp;lt;pawn&amp;gt;menu_additem ( menu, const name[], const command[], paccess=0, callback=-1 )&amp;lt;/pawn&amp;gt;&lt;br /&gt;
* menu - указатель на меню. Это указывает menu_additem меню к которому нужно добавить пункты.&lt;br /&gt;
* const name[] - имя пункта меню. Это то что будет показано в меню.&lt;br /&gt;
* const command[] - информация пункта меню.&lt;br /&gt;
&lt;br /&gt;
Теперь давайте приступим к созданию нашего меню. Как уже говорилось, это простое голосование смены карты. Так что нам надо всего 2 пункта меню. А именно &amp;quot;Да&amp;quot; и &amp;quot;Нет&amp;quot;.&lt;br /&gt;
&amp;lt;pawn&amp;gt;build_menu()&lt;br /&gt;
{&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;Yes&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;No&amp;quot;, &amp;quot;2&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	menu_setprop(g_Menu, MPROP_PERPAGE, 0);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Примечание&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Как вы можете видеть вместо command[] я указал числа. Это необходимо для более простой идентификации пунктов меню.&lt;br /&gt;
** Я так-же добавил menu_setprop. Это говорит нашему меню что оно не имеет страниц. Для дополнительной информации смотрите в amxconst.inc&lt;br /&gt;
&lt;br /&gt;
=== Показывает меню голосования ===&lt;br /&gt;
Для того что-бы показать меню мы должны использовать menu_display.&lt;br /&gt;
&amp;lt;pawn&amp;gt;menu_display ( id, menu, page )&amp;lt;/pawn&amp;gt;&lt;br /&gt;
* id - id пользователя которому надо показать это меню.&lt;br /&gt;
* menu - тут указываем хэндл меню которое показываем пользователю.&lt;br /&gt;
* page - какая страница (номер страницы меню) с которой начинаем. Страницы меню начинаются с 0.&lt;br /&gt;
&lt;br /&gt;
Ok теперь посмотрим на наш код.&lt;br /&gt;
&amp;lt;pawn&amp;gt;public startvote(id)&lt;br /&gt;
{&lt;br /&gt;
	for(new i = 0; i &amp;lt; 33; i++)&lt;br /&gt;
	{&lt;br /&gt;
		if( is_user_alive(i) )&lt;br /&gt;
		{&lt;br /&gt;
			menu_display(i, g_Menu, 0);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;Примечание:&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Используем цыкл для прохождения по всем игрокам и показываем меню тем кто живой.&lt;br /&gt;
&lt;br /&gt;
=== Обработка выборов меню ===&lt;br /&gt;
Последний этап заключается в обработке выбора меню. Это делается через функцию обработки.&lt;br /&gt;
Она вызывается каждый раз когда пользователь сделал выбор.&lt;br /&gt;
Вот  &amp;lt;b&amp;gt;3&amp;lt;/b&amp;gt; переменные которые передаются в функцию.&lt;br /&gt;
* id - id пользователя&lt;br /&gt;
* menu - открытое меню у пользователя&lt;br /&gt;
* item - тут выбор пункта меню пользователем&lt;br /&gt;
&lt;br /&gt;
Далее мы объявляем несколько специальных переменных таких как меню выхода.&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define MENU_EXIT	-3&lt;br /&gt;
#define	MENU_BACK	-2&lt;br /&gt;
#define MENU_MORE	-1&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь нам надо проверить если пункт меню выбран и он не является специальной переменной&lt;br /&gt;
&amp;lt;pawn&amp;gt;if( item &amp;lt; 0 ) return PLUGIN_CONTINUE;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующим шагом мы получаем информацию о выбранном пункте меню. Все что мы ищем это номер пункта меню. (Да = 1, Нет = 2).&lt;br /&gt;
Для этого надо использовать menu_item_getinfo.&lt;br /&gt;
&amp;lt;pawn&amp;gt;menu_item_getinfo ( menu, item, &amp;amp;access, command[], cmdlen, name[]=&amp;quot;&amp;quot;, namelen=0, &amp;amp;callback )&amp;lt;/pawn&amp;gt;&lt;br /&gt;
* menu - меню в котором находится пункт меню.&lt;br /&gt;
* item - the item itself&lt;br /&gt;
* &amp;amp;access - (edit)&lt;br /&gt;
* command[] - (edit)(это то где сохраняются идентификационные номера меню)&lt;br /&gt;
* cmdlen - размер command[]&lt;br /&gt;
* name[] - имя пункта меню&lt;br /&gt;
* namelen - размер name[]&lt;br /&gt;
* &amp;amp;callback - (edit)&lt;br /&gt;
&lt;br /&gt;
После того как мы получили информацию о пуектах меню, надо взять из command[] номера выбранных меню(это должно быть 1 или 2). &lt;br /&gt;
Теперь надо добавить в g_Votes теми голосами что были сделаны.&lt;br /&gt;
Вот как завершонная функция должна выглядеть:&lt;br /&gt;
&amp;lt;pawn&amp;gt;public menu_handle(id, menu, item)&lt;br /&gt;
{&lt;br /&gt;
	if( item &amp;lt; 0 ) return PLUGIN_CONTINUE;&lt;br /&gt;
	&lt;br /&gt;
	// Get item info&lt;br /&gt;
	new cmd[3];&lt;br /&gt;
	new access, callback;&lt;br /&gt;
	&lt;br /&gt;
	menu_item_getinfo(menu, item, access, cmd,2,_,_, callback);&lt;br /&gt;
	&lt;br /&gt;
	new iChoice = str_to_num(cmd);&lt;br /&gt;
	&lt;br /&gt;
	g_Votes[iChoice]++;&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Завершение ===&lt;br /&gt;
Это конец. Вы завершили Урок по созданию меню. Используя новую систему меню можно создать более удобное управление.&lt;br /&gt;
В следующем уроке вы увидите более сложную систему меню которая будет использовать callbacks, уничтожение меню и создание.&lt;br /&gt;
Вот код который должен получится посли всех действий.&lt;br /&gt;
&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
&lt;br /&gt;
new g_Menu;	// Переменная обработки главного меню&lt;br /&gt;
new g_Votes[3];	// Сохраняем голосования Да как 1, No как 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	// Регистрируем ваш плагин&lt;br /&gt;
	register_plugin(&amp;quot;Vote Menu&amp;quot;,&amp;quot;1.0&amp;quot;,&amp;quot;Freecode&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Регистрируем меню смены карты&lt;br /&gt;
	g_Menu = menu_create(&amp;quot;Change Level?&amp;quot;,&amp;quot;menu_handle&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	register_clcmd(&amp;quot;amx_startvote&amp;quot;,&amp;quot;startvote&amp;quot;,ADMIN_CFG,&amp;quot;Gaben&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// Теперь нам надо создать наше меню&lt;br /&gt;
	build_menu();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
build_menu()&lt;br /&gt;
{&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;Yes&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	menu_additem(g_Menu, &amp;quot;No&amp;quot;, &amp;quot;2&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	menu_setprop(g_Menu, MPROP_PERPAGE, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public startvote(id)&lt;br /&gt;
{&lt;br /&gt;
	for(new i = 0; i &amp;lt; 33; i++)&lt;br /&gt;
	{&lt;br /&gt;
		if( is_user_alive(i) )&lt;br /&gt;
		{&lt;br /&gt;
			menu_display(i, g_Menu, 0);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public menu_handle(id, menu, item)&lt;br /&gt;
{&lt;br /&gt;
	if( item &amp;lt; 0 ) return PLUGIN_CONTINUE;&lt;br /&gt;
	&lt;br /&gt;
	// Получаем информацию о пункте&lt;br /&gt;
	new cmd[3];&lt;br /&gt;
	new access, callback;&lt;br /&gt;
	&lt;br /&gt;
	menu_item_getinfo(menu, item, access, cmd,2,_,_, callback);&lt;br /&gt;
	&lt;br /&gt;
	new iChoice = str_to_num(cmd);&lt;br /&gt;
	&lt;br /&gt;
	g_Votes[iChoice]++;&lt;br /&gt;
	&lt;br /&gt;
	return PLUGIN_HANDLED;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Main_Page&amp;diff=3821</id>
		<title>Ru Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Main_Page&amp;diff=3821"/>
		<updated>2007-01-22T18:18:03Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Main Page moved to Ru Main Page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
Добро пожаловать в AMWiki, объединенный и совместный проект документации проектов [[AMX Mod X]], [[Metamod:Source]], и [[SourceMod]].&lt;br /&gt;
&lt;br /&gt;
С чего вам начать? Проверьте [[AMWiki:Community Portal|Страницу проекта]], чтобы увидеть краткий обзор.  Прочитайте [[Help:Contents|Помощь]] для понимания основных принципов и правил wiki.  Или если вы что-то ищите, можете воспользоваться поиском с левой стороны!&lt;br /&gt;
&lt;br /&gt;
=Основные статьи=&lt;br /&gt;
&lt;br /&gt;
==Оптимизация Плагинов==&lt;br /&gt;
[[Optimizing Plugins|Данная статья]] описывает много важных моментов, трюков и советов, а также рассказывает о том, как сделать ваши плагины более быстрыми. Пользователи, следующие этим инструкциям, получат существенный прирост производительности в своих плагинах. Для продолжения чтения статьи нажмите [[Optimizing Plugins|здесь]].&lt;br /&gt;
&lt;br /&gt;
==Изменения в скриптах AMX Mod X 1.70==&lt;br /&gt;
В [[AMX Mod X]] 1.70 были сделаны важные изменения. Авторам серьезных плагинов рекомендуется как можно быстрее ознакомиться с изменениями и новыми возможностями: [[AMX Mod X 1.70 Scripting Changes]].&lt;br /&gt;
&lt;br /&gt;
{| cellspacing=&amp;quot;0&amp;quot; style=&amp;quot;border:0px; margin-right:10%;&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
=Проекты=&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| '''AMX Mod X'''&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
|[[Image:Amxxsmall.gif|left]] [[AMX Mod X]] - мощная, расширяемая скриптами среда для [[Half-Life 1]].&lt;br /&gt;
* [[:Category:Ru:Documentation (AMX Mod X)|Документация]]&lt;br /&gt;
* [[:Category:Ru:Scripting (AMX Mod X)|Скриптинг]]&lt;br /&gt;
* [http://amxmodx.ucoz.ru Русский сайт AMX Mod X]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| '''Metamod:Source'''&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
|[[Image:Mms.jpg|left]][[Metamod:Source]], мощный plugin API для [[Half-Life 2]], функции перехвата интерфейсов и универсальный plugin API.&lt;br /&gt;
* [[:Category:Documentation (SourceMM)|Документация]]&lt;br /&gt;
* [[Introduction_to_SourceMM_Coding|Разработка]]&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
|&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
=Новости=&lt;br /&gt;
{| cellpadding=&amp;quot;6&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| AMX Mod X 1.70&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| ''2006-03-04'': Новая версия [[AMX Mod X]] выпущена в свет. Список изменений смотрите на [http://www.amxmodx.org/ домашней странице].  Разработчикам стоит взглянуть на новые темы, [[Optimizing Plugins|статью]] по оптимизации плагинов и [[AMX Mod X 1.70 Scripting Changes|изменения]] в AMX Mod X 1.70.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| cellpadding=&amp;quot;6&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Metamod:Source 1.2.1&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| ''2006-02-15'': Выпущена новая версия [[Metamod:Source|SourceMM]]. Список изменений смотрите на [http://www.sourcemm.net/ домашней странице].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| cellpadding=&amp;quot;6&amp;quot;&lt;br /&gt;
|- class=&amp;quot;t2th&amp;quot;&lt;br /&gt;
| Wiki Запущен!&lt;br /&gt;
|- class=&amp;quot;t2td&amp;quot;&lt;br /&gt;
| ''2006-01-17'': Запущен AMWiki проект! Пожалуйста, пишите любые предложения в разделе обсуждений [[Talk:Main_Page|Main Page]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru:Fundamental_Basics_of_AMX_Mod_X_Scripting&amp;diff=3819</id>
		<title>Ru:Fundamental Basics of AMX Mod X Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru:Fundamental_Basics_of_AMX_Mod_X_Scripting&amp;diff=3819"/>
		<updated>2007-01-22T18:17:55Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Fundamental Basics of AMX Mod X Scripting moved to Ru Fundamental Basics of AMX Mod X Scripting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
=Фундаментальные основы AMX Mod X скриптинга=&lt;br /&gt;
&lt;br /&gt;
Данная статья не дает готовых &amp;quot;рецептов&amp;quot; по [[AMX Mod X]] скриптингу, но раскрывает его фундаментальные основы. Это и типы данных, и прототипы функций и многое другое, без знания чего невозможно писать AMX Mod X плагины.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Введение=&lt;br /&gt;
&lt;br /&gt;
Прежде чем начинать писать AMX Mod X плагины, в первую очередь необходимо разобраться в основах [[Pawn]].&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Pawn – это скриптовый язык, созданный компанией ITB CompuPhase. Ранее Pawn назывался Small, но с версии 3.0 языку было решено дать более характерное название. Т.к. &amp;quot;pawn&amp;quot; в переводе с английского языка означает &amp;quot;пешка&amp;quot;, можно догадаться, что основной характерной чертой данного языка является простота.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Если вы владеете английским языком, рекомендуется ознакомиться с полным руководством по Pawn - [http://www.compuphase.com/pawn/pawn-lang.pdf Pawn The Language].&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Код плагина представляет собой текст (как правило, заключенный в файл типа *.sma), включающий множество элементов языка: комментарии, переменные, функции и др. Поэтому для оформления кода потребуется текстовый редактор. Из простейших можно выделить, например, Microsoft Notepad. Также существует AMXX-Studio – специализированый редактор для AMX Mod X плагинов, позволяющий максимально эффективно работать в соответствующей среде. Последняя версия данного редактора может быть найдена в секции [http://www.amxmodx.org/downloads.php downloads] официального сайта AMX Mod X.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Чтобы позволить AMX Mod X выполнять код, файл с кодом необходимо откомпилировать с помощью компилятора AMXXPC (AMX Mod X Pawn Compiler). Операция компилирования преобразовывает набор текстовых инструкций в последовательность инструкций абстрактной машины (от англ. abstract machine), она же AMX, а также интерпретатор (от англ. interpreter).&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Откомпилированый код обычно помещается в файл типа *.amxx, имеющий двоичный формат. Такой файл называют AMX Mod X плагином (от англ. plugin).&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Для ознакомления с инструкциями по компилированию и установке плагинов смотрите [[Ru:Compiling Plugins (AMX Mod X)]] и [[Ru:Configuring AMX Mod X]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Pawn=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Уровни кода==&lt;br /&gt;
&lt;br /&gt;
В основе любого кода лежит уровневая структура. Причиной этому является нелинейность инструкций.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.н. &amp;quot;нулевой уровень&amp;quot; или &amp;quot;глобальное пространство&amp;quot; является неотъемлемой частью любого кода. Как только вы приступаете к написанию нового кода, вы оказываетесь в его глобальном пространстве. Оно же в свою очередь будет включать в себя пространства с более низкими уровнями.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Обычно глобальное пространство содержит всю общую информацию, которая может потребоваться в ходе выполнения кода пространствам более низкого уровня. Примером такой информации могут служить общие константы, переменные, списки, макросы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Комментарии==&lt;br /&gt;
&lt;br /&gt;
Комментарий – это, как правило, текст информативного характера. Например, чтобы дать описание плагину можно использовать многострочный комментарий:&amp;lt;pawn&amp;gt;/* здесь вы помещаете&lt;br /&gt;
необходимую информацию */&amp;lt;/pawn&amp;gt;Как видно из примера, многострочный комментарий ограничивается символами /* и */, отмечающими начало и конец комментария соответственно. Недопустимо открывать последующий комментарий, не закрыв при этом предыдущий.&lt;br /&gt;
&amp;lt;BR&amp;gt;Примером однострочного комментария может быть:&amp;lt;pawn&amp;gt;/* ваш комментарий */&amp;lt;/pawn&amp;gt;Хотя, можно упростить конструкцию:&amp;lt;pawn&amp;gt;// ваш комментарий&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Как видно из последнего примера, комментарий начинается с двойного симовола обратного слеша //. Заканчивается такой комментарий вместе с концом текущей строки, поэтому не требует закрывающих символов. Такие комментарии могут быть только однострочными. Не обязательно комментарий должен начинаться с новой строки. Например, /* ... */ комментарий может быть расположен непосредственно в самом коде.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.к. комментарии не считаются кодом, они исключаются из обработки. Данная особенность позволяет при необходимости исключать части кода путем комментирования, что может быть использовано, например, при отладке кода.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Типы данных==&lt;br /&gt;
&lt;br /&gt;
Технически основой всех типов данных в Pawn является т.н. &amp;quot;cell&amp;quot; – ячейка памяти, состоящая из последовательности определенного количества бит. Количество бит в такой ячейке постоянно для определенной платформы. Так для 32х битной платформы оно будет составлять 32, а для 64х битной – 64.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.к. технически все данные не имеют отличия, для обозначения их типа применяются т.н. &amp;quot;тэги&amp;quot;. Если при создании переменной тэг не указан, то переменная является целым числом:&amp;lt;pawn&amp;gt;new ivar // создана целочисленная переменная с именем &amp;quot;ivar&amp;quot;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Если при создании переменной ей не присваивается какое-либо конкретное значение, то переменная будет равна нулю. Таким образом, вышеприведенный пример технически соответствует:&amp;lt;pawn&amp;gt;new ivar = 0&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы создать дробную переменную, необходимо использовать тэг &amp;quot;Float&amp;quot;:&amp;lt;pawn&amp;gt;new Float:fvar&amp;lt;/pawn&amp;gt;Переменная fvar также будет равна нулю, но ввиду соответствия типу данных это будет 0.0, т.е. технический аналог примера будет:&amp;lt;pawn&amp;gt;new Float:fvar = 0.0&amp;lt;/pawn&amp;gt;Таким образом, мы обеспечиваем типовое соответствие &amp;quot;левой&amp;quot; и &amp;quot;правой&amp;quot; части.&lt;br /&gt;
&amp;lt;BR&amp;gt;Одним из особых типов данных является т.н. &amp;quot;булевые&amp;quot; переменные, которые технически могут иметь только два значение, логически интерпретируемые как &amp;quot;истина&amp;quot; и &amp;quot;ложь&amp;quot; (true и false). Чтобы создать булевую переменную, необходимо использовать тэг &amp;quot;bool&amp;quot;:&amp;lt;pawn&amp;gt;new bool:bvar&amp;lt;/pawn&amp;gt;Т.к. численно false является нулем, то технический аналог примера будет выглядеть как:&amp;lt;pawn&amp;gt;new bool:bvar = false&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Примечание: чтобы запретить изменение значения переменной, необходимо использовать атрибут const, например:&amp;lt;pawn&amp;gt;new const var = 1&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Pawn также позволяет создавать массивы данных, представляющие собой набор значений определенного типа. Так примером простого массива, содержащего два целочисленных значения будет:&amp;lt;pawn&amp;gt;new array[2]&amp;lt;/pawn&amp;gt;Технически данный пример выглядит следующим образом:&amp;lt;pawn&amp;gt;new array[2] = {0, 0}&amp;lt;/pawn&amp;gt;Технические аналоги для Float и bool массивов выглядят как:&amp;lt;pawn&amp;gt;new Float:farray[2] = {0.0, 0.0}&lt;br /&gt;
new bool:barray[2] = {false, false}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Также существует особый тип данных, называемый &amp;quot;строка&amp;quot;, технически являющийся массивом целых чисел. Каждое целое число в строковом массиве соответствует числовому ASCII коду символа. Например, код 32 соответствует пробелу. Таким образом,&amp;lt;pawn&amp;gt;new string[3] = {'h', 'i', '^0'}&amp;lt;/pawn&amp;gt;является символьным представлением строкового массива&amp;lt;pawn&amp;gt;new string[3] = &amp;quot;hi&amp;quot;&amp;lt;/pawn&amp;gt;Обратите внимание на наличие специального символа '^0'. Это обязательный элемент строки, указывающий на ее окончание (численно равен нулю).&lt;br /&gt;
&amp;lt;BR&amp;gt;Также Pawn поддерживает многоуровневые массивы, например:&amp;lt;pawn&amp;gt;new multiarray[2][2]&amp;lt;/pawn&amp;gt;Технически такой массив равен:&amp;lt;pawn&amp;gt;new multiarray[2][2] = {{0, 0}, {0, 0}}&amp;lt;/pawn&amp;gt;Максимальное количество уровней массива равно 3.&lt;br /&gt;
&amp;lt;BR&amp;gt;Для любого явно заданного массива его размер может не указываться, например:&amp;lt;pawn&amp;gt;new array[] = {1, 2, 3} // размер массива равен 3&lt;br /&gt;
new string[] = &amp;quot;hello&amp;quot; // размер массива равен 6, т.к. помимо 5 символов также включает в себя символ окончания строки '^0'&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы инициализировать все элементы массива каким-либо конкретным значением, можно использовать символ троеточия ..., например:&amp;lt;pawn&amp;gt;new bool:is_active[16] = {true, ...}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Прекомпиляция==&lt;br /&gt;
&lt;br /&gt;
На начальной стадии компилирования Pawn компилятор обрабатывает т.н. &amp;quot;статическую&amp;quot; часть кода. К ней можно отнести директивы, глобальные константы, списки и др.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Директивы являются специальными инструкциями компилятора. Одна из самых широко используемых директив – это &amp;quot;include&amp;quot;. Пример ее использования может быть следующим:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&amp;lt;/pawn&amp;gt;Директива как бы &amp;quot;влаживает&amp;quot; содержимое указанного файла в текущую позицию. В данном случае указывается файл amxmodx.inc, который обычно расположен в amxmodx\scripting\include директории, и декларирует основные AMX Mod X функции.&lt;br /&gt;
&amp;lt;BR&amp;gt;Другая директива, позволяющая конструировать т.н. &amp;quot;макросы&amp;quot;, имеет название &amp;quot;define&amp;quot;. Макрос удобен тем, что способен заменять простые блоки кода. Один из простейших макросов – это т.н. &amp;quot;макроконстанта&amp;quot;, например:&amp;lt;pawn&amp;gt;#define VALUE 1&amp;lt;/pawn&amp;gt;В названиях макросов принято использовать буквы только верхнего регистра.&lt;br /&gt;
&amp;lt;BR&amp;gt;Нетехническим аналогом вышеприведенной макроконстанты является т.н. &amp;quot;глобальная константа&amp;quot;:&amp;lt;pawn&amp;gt;stock const value = 1&amp;lt;/pawn&amp;gt;stock атрибут позволяет не включать константу в плагин, если она не используется в коде.&lt;br /&gt;
&amp;lt;BR&amp;gt;Т.н. &amp;quot;список&amp;quot; – это набор нумерованных элементов определенного типа. Например:&amp;lt;pawn&amp;gt;enum {zero, one, two} // соответствует 0, 1, 2&lt;br /&gt;
enum {elem1 = 1, elem2, elem3} // соответствует 1, 2, 3&lt;br /&gt;
enum steeps {steep1 = 10, steep2 = 20} // соответствует 10, 20&amp;lt;/pawn&amp;gt;Тип списка (в вышеприведенном примере типом списка является steeps) – необязательный атрибут, по сути является тэгом, указывающим тип элементов, поэтому следующий пример является верным:&amp;lt;pawn&amp;gt;new steeps:steep = steep2&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Функции==&lt;br /&gt;
&lt;br /&gt;
Существует несколько типов функций.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Т.н. &amp;quot;обычная&amp;quot; – обычно т.н. &amp;quot;вспомогательная&amp;quot; функция; может быть вызвана непосредственно только другими функциями данного плагина; не может быть вызвана непосредственно AMX Mod X либо его модулями.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;public – обычно функция, вызываемая непосредственно AMX Mod X либо его модулями; может быть также вызвана непосредственно другими функциями данного плагина.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;native – функция, имеющая т.н. &amp;quot;глобальный&amp;quot; характер; может быть вызвана AMX Mod X плагинами.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;forward - функция, имеющая т.н. &amp;quot;глобальный&amp;quot; характер; при наличии в плагине public функции с соответствующим именем функция будет вызываться AMX Mod X или его модулями.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;stock – обычно функция, состоящая в т.н. &amp;quot;библиотеке&amp;quot; функций; не включается в плагин, если не используется в коде.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;В общем виде заголовок, а также прототип любой функции условно выглядит следующим образом (символами треуголных скобок &amp;lt;&amp;gt; ограничены обязательные элементы, символами квадратных скобок [] ограничены необязательные элементы, которые могут быть опущены в определенных случаях):&amp;lt;pawn&amp;gt;[type] [tag]:&amp;lt;name&amp;gt;([[param1], [param2], ..., [paramN]])&amp;lt;/pawn&amp;gt;, где&lt;br /&gt;
[type] – соответствует типу функции (для обычной функции тип не указывается).&lt;br /&gt;
&amp;lt;BR&amp;gt;[tag] – соответствует типу данных возвращаемого результата функции.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;name&amp;gt; - соответствует имени функции&lt;br /&gt;
&amp;lt;BR&amp;gt;([...]) – соответствует набору параметров функции; количество параметров может быть от нуля (параметры отсутствуют) до N, где N – целое положительное число.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;За заголовком функции следует т.н. &amp;quot;тело&amp;quot; функции, ограниченное символами фигурных скобок {}. Таким образом, примером простейшей функции является:&amp;lt;pawn&amp;gt;function()&lt;br /&gt;
{&lt;br /&gt;
	// это пустое тело функции, имеющей имя &amp;quot;function&amp;quot;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;Технически данная функция не выполняет никаких действий, т.к. в своем теле содержит только комментарий. Обратите внимание, что комментарий как бы сдвинут вправо относительно заголовка функции. В данном случае функция инициализирует новый уровень кода. Каждый уровень кода в целях удобочитаемости принято оформлять с соответствующим отступом. Чем более низкий уровень кода, тем больший отступ он будет иметь. Обычно в качестве отступа принято использовать символ табуляции, т.к. многие редакторы позволяют задавать видимую ширину табулированого отступа.&lt;br /&gt;
&amp;lt;BR&amp;gt;Существует два способа передачи параметров функции. Т.н. &amp;quot;основной&amp;quot; способ заключается в том, что при передаче данные дублируются путем создания соответствующих копий в памяти. Т.н. способ передачи параметров &amp;quot;по ссылке&amp;quot; (от англ. by reference) состоит в том, что данные передаются &amp;quot;как есть&amp;quot;, т.е. их дублирования не осуществляется, что позволяет функции изменять оригинальные данные непосредственно.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Для параметров функции все типы массивов, в том числе и строковые, могут передаваться исключительно по ссылке. Передача остальных данных по умолчанию осуществляется основным способом. Чтобы произвести передачу параметра функции по ссылке, в заголовке функции перед параметром необходимо добавлять символ амперсанда &amp;amp;, например:&amp;lt;pawn&amp;gt;function(&amp;amp;Float:fparam)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Параметры функции могут иметь значения по умолчанию, например:&amp;lt;pawn&amp;gt;function(param = 1)&amp;lt;/pawn&amp;gt;Таким образом, чтобы вызвать данную функцию с параметром по умолчанию, параметр можно не указывать:&amp;lt;pawn&amp;gt;function()&amp;lt;/pawn&amp;gt;Также в таких случаях можно использовать символ подчеркивания _:&amp;lt;pawn&amp;gt;function(_)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы запретить функции изменение передаваемых данных, необходимо использовать атрибут const, например:&amp;lt;pawn&amp;gt;function(const array[])&amp;lt;/pawn&amp;gt;Таким образом, можно утверждать, что в данном случае целью функции не является изменение данных массива, чего нельзя утверждать о следующей функции:&amp;lt;pawn&amp;gt;swaparray(array[2])&amp;lt;/pawn&amp;gt;Исходя из названия функции, типа параметра, его размера и отсутствия запрета на изменение, можно сделать предположение о том, что данная функция меняет элементы массива местами.&lt;br /&gt;
&amp;lt;BR&amp;gt;Важным свойством функции является способность возвращать результат, значение которого имеет определенный тип, например:&amp;lt;pawn&amp;gt;bool:is_true()&lt;br /&gt;
{&lt;br /&gt;
	return true&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Чтобы указать допустимые типы параметра функции, в заголовке функции перед параметром необходимо добавлять конструкцию, которая условно выглядит как {tag1, tag2, ..., tagN}:, т.е. представляет собой набор тэгов, количество которых может быть от одного до N, где N – целое положительное число, например:&amp;lt;pawn&amp;gt;get_integer({bool, _}:value)&lt;br /&gt;
{&lt;br /&gt;
	return _:value // возвращается значение типа &amp;quot;целое число&amp;quot;&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;Смысл вышеприведенной функции заключается в том, что она принимает параметр как типа &amp;quot;целое число&amp;quot;, так и булевого типа, в результате возвращая значение параметра в числовой форме.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=AMX Mod X=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Функции==&lt;br /&gt;
&lt;br /&gt;
При написании AMX Mod X плагинов важно уметь понимать назначение и принцип действия AMX Mod X функций.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Прототипы функций, а также используемые ими константы и списки заключены в файлы типа *.inc, т.н. &amp;quot;инклуды&amp;quot; (от англ. include), которые обычно расположены в amxmodx\scripting\include директории.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Иногда одни инклуды включают в себя другие. Так основные AMX Mod X функции (т.н. функции AMX Mod X &amp;quot;ядра&amp;quot;) продекларированы в файле amxmodx.inc, который также включает векторные и другие инклуды, декларирующие функции, константы и списки, также имеющие непосредственное отношение к AMX Mod X ядру.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Одной из основных функций AMX Mod X является forward функция plugin_init. Если в коде плагина имеется public функция plugin_init, она будет вызвана AMX Mod X после загрузки карты на сервере. Обычно в plugin_init регистрируют сам плагин, его команды, переменные и т.п.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Плагин регистрируют с помощью native функции register_plugin. Т.к. прототип register_plugin соответствует:&amp;lt;pawn&amp;gt;native register_plugin(const plugin_name[], const version[], const author[])&amp;lt;/pawn&amp;gt;, можно понять, что в качестве параметров функция принимает три строковых массива, соответствующих названию плагина, номеру его версии и автору плагина.&lt;br /&gt;
&amp;lt;BR&amp;gt;Итак, примером простого AMX Mod X плагина является:&amp;lt;pawn&amp;gt;#include &amp;lt;amxmodx&amp;gt;&lt;br /&gt;
public plugin_init()&lt;br /&gt;
{&lt;br /&gt;
	register_plugin(&amp;quot;Test&amp;quot;, &amp;quot;0.1&amp;quot;, &amp;quot;VEN&amp;quot;)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;По сути данный плагин не выполняет каких-либо действий, но регистрирует себя в AMX Mod X с указанными данными.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Системы функционирования==&lt;br /&gt;
&lt;br /&gt;
AMX Mod X предоставляет большое количество определенных систем функционирования. Так одна из основных систем – это система контроля уровней доступа. Здесь имеют место соответствующие функции, например get_user_flags, а также константы стандартных уровней доступа типа ADMIN_*.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Система регистрирования и контроля консольных команд также &amp;quot;пересекается&amp;quot; с системой контроля уровней доступа и использует такие функции, как например register_concmd и cmd_access.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Также существует множество других систем, среди которых имеется система регистрирования и контроля серверных консольных переменных (англ.: Server CVars), клиентских меню и др.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Как правило, системы регистрирования используют т.н. &amp;quot;handle&amp;quot; (или &amp;quot;hook&amp;quot;) функции, которые вызываются системой в необходимый момент.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Так после регистрирования консольной команды &amp;quot;action&amp;quot;:&amp;lt;pawn&amp;gt;register_concmd(&amp;quot;action&amp;quot;, &amp;quot;action_handler&amp;quot;)&amp;lt;/pawn&amp;gt;при исполнении данной команды из консоли сервера или клиента система попытается найти и выполнить public функцию action_handler.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Система строкового форматирования==&lt;br /&gt;
&lt;br /&gt;
Многие AMX Mod X функции используют систему строкового форматирования. Например, это все *_print функции.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;Такие функции принимают практически неограниченное количество параметров, которые используются при форматировании соответствующей строковой конструкции. Для наглядности рассмотрим пример:&amp;lt;pawn&amp;gt;server_print(&amp;quot;Formatted string: %d %f %s %c&amp;quot;, 1, 1.234567, &amp;quot;hello&amp;quot;, '!')&amp;lt;/pawn&amp;gt;Функция server_print отформатирует строковую конструкцию &amp;quot;Formatted string: %d %f %s %c&amp;quot;, используя переданные параметры, и выведет в серверной консоли строку:&amp;lt;pawn&amp;gt;Formatted string: 1 1.234567 hello !&amp;lt;/pawn&amp;gt;Таким образом, %d, %f, %s, %c – специальные элементы, используемые для форматирования целого числа, дробного числа, строки и символа соответственно.&lt;br /&gt;
&amp;lt;BR&amp;gt;Опасно при использовании функций, поддерживающих форматирование, передавать строковую переменную непосредственно в параметр строковой конструкции, например:&amp;lt;pawn&amp;gt;server_print(string)&amp;lt;/pawn&amp;gt;Безопасный вариант выглядит, следующим образом:&amp;lt;pawn&amp;gt;server_print(&amp;quot;%s&amp;quot;, string)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Т.к. символ процента % является, т.н. &amp;quot;специальным символом&amp;quot;, для его форматирования в строковой конструкции необходимо использовать двойной символ процента %%, например:&amp;lt;pawn&amp;gt; server_print(&amp;quot;This is a single symbol of percent: %%&amp;quot;)&amp;lt;/pawn&amp;gt;выведет в серверной консоли:&amp;lt;pawn&amp;gt; This is a single symbol of percent: %&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;Также существует т.н. &amp;quot;контрольный символ&amp;quot; (от англ. control character), позволяющий использовать т.н. &amp;quot;специальные символы форматирования&amp;quot;. Контрольным символом по умолчанию является символ ^, который может быть изменен директивой pragma ctrlchar, например:&amp;lt;pawn&amp;gt;#pragma ctrlchar '\'&amp;lt;/pawn&amp;gt;изменит контрольный символ на \.&lt;br /&gt;
&amp;lt;BR&amp;gt;Примеры некоторых специальных символов форматирования приведены ниже:&lt;br /&gt;
&amp;lt;BR&amp;gt;^t – табуляция&lt;br /&gt;
&amp;lt;BR&amp;gt;^n – новая строка&lt;br /&gt;
&amp;lt;BR&amp;gt;^xHH – символ, представленный в шестнадцатиричном формате, где HH – двойное число, представленное в шестнадцатиричном формате&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Compiling_Plugins_(AMX_Mod_X)&amp;diff=3817</id>
		<title>Ru Compiling Plugins (AMX Mod X)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Compiling_Plugins_(AMX_Mod_X)&amp;diff=3817"/>
		<updated>2007-01-22T18:17:37Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Compiling Plugins (AMX Mod X) moved to Ru Compiling Plugins (AMX Mod X)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ru:Scripting (AMX Mod X)]]&lt;br /&gt;
Просмотреть оригинал статьи (англ.): [[Compiling Plugins (AMX Mod X)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Компилирование плагинов=&lt;br /&gt;
&lt;br /&gt;
Эта статья описывает, как компилировать [[AMX Mod X]] плагины из [[Ru:source code|исходного кода]] (.sma).&lt;br /&gt;
&lt;br /&gt;
Для всех случаев вы должны поместить .sma файл в директорию addons/amxmodx/scripting.&lt;br /&gt;
&lt;br /&gt;
=Windows=&lt;br /&gt;
&lt;br /&gt;
==Метод перетаскивания==&lt;br /&gt;
#Перетащите .sma файл на &amp;quot;compile.exe&amp;quot;.&lt;br /&gt;
#Откомпилированный .amxx файл будет находиться в директории compiled.&lt;br /&gt;
&lt;br /&gt;
==Компилирование всех плагинов==&lt;br /&gt;
#Дважды щелкните на compile.exe, чтобы откомпилировать все плагины и поместить их в директорию compiled.&lt;br /&gt;
==Командная строка==&lt;br /&gt;
#Зайдите в &amp;quot;Пуск&amp;quot;, &amp;quot;Выполнить&amp;quot;, введите &amp;quot;cmd&amp;quot;, нажмите Ok.&lt;br /&gt;
#Используйте cd, чтобы сменить директорию, например: &amp;lt;pre&amp;gt;cd c:\hlserver\cstrike\addons\amxmodx\scripting&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Используйте amxxpc, чтобы откомпилировать плагин: &amp;lt;pre&amp;gt;amxxpc.exe myplugin.sma&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Откомпилированный плагин будет в этой же директории.&lt;br /&gt;
&lt;br /&gt;
=Linux=&lt;br /&gt;
&lt;br /&gt;
Сперва перейдите в scripting директорию в вашей оболочке следующим образом: &amp;lt;pre&amp;gt;cd addons/amxmodx/scripting&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Компилирование всех плагинов==&lt;br /&gt;
#Запустите скрипт compile.sh одним из способов: &amp;lt;pre&amp;gt;sh compile.sh&amp;lt;/pre&amp;gt; or &amp;lt;pre&amp;gt;chmod +x compile.sh&lt;br /&gt;
        ./compile.sh&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Компилирование одиночного плагина==&lt;br /&gt;
#Запустите amxxpc, например: &amp;lt;pre&amp;gt;./amxxpc myplugin.sma&amp;lt;/pre&amp;gt;&lt;br /&gt;
#Откомпилированный плагин будет в этой же директории.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Alternative_Language&amp;diff=3813</id>
		<title>Ru Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Alternative_Language&amp;diff=3813"/>
		<updated>2007-01-22T18:17:14Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Ru:Alternative Language moved to Ru Alternative Language&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Russian]]&lt;br /&gt;
&lt;br /&gt;
Если вы желаете составить документацию на языке отличном от английского, пожалуйста, начните отсюда. Приветствуется содержимое на любом языке.&lt;br /&gt;
&lt;br /&gt;
Другие языки не обязательно должны быть &amp;quot;зеркалом&amp;quot; английской документации. &lt;br /&gt;
Приветствуется не только перевод документации с английского языка, но и дополнения к ней.&lt;br /&gt;
&lt;br /&gt;
= Выбор языка =&lt;br /&gt;
&lt;br /&gt;
Переключение осуществляется подстановкой префикс-кода языка.&lt;br /&gt;
&lt;br /&gt;
* [[Alternative_Language|English]]&lt;br /&gt;
* [[ru:Alternative_Language|Russian]]&lt;br /&gt;
&lt;br /&gt;
Быстрый и эффективный способ добавления переключателя нового языка - это использование шаблона&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{LanguageSwitch}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
где-либо в статье (рекомендуется добавлять вверху, либо в самом низу). Данный код добавит маленькое меню, которое выглядит следующим образом:&lt;br /&gt;
{{LanguageSwitch}}&lt;br /&gt;
&lt;br /&gt;
После того, как новый язык добавлен в wiki, данный темплейт будет изменен автоматически. Таким образом, все страницы, которые его используют, будут также автоматически обновлены.&lt;br /&gt;
&lt;br /&gt;
= Как перевести страницу =&lt;br /&gt;
&lt;br /&gt;
1) Перейдите на страницу, которую вы желаете перевести.&lt;br /&gt;
&lt;br /&gt;
2) Вверху страницы выберите &amp;quot;edit&amp;quot;(править), затем сверху добавьте переключатель языка, если такового не существует.&lt;br /&gt;
&lt;br /&gt;
3) Скопируйте весь текст темплейта страницы.&lt;br /&gt;
&lt;br /&gt;
4) Сохраните (чтобы сохранился переключатель языка).&lt;br /&gt;
&lt;br /&gt;
5) Теперь вверху страницы должен появиться переключатель языка, как на этой странице.&lt;br /&gt;
&lt;br /&gt;
6) Выберите нажатием язык, на который вы желаете осуществить перевод.&lt;br /&gt;
&lt;br /&gt;
7) Вставьте текст, который вы скопировали, в текстовую область.&lt;br /&gt;
&lt;br /&gt;
8) Осуществите перевод, после чего сохраните его.&lt;br /&gt;
&lt;br /&gt;
Вышеприведенные инструкции позволят создать версию текущего документа на вашем языке. Существует возможность перевода любых страниц.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Ресурсы:'''&lt;br /&gt;
&lt;br /&gt;
* Список 2х-буквенных кодов языков можно найти тут: http://www.w3.org/WAI/ER/IG/ert/iso639.htm&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Ru_Alternative_Language&amp;diff=3815</id>
		<title>Talk:Ru Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Ru_Alternative_Language&amp;diff=3815"/>
		<updated>2007-01-22T18:17:14Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Talk:Ru:Alternative Language moved to Talk:Ru Alternative Language&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[User:Slogic|Slogic]]: Если вставить шаблон на русской странце, то шаблон не понимает, что мы создали его на русской странице и не правильно создает ссылки: должен на английскую версию, а создает опять на русскую.&lt;br /&gt;
:Да, замечал, есть такая вещь. Выход: помещать ссылку на оригинал, не используя шаблон, например:&lt;br /&gt;
:* [[Something|Просмотреть оригинал]]&lt;br /&gt;
:--[[User:VEN|VEN]] 05:52, 19 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3812</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3812"/>
		<updated>2007-01-22T18:15:41Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;br /&gt;
::AMWiki needs to have an &amp;quot;Ru&amp;quot; namespace added (and perhaps an &amp;quot;No&amp;quot; namespace) in order for Template:LangaugeSwitch to work as desired. [http://meta.wikimedia.org/wiki/Help:Custom_namespaces Here] are MediaWiki instructions for how to add it. Also all the old Talk:Ru:blah pages will have to be moved over to Ru_talk if you decide to use that for the Ru namespace talk pages. --[[User:CyberMind|cybermind]] 12:15, 22 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3811</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3811"/>
		<updated>2007-01-22T18:13:37Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;br /&gt;
::AMWiki needs to have an &amp;quot;Ru&amp;quot; namespace added (and perhaps an &amp;quot;No&amp;quot; namespace) in order for Template:LangaugeSwitch to work as desired.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3810</id>
		<title>Talk:Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Alternative_Language&amp;diff=3810"/>
		<updated>2007-01-22T18:10:09Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I want to translate into Norwegian, how can I add the language to the LanguageSwitch template?&lt;br /&gt;
:The language template needs to be redone, it doesn't work when you use it on a foreign page, only on English. --[[User:CyberMind|cybermind]] 12:10, 22 January 2007 (CST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Writing_Extensions&amp;diff=3791</id>
		<title>Writing Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Writing_Extensions&amp;diff=3791"/>
		<updated>2007-01-19T21:07:20Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: /* Visual Studio Users */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SourceMod's Extension System is a powerful way to greatly enhance the flexibility of your SourceMod plugins.  You can take full advantage of SourceMod's Core, using the interfaces it provides, to create C++ plugins, plugin events, plugin native functions, and shared interfaces.  Extensions can also hook into Metamod:Source.&lt;br /&gt;
&lt;br /&gt;
This article goes into the details of creating a SourceMod Extension.  Knowledge of C++ is required.&lt;br /&gt;
&lt;br /&gt;
=SDK Structure=&lt;br /&gt;
First, download the [[SourceMod SDK]] from the [[SourceMod]] website.  The directory structure looks like this:&lt;br /&gt;
*&amp;lt;tt&amp;gt;extensions&amp;lt;/tt&amp;gt;&lt;br /&gt;
**&amp;lt;tt&amp;gt;geoip/&amp;lt;/tt&amp;gt; - Source code to the GeoIP extension&lt;br /&gt;
**&amp;lt;tt&amp;gt;mysql/&amp;lt;/tt&amp;gt; - Source code to the MySQL extension&lt;br /&gt;
**&amp;lt;tt&amp;gt;threader/&amp;lt;/tt&amp;gt; - Source code to the Threader extension&lt;br /&gt;
*&amp;lt;tt&amp;gt;plugins/&amp;lt;/tt&amp;gt; - Source code to all of SourceMod's plugins&lt;br /&gt;
**&amp;lt;tt&amp;gt;include/&amp;lt;/tt&amp;gt; - The include files which document plugin API&lt;br /&gt;
*&amp;lt;tt&amp;gt;public/&amp;lt;/tt&amp;gt; - Interface files for SourceMod's Core Interfaces&lt;br /&gt;
**&amp;lt;tt&amp;gt;extensions/&amp;lt;/tt&amp;gt; - Interfaces that are provided by extensions&lt;br /&gt;
**&amp;lt;tt&amp;gt;sample_ext/&amp;lt;/tt&amp;gt; - The Sample Extension SDK&lt;br /&gt;
**&amp;lt;tt&amp;gt;sourcepawn&amp;lt;/tt&amp;gt; - The include/interface files for SourcePawn&lt;br /&gt;
*&amp;lt;tt&amp;gt;sourcepawn/&amp;lt;/tt&amp;gt;&lt;br /&gt;
**&amp;lt;tt&amp;gt;compiler/&amp;lt;/tt&amp;gt; - The SourcePawn Compiler&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Starting an Extension=&lt;br /&gt;
For simplicity, this article will assume you are using the SDK base files.  These are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;smsdk_config.h&amp;lt;/tt&amp;gt; - Configuration settings (we will be editing this)&lt;br /&gt;
*&amp;lt;tt&amp;gt;smsdk_ext.h&amp;lt;/tt&amp;gt; - Header for SDK wrappers (usually never needs to be edited)&lt;br /&gt;
**''Note: Sometimes, this may be updated by the SourceMod Dev Team.  Using a newest version is recommended.'&lt;br /&gt;
*&amp;lt;tt&amp;gt;smsdk_ext.cpp&amp;lt;/tt&amp;gt; - Source for SDK wrappers (usually never needs to be edited)&lt;br /&gt;
**''Note: Sometimes, this may be updated by the SourceMod Dev Team.  Using a newest version is recommended.'&lt;br /&gt;
*&amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; - User file for main extension header&lt;br /&gt;
*&amp;lt;tt&amp;gt;extension.cpp&amp;lt;/tt&amp;gt; - User file for main extension code&lt;br /&gt;
&lt;br /&gt;
''The &amp;lt;tt&amp;gt;extension.*&amp;lt;/tt&amp;gt; files are not technically part of the SDK.  However, they are provided to give users a starting point and some documentation.''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Note:''' For help setting up Visual Studio, please see [[#Setting up Visual Studio|Setting up Visual Studio]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first step of creating your extension is to configure it.  Open the &amp;lt;tt&amp;gt;smsdk_config.h&amp;lt;/tt&amp;gt; file and edit each of the following defines.  Use the information below to guide you.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_NAME&amp;lt;/tt&amp;gt; - The general name for your Extension (should be short).&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_DESCRIPTION&amp;lt;/tt&amp;gt; - A short description of what your extension does.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_VERSION&amp;lt;/tt&amp;gt; - A version number string.  By convention, SourceMod uses the four set build number notation.  I.e. for 1.2.3.4:&lt;br /&gt;
**&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; is the &amp;quot;Major&amp;quot; release version.&lt;br /&gt;
**&amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; is the &amp;quot;Minor&amp;quot; release version.&lt;br /&gt;
**&amp;lt;tt&amp;gt;3&amp;lt;/tt&amp;gt; is the &amp;quot;Maintenance&amp;quot; or &amp;quot;Revision&amp;quot; version.&lt;br /&gt;
**&amp;lt;tt&amp;gt;4&amp;lt;/tt&amp;gt; is the &amp;quot;Build,&amp;quot; usually an internal source control number.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_AUTHOR&amp;lt;/tt&amp;gt; - Your name (or whoever/whatever authored the plugin).&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_URL&amp;lt;/tt&amp;gt; - The URL/homepage of this extension.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_LOGTAG&amp;lt;/tt&amp;gt; - The logtag your extension will use for SourceMod logging.  By convention, try to keep this under ten characters or so, and to make it all caps.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_LICENSE&amp;lt;/tt&amp;gt; - Right now, the SourceMod Dev Team mandates that 3rd party extensions must be under an Open Source license.  Putting a license abbreviation or very short message here is appropriate.  For more information, see [[SourceMod License]].&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_DATESTRING&amp;lt;/tt&amp;gt; - You do not need to modify this.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SMEXT_CONF_METAMOD&amp;lt;/tt&amp;gt; - If your plugin requires using SourceHook or Metamod:Source, uncomment this line.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, you may want to change the name of the default class that &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; declares.  To do this...&lt;br /&gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Open &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and change &amp;quot;Sample&amp;quot; in this line:&lt;br /&gt;
&amp;lt;cpp&amp;gt;class Sample : public SDKExtension&amp;lt;/cpp&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Open &amp;lt;tt&amp;gt;extension.cpp&amp;lt;/tt&amp;gt; and change the two lines to correspond to your new class name.  You can also change the global singleton that's declared, although you cannot remove the &amp;lt;tt&amp;gt;SMEXT_LINK&amp;lt;/tt&amp;gt; line (this lets SourceMod load your extension).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Visual Studio Users==&lt;br /&gt;
Make sure you change the name of your &amp;lt;tt&amp;gt;.dll&amp;lt;/tt&amp;gt; file.  The naming convention for SourceMod extensions is &amp;lt;tt&amp;gt;name.ext.dll&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; is a short name for your extension.  You are free to change this, but it is highly recommended that you keep the &amp;lt;tt&amp;gt;.ext.dll&amp;lt;/tt&amp;gt; intact.&lt;br /&gt;
&lt;br /&gt;
You can do this by going to &amp;lt;tt&amp;gt;Project&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;Properties&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;Configuration Properties&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;Linker&amp;lt;/tt&amp;gt; -&amp;gt; &amp;lt;tt&amp;gt;General&amp;lt;/tt&amp;gt;.  Set the &amp;lt;tt&amp;gt;Output File&amp;lt;/tt&amp;gt; option appropriately.&lt;br /&gt;
&lt;br /&gt;
==Linux Users==&lt;br /&gt;
Simply edit the &amp;lt;tt&amp;gt;Makefile&amp;lt;/tt&amp;gt; and change the &amp;lt;tt&amp;gt;BINARY&amp;lt;/tt&amp;gt; line near the top.  Make sure you do not add any trailing spaces at the end of the name, or the build won't come out right.&lt;br /&gt;
&lt;br /&gt;
You should now be able to compile a blank extension!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Creating Native Functions=&lt;br /&gt;
Most of the time, an extension exists to add &amp;quot;native functions&amp;quot; to the plugin system.  Native functions are simply the functions that plugins can use in SourceMod.  They are coded in C++ and have a short prototype declaration in an include file.&lt;br /&gt;
&lt;br /&gt;
==Prototyping==&lt;br /&gt;
The first step to creating a native is to &amp;lt;tt&amp;gt;spec it&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;prototype&amp;lt;/tt&amp;gt; it.  This is a simple but often time consuming process, but if you get in the habit of it, your documentation will be much better.  Let's first create a very simply native.  Here is a prototype for it, which we will place in &amp;lt;tt&amp;gt;sample.inc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * Returns the square of a number.&lt;br /&gt;
 *&lt;br /&gt;
 * @param num	Number to square.&lt;br /&gt;
 * @return	The square of num.&lt;br /&gt;
 */&lt;br /&gt;
native SquareNumber(num);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;native&amp;lt;/tt&amp;gt; keyword tells the compiler that this function exists in an outside source.  The comment style is similar to [http://www.stack.nl/~dimitri/doxygen/ doxygen] or [http://java.sun.com/j2se/javadoc/ Javadoc], and is preferred by the SourceMod Development Team.&lt;br /&gt;
&lt;br /&gt;
==Implementing==&lt;br /&gt;
Now that our function is documented, it's time to create it!  Each native function is bound to a C++ function.  The prototype for this function looks lile:&lt;br /&gt;
&amp;lt;cpp&amp;gt;cell_t Function(IPluginContext *pContext, const cell_t *params);&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A quick explanation of these types:&lt;br /&gt;
*&amp;lt;tt&amp;gt;cell_t&amp;lt;/tt&amp;gt; - This is a 32bit signed integer, the generic data type for Pawn.&lt;br /&gt;
*&amp;lt;tt&amp;gt;IPluginContext&amp;lt;/tt&amp;gt; - This interface provides Virtual Machine functions for retrieving or modifying memory in the plugin.&lt;br /&gt;
*&amp;lt;tt&amp;gt;params&amp;lt;/tt&amp;gt; - This is the &amp;quot;stack&amp;quot; of parameters that the plugin passed.  It is an array from [0..N] where 0 contains N.  &lt;br /&gt;
**For example, if one parameter was passed, and the parameter is 25:&lt;br /&gt;
***&amp;lt;tt&amp;gt;params[0]&amp;lt;/tt&amp;gt; == 1&lt;br /&gt;
***&amp;lt;tt&amp;gt;params[1]&amp;lt;/tt&amp;gt; == 25&lt;br /&gt;
**Even though it tells you how many parameters are passed, you do not need to verify this number.  The compiler will always pass the correct number of parameters in.  The only time you need to verify it is for backwards compatibility or variable parameter lists, which will be discussed later.&lt;br /&gt;
&lt;br /&gt;
Now, let's write our native function:&lt;br /&gt;
&amp;lt;cpp&amp;gt;cell_t SquareNumber(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	cell_t number = params[1];&lt;br /&gt;
	return number * number;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Binding==&lt;br /&gt;
Now, the final step is to bind our native.  Natives are bound in ''native lists''.  Each list must be terminated by a &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt; bind.  Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;const sp_nativeinfo_t MyNatives[] = &lt;br /&gt;
{&lt;br /&gt;
	{&amp;quot;SquareNumber&amp;quot;,	SquareNumber},&lt;br /&gt;
	{NULL,			NULL},&lt;br /&gt;
};&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first column/member is a string containing the name you've assigned to the native.  The second column/member is the C++ function you're binding to.  Here, both contain the same name, but it is certainly possible to bind a function to any valid Pawn function name, and likewise, you can bind one function to more than one name.&lt;br /&gt;
&lt;br /&gt;
Lastly, you must tell Core about your native list.  There are two places that are good to do this.  Whichever you choose, you must uncomment the function in &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and implement it in &amp;lt;tt&amp;gt;extension.cpp&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SDK_OnLoad&amp;lt;/tt&amp;gt; - This is called when your extension is first loaded.  If you do not require any outside interfaces, it is safe to add natives here.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt; - This is called when all extensions have been loaded.  This is generally a better place to add natives.&lt;br /&gt;
&lt;br /&gt;
Let's say we choose &amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt;, we'd then have code like this:&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	g_pShareSys-&amp;gt;AddNatives(myself, MyNatives);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: &amp;lt;tt&amp;gt;myself&amp;lt;/tt&amp;gt; is a global variable declared in the SDK.  It is a pointer that identifies your extension.''&lt;br /&gt;
&lt;br /&gt;
For more information on writing natives, see [[Natives (SourceMod Development)]].&lt;br /&gt;
&lt;br /&gt;
=Creating Events/Forwards=&lt;br /&gt;
Events are an integral part to SourceMod.  An Event is formally called a ''Forward''.  Forwards are functions inside a plugin which are not called by the plugin itself, but are triggered from an external source.  For example, &amp;lt;tt&amp;gt;OnClientConnect&amp;lt;/tt&amp;gt; is a forward which is triggered when a player connects to a server.&lt;br /&gt;
&lt;br /&gt;
There are two major types of forwards:&lt;br /&gt;
*'''Managed''': This forward is global and has a name.  To use this forward, the function must be declared as &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt; inside the user's script.  Any plugin having this public function will receive the event.&lt;br /&gt;
*'''Unmanaged''': This forward is private in nature.  For example, the &amp;lt;tt&amp;gt;HookUserMessage&amp;lt;/tt&amp;gt; native lets users specify a function to be called when a specific user message is sent.  This is done with an unmanaged forward, and adding functions to this forward is not automatic.  In general, function calls for unmanaged forwards are not public, although they can be.&lt;br /&gt;
&lt;br /&gt;
==Managed Forwards==&lt;br /&gt;
Let's say we want to create a forward that will be called when a player uses say chat.  For simplicity, let's assume you already have a function that tells you when a player says say chat.  We will just be creating the forward for it.&lt;br /&gt;
&lt;br /&gt;
As we did before, first let's prototype our global forward.  In our include file, we add this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;/**&lt;br /&gt;
 * @brief Called whenever a client says somethign in chat.&lt;br /&gt;
 *&lt;br /&gt;
 * @param client	Index of the client.&lt;br /&gt;
 * @param text		String containing the say text.&lt;br /&gt;
 * @return 		Pl_Handled to block text from printing, Pl_Continue otherwise.&lt;br /&gt;
 */&lt;br /&gt;
forward ResultType:OnPlayerSayChat(client, const String:text[]);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;forward&amp;lt;/tt&amp;gt; keyword tells the compiler that any function having this name must be declared exactly the same.  In a plugin, this would&lt;br /&gt;
&lt;br /&gt;
The next step is to declare your forward somewhere at the top of your &amp;lt;tt&amp;gt;extension.cpp&amp;lt;/tt&amp;gt; file.  This will look like:&lt;br /&gt;
&amp;lt;cpp&amp;gt;IForward *g_pSayChat = NULL&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, re-using our code from above, let's create this forward in &amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	g_pShareSys-&amp;gt;AddNatives(myself, MyNatives);&lt;br /&gt;
	g_pSayChat = g_pForwards-&amp;gt;CreateForward(ET_Event, 2, NULL, Param_Cell, Param_String);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanation of parameters:&lt;br /&gt;
*&amp;lt;tt&amp;gt;ET_Event&amp;lt;/tt&amp;gt; - Since forwards can execute multiple functions in multiple scripts, this is one of the ways of specifying what to do with the return value of each function.  &amp;lt;tt&amp;gt;ET_Event&amp;lt;/tt&amp;gt; means &amp;quot;return the highest value, do not allow stops.&amp;quot;  A stop refers to &amp;lt;tt&amp;gt;Pl_Stop&amp;lt;/tt&amp;gt;, which lets a plugin block the rest of the event chain.&lt;br /&gt;
*&amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; - This is the number of parameters our forward will have.&lt;br /&gt;
*&amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt; - Not used in our example.  This lets you pass parameters by array rather than variable arguments.&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_Cell&amp;lt;/tt&amp;gt; - The first parameter is a cell (integer).&lt;br /&gt;
*&amp;lt;tt&amp;gt;Param_String&amp;lt;/tt&amp;gt; - The second parameter is a string.&lt;br /&gt;
&lt;br /&gt;
Now, we write a quick function in our module to call this forward:&lt;br /&gt;
&amp;lt;cpp&amp;gt;/** Fires the say chat event in plugins.  Returns true to allow the text, false to block. */&lt;br /&gt;
bool FireChatEvent(int client, const char *text)&lt;br /&gt;
{&lt;br /&gt;
	if (!g_pSayChat)&lt;br /&gt;
	{&lt;br /&gt;
		return true;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	cell_t result = 0;&lt;br /&gt;
	g_pSayChat-&amp;gt;PushCell(client);&lt;br /&gt;
	g_pSayChat-&amp;gt;PushString(text);&lt;br /&gt;
	g_pSayChat-&amp;gt;Execute(&amp;amp;result);&lt;br /&gt;
	&lt;br /&gt;
	if (result == Pl_Handled)&lt;br /&gt;
	{&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, this was pretty simple.  Each parameter is &amp;quot;pushed&amp;quot; one at a time, in ascending order.  First we push the client index as a cell, then the text as a string.  Once done, we execute, and the value will be returned by reference.&lt;br /&gt;
&lt;br /&gt;
Lastly, there is a caveat.  Unlike natives, SourceMod does not automatically clean up forwards for us when are done.  We have to make sure we destroy them.  Uncomment &amp;lt;tt&amp;gt;SDK_OnUnload&amp;lt;/tt&amp;gt; from &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and implement it like so:&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnUnload()&lt;br /&gt;
{&lt;br /&gt;
	g_pForwards-&amp;gt;ReleaseForward(g_pSayChat);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unmanaged Forwards==&lt;br /&gt;
Now things get a bit more complicated.  However, unmanaged forwards are essentially the same -- they just give you more flexibility.  Let's consider the managed example with a new twisty.  We want to let users add and remove hooks from their plugins, rather than having one global forward.  The standard way to do this is with ''function IDs''.  &lt;br /&gt;
&lt;br /&gt;
Example prototype:&lt;br /&gt;
&amp;lt;pawn&amp;gt;funcenum SayChatHook&lt;br /&gt;
{&lt;br /&gt;
	forward(client, const String:text[]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
native AddSayChatHook(SayChatHook:hook);&lt;br /&gt;
native RemoveSayChatHook(SayChatHook:hook);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;funcenum&amp;lt;/tt&amp;gt; syntax lets you define all the valid prototypes for your hook.  In this example, the only valid method is a function declared like this (only MyHook can be changed):&lt;br /&gt;
&amp;lt;pawn&amp;gt;MyHook(client, const String:text[])&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
How do we make such a beast?  The first step is setting up our forward.&lt;br /&gt;
&amp;lt;cpp&amp;gt;IChangeableForward *g_pSayChat = NULL;&lt;br /&gt;
/* ... */&lt;br /&gt;
void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	g_pSayChat = g_pForwards-&amp;gt;CreateForwardEx(NULL, ET_Hook, 2, NULL, Param_Cell, Param_String); &lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice two big difference.  We now use &amp;lt;tt&amp;gt;IChangeableForward&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;IForward&amp;lt;/tt&amp;gt;, and we use &amp;lt;tt&amp;gt;CreateForwardEx&amp;lt;/tt&amp;gt; instead.  The initial first parameter specifies a name for our forward - we're going to ignore this.&lt;br /&gt;
&lt;br /&gt;
Now, we need to create our natives.  These will be fairly simple:&lt;br /&gt;
&amp;lt;cpp&amp;gt;cell_t AddSayChatHook(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	g_pSayChat-&amp;gt;AddFunction(pContext, static_cast&amp;lt;funcid_t&amp;gt;(params[1]));&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
cell_t RemoveSayChatHook(IPluginContext *pContext, const cell_t *params)&lt;br /&gt;
{&lt;br /&gt;
	IPluginFunction *pFunction = pContext-&amp;gt;GetFunctionById(static_cast&amp;lt;funcid_t&amp;gt;(params[1]));&lt;br /&gt;
	g_pSayChat-&amp;gt;RemoveFunction(pFunction);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: These natives must be added -- that step is removed here and explained earlier.''&lt;br /&gt;
&lt;br /&gt;
You do not need to worry about a plugin unloading - Core will automatically remove the functions for you.  Since an &amp;lt;tt&amp;gt;IChangeableForward&amp;lt;/tt&amp;gt; is also an &amp;lt;tt&amp;gt;IForward&amp;lt;/tt&amp;gt;, the &amp;lt;tt&amp;gt;FireChatEvent&amp;lt;/tt&amp;gt; function from earlier does not need to change.  We're done!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Creating Interfaces==&lt;br /&gt;
Do you want your extension to share an interface?  If so, first you should create an ''interface file''.  This file should contain everything your interface needs - this way other authors can easily reference it.  Your interface must inherit the &amp;lt;tt&amp;gt;SMInterface&amp;lt;/tt&amp;gt; class.  It must also declare two global macros that uniquely identify your interface.  It must also implement two functions: &amp;lt;tt&amp;gt;GetInterfaceName&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;GetInterfaceVersion&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The two defines must start with &amp;lt;tt&amp;gt;SMINTERFACE_&amp;lt;/tt&amp;gt; and end with &amp;lt;tt&amp;gt;_NAME&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;_VERSION&amp;lt;/tt&amp;gt; respectively.  The first must be a string and the second must be an unsigned integer.  This integer represents your interface's version number.  While you are free to use it however you please, by default it should be linearly increased.  If you make breaking changes or change the versioning scheme, you must overload the &amp;lt;tt&amp;gt;IsVersionCompat&amp;lt;/tt&amp;gt; function in &amp;lt;tt&amp;gt;SMInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#ifndef _INCLUDE_MYINTERFACE_FILE_H_&lt;br /&gt;
#define _INCLUDE_MYINTERFACE_FILE_H_&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;IShareSys.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define SMINTERFACE_MYINTERFACE_NAME	&amp;quot;IMyInterface&amp;quot;&lt;br /&gt;
#define SMINTERFACE_MYINTERFACE_VERSION	1&lt;br /&gt;
&lt;br /&gt;
class IMyInterface : public SourceMod::SMInterface&lt;br /&gt;
{&lt;br /&gt;
public:&lt;br /&gt;
	virtual const char *GetInterfaceName()&lt;br /&gt;
	{&lt;br /&gt;
		return SMINTERFACE_MYINTERFACE_NAME;&lt;br /&gt;
	}&lt;br /&gt;
	virtual unsigned int GetInterfaceVersion()&lt;br /&gt;
	{&lt;br /&gt;
		return SMINTERFACE_MYINTERFACE_VERSION;&lt;br /&gt;
	}&lt;br /&gt;
public:&lt;br /&gt;
	/**&lt;br /&gt;
	 * @brief This function does nothing.&lt;br /&gt;
	 */&lt;br /&gt;
	virtual void DoNothingAtAll() =0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
#endif //_INCLUDE_MYINTERFACE_FILE_H_&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice, of course, that our interface is ''pure virtual''.  This means it must be implemented in the extension.  Assuming you know C++, this should be fairly straight forward, so let's skip right to how to add this interface to the SourceMod shared system:&lt;br /&gt;
&amp;lt;cpp&amp;gt;bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late)&lt;br /&gt;
{&lt;br /&gt;
	g_pShareSys-&amp;gt;AddInterface(myself, &amp;amp;g_MyInterface);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
''Note: We do this in &amp;lt;tt&amp;gt;SDK_OnLoad()&amp;lt;/tT&amp;gt; instead of &amp;lt;tt&amp;gt;SDK_OnAllLoaded()&amp;lt;/tt&amp;gt;.  Otherwise, an extension might try to search for your interface during &amp;lt;tt&amp;gt;SDK_OnAllLoaded()&amp;lt;/tt&amp;gt;, and it might fail depending on the load order.''&lt;br /&gt;
&lt;br /&gt;
That simple?  Yup!  Now other extensions can use your interface.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Using Interfaces/Other Extensions=&lt;br /&gt;
There are a variety of interfaces that are available, but not loaded by default in the Extension SDK.  These interfaces can be retrieved and used in your extension.&lt;br /&gt;
&lt;br /&gt;
==Core Interfaces==&lt;br /&gt;
If they are provided by Core, getting them is very simple.  Most of the &amp;lt;tt&amp;gt;.h&amp;lt;/tt&amp;gt; interface files in the root of the &amp;lt;tt&amp;gt;public&amp;lt;/tt&amp;gt; folder in the SDK are Core interfaces.  For example, code to use the IPluginManager interface might look like this:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#include &amp;lt;IPluginSys.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IPluginManager *g_pPlugins = NULL;&lt;br /&gt;
&lt;br /&gt;
bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late)&lt;br /&gt;
{&lt;br /&gt;
	SM_GET_IFACE(PLUGINSYSTEM, g_pPlugins);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where did we get &amp;lt;tt&amp;gt;PLUGINSYSTEM&amp;lt;/tt&amp;gt; from?  Observe the two lines in &amp;lt;tt&amp;gt;IPluginSys.h&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;cpp&amp;gt;#define SMINTERFACE_PLUGINSYSTEM_NAME		&amp;quot;IPluginManager&amp;quot;&lt;br /&gt;
#define SMINTERFACE_PLUGINSYSTEM_VERSION	1&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;SM_GET_IFACE&amp;lt;/tt&amp;gt; macro uses the text in between the &amp;lt;tt&amp;gt;SMINTERFACE_&amp;lt;/tt&amp;gt; and the &amp;lt;tt&amp;gt;_NAME&amp;lt;/tt&amp;gt; characters.  It also uses the version for compatibility checking.  If it can't find the interface, it automatically prints to the error buffer and returns false.&lt;br /&gt;
&lt;br /&gt;
===Default Interfaces===&lt;br /&gt;
There are interfaces which are grabbed by the Extension SDK by default.  You do not need to query for them on load, or even check if they are valid or not.  They are:&lt;br /&gt;
*&amp;lt;tt&amp;gt;IShareSys&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;g_pShareSys&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;IShareSys.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;HANDLESYSTEM&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;g_pHandleSys&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;IHandleSys.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;SOURCEMOD&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;g_pSM&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;ISourceMod.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;FORWARDMANAGER&amp;lt;/tt&amp;gt; - Exposed as &amp;lt;tt&amp;gt;g_pForwards&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;IForwardSys.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==External Interfaces==&lt;br /&gt;
The situation changes if your extension requires ''another extension'', since extensions may load in a completely random order.  The first step is to mark the other extension as a dependency.  Let's say you want to use the &amp;lt;tt&amp;gt;IThreader.h&amp;lt;/tt&amp;gt; interfaces from &amp;lt;tt&amp;gt;threader.ext.dll&amp;lt;/tt&amp;gt;.  First, we declare it as such:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;bool Sample::SDK_OnLoad(char *error, size_t err_max, bool late)&lt;br /&gt;
{&lt;br /&gt;
	g_pShareSys-&amp;gt;AddDependency(myself, &amp;quot;thread.ext&amp;quot;, true, true);&lt;br /&gt;
	return true;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two boolean parameters to &amp;lt;tt&amp;gt;AddDependency&amp;lt;/tt&amp;gt; mean, respectively: &amp;quot;try to automatically load this extension&amp;quot; and &amp;quot;this extension cannot work without the dependency.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Second, we query for the interface in &amp;lt;tt&amp;gt;SDK_OnAllLoaded&amp;lt;/tt&amp;gt;.  Since we don't know when &amp;lt;tt&amp;gt;thread.ext&amp;lt;/tt&amp;gt; will actually be loaded, we have to wait until everything is definitely loaded.&lt;br /&gt;
&amp;lt;cpp&amp;gt;IThreader *g_pThreader = NULL;&lt;br /&gt;
/* ... */&lt;br /&gt;
void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	SM_GET_IFACE(THREADER, g_pThreader);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Third, we need to find a way to fail if this interface was never found.  The way to do this is by uncommenting &amp;lt;tt&amp;gt;QueryRunning&amp;lt;/tt&amp;gt; from &amp;lt;tt&amp;gt;extension.h&amp;lt;/tt&amp;gt; and implementing it:&lt;br /&gt;
&amp;lt;cpp&amp;gt;bool Sample::QueryRunning(char *error, size_t err_max)&lt;br /&gt;
{&lt;br /&gt;
	SM_CHECK_IFACE(THREADER, g_pThreader);&lt;br /&gt;
	return false;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When SourceMod queries your extension, the macro above will either vaildate the pointer or return false.  If it returns false, SourceMod marks your extension as failed.&lt;br /&gt;
&lt;br /&gt;
==Caveats==&lt;br /&gt;
===NULL Interfaces===&lt;br /&gt;
There are a few ways that external interfaces can make your code complicated.  The first is simple but a common oversight.  Don't assume interfaces will be okay.  For example, say we want to create a thread once we get the &amp;lt;tt&amp;gt;IThreader&amp;lt;/tt&amp;gt; interface.  Our code should something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;void Sample::SDK_OnAllLoaded()&lt;br /&gt;
{&lt;br /&gt;
	SM_GET_IFACE(THREADER, g_pThreader);&lt;br /&gt;
	&lt;br /&gt;
	if (QueryRunning(NULL, 0))&lt;br /&gt;
	{&lt;br /&gt;
		g_pThreader-&amp;gt;MakeThread(/* stuff */);&lt;br /&gt;
	}&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we ''query ourself'' in order to find if it's safe to continue executing code.  We could also have simply checked if &amp;lt;tt&amp;gt;g_pThreader&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;, but self-querying has a bonus: if your extension continues to do things like hook events or add listeners, you will be preventing your extension from entirely initializing itself while one interface is bad.  Always make sure you have sanity checks like this where needed.&lt;br /&gt;
&lt;br /&gt;
===Dynamic Unloading===&lt;br /&gt;
The second major caveat is that extensions can be dynamically unloaded.  If you specified yourself as having a dependency and that each dependency is required, you will have no problem.  Your extension will be unloaded before the interface is removed, and you can clean up memory/hooks in your &amp;lt;tt&amp;gt;SDK_OnUnload()&amp;lt;/tt&amp;gt; code.  There are two situations where this is a different story.&lt;br /&gt;
&lt;br /&gt;
====Optional Interfaces====&lt;br /&gt;
The first situation is if you are not requiring an extension that contains an interface.  Now, when the extension unloads, your extension will not be unloaded first.  This creates a small problem, as you must clean up without being unloaded.  There are two functions you can implement in your extension class to resolve this, both documented in &amp;lt;tt&amp;gt;IExtensionSys.h&amp;lt;/tt&amp;gt;:&lt;br /&gt;
*&amp;lt;tt&amp;gt;QueryInterfaceDrop&amp;lt;/tt&amp;gt; - Allows you to request unloading when a specific interface is unloaded.  This is the default behaviour for all interfaces.  If you want to block this functionality, continue reading.&lt;br /&gt;
*&amp;lt;tt&amp;gt;NotifyInterfaceDrop&amp;lt;/tt&amp;gt; - This is called when an interface is dropped.  If your plugin will not be unloaded, you can use this to clean up any resources on a specific inteface being removed.&lt;br /&gt;
&lt;br /&gt;
====Circular Dependencies====&lt;br /&gt;
The second situation is a bit more complicated.  It is possible for two extensions to have circular dependencies.  For example:&lt;br /&gt;
*Extension &amp;quot;A&amp;quot; requires extension &amp;quot;B.&amp;quot;&lt;br /&gt;
*Extension &amp;quot;B&amp;quot; requires extension &amp;quot;A.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If either extension is unloaded, the opposite extension is unloaded normally.  The first extension then receives the interface drop callbacks.  In this situation, it is essential that the &amp;lt;tt&amp;gt;NotifyInterfaceDrop&amp;lt;/tt&amp;gt; function be implemented and used with the circular interface.  Otherwise, you risk crashing when your extension unloads (or at the very least, leaking memory).  Since the actual drop order is undefined, it means both extensions must implement this function to be safe.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Setting up Visual Studio=&lt;br /&gt;
==Paths==&lt;br /&gt;
'''Visual Studio 2003''': Tools -&amp;gt; Options -&amp;gt; Projects, VC++ Directories&lt;br /&gt;
&lt;br /&gt;
'''Visual Studio 2005''': Tools -&amp;gt; Options -&amp;gt; Projects and Solutions -&amp;gt; VC++ Directories&lt;br /&gt;
&lt;br /&gt;
===Include Paths===&lt;br /&gt;
*SourceMod only:&lt;br /&gt;
**sdk\public\extensions&lt;br /&gt;
**sdk\public\sourcepawn&lt;br /&gt;
**sdk\public&lt;br /&gt;
*SourceMM (Note that sourcemm might be 'trunk' for you):&lt;br /&gt;
**sourcemm\sourcemm&lt;br /&gt;
**sourcemm\sourcehook&lt;br /&gt;
**sourcemm&lt;br /&gt;
*HL2SDK:&lt;br /&gt;
**game_shared&lt;br /&gt;
**public\vstdlib&lt;br /&gt;
**public\tier1&lt;br /&gt;
**public\tier0&lt;br /&gt;
**public\engine&lt;br /&gt;
**public\dlls&lt;br /&gt;
**public&lt;br /&gt;
**dlls&lt;br /&gt;
&lt;br /&gt;
===Link Paths===&lt;br /&gt;
*HL2SDK:&lt;br /&gt;
**lib\public&lt;br /&gt;
**lib\public\msvc8 for version 2005&lt;br /&gt;
**lib\public\msvc7 for version 2003&lt;br /&gt;
&lt;br /&gt;
==Compiler Options==&lt;br /&gt;
&amp;lt;b&amp;gt;Note:&amp;lt;/b&amp;gt; These options are set by default in the sample Extension SDK.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Note:&amp;lt;/b&amp;gt; These options should be set for every build (Release/Debug/others).&lt;br /&gt;
&lt;br /&gt;
*General&lt;br /&gt;
**&amp;lt;tt&amp;gt;Character Set&amp;lt;/tt&amp;gt;: '''Use Multi-Byte Character Set'''&lt;br /&gt;
*C/C++&lt;br /&gt;
**General&lt;br /&gt;
***&amp;lt;tt&amp;gt;Detect 64-bit Portability Issues&amp;lt;/tt&amp;gt;: '''No'''&lt;br /&gt;
**Preprocessor&lt;br /&gt;
***&amp;lt;tt&amp;gt;Preprocessor Defines&amp;lt;/tt&amp;gt;: Add &amp;lt;tt&amp;gt;_CRT_SECURE_NO_DEPRECATE&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;_CRT_NONSTDC_NO_DEPRECATE&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Code Generation&lt;br /&gt;
***&amp;lt;tt&amp;gt;Runtime Library&amp;lt;/tt&amp;gt;: Multi-threaded or /MT (for Release), Multi-threaded Debug or /MTd (for Debug)&lt;br /&gt;
*Linker&lt;br /&gt;
**General&lt;br /&gt;
***&amp;lt;tt&amp;gt;Output File&amp;lt;/tt&amp;gt;: Change &amp;lt;tt&amp;gt;$(ProjectName)&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;$(ProjectName).ext&amp;lt;/tt&amp;gt;, or use your own custom string.&lt;br /&gt;
**Input&lt;br /&gt;
***&amp;lt;tt&amp;gt;Additional Dependencies&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;tier0.lib tier1.lib vstdlib.lib&amp;lt;/tt&amp;gt; (for SourceMM attached extensions only)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceMod]]&lt;br /&gt;
[[Category:SourceMod Development]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=3773</id>
		<title>Talk:Optimizing Plugins (AMX Mod X Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=3773"/>
		<updated>2007-01-18T23:42:55Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Qqqqqqq, changed back to last version by BAILOPAN&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Let's say i have Float:{233.594378, 345.634256, 1234.756464} array and i need reindex it two times. Two example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;if (array[0] &amp;gt; some_float_variable)&lt;br /&gt;
      x = 1.2 + array[0]&amp;lt;/pawn&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pawn&amp;gt;y = array[1] * array[1]&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Would it be more efficient (in fact)?&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Float:temp = array[0]&lt;br /&gt;
if (temp &amp;gt; some_float_variable)&lt;br /&gt;
      x = 1.2 + temp&amp;lt;/pawn&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pawn&amp;gt;new Float:temp = array[1]&lt;br /&gt;
y = temp * temp&amp;lt;/pawn&amp;gt;--[[User:VEN|VEN]] 08:32, 3 March 2006 (EST)&lt;br /&gt;
:The bottom two are more efficient.  However, it only really matters if you're repeating this computation a lot.  If this is a one-time computation it won't make a difference. -- [[User:BAILOPAN|BAILOPAN]] 18:25, 3 March 2006 (EST)&lt;br /&gt;
----&lt;br /&gt;
Regarding [[User:NiLuJe|NiLuJe]]'s change of '\0' to 0: while they are both the same, keeping the syntax in terms of characters would probably be better for people to understand when dealing with strings, so I reverted the changes back.&lt;br /&gt;
:Perhaps it should be changed to '^0'... by default we don't use \ for a backtick.  This is probably what he meant to correct. -- [[User:BAILOPAN|BAILOPAN]] 18:55, 1 March 2006 (EST)&lt;br /&gt;
::Ah, indeed, fixing that now --[[User:CyberMind|cybermind]] 02:39, 2 March 2006 (EST)&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Is there evidence that when something is const it's faster?  I think this might be to the contrary, as the compiler has to copy it into the heap first to ensure that it isn't modified. -- [[User:BAILOPAN|BAILOPAN]] 00:54, 1 February 2006 (EST)&lt;br /&gt;
&lt;br /&gt;
:Whether or not const variables/arrays are copied to the heap depends on the situation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;For a function that has an array argument with a default value, the compiler allocates space for&lt;br /&gt;
:the default array value on the heap. However, if the array argument (with a default value) is&lt;br /&gt;
:also const, the pawn compiler passes the default array directly (there is no need to make a copy&lt;br /&gt;
:on the heap here, as the function will not attempt to change the array argument and, thereby,&lt;br /&gt;
:overwrite the default value).&lt;br /&gt;
&lt;br /&gt;
:The arguments of a function that has &amp;quot;variable arguments&amp;quot; (denoted with the ... operator, see&lt;br /&gt;
:the pawn booklet &amp;quot;The Language&amp;quot;) are always passed by reference. For constants and expressions&lt;br /&gt;
:that are not lvalues, the compiler copies the values to a cell that is allocated from the heap,&lt;br /&gt;
:and it passes the address of the cell to the function.&amp;lt;/tt&amp;gt;&lt;br /&gt;
:-Page 106 (PDF page 108) of &amp;quot;The Implentor's Guide&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;Function &amp;lt;i&amp;gt;insert&amp;lt;/i&amp;gt; copies in the other direction and it does not change its function argument item.&lt;br /&gt;
:In such a case, it is advised to mark the function argument as &amp;quot;const&amp;quot;. This helps the pawn parser&lt;br /&gt;
:to both check for errors and to generate better (more compact,  quicker) code.&amp;lt;/tt&amp;gt;&lt;br /&gt;
:-Page 21 (PDF page 23) of &amp;quot;The Language Guide&amp;quot;&lt;br /&gt;
:--[[User:CyberMind|cybermind]] 01:24, 1 February 2006 (EST)&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::I see, thanks for the clarification.  Twilight, I'd amend your part somewhat to mirror that.  -- [[User:BAILOPAN|BAILOPAN]] 02:54, 1 February 2006 (EST)&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=AlliedModders_Wiki:Site_support&amp;diff=3736</id>
		<title>AlliedModders Wiki:Site support</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=AlliedModders_Wiki:Site_support&amp;diff=3736"/>
		<updated>2007-01-12T10:39:25Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Avol, changed back to last version by Googol&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Currently a central hub in between projects is in the works.&lt;br /&gt;
In the meantime, you should use the donations link from the [http://www.sourcemod.net/ SourceMod] website.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=3459</id>
		<title>Optimizing Plugins (AMX Mod X Scripting)</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Optimizing_Plugins_(AMX_Mod_X_Scripting)&amp;diff=3459"/>
		<updated>2006-10-24T17:55:53Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Reiko, changed back to last version by UserError&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
[[Admin-Mod]] and [[AMX Mod X]] became very popular because of their easy to use scripting language.  However, the words &amp;quot;scripting language&amp;quot; come with a lot of loaded preconceptions.  Most people assume that because it's scripted:&lt;br /&gt;
*You can't possibly make it any faster&lt;br /&gt;
*It's pre-compiled, so it's already quite fast&lt;br /&gt;
*Details don't matter, as it's only &amp;quot;scripting&amp;quot; anyway&lt;br /&gt;
&lt;br /&gt;
Especially, with [[Pawn]] (formerly Small), none of these are true.  The compiler, in fact, is very poor at optimizing, and you can '''greatly''' increase the speed and efficiency of your plugins by keeping a few rules in mind.  Remember - it's more important to minimize instructions than it is to minimize lines of code.&lt;br /&gt;
&lt;br /&gt;
===Terms===&lt;br /&gt;
To read this document, you will need to understand a few concepts beforehand:&lt;br /&gt;
*&amp;lt;tt&amp;gt;BRANCHING&amp;lt;/tt&amp;gt; - When the processor takes a different path of code.  For example, to call a function or to use an if statement, the processor will &amp;quot;branch&amp;quot;.  Modern processors attempt to predict pathways with &amp;quot;branch prediction&amp;quot;, but it's best to avoid branching a lot if possible.&lt;br /&gt;
*&amp;lt;tt&amp;gt;STACK ALLOCATION&amp;lt;/tt&amp;gt; - In Pawn, all local data is stored on the stack, a big chunk of continuous memory.  Whenever you create a variable on the stack, it is automatically written with zeroes.&lt;br /&gt;
*&amp;lt;tt&amp;gt;HEAP ALLOCATION&amp;lt;/tt&amp;gt; - In Pawn, temporary data that needs to be referenced by a native is stored on the heap, another area of contiguous, but less restrictive memory.&lt;br /&gt;
*&amp;lt;tt&amp;gt;DATA SECTION&amp;lt;/tt&amp;gt; - This is an area of memory built into your .amxx file.  In fact, it &amp;quot;becomes&amp;quot; the heap at load time.  All your strings and arrays are hardcoded into this area.&lt;br /&gt;
*&amp;lt;tt&amp;gt;EXPENSIVENESS&amp;lt;/tt&amp;gt; - To be &amp;quot;expensive&amp;quot; in computer science means an operation requires a lot of CPU processing.  It usually does not refer to memory size, only to processing cycles and time.  Addition is inexpensive, floating power operations are expensive.  However, both are inexpensive in comparison to writing a file.  An inexpensive operation can also be called &amp;quot;cheap&amp;quot;.&lt;br /&gt;
*&amp;lt;tt&amp;gt;BIG-OH NOTATION&amp;lt;/tt&amp;gt; - O(*) notation refers to the expensiveness of an algorithm.  If something is O(n), it occurs in linear time -- meaning that for N items, it will complete relative to N.  O(N^2) means with N items, it will complete relative to N^2.  O(1) means &amp;quot;constant time&amp;quot; - no matter what N is, it will run in the same amount of time.&lt;br /&gt;
&lt;br /&gt;
==Compiler Optimizations==&lt;br /&gt;
These optimizations have to do with changing how your code is compiled.  While the syntax may remain the same, you are not only increasing compile time, but increasing your plugin's efficiency and speed at run time.&lt;br /&gt;
&lt;br /&gt;
===Always Save Results===&lt;br /&gt;
Observe the example code snippet below:&lt;br /&gt;
&amp;lt;pawn&amp;gt;if (get_user_team(player) == TEAM_T)&lt;br /&gt;
{&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (get_user_team(player) == TEAM_CT) {&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (get_user_team(player) == TEAM_SPECTATOR) {&lt;br /&gt;
    //...code&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This is a mild example of &amp;quot;cache your results&amp;quot;.  When the compiler generates assembly for this code, it will (in pseudo code) generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Notice the problem?  We have called &amp;lt;tt&amp;gt;get_user_team&amp;lt;/tt&amp;gt; an extra two times than necessary.  The result doesn't change, so we can save it.  Observe:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new team = get_user_team(player)&lt;br /&gt;
if (team == TEAM_T)&lt;br /&gt;
{&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (team == TEAM_CT) {&lt;br /&gt;
    //...code&lt;br /&gt;
} else if (team == TEAM_SPECTATOR) {&lt;br /&gt;
    //...code&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Now, the compiler will only generate this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
  COMPARE+BRANCH&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If &amp;lt;tt&amp;gt;get_user_team&amp;lt;/tt&amp;gt; were an expensive operation (it's relatively cheap), we would have recalculated the entire result each branch of the &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; case.&lt;br /&gt;
&lt;br /&gt;
===Switch instead of If===&lt;br /&gt;
If you can, you should use &amp;lt;tt&amp;gt;switch&amp;lt;/tt&amp;gt; cases instead of &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;.  This is because for an if statement, the compiler must branch to each consecutive &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; case.  Using the example from above, observe the switch version:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new team = get_user_team(player)&lt;br /&gt;
switch (team)&lt;br /&gt;
{&lt;br /&gt;
  case TEAM_T:&lt;br /&gt;
     //code...&lt;br /&gt;
  case TEAM_CT:&lt;br /&gt;
     //code...&lt;br /&gt;
  case TEAM_SPECTATOR:&lt;br /&gt;
     //code...&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This will generate what's called a &amp;quot;case table&amp;quot;.  Rather than worm through displaced &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; tests, the compiler generates a table of possible values, which the virtual machine knows to browse through:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  CALL get_user_team&lt;br /&gt;
  COMPARE&lt;br /&gt;
  COMPARE&lt;br /&gt;
  COMPARE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Don't Re-index Arrays===&lt;br /&gt;
A common practice in Small is to &amp;quot;save space&amp;quot; by re-indexing arrays.  There are a few myths behind this, such as saving memory, assuming the compiler does it for you, or readability.  Fact: none of these are true.  Observe the code below:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new players[32], num, team&lt;br /&gt;
get_players(players, num)&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   if (!is_user_connected(players[i]))&lt;br /&gt;
      continue;&lt;br /&gt;
   team = get_user_team(players[i])&lt;br /&gt;
   set_user_frags(players[i], 0)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
For this, the compiler generates code similar to:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
:LOOP_BEGIN&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   CALL is_user_connected&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   CALL get_user_team&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   CALL set_user_frags&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See what happened?  The compiler does not cache array indexing.  Because we've used &amp;lt;tt&amp;gt;players[i]&amp;lt;/tt&amp;gt; each time, every instance generates 4-6 (or more) instructions which load &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt;, the address of &amp;lt;tt&amp;gt;players&amp;lt;/tt&amp;gt;, computes the final location, and then grabs the data out of memory.  It is much faster to do:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new player&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   player = players[i]&lt;br /&gt;
   if (!is_user_connected(player))&lt;br /&gt;
      continue;&lt;br /&gt;
   team = get_user_team(player)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Not only is this more readable, but look at how much cruft we've shaved off the compiler's generated code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
:LOOP_BEGIN&lt;br /&gt;
   LOAD i&lt;br /&gt;
   LOAD players&lt;br /&gt;
   CALC&lt;br /&gt;
   LOAD players[i]&lt;br /&gt;
   STORE player&lt;br /&gt;
   CALL is_user_connected&lt;br /&gt;
   LOAD player&lt;br /&gt;
   CALL get_user_team&lt;br /&gt;
   LOAD player&lt;br /&gt;
   CALL set_user_frags&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In a large loop you can drastically reduce codesize in this manner.&lt;br /&gt;
&lt;br /&gt;
===Global vs Local and Variables in Loops===&lt;br /&gt;
It is important to realize that every variable in [[Pawn]] is automatically zeroed.  For global variables, they are static and permanent, thus they are zeroed when your plugin is loaded.  Variables in functions, however, must be zeroed dynamically.  This is a slow and tedious operation, and you should not only avoid relying on it when necessary, but you should keep that fact in mind when using arrays.&lt;br /&gt;
&lt;br /&gt;
[[Arrays]] in [[Pawn]] are &amp;quot;cells&amp;quot; of data.  Each cell is four or eight bytes, depending on whether your processor is 32bit or 64bit.  To create an array of 4096 cells, for example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new array[4096]&amp;lt;/pawn&amp;gt;&lt;br /&gt;
The compiler generates code to manually zero every single one of the 16,384 bytes in that location.  Normally, this isn't too bad -- but it can be absolutely deadly in a function which is called quite often.  For example, &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; is called on every [[server tick]] in [[AMX Mod X]].  To declare an array of that size in &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; is highly unnecessary.  Instead, you can take advantage of the fact that not only are globals free of charge, but &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; does not need to be re-entrant.  That is, you will never call &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt; inside of &amp;lt;tt&amp;gt;server_frame&amp;lt;/tt&amp;gt;, so making the variable global will not bring up the problem of one instance of the function overwriting data from another instance of the same function.  Observe:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new g_serverframe_array[4096]&lt;br /&gt;
public server_frame()&lt;br /&gt;
{&lt;br /&gt;
  //...code that uses g_serverframe_array&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This will execute conseridably faster.  You can do this with smaller arrays too.&lt;br /&gt;
&lt;br /&gt;
Likewise, it is equally important to avoid declaring arrays inside of loops.  Consider the following block of code:&lt;br /&gt;
&amp;lt;pawn&amp;gt;for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   new message[255], name[32], player&lt;br /&gt;
   player = players[i]&lt;br /&gt;
   get_user_name(player, name, 31)&lt;br /&gt;
   format(message, 254, &amp;quot;Hello, %s&amp;quot;, name)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
If there are 32 players, this loop will actually resize and zero out over 1K of memory thirty two times in a row.  Not good!  However, on the other hand, it's nice that the message is zeroed out for us each time.  &amp;lt;tt&amp;gt;Tip:&amp;lt;/tt&amp;gt; you often only need to zero out the first character of a string.  This will make the entire string empty.  The code below is much more efficient:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new message[255], name[32], player&lt;br /&gt;
for (new i=0; i&amp;lt;num; i++)&lt;br /&gt;
{&lt;br /&gt;
   player = players[i]&lt;br /&gt;
   name[0] = '^0'&lt;br /&gt;
   message[0] = '^0'&lt;br /&gt;
   get_user_name(player, name, 31)&lt;br /&gt;
   format(message, 254, &amp;quot;Hello, %s&amp;quot;, name)&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This has the effect of safely making the string empty beforehand, as well as largely reducing a lot of run-time overhead.&lt;br /&gt;
&lt;br /&gt;
===Static vs Global===&lt;br /&gt;
An alternative to global variables is static variables, which are internally the same but easier to work with for programming.&lt;br /&gt;
&lt;br /&gt;
A variable declared with the keyword &amp;quot;static&amp;quot; instead of &amp;quot;new&amp;quot; operates in the same way a global does (it is created only once) but the variable is local to the function; this means the code is much easier to read, while drastically improving speed just like a global variable.  Example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;stock SomeBigFunction()&lt;br /&gt;
{&lt;br /&gt;
   static gaben[255];&lt;br /&gt;
   format(gaben, &amp;quot;%L&amp;quot;, LANG_SERVER, &amp;quot;STUFF&amp;quot;);&lt;br /&gt;
}&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has the same effect as declaring &amp;lt;tt&amp;gt;gaben&amp;lt;/tt&amp;gt; as global, except only &amp;lt;tt&amp;gt;SomeBigFunction&amp;lt;/tt&amp;gt; can use it.  &lt;br /&gt;
&lt;br /&gt;
{{qnotice|Be careful of re-entrancy!}}&lt;br /&gt;
When a variable is static, it has the same re-entrancy problems of a global variable.  That means, if your function might be called recursively, or twice in the same stack frame, you should not use static variables.  This is most often the case for API provided to other plugins or helper functions.  Triggered events are usually never called twice on the same execution chain.&lt;br /&gt;
&lt;br /&gt;
===Constant variables===&lt;br /&gt;
You can declare a variable &amp;quot;constant&amp;quot; by adding the &amp;quot;const&amp;quot; keyword before the variable name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new const AMX_GABEN[] = &amp;quot;amx_gaben&amp;quot;&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this does is prevents the variable from being changed; essentially, you've locked the variable to a certain value. In this way, a constant can offer a type safe method of simplifying code, unlike a define, which is not type safe.&lt;br /&gt;
&lt;br /&gt;
In addition, constant variables are often optimized out, resulting in quicker and smaller code.&lt;br /&gt;
&lt;br /&gt;
===For Loop Comparisons===&lt;br /&gt;
A common mistake is to write code like this:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new string[256] = &amp;quot;something long&amp;quot;&lt;br /&gt;
for (new i=0; i&amp;lt;strlen(string); i++)&lt;br /&gt;
   //...code&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This plays off a similar principle from before: cache results.  The compiler will actually recompute your string length on each iteration of the loop.  This will have even worse effects if your string changes mid-loop.  A more sensible method is:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new string[256] = &amp;quot;something long&amp;quot;&lt;br /&gt;
new len = strlen(string)&lt;br /&gt;
for (new i=0; i&amp;lt;len; i++)&lt;br /&gt;
   //...code&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Tips and Tricks==&lt;br /&gt;
===Lookup Tables===&lt;br /&gt;
Precompute what can be precomputed.  For example, say you have a mapping of weapon indices to names:&lt;br /&gt;
&amp;lt;pawn&amp;gt;if (weapon == CSW_AK47)&lt;br /&gt;
   copy(name, len, &amp;quot;weapon_ak47&amp;quot;)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
Ignoring the fact that we have &amp;lt;tt&amp;gt;get_weapon_name&amp;lt;/tt&amp;gt; in [[AMX Mod X]], this is inefficient.  We could precompute this result in a table:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new g_WeaponNamesTable[TOTAL_WEAPONS][] = {&lt;br /&gt;
   //..0 to CSW_AK47-1&lt;br /&gt;
   &amp;quot;weapon_ak47&amp;quot;,&lt;br /&gt;
   //..CSW_AK47+1 to TOTAL_WEAPONS-1&lt;br /&gt;
};&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Perfect Hashing===&lt;br /&gt;
:TODO: explain this&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Local Strings===&lt;br /&gt;
The [[Pawn]] compiler does not optimize the DATA section, which stores all hardcoded strings and global arrays.  If you reference the same hardcoded string 500 times in your plugin, it will appear 500 different times.  If this seems bad enough, it actually does this with all strings.  For example, the empty string (&amp;quot;&amp;quot;) appears everywhere in the include files, usually used as a default parameter to many natives.  This too is copied into the data section for each unique reference.  &lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;set_cvar_string(&amp;quot;amx_gaben&amp;quot;, get_cvar_string(&amp;quot;amx_gaben&amp;quot;) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
This will create two copies of &amp;quot;amx_gaben&amp;quot; in the DATA section.  While this doesn't really hurt, it does increase the size of your plugin.  &lt;br /&gt;
&lt;br /&gt;
Similarly, this has the same problem:&lt;br /&gt;
&amp;lt;pawn&amp;gt;#define AMX_GABEN &amp;quot;amx_gaben&amp;quot;&lt;br /&gt;
set_cvar_string(AMX_GABEN, get_cvar_string(AMX_GABEN) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
The only way to avoid this mess is to use global variables.  As stated earlier, they're basically free storage.&lt;br /&gt;
&amp;lt;pawn&amp;gt;new AMX_GABEN[] = &amp;quot;amx_gaben&amp;quot;&lt;br /&gt;
set_cvar_string(AMX_GABEN, get_cvar_string(AMX_GABEN) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, while not necessary, this will reduce your plugin's size in memory and on disk.  If you're already using defines, you can make this switch easily.&lt;br /&gt;
&lt;br /&gt;
In order to prevent this from changing, you may want to declare it constant:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pawn&amp;gt;new const AMX_GABEN[] = &amp;quot;amx_gaben&amp;quot;&lt;br /&gt;
set_cvar_string(AMX_GABEN, get_cvar_string(AMX_GABEN) + 1)&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now it is a perfectly safe method of storage.&lt;br /&gt;
&lt;br /&gt;
==Faster Natives==&lt;br /&gt;
AMX Mod X replaces many of the old AMX Mod natives with faster versions.  Read below to discover them.&lt;br /&gt;
&lt;br /&gt;
===Cvar Pointers===&lt;br /&gt;
As of AMX Mod X 1.70, you can cache &amp;quot;cvar pointers&amp;quot;.  These are direct accesses to cvars, rather than named access.  This is a critical optimization which is dozens of times faster.  For example:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new g_enabled = register_cvar(&amp;quot;csdm_enabled&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
//OR&lt;br /&gt;
new g_enabled = get_cvar_pointer(&amp;quot;csdm_enabled&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
stock SetCSDM(num)&lt;br /&gt;
   set_pcvar_num(g_enabled, num)&lt;br /&gt;
&lt;br /&gt;
stock GetCSDM()&lt;br /&gt;
   return get_pcvar_num(g_enabled)&lt;br /&gt;
&amp;lt;/pawn&amp;gt;&lt;br /&gt;
All of the cvar* functions (except for set_cvar_string) are mapped to [get|set]_pcvar_*.  You can get a cached cvar pointer with get_cvar_pointer() or register_cvar().&lt;br /&gt;
&lt;br /&gt;
===FormatEX===&lt;br /&gt;
As of AMX Mod X 1.70, there is an ultra high-speed version of format() called formatex().  It skips copy-back checking, unlike format().  formatex() cannot be used if a source input is the same as the output buffer.  For example, these are invalid:&lt;br /&gt;
&amp;lt;pawn&amp;gt;new buffer[255]&lt;br /&gt;
formatex(buffer, 254, &amp;quot;%s&amp;quot;, buffer);&lt;br /&gt;
formatex(buffer, 254, buffer);&lt;br /&gt;
formatex(buffer, 254, &amp;quot;%d %s&amp;quot;, buffer[2]);&amp;lt;/pawn&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It should be noted that format() will behave the same as formatex() if it detects that there will be no copy-back needed.  However, formatex() does not check this, and thus is slightly faster for situations where the coder is sure of its usage.&lt;br /&gt;
&lt;br /&gt;
===File Writing===&lt;br /&gt;
As of AMX Mod X 1.70, there are new natives for file writing.  Read_file and write_file are O(n^2) functions for consecutive read/writes.  fopen(), fgets(), fputs(), and fclose() are O(n) (or better) depending on how you use them.&lt;br /&gt;
&lt;br /&gt;
[[Category:Scripting (AMX Mod X)]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=GNU_General_Public_License&amp;diff=3458</id>
		<title>GNU General Public License</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=GNU_General_Public_License&amp;diff=3458"/>
		<updated>2006-10-24T17:55:50Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Blackgizmo, changed back to last version by BAILOPAN&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
Perhaps the most well known of stock licenses, the GPL is a viral license because of how it controls copying.  A common misconception about the GPL is how it &amp;quot;makes things open source&amp;quot;.  The GPL only affects the act of copying or distributing a piece of work.  It simply mandates that for each person you distribute or copy the software to, that person must have the same freedoms as enumerated in the license.  The essential freedom is GPL'd access to the source code and the ability to freely modify and redistribute the source code.&lt;br /&gt;
&lt;br /&gt;
==License Text==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GNU GENERAL PUBLIC LICENSE&lt;br /&gt;
&lt;br /&gt;
Version 2, June 1991&lt;br /&gt;
&lt;br /&gt;
Copyright (C) 1989, 1991 Free Software Foundation, Inc.  &lt;br /&gt;
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA&lt;br /&gt;
&lt;br /&gt;
Everyone is permitted to copy and distribute verbatim copies&lt;br /&gt;
of this license document, but changing it is not allowed.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Preamble===&lt;br /&gt;
&lt;br /&gt;
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.&lt;br /&gt;
&lt;br /&gt;
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.&lt;br /&gt;
&lt;br /&gt;
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.&lt;br /&gt;
&lt;br /&gt;
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.&lt;br /&gt;
&lt;br /&gt;
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.&lt;br /&gt;
&lt;br /&gt;
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.&lt;br /&gt;
&lt;br /&gt;
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.&lt;br /&gt;
&lt;br /&gt;
The precise terms and conditions for copying, distribution and modification follow.&lt;br /&gt;
===TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION===&lt;br /&gt;
&lt;br /&gt;
*0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The &amp;quot;Program&amp;quot;, below, refers to any such program or work, and a &amp;quot;work based on the Program&amp;quot; means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term &amp;quot;modification&amp;quot;.) Each licensee is addressed as &amp;quot;you&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.&lt;br /&gt;
&lt;br /&gt;
*1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.&lt;br /&gt;
&lt;br /&gt;
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.&lt;br /&gt;
&lt;br /&gt;
*2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:&lt;br /&gt;
**a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. &lt;br /&gt;
**b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. &lt;br /&gt;
**c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) &lt;br /&gt;
&lt;br /&gt;
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.&lt;br /&gt;
&lt;br /&gt;
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.&lt;br /&gt;
&lt;br /&gt;
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.&lt;br /&gt;
&lt;br /&gt;
*3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:&lt;br /&gt;
**a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, &lt;br /&gt;
**b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, &lt;br /&gt;
**c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) &lt;br /&gt;
&lt;br /&gt;
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.&lt;br /&gt;
&lt;br /&gt;
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.&lt;br /&gt;
&lt;br /&gt;
*4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.&lt;br /&gt;
&lt;br /&gt;
*5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.&lt;br /&gt;
&lt;br /&gt;
*6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.&lt;br /&gt;
&lt;br /&gt;
*7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.&lt;br /&gt;
&lt;br /&gt;
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.&lt;br /&gt;
&lt;br /&gt;
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.&lt;br /&gt;
&lt;br /&gt;
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.&lt;br /&gt;
&lt;br /&gt;
*8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.&lt;br /&gt;
&lt;br /&gt;
*9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.&lt;br /&gt;
&lt;br /&gt;
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and &amp;quot;any later version&amp;quot;, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.&lt;br /&gt;
&lt;br /&gt;
*10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.&lt;br /&gt;
&lt;br /&gt;
NO WARRANTY&lt;br /&gt;
&lt;br /&gt;
*11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &amp;quot;AS IS&amp;quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.&lt;br /&gt;
&lt;br /&gt;
*12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.&lt;br /&gt;
&lt;br /&gt;
===How to Apply These Terms to Your New Programs===&lt;br /&gt;
&lt;br /&gt;
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.&lt;br /&gt;
&lt;br /&gt;
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the &amp;quot;copyright&amp;quot; line and a pointer to where the full notice is found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
one line to give the program's name and an idea of what it does.&lt;br /&gt;
Copyright (C) yyyy  name of author&lt;br /&gt;
&lt;br /&gt;
This program is free software; you can redistribute it and/or&lt;br /&gt;
modify it under the terms of the GNU General Public License&lt;br /&gt;
as published by the Free Software Foundation; either version 2&lt;br /&gt;
of the License, or (at your option) any later version.&lt;br /&gt;
&lt;br /&gt;
This program is distributed in the hope that it will be useful,&lt;br /&gt;
but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
GNU General Public License for more details.&lt;br /&gt;
&lt;br /&gt;
You should have received a copy of the GNU General Public License&lt;br /&gt;
along with this program; if not, write to the Free Software&lt;br /&gt;
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also add information on how to contact you by electronic and paper mail.&lt;br /&gt;
&lt;br /&gt;
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Gnomovision version 69, Copyright (C) year name of author&lt;br /&gt;
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details&lt;br /&gt;
type `show w'.  This is free software, and you are welcome&lt;br /&gt;
to redistribute it under certain conditions; type `show c' &lt;br /&gt;
for details.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.&lt;br /&gt;
&lt;br /&gt;
You should also get your employer (if you work as a programmer) or your school, if any, to sign a &amp;quot;copyright disclaimer&amp;quot; for the program, if necessary. Here is a sample; alter the names:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Yoyodyne, Inc., hereby disclaims all copyright&lt;br /&gt;
interest in the program `Gnomovision'&lt;br /&gt;
(which makes passes at compilers) written &lt;br /&gt;
by James Hacker.&lt;br /&gt;
&lt;br /&gt;
signature of Ty Coon, 1 April 1989&lt;br /&gt;
Ty Coon, President of Vice&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the [[GNU Lesser General Public License]] instead of this License.&lt;br /&gt;
&lt;br /&gt;
==Projects==&lt;br /&gt;
*[[Metamod]]&lt;br /&gt;
*[[AMX Mod X]]&lt;br /&gt;
&lt;br /&gt;
==External Links==&lt;br /&gt;
*[http://www.gnu.org/copyleft/gpl.html GNU GPL Site]&lt;br /&gt;
*[http://www.fsf.org/ Free Software Foundation]&lt;br /&gt;
*[http://www.opensource.org/licenses/gpl-license.php OSI GPL Site]&lt;br /&gt;
*[http://www.opensource.org Open Source Initiative]&lt;br /&gt;
&lt;br /&gt;
[[Category:Copyright]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Help:Editing&amp;diff=3447</id>
		<title>Help:Editing</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Help:Editing&amp;diff=3447"/>
		<updated>2006-10-21T12:12:46Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Tictac, changed back to last version by Twilight Suzuka&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;To read more about editing a wiki, see the MediaWiki editing documentation here: [http://meta.wikimedia.org/wiki/Help:Editing MediaWiki Editing]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=User:Twistedeuphoria&amp;diff=3446</id>
		<title>User:Twistedeuphoria</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=User:Twistedeuphoria&amp;diff=3446"/>
		<updated>2006-10-21T12:10:13Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Cl flushentity, changed back to last version by Twilight Suzuka&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== TwistedEuphoria==&lt;br /&gt;
Euphoria, known as &amp;quot;Twisty&amp;quot; or &amp;quot;The twisted one&amp;quot; by his firneds (of whom you are NOT a part of), is an insane but quite lazy and lethargic man, who is also a basement dweller. He is the only person to date to have communicated over IRC without moving.&lt;br /&gt;
&lt;br /&gt;
=== Childhood ===&lt;br /&gt;
From the moment he was born, Twisty's parents knew he would be a failure of epic proportions.&lt;br /&gt;
This story is, remarkably, about Twisty's birth:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
euphoriasai	once the doctor hit me and i didnt move&lt;br /&gt;
euphoriasai	then i was like oh hey i should move&lt;br /&gt;
euphoriasai	then i did&lt;br /&gt;
euphoriasai	true story&lt;br /&gt;
BAILOPAN	then you collapsed from exhaustion&lt;br /&gt;
euphoriasai	yeah that moving thing is overrated&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From that moment on, not much changed. &lt;br /&gt;
&lt;br /&gt;
Twisty didn't move more than an inch until his tenth birthday, when he was plyed with alcohol to move towards a large peice of cake. This is also the day that Twisty became an orphan, as his parents were caught plying many young girls with alcohol, along with Twisty. In a feat of untold horror, the police uncovered an amount of child pornography that made the great egyptian pyramids look like mole hills.&lt;br /&gt;
&lt;br /&gt;
At this point, Twisty was over 500 pounds, and used a computer with OSX on it.&lt;br /&gt;
&lt;br /&gt;
Currently, Twisty is at a much more acceptable weight, and uses a PC, but unfortunately, he still doesn't move much. In a feat of untold will, he has managed to link with IRC telepathically, so that he can sleep and chat with friends. Well, not really &amp;quot;friends&amp;quot;, more like people...that work and talk with other people....that they hate.&lt;br /&gt;
&lt;br /&gt;
Twisty has a great deal of telekenetic skill, as he refuses to move very much. Unfortunately, he is also very lazy, and telekenesis takes a lot of energy and concentration.&lt;br /&gt;
&lt;br /&gt;
Twisty also has the innate ability to see ghosts. At some point, he had orange hair, and was actually muscular, as his fat imploded into him due to the immense tidal forces, forming muscle somehow, and met some girl, stole her virginity and powerz, and got a kickass sword. Luckily for all humanity, some homeless guy named Aizen managed to steal the sword from him. In a fit of rage, Twisty locked himself in his basement. He has not come out since.&lt;br /&gt;
&lt;br /&gt;
For a detailed analysis of these events in Twisty's life, read the manga &amp;quot;Bleach&amp;quot;. While slightly exaggerated for marketing purpose, it is Twisty's teenage years. More or less.&lt;br /&gt;
&lt;br /&gt;
=== A average day with the Twisted One ===&lt;br /&gt;
All he does is sleep, masturbate, and communicate online. Thats it. Stop reading. Theres no more to tell! I'm serious!&lt;br /&gt;
&lt;br /&gt;
=== Twisty on virginity ===&lt;br /&gt;
Twisty will take your virginity. If you think this is impossible, because you've already lost yours, you are wrong.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; Dead wrong &amp;lt;/tt&amp;gt;&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:Installing_Metamod:Source&amp;diff=3429</id>
		<title>Talk:Installing Metamod:Source</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:Installing_Metamod:Source&amp;diff=3429"/>
		<updated>2006-10-04T05:33:06Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Hpc1ne2006, changed back to last version by Cybot&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I had a problem while installing SourceMM to Source Dedicated Server (STEAM version, not independent, windows). My gameinfo.txt ShearchPaths changed after server load to this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
		SearchPaths&lt;br /&gt;
		{&lt;br /&gt;
			Game				|gameinfo_path|.&lt;br /&gt;
			Game				cstrike&lt;br /&gt;
			Game				hl2&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
			Game				cstrike&lt;br /&gt;
			Game				hl2&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
and plugin didn't work. I solve this by putting &amp;quot;Read Only&amp;quot; flag to gameinfo.txt file.&lt;br /&gt;
&lt;br /&gt;
== Where 'before'? ==&lt;br /&gt;
&lt;br /&gt;
 GameBin				|gameinfo_path|addons/metamod/bin&lt;br /&gt;
 SearchPaths&lt;br /&gt;
 {&lt;br /&gt;
 	Game				|gameinfo_path|. &lt;br /&gt;
 	Game				cstrike&lt;br /&gt;
 	Game				hl2&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
 SearchPaths&lt;br /&gt;
 {&lt;br /&gt;
 	GameBin				|gameinfo_path|addons/metamod/bin&lt;br /&gt;
 	Game				|gameinfo_path|. &lt;br /&gt;
 	Game				cstrike&lt;br /&gt;
 	Game				hl2&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
???&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod&amp;diff=3175</id>
		<title>Metamod</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod&amp;diff=3175"/>
		<updated>2006-07-16T06:59:00Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Metamod ==&lt;br /&gt;
[[Category:Half-Life_1]]&lt;br /&gt;
Metamod is a plugin/DLL manager that sits between the [[Half-Life_1|Half-Life]] Engine and an HL Game mod, allowing the dynamic loading/unloading of mod-like DLL plugins to add functionality to the HL server or game mod.&lt;br /&gt;
&lt;br /&gt;
[[AMX_Mod_X|AMX Mod X]] is a Metamod plugin.&lt;br /&gt;
&lt;br /&gt;
{{Stub}}&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Talk:FTP&amp;diff=2968</id>
		<title>Talk:FTP</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Talk:FTP&amp;diff=2968"/>
		<updated>2006-05-31T17:31:49Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;quot;how do i find out FTP information?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Get it from your server provider.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2900</id>
		<title>Metamod:Source Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2900"/>
		<updated>2006-04-26T09:02:48Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Cpufreak04, changed back to last version by CyberMind&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article is an introduction to [[SourceMM]] coding.  &lt;br /&gt;
&lt;br /&gt;
{{qnotice|The majority of this documentation should be merged or moved into an article about [[SourceHook]].}}&lt;br /&gt;
&lt;br /&gt;
{{qnotice|This article probably needs some better formatting.}}&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
You must have the Valve [[HL2SDK]], available from your [[Steam]] Menu. For Windows, you must have [[Microsoft Visual Studio]] 7.0 or 7.1 (we have not tried 6.0). For [[Linux]], Valve requires you use at least [[GCC]] 3.4.1. You should also have a copy of the [[Metamod:Source]] source code, available [http://www.sourcemm.net/ here] (sourcemm/sourcehook and sourcemm/sourcemm).&lt;br /&gt;
&lt;br /&gt;
For [[Microsoft Visual Studio]], you should make sure that you have the following HL2SDK paths in your include settings (Tools -&amp;gt; Options -&amp;gt; Projects, VC++ Directories, Include Files), as well as the &amp;quot;sourcehook&amp;quot; and &amp;quot;sourcemm&amp;quot; folders:&lt;br /&gt;
*dlls&lt;br /&gt;
*public&lt;br /&gt;
*public\vstdlib&lt;br /&gt;
*public\tier1&lt;br /&gt;
*public\tier0&lt;br /&gt;
*public\engine&lt;br /&gt;
*public\dlls&lt;br /&gt;
*tier1&lt;br /&gt;
*lib\public (this should be in your Library Paths!)&lt;br /&gt;
&lt;br /&gt;
=Plugin API=&lt;br /&gt;
In order to write a plugin, you must implement the ISmmPlugin interface, similar to IServerPluginCallbacks. Each Metamod:Source release has a minimum required interface version and a current version. The minimum version is guaranteed to be upward compatible to the current, however, it may be lacking some features.&lt;br /&gt;
&lt;br /&gt;
Once you've implemented the interface, you must also have a global singleton of your plugin available. There are a few macros to assist you in properly exposing the interface as a DLL and setting up the API states.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|PLUGIN_GLOBALVARS}}() - Place in header. Declares the global variables that some API calls require (such as g_SHPtr and g_PLAPI).&lt;br /&gt;
*{{bcode|PLUGIN_EXPOSE}}(class, singleton) - Place in .cpp file. Declares the external CreateInterface function which exposes the API.&lt;br /&gt;
*{{bcode|PLUGIN_SAVEVARS}}() - Use first thing in ISmmPlugin::Load(), saves the global variables sent from SourceMM.&lt;br /&gt;
&lt;br /&gt;
The actual plugin API you must implement as of this writing is version 004. To see a description of each of the functions, you can view the doxygen information here. Note that the Load, Unload, Pause, and Unpause functions allow you to refuse the action and copy an error message (you should check to make sure error is not NULL - it can be).&lt;br /&gt;
&lt;br /&gt;
=SourceHook (Hooking)=&lt;br /&gt;
SourceHook is the engine used to intercept function calls, much like Metamod. The difference with SourceHook is that it can intercept any virtual function in any class that, at compile time, you have the header for. SourceHook has the following steps of operation:&lt;br /&gt;
&lt;br /&gt;
* Declare the prototype of the function you are going to hook. This generates compile-time code that is able to pinpoint exactly how to go about hooking the function.&lt;br /&gt;
* Hook the function - as a member function of another class or a regular static function.&lt;br /&gt;
* Before the hooked function is called, all of the &amp;quot;pre&amp;quot; hook handlers attached to it are called. Each hook can set a special flag, the highest of which is chosen as a final operation. This flag specifies whether the original function should be called or not.&lt;br /&gt;
* Once all the hooks have been called, SourceHook decides whether to call the original function. Another set of hooks are called directly after, called &amp;quot;post&amp;quot; hook handlers. You can specify whether each hook is a post or pre hook - it simply changes whether it's called before or after the original call is made.&lt;br /&gt;
* After you are done using a hook, you can safely remove it.&lt;br /&gt;
&lt;br /&gt;
For example, let's say you wanted to intercept log messages in VEngineServer. Observe the prototype:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
virtual void		LogPrint( const char *msg ) = 0;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a virtual, public function of a class we have an instance of (let's say in IVEngineServer *m_Engine) and that we have the header for. It can be intercepted.&lt;br /&gt;
&lt;br /&gt;
The first step is to figure out how to declare its prototype to SourceHook. This function is void, and has one parameter. The declaration macro follows these formats:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_DECL_HOOK}}n - n is the number of parameters&lt;br /&gt;
**The parameters are: Class name, member function name, attributes, overloaded?, the return type, and a list of the parameter types.&lt;br /&gt;
*{{bcode|SH_DECL_HOOKn_void}} - n is the number of parameters&lt;br /&gt;
**_void specifies that the function does not return a value. The format is the same as above except the &amp;quot;return type&amp;quot; parameter is missing.&lt;br /&gt;
*'''Note:''' Not covered here are the SH_DECL_HOOKn[_void]_vafmt hooks. These can hook string-formattable variable argument lists. You do not pass the string format or ellipses parameter. SourceHook will automatically format the string for your hook.&lt;br /&gt;
&lt;br /&gt;
Our macro will look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, 0, const char *);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This line must appear outside of a function. It means &amp;quot;Declare a hook prototype for LogPrint in IVEngineServer, which is a void function that has one parameter, which is a const char *&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Next we must actually hook the function. You can do this wherever you want to begin the interception. The two macros for hooking look like this:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_STATICFUNC}}(class, memberfunction, instance_pointer, handler, post) Hooks a virtual function to a static/global function.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - A pointer to an instance of the class&lt;br /&gt;
**handler - Your function that will be called on hooking&lt;br /&gt;
**post - true for post operation, false for pre operation&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_MEMFUNC}}(class, memberfunction, instance, myinstance, myfunction, post) Hooks a virtual function to a member function of another class.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - An pointer to an instance of the class&lt;br /&gt;
**myinstance - A pointer to an instance of the class that has the handler member function&lt;br /&gt;
**myfunction - The name of the handler member function in your class&lt;br /&gt;
**post - true for post operation, false for pre-operation&lt;br /&gt;
&lt;br /&gt;
Let's continue with the example. To hook LogPrint to a function in your class, CMetaHooks (instance, g_MetaHooks), you would use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine, &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To remove the hook (either once it will no longer be unused, or at unload time):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, your function contents will look something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void CMetaHooks::LogPrint(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note this return statement. This style of returning is similar to Metamod's, where you can set four different flags to indicate how you would like SourceHook to proceed. In Metamod, this return statement was required. In SourceMM, it is only required if you wish to set a return state other than MRES_IGNORED.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|MRES_IGNORED}} - No states were changed, act as though nothing happened. Original function is still called.&lt;br /&gt;
*{{bcode|MRES_HANDLED}} - Something changed, but the original function was still called. This can be used to tell another plugin that you did something.&lt;br /&gt;
*{{bcode|MRES_OVERRIDE}} - The original function will still be called, but your return value will override whatever it returns.&lt;br /&gt;
*{{bcode|MRES_SUPERCEDE}} - The original function is not called, and your return value will be what is returned to the caller.&lt;br /&gt;
&lt;br /&gt;
Note, that if you need to return a value, there is another macro. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RETURN_META_VALUE(MRES_SUPERCEDE, value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is required for non-void functions, athough the return value is ignored using MRES_IGNORED or MRES_HANDLED.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can hook to static member functions which has a slightly easier syntax. The DECL_HOOK line does not change. To add the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removing the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Declaring the handler:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void LogPrint_handler(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that vafmt functions hooked with SourceHook assume that the vafmt is for a printf style string, and that the vafmt occurs at the end. When setting the parameters, you do not include the '...' notation, and SourceHook will vafmt the input string for you (meaning you also don't specify ... in your hooked function).&lt;br /&gt;
&lt;br /&gt;
=Calling Original Functions=&lt;br /&gt;
Often it will be necessary for you to call a function that's hooked, however, you don't want the hooks to be included in the calling. For example, if you want to entirely supercede a function and call it yourself from within a hook. To do this, you must request a call class. This is similar to MDLL_x() from Metamod for Half-Life 1.&lt;br /&gt;
&lt;br /&gt;
Continuing with the above example, let's say we want to supercede the original call and log a different message. Assume we also have the pointer m_Engine which is a &amp;lt;tt&amp;gt;IVEngineServer *&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SourceHook::CallClass&amp;lt;IVEngineServer&amp;gt; *Engine_CC = SH_GET_CALLCLASS(m_Engine);&lt;br /&gt;
&lt;br /&gt;
SH_CALL(Engine_CC, &amp;amp;IVEngineServer::LogPrint)(&amp;quot;This is a log message!\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
//When you are done with the pointer..&lt;br /&gt;
SH_RELEASE_CALLCLASS(Engine_CC);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because of the complex nature of inheritance, instance pointers, and vtables, this syntax can be quite daunting. You may wish to make macros for specific functions or classes you use quite often, to reduce the amount of typing. For example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
//Assuming you have a global pointer g_Engine...&lt;br /&gt;
#define ENGCALL(func) SH_CALL(g_Engine, &amp;amp;IVEngineServer::func)&lt;br /&gt;
&lt;br /&gt;
//Then you can do:&lt;br /&gt;
ENGCALL(LogPrint)(&amp;quot;This is a test!&amp;quot;);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The syntax of calling class construction is:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SourceHook::CallClass&amp;lt;class&amp;gt; *ptr = SH_GET_CALLCLASS(instance);&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Returns an object which allows you to call the original function. Class is the name of the class which is the target, instance is an instance of that class.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_CALL(cc_ptr, &amp;amp;class::func)([params])&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Pass the pointer returned from SH_GET_CALLCLASS as cc_ptr. The target function you call must be passed as a pointer-to-member-function, which takes the form &amp;amp;Class::Function as seen in previous examples. You must then complete the function call by adding a parenthetical parameter expression, even for void functions, which would be ().&lt;br /&gt;
&lt;br /&gt;
=Other Macros=&lt;br /&gt;
All of the macros take g_PLAPI as the first parameter. For more information on this, see the global variables section.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|META_CONPRINT}}(const char *msg)&lt;br /&gt;
*{{bcode|META_CONPRINTF}}(const char *fmt, ...)&lt;br /&gt;
**These two functions are recommended over Msg() for printing to the server console. Msg() does not relay commands back through rcon, and as of this writing Valve does not expose the function which does. To be able to display text through the rcon console (much like HL1), you should use these functions. If SourceMM is unable to extract the function properly, it will automatically default to Msg.&lt;br /&gt;
*{{bcode|META_LOG}}(g_PLAPI, const char *msg, ...)&lt;br /&gt;
**Logs a message through IVEngineServer::LogPrint(). A newline is automatically added, and msg is formatted as a sprintf() style string.&lt;br /&gt;
*{{bcode|META_REGCVAR}}(var)&lt;br /&gt;
**Registers a ConCommandBase pointer through SourceMM. The correct way to use this is to create an IConCommandBaseAccessor, and inside RegisterConCommandBase, call the macro on the given ConComandBase. This will ensure that SourceMM correctly detects and unloads your cvars and concommands at the appopriate time. Otherwise, unloading your plugin will cause a crash.&lt;br /&gt;
*{{bcode|META_UNREGCVAR}}(var)&lt;br /&gt;
**Unregisters a ConCommandBase pointer. This is not needed if you have set up your IConCommandBaseAccessor correctly (and called ConCommandBaseMngr::OneTimeInit()).&lt;br /&gt;
&lt;br /&gt;
=Events System=&lt;br /&gt;
The Events System is based on IMetamodListener. By implementing the IMetamodListener class and using g_SMAPI-&amp;gt;AddListener, you can watch for certain, low-traffic events. These events are split into three categories:&lt;br /&gt;
&lt;br /&gt;
*Plugin Events let you listen for plugin pauses and unloads. This is important if you're relying on information from another plugin, as you can handle cases where a live plugin has become invalid.&lt;br /&gt;
*Game Events are simple events that SourceMM is already hooking and makes available. These are LevelShutdown and LevelInit right now.&lt;br /&gt;
*Query Events occur when a factory is used. The four main factories (Engine, GameDLL, FileSystem, and Physics) are all overridable. You should simply return a non-NULL result to override, and fill the return code with IFACE_OK if available. There is no way to handle the case of two plugins overriding right now. The final factory is the Metamod Factory, which is the factory that Metamod:Source adds to the runtime space for plugins. By default, it only contains the interfaces for the PluginManager and SourceHook. Plugins can use this to add new interfaces. Other plugins request these interfaces through g_SMAPI-&amp;gt;MetaFactory().&lt;br /&gt;
&lt;br /&gt;
=Global Variables=&lt;br /&gt;
These global variables are saved by PLUGIN_EXPOSE and PLUGIN_SAVEVARS. They are declared with PLUGIN_GLOBALVARS.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|g_PLAPI}}&lt;br /&gt;
**ISmmPlugin * pointer to your global class singleton.&lt;br /&gt;
*{{bcode|g_PLID}}&lt;br /&gt;
**The internal PluginId of your plugin.&lt;br /&gt;
*{{bcode|g_SHPtr}}&lt;br /&gt;
**The SourceHook::ISourceHook * pointer to SourceHook's interface.&lt;br /&gt;
*{{bcode|g_SMAPI}}&lt;br /&gt;
**The ISmmAPI * pointer to SourceMM's interface.&lt;br /&gt;
&lt;br /&gt;
=Compiling=&lt;br /&gt;
To see more about compiling, see the Sample Plugin Compiling section.&lt;br /&gt;
&lt;br /&gt;
Modifying the default Makefiles for your own projects:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;OPT_FLAGS&amp;lt;/tt&amp;gt; - Optimization flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;DEBUG_FLAGS&amp;lt;/tt&amp;gt; - Debug flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;CPP&amp;lt;/tt&amp;gt; - C++ Compiler&lt;br /&gt;
*&amp;lt;tt&amp;gt;OBJECTS&amp;lt;/tt&amp;gt; - List of C++ files to compile&lt;br /&gt;
*&amp;lt;tt&amp;gt;LINK&amp;lt;/tt&amp;gt; - Linker Options&lt;br /&gt;
*&amp;lt;tt&amp;gt;CFLAGS&amp;lt;/tt&amp;gt; - Base Compiler Flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;BINARY&amp;lt;/tt&amp;gt; - Output Binary Name&lt;br /&gt;
&lt;br /&gt;
Makefile commands:&lt;br /&gt;
&lt;br /&gt;
*clean - Cleans all build files&lt;br /&gt;
*debug - Builds debug version&lt;br /&gt;
&lt;br /&gt;
=1.1 Changes - Late Loading, Events=&lt;br /&gt;
SourceMM 1.1 changed quite a few things internally, and externally made many breaking changes. These include:&lt;br /&gt;
&lt;br /&gt;
*ISmmPlugin::Load() has removed the factory list parameter (the factory system was replaced with the event system). Also, a boolean parameter was added, specifying whether the plugin was loaded late or not.&lt;br /&gt;
*ISmmPlugin::Load() is now called BEFORE DLLInit(), rather than after. This means it might not have all information it needs -- for example, IGameEvents won't be parsed yet. You will need to do things like this in ISmmPlugin:AllPluginsLoaded() instead, as it is guaranteed to occur when all DLLs are initialized.&lt;br /&gt;
*ISmmPlugin now has default functions -- you don't have to implement all of them.&lt;br /&gt;
*SourceHook was modified to use interfaces rather than straight struct pointers. This breaking changes will ensure that future SourceHook modifications do not break older plugins.&lt;br /&gt;
*SourceHook was modified to be re-entrant.&lt;br /&gt;
*SourceHook now has a tiny template library with it. This removes the necessity to link against libstdc++.so.*, which harms binary compatibility across linux distributions.&lt;br /&gt;
*SourceMM's GameDLL code was completely rewritten. It will now work with newer mods much easier, and issues like the DoD:S release will be much easier to deal with (if at all). It also removes a few important speed bottlenecks.&lt;br /&gt;
*An events system was added.&lt;br /&gt;
&lt;br /&gt;
=1.2 Changes - Changing Parameters, Manual Hooking=&lt;br /&gt;
SourceMM 1.2 now supports changing the parameters in a hook chain. For example, say the GameDLL has a function called IGameDLL::PrintString(const char *str). You can hook this, let it continue, but change the &amp;quot;str&amp;quot; parameter passed in to the rest of the hooks and the GameDLL. To do this, use the following macros:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_VALUE_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
class ISomething&lt;br /&gt;
{&lt;br /&gt;
   virtual void Function1(int num) =0;&lt;br /&gt;
   virtual bool Function2(bool what, int hi) =0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyHook1(int num)&lt;br /&gt;
{&lt;br /&gt;
   //if num is 0, &lt;br /&gt;
   // we will change the num parameter in the rest of the hooks, and the gamedll, to be 1.&lt;br /&gt;
   if (num == 0)&lt;br /&gt;
       RETURN_META_NEWPARAMS(MRES_IGNORED, &amp;amp;ISomething::Function1, (1))&lt;br /&gt;
   RETURN_META(MRES_SUPERCEDE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool MyHook2(bool what, int hi)&lt;br /&gt;
{&lt;br /&gt;
   //change the &amp;quot;what&amp;quot; and &amp;quot;hi&amp;quot; parameters to be false and 3 respectively&lt;br /&gt;
   //also, return true, but specify that the value is ignored&lt;br /&gt;
   RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &amp;amp;ISomething::Function2, (false, 3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
SourceHook also supports manual hooking of functions. This means you must know the virtual table index, the virtual table offset (for polymorphism), and the &amp;quot;this&amp;quot; pointer offset. Luckily, the polymorphic offsets are usually zero. This type of hook is ideal when supporting different ABI, for example, across different gamedlls. The API is almost identical:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_DECL_MANUALHOOKn[_void|_vafamt]&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Declares the manual hook. A unique name must be given to each manual hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_[ADD|REMOVE]_MANUALHOOK_[STATIC|MEM]FUNC&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Adds or removes a static or member function hook on a manually declared hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_MANUALHOOK_RECONFIGURE&amp;lt;/tt&amp;gt; - &lt;br /&gt;
**Reconfigures the indexes and offsets of a manual hook.&lt;br /&gt;
&lt;br /&gt;
An example is below, using the ISomething class from above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SH_DECL_MANUALHOOK2(_M_Function1, 1, 0, 0, bool, bool, int);&lt;br /&gt;
&lt;br /&gt;
void OnLoad(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	//we reference the static function by its unique handle we gave it&lt;br /&gt;
	//the parameters are otherwise the same - this pointer, hook handler, and post/non-post&lt;br /&gt;
	SH_ADD_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void OnUnload(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	SH_REMOVE_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more examples of the above features, you can look in SourceHook CVS's [http://www.tcwonline.org/cgi-bin/viewcvs.cgi/sourcemm/sourcehook/test/ test suite], which demonstrates a variety of hooking scenarios.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceHook]]&lt;br /&gt;
[[Category:Documentation (SourceMM)]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2886</id>
		<title>Metamod:Source Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Metamod:Source_Development&amp;diff=2886"/>
		<updated>2006-04-17T19:37:10Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: Reverted edit of Eldron, changed back to last version by Belsebub&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article is an introduction to [[SourceMM]] coding.  &lt;br /&gt;
&lt;br /&gt;
{{qnotice|The majority of this documentation should be merged or moved into an article about [[SourceHook]].}}&lt;br /&gt;
&lt;br /&gt;
{{qnotice|This article probably needs some better formatting.}}&lt;br /&gt;
&lt;br /&gt;
=Requirements=&lt;br /&gt;
You must have the Valve [[HL2SDK]], available from your [[Steam]] Menu. For Windows, you must have [[Microsoft Visual Studio]] 7.0 or 7.1 (we have not tried 6.0). For [[Linux]], Valve requires you use at least [[GCC]] 3.4.1. You should also have a copy of the [[Metamod:Source]] source code, available [http://www.sourcemm.net/ here] (sourcemm/sourcehook and sourcemm/sourcemm).&lt;br /&gt;
&lt;br /&gt;
For [[Microsoft Visual Studio]], you should make sure that you have the following HL2SDK paths in your include settings (Tools -&amp;gt; Options -&amp;gt; Projects, VC++ Directories, Include Files), as well as the &amp;quot;sourcehook&amp;quot; and &amp;quot;sourcemm&amp;quot; folders:&lt;br /&gt;
*dlls&lt;br /&gt;
*public&lt;br /&gt;
*public\vstdlib&lt;br /&gt;
*public\tier1&lt;br /&gt;
*public\tier0&lt;br /&gt;
*public\engine&lt;br /&gt;
*public\dlls&lt;br /&gt;
*tier1&lt;br /&gt;
*lib\public (this should be in your Library Paths!)&lt;br /&gt;
&lt;br /&gt;
=Plugin API=&lt;br /&gt;
In order to write a plugin, you must implement the ISmmPlugin interface, similar to IServerPluginCallbacks. Each Metamod:Source release has a minimum required interface version and a current version. The minimum version is guaranteed to be upward compatible to the current, however, it may be lacking some features.&lt;br /&gt;
&lt;br /&gt;
Once you've implemented the interface, you must also have a global singleton of your plugin available. There are a few macros to assist you in properly exposing the interface as a DLL and setting up the API states.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|PLUGIN_GLOBALVARS}}() - Place in header. Declares the global variables that some API calls require (such as g_SHPtr and g_PLAPI).&lt;br /&gt;
*{{bcode|PLUGIN_EXPOSE}}(class, singleton) - Place in .cpp file. Declares the external CreateInterface function which exposes the API.&lt;br /&gt;
*{{bcode|PLUGIN_SAVEVARS}}() - Use first thing in ISmmPlugin::Load(), saves the global variables sent from SourceMM.&lt;br /&gt;
&lt;br /&gt;
The actual plugin API you must implement as of this writing is version 004. To see a description of each of the functions, you can view the doxygen information here. Note that the Load, Unload, Pause, and Unpause functions allow you to refuse the action and copy an error message (you should check to make sure error is not NULL - it can be).&lt;br /&gt;
&lt;br /&gt;
=SourceHook (Hooking)=&lt;br /&gt;
SourceHook is the engine used to intercept function calls, much like Metamod. The difference with SourceHook is that it can intercept any virtual function in any class that, at compile time, you have the header for. SourceHook has the following steps of operation:&lt;br /&gt;
&lt;br /&gt;
* Declare the prototype of the function you are going to hook. This generates compile-time code that is able to pinpoint exactly how to go about hooking the function.&lt;br /&gt;
* Hook the function - as a member function of another class or a regular static function.&lt;br /&gt;
* Before the hooked function is called, all of the &amp;quot;pre&amp;quot; hook handlers attached to it are called. Each hook can set a special flag, the highest of which is chosen as a final operation. This flag specifies whether the original function should be called or not.&lt;br /&gt;
* Once all the hooks have been called, SourceHook decides whether to call the original function. Another set of hooks are called directly after, called &amp;quot;post&amp;quot; hook handlers. You can specify whether each hook is a post or pre hook - it simply changes whether it's called before or after the original call is made.&lt;br /&gt;
* After you are done using a hook, you can safely remove it.&lt;br /&gt;
&lt;br /&gt;
For example, let's say you wanted to intercept log messages in VEngineServer. Observe the prototype:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
virtual void		LogPrint( const char *msg ) = 0;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a virtual, public function of a class we have an instance of (let's say in IVEngineServer *m_Engine) and that we have the header for. It can be intercepted.&lt;br /&gt;
&lt;br /&gt;
The first step is to figure out how to declare its prototype to SourceHook. This function is void, and has one parameter. The declaration macro follows these formats:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_DECL_HOOK}}n - n is the number of parameters&lt;br /&gt;
**The parameters are: Class name, member function name, attributes, overloaded?, the return type, and a list of the parameter types.&lt;br /&gt;
*{{bcode|SH_DECL_HOOKn_void}} - n is the number of parameters&lt;br /&gt;
**_void specifies that the function does not return a value. The format is the same as above except the &amp;quot;return type&amp;quot; parameter is missing.&lt;br /&gt;
*'''Note:''' Not covered here are the SH_DECL_HOOKn[_void]_vafmt hooks. These can hook string-formattable variable argument lists. You do not pass the string format or ellipses parameter. SourceHook will automatically format the string for your hook.&lt;br /&gt;
&lt;br /&gt;
Our macro will look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, 0, const char *);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This line must appear outside of a function. It means &amp;quot;Declare a hook prototype for LogPrint in IVEngineServer, which is a void function that has one parameter, which is a const char *&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Next we must actually hook the function. You can do this wherever you want to begin the interception. The two macros for hooking look like this:&lt;br /&gt;
&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_STATICFUNC}}(class, memberfunction, instance_pointer, handler, post) Hooks a virtual function to a static/global function.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - A pointer to an instance of the class&lt;br /&gt;
**handler - Your function that will be called on hooking&lt;br /&gt;
**post - true for post operation, false for pre operation&lt;br /&gt;
*{{bcode|SH_ADD_HOOK_MEMFUNC}}(class, memberfunction, instance, myinstance, myfunction, post) Hooks a virtual function to a member function of another class.&lt;br /&gt;
**class - The name of the class&lt;br /&gt;
**memberfunction - The name of the member function&lt;br /&gt;
**instance - An pointer to an instance of the class&lt;br /&gt;
**myinstance - A pointer to an instance of the class that has the handler member function&lt;br /&gt;
**myfunction - The name of the handler member function in your class&lt;br /&gt;
**post - true for post operation, false for pre-operation&lt;br /&gt;
&lt;br /&gt;
Let's continue with the example. To hook LogPrint to a function in your class, CMetaHooks (instance, g_MetaHooks), you would use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine, &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To remove the hook (either once it will no longer be unused, or at unload time):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, m_Engine &amp;amp;g_MetaHooks, &amp;amp;CMetaHooks::LogPrint, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, your function contents will look something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void CMetaHooks::LogPrint(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note this return statement. This style of returning is similar to Metamod's, where you can set four different flags to indicate how you would like SourceHook to proceed. In Metamod, this return statement was required. In SourceMM, it is only required if you wish to set a return state other than MRES_IGNORED.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|MRES_IGNORED}} - No states were changed, act as though nothing happened. Original function is still called.&lt;br /&gt;
*{{bcode|MRES_HANDLED}} - Something changed, but the original function was still called. This can be used to tell another plugin that you did something.&lt;br /&gt;
*{{bcode|MRES_OVERRIDE}} - The original function will still be called, but your return value will override whatever it returns.&lt;br /&gt;
*{{bcode|MRES_SUPERCEDE}} - The original function is not called, and your return value will be what is returned to the caller.&lt;br /&gt;
&lt;br /&gt;
Note, that if you need to return a value, there is another macro. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RETURN_META_VALUE(MRES_SUPERCEDE, value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is required for non-void functions, athough the return value is ignored using MRES_IGNORED or MRES_HANDLED.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can hook to static member functions which has a slightly easier syntax. The DECL_HOOK line does not change. To add the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_ADD_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removing the hook:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SH_REMOVE_HOOK_STATICFUNC(IVEngineServer, LogPrint, m_Engine, LogPrint_handler, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Declaring the handler:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void LogPrint_handler(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	//Code here&lt;br /&gt;
	RETURN_META(MRES_IGNORED);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that vafmt functions hooked with SourceHook assume that the vafmt is for a printf style string, and that the vafmt occurs at the end. When setting the parameters, you do not include the '...' notation, and SourceHook will vafmt the input string for you (meaning you also don't specify ... in your hooked function).&lt;br /&gt;
&lt;br /&gt;
=Calling Original Functions=&lt;br /&gt;
Often it will be necessary for you to call a function that's hooked, however, you don't want the hooks to be included in the calling. For example, if you want to entirely supercede a function and call it yourself from within a hook. To do this, you must request a call class. This is similar to MDLL_x() from Metamod for Half-Life 1.&lt;br /&gt;
&lt;br /&gt;
Continuing with the above example, let's say we want to supercede the original call and log a different message. Assume we also have the pointer m_Engine which is a &amp;lt;tt&amp;gt;IVEngineServer *&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SourceHook::CallClass&amp;lt;IVEngineServer&amp;gt; *Engine_CC = SH_GET_CALLCLASS(m_Engine);&lt;br /&gt;
&lt;br /&gt;
SH_CALL(Engine_CC, &amp;amp;IVEngineServer::LogPrint)(&amp;quot;This is a log message!\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
//When you are done with the pointer..&lt;br /&gt;
SH_RELEASE_CALLCLASS(Engine_CC);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because of the complex nature of inheritance, instance pointers, and vtables, this syntax can be quite daunting. You may wish to make macros for specific functions or classes you use quite often, to reduce the amount of typing. For example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
//Assuming you have a global pointer g_Engine...&lt;br /&gt;
#define ENGCALL(func) SH_CALL(g_Engine, &amp;amp;IVEngineServer::func)&lt;br /&gt;
&lt;br /&gt;
//Then you can do:&lt;br /&gt;
ENGCALL(LogPrint)(&amp;quot;This is a test!&amp;quot;);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The syntax of calling class construction is:&lt;br /&gt;
*&amp;lt;tt&amp;gt;SourceHook::CallClass&amp;lt;class&amp;gt; *ptr = SH_GET_CALLCLASS(instance);&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Returns an object which allows you to call the original function. Class is the name of the class which is the target, instance is an instance of that class.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_CALL(cc_ptr, &amp;amp;class::func)([params])&amp;lt;/tt&amp;gt;&lt;br /&gt;
**Pass the pointer returned from SH_GET_CALLCLASS as cc_ptr. The target function you call must be passed as a pointer-to-member-function, which takes the form &amp;amp;Class::Function as seen in previous examples. You must then complete the function call by adding a parenthetical parameter expression, even for void functions, which would be ().&lt;br /&gt;
&lt;br /&gt;
=Other Macros=&lt;br /&gt;
All of the macros take g_PLAPI as the first parameter. For more information on this, see the global variables section.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|META_CONPRINT}}(const char *msg)&lt;br /&gt;
*{{bcode|META_CONPRINTF}}(const char *fmt, ...)&lt;br /&gt;
**These two functions are recommended over Msg() for printing to the server console. Msg() does not relay commands back through rcon, and as of this writing Valve does not expose the function which does. To be able to display text through the rcon console (much like HL1), you should use these functions. If SourceMM is unable to extract the function properly, it will automatically default to Msg.&lt;br /&gt;
*{{bcode|META_LOG}}(g_PLAPI, const char *msg, ...)&lt;br /&gt;
**Logs a message through IVEngineServer::LogPrint(). A newline is automatically added, and msg is formatted as a sprintf() style string.&lt;br /&gt;
*{{bcode|META_REGCVAR}}(var)&lt;br /&gt;
**Registers a ConCommandBase pointer through SourceMM. The correct way to use this is to create an IConCommandBaseAccessor, and inside RegisterConCommandBase, call the macro on the given ConComandBase. This will ensure that SourceMM correctly detects and unloads your cvars and concommands at the appopriate time. Otherwise, unloading your plugin will cause a crash.&lt;br /&gt;
*{{bcode|META_UNREGCVAR}}(var)&lt;br /&gt;
**Unregisters a ConCommandBase pointer. This is not needed if you have set up your IConCommandBaseAccessor correctly (and called ConCommandBaseMngr::OneTimeInit()).&lt;br /&gt;
&lt;br /&gt;
=Events System=&lt;br /&gt;
The Events System is based on IMetamodListener. By implementing the IMetamodListener class and using g_SMAPI-&amp;gt;AddListener, you can watch for certain, low-traffic events. These events are split into three categories:&lt;br /&gt;
&lt;br /&gt;
*Plugin Events let you listen for plugin pauses and unloads. This is important if you're relying on information from another plugin, as you can handle cases where a live plugin has become invalid.&lt;br /&gt;
*Game Events are simple events that SourceMM is already hooking and makes available. These are LevelShutdown and LevelInit right now.&lt;br /&gt;
*Query Events occur when a factory is used. The four main factories (Engine, GameDLL, FileSystem, and Physics) are all overridable. You should simply return a non-NULL result to override, and fill the return code with IFACE_OK if available. There is no way to handle the case of two plugins overriding right now. The final factory is the Metamod Factory, which is the factory that Metamod:Source adds to the runtime space for plugins. By default, it only contains the interfaces for the PluginManager and SourceHook. Plugins can use this to add new interfaces. Other plugins request these interfaces through g_SMAPI-&amp;gt;MetaFactory().&lt;br /&gt;
&lt;br /&gt;
=Global Variables=&lt;br /&gt;
These global variables are saved by PLUGIN_EXPOSE and PLUGIN_SAVEVARS. They are declared with PLUGIN_GLOBALVARS.&lt;br /&gt;
&lt;br /&gt;
*{{bcode|g_PLAPI}}&lt;br /&gt;
**ISmmPlugin * pointer to your global class singleton.&lt;br /&gt;
*{{bcode|g_PLID}}&lt;br /&gt;
**The internal PluginId of your plugin.&lt;br /&gt;
*{{bcode|g_SHPtr}}&lt;br /&gt;
**The SourceHook::ISourceHook * pointer to SourceHook's interface.&lt;br /&gt;
*{{bcode|g_SMAPI}}&lt;br /&gt;
**The ISmmAPI * pointer to SourceMM's interface.&lt;br /&gt;
&lt;br /&gt;
=Compiling=&lt;br /&gt;
To see more about compiling, see the Sample Plugin Compiling section.&lt;br /&gt;
&lt;br /&gt;
Modifying the default Makefiles for your own projects:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;OPT_FLAGS&amp;lt;/tt&amp;gt; - Optimization flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;DEBUG_FLAGS&amp;lt;/tt&amp;gt; - Debug flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;CPP&amp;lt;/tt&amp;gt; - C++ Compiler&lt;br /&gt;
*&amp;lt;tt&amp;gt;OBJECTS&amp;lt;/tt&amp;gt; - List of C++ files to compile&lt;br /&gt;
*&amp;lt;tt&amp;gt;LINK&amp;lt;/tt&amp;gt; - Linker Options&lt;br /&gt;
*&amp;lt;tt&amp;gt;CFLAGS&amp;lt;/tt&amp;gt; - Base Compiler Flags&lt;br /&gt;
*&amp;lt;tt&amp;gt;BINARY&amp;lt;/tt&amp;gt; - Output Binary Name&lt;br /&gt;
&lt;br /&gt;
Makefile commands:&lt;br /&gt;
&lt;br /&gt;
*clean - Cleans all build files&lt;br /&gt;
*debug - Builds debug version&lt;br /&gt;
&lt;br /&gt;
=1.1 Changes - Late Loading, Events=&lt;br /&gt;
SourceMM 1.1 changed quite a few things internally, and externally made many breaking changes. These include:&lt;br /&gt;
&lt;br /&gt;
*ISmmPlugin::Load() has removed the factory list parameter (the factory system was replaced with the event system). Also, a boolean parameter was added, specifying whether the plugin was loaded late or not.&lt;br /&gt;
*ISmmPlugin::Load() is now called BEFORE DLLInit(), rather than after. This means it might not have all information it needs -- for example, IGameEvents won't be parsed yet. You will need to do things like this in ISmmPlugin:AllPluginsLoaded() instead, as it is guaranteed to occur when all DLLs are initialized.&lt;br /&gt;
*ISmmPlugin now has default functions -- you don't have to implement all of them.&lt;br /&gt;
*SourceHook was modified to use interfaces rather than straight struct pointers. This breaking changes will ensure that future SourceHook modifications do not break older plugins.&lt;br /&gt;
*SourceHook was modified to be re-entrant.&lt;br /&gt;
*SourceHook now has a tiny template library with it. This removes the necessity to link against libstdc++.so.*, which harms binary compatibility across linux distributions.&lt;br /&gt;
*SourceMM's GameDLL code was completely rewritten. It will now work with newer mods much easier, and issues like the DoD:S release will be much easier to deal with (if at all). It also removes a few important speed bottlenecks.&lt;br /&gt;
*An events system was added.&lt;br /&gt;
&lt;br /&gt;
=1.2 Changes - Changing Parameters, Manual Hooking=&lt;br /&gt;
SourceMM 1.2 now supports changing the parameters in a hook chain. For example, say the GameDLL has a function called IGameDLL::PrintString(const char *str). You can hook this, let it continue, but change the &amp;quot;str&amp;quot; parameter passed in to the rest of the hooks and the GameDLL. To do this, use the following macros:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
*&amp;lt;tt&amp;gt;RETURN_META_VALUE_NEWPARAMS&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
class ISomething&lt;br /&gt;
{&lt;br /&gt;
   virtual void Function1(int num) =0;&lt;br /&gt;
   virtual bool Function2(bool what, int hi) =0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyHook1(int num)&lt;br /&gt;
{&lt;br /&gt;
   //if num is 0, &lt;br /&gt;
   // we will change the num parameter in the rest of the hooks, and the gamedll, to be 1.&lt;br /&gt;
   if (num == 0)&lt;br /&gt;
       RETURN_META_NEWPARAMS(MRES_IGNORED, &amp;amp;ISomething::Function1, (1))&lt;br /&gt;
   RETURN_META(MRES_SUPERCEDE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
bool MyHook2(bool what, int hi)&lt;br /&gt;
{&lt;br /&gt;
   //change the &amp;quot;what&amp;quot; and &amp;quot;hi&amp;quot; parameters to be false and 3 respectively&lt;br /&gt;
   //also, return true, but specify that the value is ignored&lt;br /&gt;
   RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &amp;amp;ISomething::Function2, (false, 3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
SourceHook also supports manual hooking of functions. This means you must know the virtual table index, the virtual table offset (for polymorphism), and the &amp;quot;this&amp;quot; pointer offset. Luckily, the polymorphic offsets are usually zero. This type of hook is ideal when supporting different ABI, for example, across different gamedlls. The API is almost identical:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_DECL_MANUALHOOKn[_void|_vafamt]&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Declares the manual hook. A unique name must be given to each manual hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_[ADD|REMOVE]_MANUALHOOK_[STATIC|MEM]FUNC&amp;lt;/tt&amp;gt; -&lt;br /&gt;
**Adds or removes a static or member function hook on a manually declared hook.&lt;br /&gt;
*&amp;lt;tt&amp;gt;SH_MANUALHOOK_RECONFIGURE&amp;lt;/tt&amp;gt; - &lt;br /&gt;
**Reconfigures the indexes and offsets of a manual hook.&lt;br /&gt;
&lt;br /&gt;
An example is below, using the ISomething class from above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
SH_DECL_MANUALHOOK2(_M_Function1, 1, 0, 0, bool, bool, int);&lt;br /&gt;
&lt;br /&gt;
void OnLoad(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	//we reference the static function by its unique handle we gave it&lt;br /&gt;
	//the parameters are otherwise the same - this pointer, hook handler, and post/non-post&lt;br /&gt;
	SH_ADD_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void OnUnload(ISomething *pSomething)&lt;br /&gt;
{&lt;br /&gt;
	SH_REMOVE_MANUALHOOK_STATICFUNC(_M_Function1, pSomething, MyHook1, false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more examples of the above features, you can look in SourceHook CVS's [http://www.tcwonline.org/cgi-bin/viewcvs.cgi/sourcemm/sourcehook/test/ test suite], which demonstrates a variety of hooking scenarios.&lt;br /&gt;
&lt;br /&gt;
[[Category:SourceHook]]&lt;br /&gt;
[[Category:Documentation (SourceMM)]]&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Category:Translations&amp;diff=2877</id>
		<title>Category:Translations</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Category:Translations&amp;diff=2877"/>
		<updated>2006-04-04T21:21:18Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Translations of pages and related information.&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Category:Russian&amp;diff=2876</id>
		<title>Category:Russian</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Category:Russian&amp;diff=2876"/>
		<updated>2006-04-04T21:20:53Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Russian translations of pages&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.alliedmods.net/index.php?title=Ru_Alternative_Language&amp;diff=2875</id>
		<title>Ru Alternative Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.alliedmods.net/index.php?title=Ru_Alternative_Language&amp;diff=2875"/>
		<updated>2006-04-04T21:20:22Z</updated>

		<summary type="html">&lt;p&gt;CyberMind: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Translations]]&lt;br /&gt;
[[Category:Russian]]&lt;br /&gt;
&lt;br /&gt;
Если вы хотите писать документацию на другом языке, отличном от Английского. Пожалуйста, начните отсюда. Любое содержимое на любом языке приветствуется.&lt;br /&gt;
&lt;br /&gt;
Другие языки не обязаны быть '''зеркалом''' английской документации. Перевод всегда приветствуется, но и новое содержимое приветствуется тоже.&lt;br /&gt;
&lt;br /&gt;
= Выбор языка =&lt;br /&gt;
&lt;br /&gt;
Переключение осуществляется подставлением кода прификса языка.&lt;br /&gt;
&lt;br /&gt;
* [[Alternative_Language|English]]&lt;br /&gt;
* [[ru:Alternative_Language|Russian]]&lt;br /&gt;
&lt;br /&gt;
Быстрый и эффективный путь добавления переключателя нового языка это использование&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{LanguageSwitch}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
где-нибудь в темплейте. Рекомендуется вверху или в самом низу. Этот код добавит маленькое меню, которое выглядит как это:&lt;br /&gt;
{{LanguageSwitch}}&lt;br /&gt;
&lt;br /&gt;
Когда новый язык добавлен в wiki, данный темплейт будет изменен автоматически. Таким образом, все страницы использующие его. Автоматически будут обновлены.&lt;br /&gt;
&lt;br /&gt;
= Как перевести страницу =&lt;br /&gt;
&lt;br /&gt;
1) Идите на ту страницу, которую хотите перевести.&lt;br /&gt;
&lt;br /&gt;
2) Выберите править (вверху страницы) и добавьте переключатель языка наверху, если его еще нет.&lt;br /&gt;
&lt;br /&gt;
3) Скопируйте весь текст темплейта страницы.&lt;br /&gt;
&lt;br /&gt;
4) Сохраните (чтобы сохранился переключатель языка)&lt;br /&gt;
&lt;br /&gt;
5) Теперь вверху страницы должен появиться переключатель языка, как на этой странице.&lt;br /&gt;
&lt;br /&gt;
6) Выберите(нажмите) на язык, который вы хотите перевести.&lt;br /&gt;
&lt;br /&gt;
7) Вставьте текст, который вы скопировали в текстовую область&lt;br /&gt;
&lt;br /&gt;
8) Начинайте перевод. Затем как закончите нужно сохранить, что вы перевели.&lt;br /&gt;
&lt;br /&gt;
Данные манипуляции дадут вам полную версию текущего документа на вашем языке. И вы можете переводить любую страницу, какую захотите.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Ресурсы:'''&lt;br /&gt;
&lt;br /&gt;
* Список 2'х буквенных кодов языков можно посмотреть тут http://www.w3.org/WAI/ER/IG/ert/iso639.htm&lt;/div&gt;</summary>
		<author><name>CyberMind</name></author>
		
	</entry>
</feed>