[Tutorial] Basics of scripting
#1

Following is a "tutorial" of what you should make sure you know, and even though it does look really boring this is some very useful piece of information that will help you to get better much faster rather than just fumbling around "in the dark", not knowing what stuff actually means.

I've put this together basing it from a C++ tutorial, but I have modified many parts to make sure it applies to pawn, and pawn only.

If you have more questions and/or concerns (Or if you think something is wrong!), feel free to contact me via PM if you don't want to post a reply I wrote this primarily for people that were interested in scripting on LS-RP, and thought why not give people here a chance too!

Structure of a script
Probably the best way to start learning a programming language is by writing a program. Therefore, here is our first pawn gamemode:
pawn Code:
// my first gamemode
#include <a_samp>

main()
{
    print("Hello World!");
    return 1;
}
Quote:
Originally Posted by SA-MP Server Console
...<Standard SA-MP dedicated server stuff>...
Hello World!
The first panel (with code tags) shows the script for our first gamemode. The second one (with quote tags) shows the result of the program once compiled and executed.

This gamemode is the typical program that programmer apprentices write for the first time, and its result is the printing on screen of the "Hello World!" sentence. It is one of the simplest gamemode that can be written in pawn, but it already contains the fundamental components that every pawn script has. We are going to look line by line at the code we have just written:

// my first gamemode
  • This is a comment line. All lines beginning with two slash signs (//) are considered comments and do not have any effect on the behavior of the program. The scripter can use them to include short explanations or observations within the source code itself. In this case, the line is a brief description of what our gamemode is.
#include <a_samp>
  • Lines beginning with a hash sign (#) are directives for the preprocessor. They are not regular code lines with expressions but indications for the compiler's preprocessor. In this case the directive #include <a_samp> tells the preprocessor to include the a_samp standard file. This specific file (a_samp) includes the declarations of the basic standard input-output library in pawn, and it is included because its functionality is going to be used later in the program.
main()
  • This line corresponds to the beginning of the definition of a function that occurs when the program (Server) is loaded.

    The word main is followed in the script by a pair of parentheses (()). That is because it is a function declaration: In pawn, what differentiates a function declaration from other types of expressions are these parentheses that follow its name. Optionally, these parentheses may enclose a list of parameters within them.

    Right after these parentheses we can find the body of the main function enclosed in braces ({ }). What is contained within these braces is what the function does when it is executed.
print("Hello World!");
  • This line is a pawn statement. A statement is a simple or compound expression that can actually produce some effect. In fact, this statement performs the only action that generates a visible effect in our first program.

    print is an output function in pawn, and the meaning of the entire statement is to insert a sequence of characters (in this case the Hello World sequence of characters) into the standard output stream (print, which usually corresponds to the screen).

    print is declared in the a_samp standard file, so that's why we needed to include that specific file in our script.

    Notice that the statement ends with a semicolon character ( ; ). This character is used to mark the end of the statement and in fact it must be included at the end of all expression statements in all pawn scripts (one of the most common syntax errors is indeed to forget to include some semicolon after a statement).
return 1;
  • The return statement causes the main function to finish. return may be followed by a return code (in our example is followed by the return code with a value of one). A return code of 1 for the OnGameModeInit function is generally interpreted as the program worked as expected without any errors during its execution. This is the most usual way to end a pawn script. While it doesn't really matter which number you put in most cases, sometimes it does and because the gamemode that LS-RP is running is based on the GodFather/Pen1 script some functions (Like OnPlayerCommandText) looks for a 1 to make sure things have happened properly.

You may have noticed that not all the lines of this gamemode perform actions when the code is executed. There were lines containing only comments (those beginning by //). There were lines with directives for the compiler's preprocessor (those beginning by #). Then there were lines that began the declaration of a function (in this case, the OnGameModeInit function) and, finally lines with statements (like the insertion into print), which were all included within the block delimited by the braces ({ }) of the function.

The program has been structured in different lines in order to be more readable, but in pawn, we do not have strict rules on how to separate instructions in different lines. For example, instead of
pawn Code:
public OnGameModeInit()
{
  print("Hello World!");
  return 1;
}
We could have written:
pawn Code:
public OnGameModeInit() { print("Hello World!"); return 1; }
All in just one line and this would have had exactly the same meaning as the previous code.


In pawn, the separation between statements is specified with an ending semicolon ( ; ) at the end of each one, so the separation in different lines does not matter at all for this purpose. We can write many statements per line or write a single statement that takes many script lines. The division of code in different lines serves only to make it more legible and schematic for the humans that may read it.

Let us add an additional instruction to our first gamemode:
pawn Code:
// my second gamemode
#include <a_samp>

public OnGameModeInit()
{
    print("Hello World!");
    print("I'm a pawn gamemode!");
    return 1;
}
Quote:

...<Standard SA-MP dedicated server stuff>...
Hello World!
I'm a pawn gamemode!

In this case, we performed two insertions into print in two different statements. Once again, the separation in different lines of code has been done just to give greater readability to the program, since OnGameModeInit could have been perfectly valid defined this way:
pawn Code:
public OnGameModeInit() { print("Hello World!"); print("I'm a pawn gamemode!"); return 1; }
We were also free to divide the code into more lines if we considered it more convenient:
pawn Code:
public OnGameModeInit()
{
    print
        ("Hello World!");

    print
        ("I'm a pawn gamemode!");

    return
        1;
}
And the result would again have been exactly the same as in the previous examples.

Preprocessor directives (those that begin by #) are out of this general rule since they are not statements. They are lines read and processed by the preprocessor and do not produce any code by themselves. Preprocessor directives must be specified in their own line and do not have to end with a semicolon ( ; ).

Comments
Comments are parts of the script disregarded by the compiler. They simply do nothing. Their purpose is only to allow the scripter to insert notes or descriptions embedded within the source code.

pawn supports two ways to insert comments:
pawn Code:
// line comment
/* block comment */
The first of them, known as line comment, discards everything from where the pair of slash signs (//) is found up to the end of that same line. The second one, known as block comment, discards everything between the /* characters and the first appearance of the */ characters, with the possibility of including more than one line.

We are going to add comments to our second program:
pawn Code:
/* my second gamemode
   with more comments! */

#include <a_samp>

public OnGameModeInit()
{
    print("Hello World!"); // Prints "Hello World!" into the server window
    print("I'm a pawn gamemode!"); // Prints "I'm a pawn gamemode!" into the server window
    return 1;
}
Quote:

...<Standard SA-MP dedicated server stuff>...
Hello World!
I'm a pawn gamemode!

If you include comments within the script of your gamemodes or filterscripts without using the comment characters combinations //, /* or */, the compiler will take them as if they were pawn expressions, most likely causing one or several error messages when you compile it.

Variables and Data Types
The usefulness of the "Hello World" gamemode shown in the previous section is quite questionable. We had to write several lines of script, compile it, and then execute the resulting program just to obtain a simple sentence written on the screen as result. It certainly would have been much faster to type the output sentence by ourselves. However, programming is not limited only to printing simple texts on the screen. In order to go a little further on and to become able to write scripts that perform useful tasks that really save us work we need to introduce the concept of variable.

Let us think that I ask you to retain the number 5 in your mental memory, and then I ask you to memorize also the number 2 at the same time. You have just stored two different values in your memory. Now, if I ask you to add 1 to the first number I said, you should be retaining the numbers 6 (that is 5+1) and 2 in your memory. Values that we could now for example subtract and obtain 4 as result.

The whole process that you have just done with your mental memory is a simile of what a computer can do with two variables. The same process can be expressed in C++ with the following instruction set
pawn Code:
a = 5;
b = 2;
a = a + 1;
result = a - b;
Obviously, this is a very simple example since we have only used two small integer values, but consider that your computer can store millions of numbers like these at the same time and conduct sophisticated mathematical operations with them.

Therefore, we can define a variable as a portion of memory to store a determined value.

Each variable needs an identifier that distinguishes it from the others. For example, in the previous piece of script the variable identifiers were a, b and result, but we could have called the variables any names we wanted to invent, as long as they were valid identifiers.

Identifiers
A valid identifier is a sequence of one or more letters, digits or underscore characters (_). Neither spaces nor punctuation marks or symbols can be part of an identifier. Only letters, digits and single underscore characters are valid. In addition, variable identifiers always have to begin with a letter. They can also begin with an underline character (_ ), but in some cases these may be reserved for compiler specific keywords or external identifiers, as well as identifiers containing two successive underscore characters anywhere. In no case they can begin with a digit.

Another rule that you have to consider when inventing your own identifiers is that they cannot match any keyword of the pawn language nor your compiler's specific ones, which are reserved keywords. some examples for reserved keywords are: bool, break, case, default, do, else, enum, false, float, for, if, new, public, return, sizeof, static, switch, true, while

Your includes may also include some additional specific reserved keywords.

Very important: The pawn language is a "case sensitive" language. That means that an identifier written in capital letters is not equivalent to another one with the same name but written in small letters. Thus, for example, the RESULT variable is not the same as the result variable or the Result variable. These are three different variable identifiers.

Variables
A variable is basically a bit of memory, it's where data is stored and can be changed and read as required. Variables are one or more cells, a cell is 32 bits (4 bytes) big and by default signed so they can store from -2147483648 to 2147483647 (although -2147483648 gives odd results if displayed). A variable made from more than one cell is called an array, strings are a special type of array where each cell holds a character of the string.

There are many things you can do with a variable, here are a few examples (Read the comments for explanations!)
pawn Code:
myVariable = myVariable + 4; // Changes the value of the variable from (For example) 7 to 7 + 4= 11
myVariable += 4; // Does the same thing, but the difference is that this means "Add 4"
pawn Code:
myVariable -= 4; // Decreases the value by 4
pawn Code:
myVariable *= 4; // Multiplies the variable by 4
pawn Code:
myVariable /= 4; // Divides the number by 4

Arrays
An array is a variable in which you can store multiple pieces of data at once and access them dynamically. An array is declared to a set size at compile time so you need to know how many pieces of data you need to store in advance, a good example of this is the very common MAX_PLAYERS array, this will have one slot for every possibly connected player, so you know data for one player will not interfere with data for another player.
pawn Code:
new myVariable[5];
That code will declare an array 5 slots big, so you can store 5 pieces of normal data at once in that single variable.

To set a value in an array you need to say which part of the array you want to store the data in, this CAN be done with another variable:
pawn Code:
new myVariable[5];
myVariable[2] = 7;
This will declare an array with 5 slots and give the THIRD slot a value of 7, given that variables always start as 0 this will make the values in the array:
pawn Code:
0, 0, 7, 0, 0
Why is it not:
pawn Code:
0, 7, 0, 0, 0
you're wondering? It's because counting actually starts from the number 0, not 1. Consider the following:
pawn Code:
2, 4, 6, 8
If you go through the list then after the number 2 you have already had one number (the 2), this means that if you are counting the numbers by the time you reach the number 4 you are already at one, you're not at one when you reach the 2, you're at zero. Thus the 2 is at position zero and the 4 is at position one, and thus it follows that the 6 is at position two, which is where the 7 in the first example above is. If we label the slots for the first example we get:
pawn Code:
0 1 2 3 4
0 0 7 0 0
There are five slots but as you can see, and this is very important, there is no slot five, doing the following will give you an error:
pawn Code:
new myVariable[5];
myVariable[5] = 7;
As mentioned above the array index (the index is the slot to which you're writing) can be anything, a number, a variable, or even a function which returns a value.
pawn Code:
new myVariable[5],
    myIndex = 2;
myVariable[myIndex] = 7;
Once you have an array and an index you can use that block exactly as if it were any other variable:
pawn Code:
myVariable[2] = myVariable[2] + 1;
myVariable[2] += 1;
myVariable[2]++;
Strings
A string is a special type of array, one which is used to hold multiple characters to create a word or sentence or other human readable text. A character is one byte big (although there are extended sets where a character is multiple bytes but these are not well defined in pawn) and by default a character takes up one cell (one normal variable or one array slot). Characters are encoded in a system called ASCII, the character "A" is represented by the number 65, telling the system to display a number will give 65, telling the system to display a character will give a capital a. Obviously is a single character takes up a single cell multiple characters (i.e. text) will take up multiple cells, collections of cells, as just explained, are called arrays.

Strings in PAWN (and other languages) are what's called "NULL terminated", this means that when 0 is reached, the string ends. This is not the same as the character "0", represented by the number 48, this is the NULL character, represented by the number 0. This means that you can have a string array 20 cells large but only have a string 3 characters long if the fourth character is the NULL character, signalling the end of the string. You can not however have a string 20 characters long as the NULL character MUST be in the string, so in a 20 cell array you can have a 19 character string and a NULL termination character.

pawn Code:
new myVariable[16] = "hello";
That code declares a new string with enough space for a 15 character string and sets it initially to the 5 character string "hello", the double quotes around the text indicate that it's a string. Internally the array will look like:
pawn Code:
104 101 108 108 111 0 x x x x x x x x x x
The "x"s mean anything, in this example they will all be 0 but as they're after the null character is doesn't matter what they are, they won't affect the string.

Strings can be manipulated like normal arrays, for example:
pawn Code:
new myVariable[16] = "hello";
myVariable[1] = 97;
Will change the character in slot 1 to the character represented by the number 97 (a lower case "a"), resulting in the string reading "hallo". This can be written much more readably and easy to edit as:
pawn Code:
new myVariable[16] = "hello";
myVariable[1] = 'a';
The single quotes around the "a" mean it's a character, not a string, characters don't need to be NULL terminated as they're only ever one cell long, they can also be used interchangeably with numbers if you know what they represent.
pawn Code:
new myVariable[16] = "hello";
myVariable[1] = '\0';
'\0' is one character, however it is a special character which modifies the next character, \0 means NULL, that code is the same as doing:
pawn Code:
new myString[16] = "hello";
myString[1] = 0;
But is NOT the same as doing:
pawn Code:
new myString[16] = "hello";
myString[1] = '0';
The first and second versions will result in the string being simply:
Quote:

h

The third version will result in the string being:
Quote:

h0llo

Most importantly of all string functions, pawn often makes use of the function format, here is an example:
pawn Code:
new result[128];
new number = 42;
format(result,sizeof(result), "The number is %i.",number);  //-> The number is 42.
new string[]= "simple message";
format(result,sizeof(result), "This is a %s containing the number %i.", string, number);
Reply
#2

Good Work!

you serious here??
Quote:

When scripting, we store the variables in our computer's memory, but the computer has to know what kind of data we want to store in them, since it is not going to occupy the same amount of memory to store a simple number than to store a single letter or a large number, and they are not going to be interpreted the same way.

Reply
#3

Yes, an array and an integer uses up a different amount of memory
Reply
#4

Very nice. It's useful for a lot of people imo. Never knew what Kar said about memory usage.
Reply
#5

owell I defragment every 1-3 days now so that memory thing wont bother me.

tahk you again lenny!
Reply
#6

Oh, that's not what it means

It means that, for example, an integer (new var takes up less space than a string with for example five cells (new var[5]
Reply
#7

o i thought u meant it took me computer space ._> not the server sided part D:
Reply
#8

Nice tutorial! This should help a lot of people
Reply
#9

Quote:
Originally Posted by Y_Less
View Post
As you should know - PAWN is NOT a sub-language of C++. PAWN is a typeless imperative language, C++ is a typed object oriented language. Both PAWN (through SMALL-C/SMALL) and C++ are based on C, but they have nothing to do with each other directly. That's like saying a TV is a type of microwave because they're both based on electricity, or that gorrilas are a type of human because they're both descended from primative primates. PAWN and C++ followed very different develpoment paths from C and saying they're related is just misleading and wrong!

Also, starting a tutorial with "this is boring" is NOT a good start!

And there are [pawn] and [code] tags you can use instead of code and quote (and pawn gives syntax highlighting).

And your very first example will not run - there is no "main" function, which is more important that OnGameModeInit.

Fundamental data types <- PAWN is typeless, there is only one type, the cell. This section is entirely redundant.

Strings are not special arrays, they are just arrays. And characters are not 1 byte big, as I just said there is only one type in PAWN - the cell, so characters are one cell big (excluding packed strings, but they're rarely mentioned).

'\0' is not two characters - it is one character, the '\0' character.

PAWN has native array bounds checking - accessing an array element which doesn't exist will not crash the server it will give an error in the console.

// is not known as a line comment (at least not in any documentation I've ever seen) - "called by me" and "known as" are not the same thing - this is a "stream" comment. Block comment is accurate.

print is not an output stream - I can tell you've lifted that straight from the C++ tutorial, where streams do exist. print is an output function.

void is not a reserved word - this only has meaning in a typed language, and PAWN is typeless.

class is not a reserved word - this only has meaning in an object oriented language such as C++, which PAWN is in no way related to.

It is the "SA-MP wiki" - "wiki" is a noun, "wikipedia" is a trademark name for one wiki.

The major missing section in here is control flow - you're not going to get very far in coding without "if" or "for" etc.

-2147483648 is not poorly defined in PAWN, it is just a number, it is however not well handled by the printf function - which is part of the SA-MP API, NOT part of PAWN. PAWN defines the syntax and operators used, the SA-MP library is a set of functions within the PAWN language construct - separating these two is very important. The pawn homepage is here: http://www.compuphase.com/pawn/pawn.htm and makes no mention of SA-MP or most of the functions anywhere. That site also includes the infamous PAWN language guide: http://www.compuphase.com/pawn/Pawn_Language_Guide.pdf - which I suggest you read thoroughly!

Some bits were good though.
Holy shit... "owned"
Reply
#10

Heh, oh well Thanks for correcting me

I wrote this because people have come to me and said that the SAMP wiki tutorial is too messy to understand, I was hoping this would be easier

Edit: I think I fixed everything you mentioned, Y_Less, except for some minor things I thought I'd leave in
Reply
#11

Quote:
Originally Posted by Y_Less
View Post
Fair enough. You do know that the point of a wiki is that anyone can edit it right? If you think it's messy clean it up.
We can't edit it without a username can we?

Edit: Oh, seems like you can register now Nevermind
Reply
#12

No worries, I'm just glad to have learned something myself
Reply
#13

@Y_Less, I know you didn't do that because of that. I just have my own reasons to find this very funny.
Reply
#14

Never-the-less,

Great tutorial, you really spent some time in this, and it's good to see people taking the time to make good hard learning for the little people like me.

-Kevin, Crazy Awesome, Owner
Reply
#15

Quote:
Originally Posted by Y_Less
View Post
It is the "SA-MP wiki" - "wiki" is a noun, "wikipedia" is a trademark name for one wiki.
Well said.
Reply
#16

I found this almost useless, no offense i am sorry but yeah....like someone above said thats what the SA-MP wiki is for.
Reply
#17

If you think it was useless, then why did you bother to reply? give constructive critism, use it or get out of the post. He didn't make it to be amazing, he made it so you know some of the basics.

For the rest "owned" "Ha good to see a high pride LS RP'er get owned"
Go do one, he hardly got owned he done something to help you all and you reply with horrible messages. I see you all as sellfish and hope you never step on LS RP as I will ban you clean off it.
Reply
#18

Quote:
Originally Posted by Steven82
View Post
I found this almost useless, no offense i am sorry but yeah....like someone above said thats what the SA-MP wiki is for.
If you think this stuff is useless, you have no idea what scripting really is. And I'm not being defensive or something, it's the truth.
Reply
#19

You can find this tutorial on samp wiki
Reply
#20

You can find a similar tutorial, not this tutorial
Reply


Forum Jump:


Users browsing this thread: 4 Guest(s)