Author Topic: The Absolute Beginner's Guide to Pawn (w/ examples)  (Read 19179 times)

0 Members and 1 Guest are viewing this topic.

Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
The Absolute Beginner's Guide to Pawn (w/ examples)
« on: April 24, 2011, 08:45:28 am »
NOTE
This topic is locked to prevent people from ruining the succession of posts while the guide is being written. PM any errors or suggestions to stormeus.

The Absolute Beginner's
Guide to Pawn

« Last Edit: February 11, 2012, 07:32:57 pm by stormeus »
Do not PM me for support.




Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
The Absolute Beginner's Guide to Pawn, Part I
« Reply #1 on: April 24, 2011, 08:45:53 am »
Part I
Concepts of Pawn

Welcome to the absolute beginner's guide to Pawn! Before you can get into the nooks and crannies of Pawn, first we have to learn about the concepts of Pawn and programming in General.

Introduction
Pawn is an embeddable programming language and has a C-like syntax. Pawn was designed as an embeddable programming language, and is now used by projects like AMX Mod X, SA:MP, and, of course, VC:MP. Pawn scripts need to be compiled, or translate source code into computer-readable instructions. Pawn scripts have a structured flow, which means instructions are run one after another, but control statements can change what instructions come next.

The Compiler
The compiler translates source code into computer-readable code which will get run by the server. To use the compiler, you can download Pawno from the SA:MP server package, then go to Build > Compile. I recommend you use Pawno for this tutorial series so you can compile your test scripts and get compiler feedback if anything's wrong with the code.

Basic Program Structure
A very basic "Hello World" Pawn script would look like this:
Code: [Select]
main()
{
    print("Hello World!");
}

The main() function is the entry-point for the script, or where the program starts. The print() function writes a line of text in the console. The main() function doesn't concern us much in VC:MP scripting, but is good for printing script copyrights.

Note how the end of the Hello World line ends with a semicolon (;), but the rest of the code does not. That is because semicolons define where commands end, whereas control flow contains commands.

Variables
Variables are placeholders for information that a script can use, and can be changed at any time by the script. Variables are given names so we can not only get the variable's value, but so that we can also change it later if we need to. Variables can be assigned types so that their values can only be of a given type. Some common types are:

  • Integer: Sometimes represented as int, this is any integer or "whole" number.
  • Float: Stores decimals and any real number
  • Character: Or char, stores a letter, number, or punctuation. Arrays of characters create strings.

The only type that needs to be explicitly declared is a float. Otherwise, Pawn will assume that a variable is an integer, and that arrays are either strings or arrays of integers. However, variables still need to be declared at some point in the script. A variable declaration consists of the word new, followed by the name of the variable, and a semicolon. For example:

  • new myInt; defines a new integral variable named "myInt"
  • new Float:myFloat; defines a new floating point number named "myFloat" -- note the Type: prefix.

Boolean
Boolean algebra is when a mathematical expression is evaluated as either true or false. Therefore, a boolean value can only have one of two values: true or false. However, it evaluates entire expressions. Let's take a few expressions into consideration.

If I were to say 3 < (is less than) 6, obviously the statement is true.
If I were to say I am 5' 9" tall, this statement is also true.

However, if I were to say I am 5' 9" tall AND I am President of the United States, boolean logic states that the ENTIRE expression is false. While it may be true that I am 5' 9", I am not the President. Therefore, the entire expression is false.

A similar sentence: I am 5' 9" tall OR I am President of the United States.
Since only one part of the sentence has to be true, the entire sentence is considered true.

Note
0 is considered false, and 1 is considered true.

Boolean Operators
There are three boolean operators: AND, OR, and NOT. In Pawn:

  • AND is written as &&
  • OR is written as ||
  • NOT is written as !

Boolean operators are evaluated like so. For AND, the combination of two "True" values results in "True" while two "False" values results in "True." Any other combinations returns False. For example:

True AND True is true.
True AND False is false.
False AND True is false.
False AND False is true.

For OR, as long as one value is true, the entire statement is true.

True OR True is true.
True OR False is true.
False OR False is false.
False OR True is true.

The AND operator negates the value of an expression.
NOT True is false.
NOT False is true.

Comparison Operators
Boolean expressions most often involve comparison operators to see if they are true or false. These operators are equal to, greater than (or equal to), less than (or equal to), and not equal. In Pawn:

  • Equal to is written as ==
  • Less than is written as <
  • Greater than is written as >
  • Less than or equal to is written as <=
  • Greater than or equal to is written as >=
  • Inequality is written as !=

Comparison operators form expressions that can be evaluated as true or false. For example, Number_of_Students > 30. IF there are more than 30 students in the class, the entire expression is true. Otherwise, it is false.

Combining Boolean and Comparison Operators
We've looked at how boolean and comparison operators work to form expressions. Now, we'll look at how we can combine them to form more complex expressions.

If we wanted to know if there were more than 30 students in a class and if there were more than 30 seats, we could express this as:
Number_of_Students > 30 && Number_of_Seats > 30

Pawn has to determine the boolean (true/false) value of each expression, then use those values to evaluate the expression as a whole. Let's say we declare two new variables:
Code: [Select]
new Number_of_Students = 35;
new Number_of_Seats = 38;

Pawn will break this down into 35 > 30 && 38 > 30, which then evaluates to TRUE && TRUE. Therefore, the entire expression is true. The following example uses the following assumptions:

  • All employees work in a department.
  • All employees in department 5 have salaries greater than $25,000
  • Alice is an employee in department 5

Consider the truth of these few expressions:

Alice_salary < 25000 && Alice_department == 5
Alice_salary < 25000 is False. Alice_department == 5 is true. False && True is false.

!Alice_salary < 25000
Alice_salary < 25000 is false. NOT FALSE is true.

Appendix I: Mathematical Operators
Pawn offers mathematical operators as well if you wish to do math with scripts, which will come in handy a lot.
Note that "var" is shorthand for variable.

var + var - Addition
var - var - Subtraction
var * var - Multiplication
var / var - Division
var ^ power - Exponentiation
dividend % divisor - Modulus

variable += number - Adds number to variable and saves in variable
variable *= number - Multiplies number to variable and saves in variable
variable -= number - Subtracts number from variable and saves in variable
variable /= number - Divides number into variable and saves in variable

Appendix II: Comments
Comments allow you to make notes in your code to explain to people who might view it, including yourself, what a piece of code does. Comments can be one line long: one-line comments start with // and continue until the line ends. Multi-line comments begin with /* and end with */ and last between the two markers. Anything that is commented is NOT run or compiled.

Examples:
// One-line long comment
/* Multi
 * line
 * comment
 */
« Last Edit: April 25, 2011, 02:14:20 am by stormeus »
Do not PM me for support.




Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
The Absolute Beginner's Guide to Pawn, Part II
« Reply #2 on: April 24, 2011, 12:07:10 pm »
Part II
Control Structures

Introduction
Control flow is the order that Pawn (and any programming language) runs instructions and functions in. The use of loops and switch blocks can change the flow of a program, and repeat a piece of code or execute code specific to an expression.

If, Else If, Else
Toward the end of Part I, we learned about boolean algebra and comparison operators. Here's how such expressions would be used in Pawn. If, Else If, and Else are control statements, which "control" which pieces of code are run. For example, we might want a piece of code to run only if certain conditions are met.

Going back to our previous example with Alice, let's say we want to see how much a department should be paid based on the department ID. If we say new department is equal to 5, employees should be paid at least $25,000. If they're in department 3, they get paid more than $50,000. Otherwise, they should be paid exactly $40,000. In our main function, we have this so far:

Code: [Select]
main()
{
new department = 5;
}

This still doesn't tell us how much an employee should be paid in department 5, so we'll come back to this example.

The standard syntax for an if/else statement is:
Code: [Select]
if(expression)
{
// Expression is true.
// <code to run>
}
else if(expression)
{
// Other expression is true.
// <code to run>
}
else
{
// Neither are true.
// <code to run>
}

Keep in mind that you can have multiple else if statements in one conditional block and that else if statements are optional. Using this and our comparison operators, we can now make a conditional block to see how much a department gets paid, like so:

Code: [Select]
main()
{
new department = 5;
if(department == 5)
{
print("Employees get paid at least $25,000.");
}
else if(department == 3)
{
print("Employees get paid more than $50,000.");
}
else
{
print("Employees get paid exactly $40,000.");
}
}

For/While Loops and Switch
As well as conditional blocks of code, we can also run a piece of code as long as a given condition is true. For example, let's say we have a list of departments and we want to see how much each department is paid:

  • Department 1 - $10,000
  • Department 2 - $20,000
  • Department 3 - $30,000
  • Department 4 - $40,000
  • Department 5 - $50,000

If we wanted to go through each department, we could use a for or while loop. Let's start with the for loop.

The for loop looks a little something like this:
Code: [Select]
for(variable = counter; condition; counter++)
{
// <code>
}

Let's break this down.
variable is the variable we want to use as our counter. You can also declare a new variable inline like this:
Code: [Select]
for(new i = [...]

counter is the number we want to start counting from. Usually this is 0. In our case, it's 1.
condition is a condition we want to fulfill. As long as it's true, the for loop will run.
counter++ increments the counter by one. This can also be counter-- to reduce the counter by one.

In the end we get something like this:
Code: [Select]
for(new i = 1; i < 5; i++)
{
// <code>
}

With 1 being the first department and 5 being the last. Here's where we're also going to introduce switch blocks. Switch blocks consist of a variable and multiple "cases," which are one line long each. Each case is a possible value for the variable, and a default case can be used if none match.

Syntax for switch blocks
Code: [Select]
switch(variable)
{
case <case>:
// <one line of code>
case <case>:
// <one line of code>
default:
// <one line of code>
}

With each case being a possible value for variable. Now, let's say we want to get the payroll of a department, between 1 and 5. Here's how our switch block would look:

Code: [Select]
switch(i)
{
case 1:
print("Department 1 gets paid $10,000");
case 2:
print("Department 2 gets paid $20,000");
case 3:
print("Department 3 gets paid $30,000");
case 4:
print("Department 4 gets paid $40,000");
case 5:
print("Department 5 gets paid $50,000");
default:
print("Unknown department.");
}

After placing this in our for block, we get this:
Code: [Select]
for(new i = 1; i < 5; i++)
{
switch(i)
{
case 1:
print("Department 1 gets paid $10,000");
case 2:
print("Department 2 gets paid $20,000");
case 3:
print("Department 3 gets paid $30,000");
case 4:
print("Department 4 gets paid $40,000");
case 5:
print("Department 5 gets paid $50,000");
default:
print("Unknown department.");
}
}

Which will go through each department and print their payroll in the console, or "Unknown department." if the department does not exist. This same result can be achieved with a while loop, which executes a piece of code while a certain expression is true.

Syntax of a while loop
Code: [Select]
while(condition)
{
// <code here>
}

If we declare a variable named i and set it to 1, a while loop could be used like so:

Code: [Select]
new i = 1;
while(i < 5)
{
switch(i)
{
case 1:
print("Department 1 gets paid $10,000");
case 2:
print("Department 2 gets paid $20,000");
case 3:
print("Department 3 gets paid $30,000");
case 4:
print("Department 4 gets paid $40,000");
case 5:
print("Department 5 gets paid $50,000");
default:
print("Unknown department.");
}
i++;
}

With the i++; placed at the end to add 1 to the variable i so we don't have an endless loop, which can lead to memory leaks or crashes.
Do not PM me for support.




Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
The Absolute Beginner's Guide to Pawn, Part III
« Reply #3 on: April 25, 2011, 02:09:41 am »
Part III
Arrays and Strings

Introduction
Arrays are like variables, except that they allow you to store more than one value in a given variable while only using one reference. Imagine a variable as a box that can hold a certain type. An array would be the equivalent of that same box divided into multiple pieces, each piece containing a piece of data. Of course, since the array box stores more information than the single variable box, it is bigger, so it uses more memory.

Array Indexes
We can use the same name to get the value of a part in the array, but we need a way to differentiate between each cell, or part, of the array. To do this, we use a zero-index in the array. Let's say we have an array that's 100 cells large. The zero-index, as you might assume, starts at zero, so our first value is myArray[0], and the 100th value is myArray[99]. The fifth value is myArray[4], so think of it as myArray[item number - 1].

Creating Arrays
Arrays are declared similarly to regular variables, except we specify how many array cells we want to use. Unlike the zero-index, when you create the array, you specify exactly how many cells you want to use, i.e. new myArray[10] for an array named myArray 10 cells long.

Using Array Cells
Once you have declared an array, you can use an array index to both store and get information stored in that cell. Right now, we can only store integers and floats in our arrays. Strings and characters will come later. Let's say we want to, like our last example, set the payrolls of each department into an array, with payrollArray[0] reserved for department 1, payrollArray[1] for department 2, etc. First, instantiate (create) a new array with new payrollArray[5];

Given that we know each department's payroll is $10,000 times the department ID, we can use our mathematical operators, a for loop, and our array. We've declared our array, so now let's create our for loop to iterate through each department, starting at 1 and ending at 5.

Code: [Select]
// Declare our new array
new payrollArray[5];

// Iterate through each department.
for(new i = 1; i < 5; i++)
{
// <code here>
}

However, this still doesn't store each department's payroll in the array. Trying to compile this will result in an array something like payrollArray is unused. Since our array starts at index 0 while our department IDs start at 1, we can subtract 1 from the department ID to get the array index that goes with it. Array indexes, as long as they're integral, are valid, so mathematical expressions can also be array indexes, like so: payrollArray[i - 1]; with i - 1 being the array index (DepartmentID - 1). If i was 1, the index would be 0, which is valid, so let's use this to our advantage.

We also know that our payroll is $10,000 times the department ID, so whatever the cell is, it will be equal to the department ID * 10000 (note that there are NO commas in numbers).

Code: [Select]
// Declare our new array.
new payrollArray[5];

// Iterate through each department.
for(new i = 1; i < 5; i++)
{
// i - 1 = DepartmentID - 1, for our zero-indexed array
payrollArray[i - 1] = i * 10000; // Department ID * 10000
}

We can now get the payroll from this array by using payrollArray[ID - 1]

Strings
A string is simply an array of characters (letters and punctuation) which, when put together, form a sentence, phrase, word, etc. Since they are arrays, they work similar to integral arrays, except each cell is one letter or punctuation mark. In addition, the last character in the string has to be a null character (\0), which tells the computer when the string ends. Strings can be as long or longer than the sentence that they hold. For example, the following sentence is 12 characters long:

I like pie.

It consists of 11 letters and punctuation marks, plus the null character at the end. myString[12] would work for it. myString[25] would work too. However, myString[11] is invalid. Each cell is going to be one letter, thus:

myString[0] = "I"
myString[1] = " "
myString[4] = "k"

Strings can also be formatted using the format() function, which will be described in further detail later. Entire strings can be created at once as well. If we want to use our "I like pie." sentence for our string, we first have to declare our new array.

new myString[12];

Instead of saving to individual cells, we can instead reference just the variable, then place the sentence inside a string, enclosed by double quotes (""). For example:

myString = "I like pie."

This will automatically include the null character at the end.
« Last Edit: April 25, 2011, 02:17:10 am by stormeus »
Do not PM me for support.




Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
Re: The Absolute Beginner's Guide to Pawn (w/ examples)
« Reply #4 on: October 29, 2011, 06:55:20 pm »
Part IV
Basic Functions/Constructs

Introduction
Well, what is a function? A function, according to Wikipedia, is "a portion of code within a larger program that performs a specific task and is relatively independent of the remaining code." In other words, a function performs a specific task without relying as much on the other code.

Functions are useful, as they allow you to perform repetitive tasks in one line of code instead of ten. For example, instead of using this code in dozens of different places:
Code: [Select]
new a = 1;
new b = a;
new c = b;
new d = a;
print(d + c + b + a);

I could make a function and use that instead. That said, let's look at how a function is made.

Public Functions
Public functions are the heart of VC:MP scripts, since they're functions that can be called from anywhere else in the script. However, a public function has to return a value. Returning just means going back to the code that was being called when the function was used. Returning a value passes something back to the code that used the function.

A public function is also usually forwarded, to let the compiler know that a public function with that name and header. To declare a public function, you'd use a line of code something like this:
[pawn]
public myFunction( <parameters> ) { return 1; }
[/pawn]

myFunction can be any name you want. Don't forget, you need to return something, since it's required by Pawn. You can use parameters, but they're optional. Parameters work like variables that are given to the function to work with. For example, you might need a player's ID to kick them.

[pawn]
public myKickFunction( playerid )
{
    Kick( playerid );
    return 1;
}
[/pawn]

And to forward this, you'd have this line of code before the function:
[pawn]
forward myKickFunction( playerid );
[/pawn]

Or
[pawn]
forward myFunction( playerid );
[/pawn]

Stock Functions
Stock functions are like public functions, except:
  • They don't need to be forwarded
  • The compiler only includes them in the script if it's actually used
  • They don't need to return anything, but they can

Stock functions are useful for includes as the compiler will not actually compile that function if it's not used. A stock function is declared like a public function:
[pawn]
stock myFunction( <parameters> )
{
}
[/pawn]

Default Parameters
In a function, you can have a default value for a parameter in a function. You would list your parameters like usual, but like a variable, you would set it equal to something. The only difference is it's in the middle of a function and you don't need the new keyword. For example:
[pawn]
stock myFunction( a, b, c = 2 )
{
}
[/pawn]

We need to tell the function what a and b are, but it will automatically know that c is 2. Both of the following examples are, as a result, valid.

[pawn]
myFunction( 1, 3 );
[/pawn]

a will be 1, b will be 3, and c will default to 3. We can also do:

[pawn]
myFunction( 1, 3, 5 );
[/pawn]

Which is like the example above, except now c can be 5.

Strings as Parameters
Strings can be used as parameters, and are declared like any other parameter, except for the fact that you need to use [] after their variable name, like so:

[pawn]public myFunction( string[], number ) { }[/pawn]

Floats as Parameters
You can require a float (floating-point number, or decimal number) to be used as a parameter simply by adding Float: before their variable name, like so:

[pawn]public myFunction( string[], number, Float:decimal ) { }[/pawn]

This will require that decimal be type float.

Non-Special Functions
These are essentially the same as public and stock functions, except they don't need any keywords. These functions would be declared like so:
[pawn]
myFunction( <parameters> )
{
}
[/pawn]

They act like public functions, except they don't need to be forwarded, and can't be used by timers.
However, any VC:MP function that starts with On needs to be public.
Do not PM me for support.




Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
Re: The Absolute Beginner's Guide to Pawn (w/ examples)
« Reply #5 on: February 11, 2012, 06:55:40 pm »
Part V
Introduction to VC:MP Functions

A quick note before we start.
A list of functions offered by VC:MP can be found at:
http://thijn.vrocker-hosting.co.uk/VCWiki/index.php/Functions

Introduction
VC:MP, officially, supports Pawn servers and scripts, and offers a diverse number of functions to help you make the most out of your gamemode, whether it's a simple DM or TDM script to the most amazing stunt server ever made. These functions can be used inside other functions, in callbacks (which we'll cover later), and almost anywhere.

Function Syntax
The link offered above shows not only a list of functions, but their syntaxes. In some cases, the function will also be documented, offering more information than on the list. For example, ShowPlayerMarkers has one parameter: a boolean value, which determines whether or not to show player markers. You would call it like so:

[pawn]ShowPlayerMarkers(true);[/pawn]

However, SetPlayerSkin has two parameters: an integer, for the player's ID, and another integer for the player's new skin. If we wanted a player with ID 3 to look like Tommy Vercetti, we would use:

[pawn]SetPlayerSkin( 3, 0 );[/pawn]

Where 3 represents the ID, and 0 represents the skin. In a function, you can never change the order of the parameters. Otherwise, it will not work as expected, or may not work at all. From what you learned earlier, you should be able to piece together the use of these functions.

Notice
Most of these functions will work normally. However, some of these functions, due to r2 bugs, do not work or not as expected. For example, SendDeathMessage and SetTeamCount have no effect.
Do not PM me for support.




Offline stormeus

  • VC:MP Developer
  • VC:MP Veteran
  • *
  • Posts: 1122
    • View Profile
Re: The Absolute Beginner's Guide to Pawn (w/ examples)
« Reply #6 on: February 11, 2012, 07:32:31 pm »
Part VI
Introduction to VC:MP Callbacks

Introduction
What exactly is a callback? In the context of VC:MP scripting, a callback is a function or method in a script that gets A certain event is done. For example, there's a callback for when a player joins, one for when a player leaves, and one for when a player kills another player, just to name a few. There are many more callbacks.

How do I use one?
In Appendix I, you'll see a list of callbacks and the forward statement. The forward statement is not how you exactly declare the function; as stated before, it just tells the compiler that the function is there. If you had a forward statement like the one below, you'd replace the forward with public and the semicolon with braces:

[pawn]
// Original
forward myFunction( param1, param2 );

// Method Declaration
public myFunction( param1, param2 )
{
}
[/pawn]

Callbacks can be used for many different, creative functions, and work just like regular functions. However, callbacks must always be public. Otherwise, the server will not be able to find and call the function as needed.

Appendix I: List of Callbacks

Callback Name                 What it's used for                                               Syntax
OnGameModeInitThe script is loaded.forward OnGameModeInit()
OnGameModeExitThe script exits/server stops.forward OnGameModeExit()
OnFilterScriptInitA filterscript (to be discussed later) is loaded.forward OnFilterScriptInit()
OnFilterScriptExitA filterscript unloads/server stops.forward OnFilterScriptExit()
OnPlayerConnectA player joins the server.forward OnPlayerConnect( playerid );
OnPlayerDisconnectA player leaves, crashes, or times out.forward OnPlayerDisconnect( playerid, reason );
OnPlayerSpawnA player spawns.forward OnPlayerSpawn( playerid, classid );
OnPlayerDeathA player dies or is killed.forward OnPlayerDeath( playerid, killerid, reason, bodypart );
OnPlayerTextA player talks in chat.forward OnPlayerText( playerid, message[] );
OnPlayerCommandTextA player uses a /c command.forward OnPlayerCommandText( playerid, text[] );
OnPlayerRequestClassA player requests a class.forward OnPlayerRequestClass( playerid, classid );
OnPlayerEnterVehicleA player gets in a vehicle.forward OnPlayerEnterVehicle( playerid, vehicleid, isPassenger );
OnPlayerExitVehicleA player leaves a vehicle.forward OnPlayerExitVehicle( playerid, vehicleid );
OnPickedUpA pickup is picked up.forward OnPickedUp( playerid, pickupid );
OnRconCommandAn RCON command is used.forward OnRconCommand( cmdtext[] );

Appendix II: Reason IDs for OnPlayerDisconnect
  • 0 - Timeout
  • 1 - Quit
  • 2 - Kicked or Banned

Appendix III: List of Bodyparts
  • 0 - Body
  • 1 - Torso
  • 2 - Left Arm
  • 3 - Right Arm
  • 4 - Left Leg
  • 5 - Right Leg
  • 6 - Head

Appendix IV: OnPlayerDeath
OnPlayerDeath has four parameters, but not all of them are used. For example, if a player commits suicide, killerid would be -1.
  • playerid - The player who was killed.
  • killerid - The player who killed the player, or -1 if suicide.
  • reason - The weapon ID with which the player was killed.
  • bodypart - The body part ID where the player was lethally hit.

Appendix V: A player uses the command /c test
[pawn]
// Forward the callback
forward OnPlayerCommandText( playerid, text[] );

// Declare the callback function
public OnPlayerCommandText( playerid, text[] )
{
    // Figure out what the command name is
    new idx, command[128];
    command = strtok( text, idx );

    // If the player used /c test...
    if( strcmp( command, "test", true ) == 0 )
    {
        // ... send them a message
        SendClientMessage( playerid, 0x98FB98FF, "You just used /c test." );
    }
    else
    {
        // We didn't have any code for the command they used
        SendClientMessage( playerid, 0x98FB98FF, "That's an unknown command." );
    }
}
[/pawn]
Do not PM me for support.