[Tutorial] Aprender pawn (nivel basico/medio/avanzado)
#1

Aprender pawn
(nivel bбsico/medio/avanzado)



Introducciуn
Hacнa rato que no creaba ningъn tutorial, y tenнa ganas de aportar con algo nuevo y ъtil, asн que se me ocurriу hacer este tutorial.
Bueno en este tutorial, voy a tratar de ayudar a los mбs nuevos a dar sus primeros pasos con este lenguaje de programaciуn de scripts llamado pawn. Y a aquellos que saben un poco, a que sigan aprendiendo cosas nuevas, o a recordar cosas que se habнan olvidado.
Este tutorial va a ir desde lo mбs bбsico, hasta cosas no tan bбsicas o que requieren pensar mas. Y el ъnico objetivo es aprender. Espero que les sirva y cualquier error que cometa, publiquenlo asн lo corrijo, ya que todos siempre estamos aprendiendo algo y nos podemos equivocar.



Forma de uso
Primero, antes que se manden a empezar a leer, quiero aclarar, que este tutorial estб dividido en 3 niveles: Nivel Bбsico/Nulo, Medio y Avanzado. Cada nivel consta con conocimientos acorde al nivel propuesto, pero les sugiero a aquellos que no han leнdo demasiado sobre pawn, que lean desde el principio, aun que tengan los conocimientos, porque lo que se dice en el nivel bбsico, se da por entendido en los demбs niveles y se usa como base.
Segundo, lo ideal para que fijen bien los conocimientos sobre este tutorial, seria que cuando aprenden algo nuevo, lo prueben y si no lo terminan de entender o no les sale cuando lo practican, paren y piensen a ver que puede estar mal y si es necesario pregunten y luego cuando lo tengan bien claro, sigan.



Indice:
  • Introducciуn
  • Forma de uso
  • Indice:
  • Nivel: Bбsico/Nulo
    • Variables y Arrays
      • Primeros pasos con variables y arrays
        • їQuй es una variable?
        • їPara quй sirve una variable?
        • їCуmo defino una variable?
        • їCуmo utilizo una variable?
        • їQuй es un tag y cuбles existen?
        • їCуmo definimos una variable con un tag?
        • їQuй es un array?
        • їCуmo defino un array?
        • їCуmo utilizo un array?
        • їCuales son los tags de los arrays?
        • їPodemos definir arrays con tags? Y si es asн їCuбles son los tags de los arrays?
      • Un 'tipo' de array particular, los strings
        • їQuй es un string?
        • їCуmo guardo un string?
        • Salvedades
          • Comparaciуn
          • Asignaciуn
      • Arrays multi-dimensionales
        • їQuй es una dimensiуn?
        • їQuй es un array multi-dimensional?
        • їCuбntas dimensiones existen?
        • їCуmo crear un array multi-dimensional?
        • їCуmo utilizo un array multi-dimensional?
      • Alcance de una variable/array
        • їQuй es el alcance de una variable/array?
        • Local
        • Global
    • Operadores
      • Introducciуn
        • їQuй es un operador?
        • їCuбles son los Operadores y cuбl es su forma de uso?
    • Caracteres Especiales
      • Script
      • Strings
    • Sentencias, Expresiones y estructuras (condicionales y no condicionales)
      • їQuй es una sentencia?
      • їQuй es una expresiуn?
      • їCuбles son las expresiones que existen y cуmo se utilizan?
      • if, else, combinaciуn (else if), assert, for, do, while y return
    • Funciones
      • Funciones Simples
        • їQuй es una funciуn?
        • їCуmo crear una funciуn?
        • Funciones sin parбmetros
        • Funciones con parбmetros
        • Funciones con retorno de valores
    • Callbacks
      • їQuй es un callback?
      • їPara quй sirve un callback?
      • їCуmo utilizo un callback?
      • їPor quй 'forward' y quй es?
      • їPuedo crear mis propios callbacks?
  • Nivel: Medio
    • Inicializadores
      • stock
        • їQuй es stock?
        • їCуmo se utiliza?
        • їPara quй se utiliza?
      • const
        • їQuй es const?
        • їCуmo se utiliza?
        • їPor quй se utiliza?
      • static
        • їQuй es static?
      • enum
        • їQuй es un enum?
        • їCуmo se utiliza?
        • Usos comunes
        • Algo mбs...
    • Definiciones
      • Inicializaciуn
        • їCуmo inicializar una variable?
        • їCуmo inicializar un array?
        • Ops їQuй son los "..."?
      • Strings empaquetados
        • їQuй son los strings empaquetados?
        • La trampa
        • їCуmo se utilizan?
        • їCuбndo deben usarse strings empaquetados?
    • Operadores
      • Operadores miselaneos
        • {}
        • defined
        • sizeof
        • tagof
        • char
        • Ternario
    • Expresiones
      • Bucles, switch, saltos, sleep
        • switch, case y default
        • break
        • continue
        • goto
        • sleep
        • state
      • Loops(infinitos)
    • Directivas
      • Directivas bбsicas
        • #if, #elseif, #else, #endif
        • #error
        • #assert
        • #include
        • #tryinclude
        • #endinput
        • #define
        • #undef
    • Archivos
      • Introducciуn
      • Creaciуn
      • Lectura
      • Escritura
    • Funciones
      • Funciones Complejas
        • Parбmetros opcionales
        • Parбmetros por valor y por referencia
        • Parбmetros variables
  • Nivel: Avanzado
    • Operadores
      • Operadores de Bits(manipulaciуn)
      • Operadores de Bits(Asignaciуn)
    • Nъmeros binarios[/b]
      • Introducciуn
      • Binario a Decimal
      • Decimal a binario
      • Nъmeros negativos
      • Operaciones con bits
        • AND (&)
        • OR (|)
        • XOR (^)
        • NOT (~)
      • Shifts aritmйticos
        • Izquierdo
        • Derecho
      • Shifts lуgicos
        • Izquierdo
        • Derecho
      • їPara quй sirven realmente los nъmeros binarios?
    • Directivas
      • Directivas avanzadas
        • #define
        • #pragma
          • amxlimit
          • amxram
          • codepage
          • ctrlchar
          • deprecated
          • dynamic
          • Library
          • pack
          • tabsize
          • unused
  • Final

Nivel: Bбsico/Nulo


Variables y Arrays

Primeros pasos con variables y arrays

їQuй es una variable?
La respuesta es muy simple:
Una variable es un pedacito de memoria que se reserva para el programa durante la ejecuciуn del mismo, para almacenar informaciуn, que luego usaremos para almacenar algъn dato.

їPara quй sirve una variable?
Una variable sirve para guardar datos y realizar alguna tarea con los mismos. Lo importante de estos datos, es que desconocemos cuales son en si, y pueden ser diferentes siempre. Sin embargo, lo que si conocemos el tipo de datos que son (hablaremos sobre los tipos en unos minutos).

їCуmo defino una variable?
Para definir una variable en pawn, la forma mбs simple es utilizar "new" y se utiliza de la siguiente forma.

pawn Код:
new MiVariable;
Esa sentencia define "MiVariable" como una variable de tipo entero (en ingles integer).

їCуmo utilizo una variable?
La variable representa el dato que se almaceno en ella, es decir el dato o la variable es casi lo mismo, entonces la forma de utilizarla seria algo asi:
pawn Код:
new MiVariable;
MiVariable = 15;//Asignamos el valor 15 a la variable
printf("El valor de MiVariable es %i.", MiVariable);//Obtenemos el numero almacenado en la variable y lo mostramos en la consola con el texto escrito.
La salida de este codigo es:
Код:
El valor de MiVariable es 15.
їEntonces en las variables solo podemos almacenar nъmeros enteros?
Por el momento diremos que no, para poder almacenar otros datos como por ejemplo nъmeros decimales, utilizaremos 'Tags'.

їQuй es un tag y cuбles existen?
Un tag es un pedacito de cуdigo, que informa al compilador el tipo de dato que se almacenara en esa variable.

Existen infinitos tags, pues podemos crear los nuestros propios, pero por defecto pawn tiene los siguientes:
Float
Almacena nъmeros enteros y nъmeros con coma
File
Almacena el handle de un archivo abierto (no se preocupen de que es un handle, luego lo explicare)
bool
Almacena true o false (verdadero o falso)
int
Almacena nъmeros enteros (Este es el tag por defecto utilizado en pawn)
їCуmo definimos una variable con un tag?
Para definir una variable taggeada (con un tag), lo vamos a hacer de la siguiente forma:
pawn Код:
new tag:Nombre;
Ejemplos
Float
pawn Код:
new Float:MiFloat;
File
pawn Код:
new File:MiFile;
Bool
pawn Код:
new bool:MyBool;
Integer
pawn Код:
new MiInteger;
їQuй es un array?
Un array es como si definiйramos muchas variables y las uniйramos todas, de esta forma tendrнamos una sucesiуn de variables, en las cuales podrнamos almacenar varios datos (1 dato por variable).

їCуmo defino un array?
La forma de definir un array es muy sencilla, de hecho es casi igual que definir una variable.

Ejemplo:
pawn Код:
new MiArray[4];
Como pueden ver, solo varia [n]; en este caso, n=4. Pero... їQuй representa 'n'? 'n' representa el tamaсo de ese array, es decir la cantidad de datos que podemos almacenar.

їCуmo utilizo un array?
Para utilizar un array, lo que hacemos es almacenar o leer los datos indicando la posiciуn que ocupa el mismo (Las posiciones o indices comienzan en 0 y van hasta n-1).

Ejemplo:
pawn Код:
new MiArray[3];
//Asignaciуn:
MiArray[0] = 1;//Asignamos el valor '1' en el index 0 de nuestro array
MiArray[1] = 50;//Asignamos el valor '50' en el index 1 de nuestro array
//Lectura:
printf("El valor almacenado en el index 0 de MiArray es %i", MiArray[0]);//Accedemos al valor almacenado en el index 0
Importante: A la hora de definir un array, debemos tener en cuenta, que este nunca puede tomar el valor de la definiciуn.

Ejemplo:
pawn Код:
new Array[5];
Array[5] = 4;//esto causara un error, dado que el нndex mбximo de Array es 4
Ejemplo 2:
pawn Код:
new MiArray[4];
//Asignaciуn
MiArray = {1, 5, 8, 10};//Realizamos una asignaciуn multiple, para realizar esto, colocamos entre llaves ('{' & '}') los valores separados por una coma

//Lectura
printf("Valores del array 0-3: %d %d %d %d", MiArray[0], MiArray[1], MiArray[2], MiArray[3]);
Importante: Cuando realizamos una asignaciуn mъltiple, esta debe ser completa, es decir debemos asignar un valor a cada index (lugarcito) de nuestro array.

їPodemos definir arrays con tags? Y si es asi їCuбles son los tags de los arrays?
Los mismos tags que tienen las variables, y se los especifica de igual forma:
pawn Код:
new tag:nombre[tamaсo];
Ahora que mбs o menos tenemos idea de cуmo se declara una variable y un array, un caso algo mбs particular de los arrays, los strings.

Un 'tipo' de array particular, los strings

їQuй es un string?
Un string es una cadena de caracteres. Ahora bien si los caracteres no son nъmeros (y en los arrays se almacenan nъmeros ъnicamente) їCуmo podemos almacenar estos caracteres?
Hace mucho tiempo se decidiу que se crearнa una tabla de cуdigos, donde a cada carбcter se le asignarнa un numero que lo representaba, a esta tabla se la llamo tabla ASCII.

їCуmo guardo un string?
Para almacenar un string solo basta convertir la cadena y guardarla en el array que queremos.

Ejemplo:
pawn Код:
//Almacenaremos el string "hola" en un array llamado MiArray
new MiArray[4] = {72, 111, 108, 97};//En la tabla ascii: H=92, 0=111, l=108, a=97  (Notar que en esta tabla existen mayъsculas y minъsculas)
Ahora bien, logramos almacenar un string en el array como querнamos, pero tenemos un nuevo problema, dado que los arrays se guardan en la memoria seguidos, como sabrнa el compilador como dejar de leer?
Es decir, supongamos el siguiente ejemplo:
pawn Код:
new Array_1[5], Array_2[4], Array_3[10];
Array_1 = {10, 15, 25, 40, 65};
Array_2 = {72, 111, 108, 97};//Este es nuestro string que contiene la palabra "Hola"
Array_3 = {15, 26, 14, 51, 85, 64, 35, 12, 45, 36};

//Para ejemplificar simplificaremos todo y pensaremos que esto en memoria, se almacena algo asi:
10 15 25 40 65 72 111 108 97 15 26 14 51 85 64 35 12 45 36
               |           |
Nuestra cadena (Array_2) esta indicada con '|', el problema es que esta no indica su fin. Por este motivo, se creo una convenciуn la cual indica que todos los strings deben terminar
en el carбcter nulo. el cual es representado por el 0. Por este motivo, debemos agregar un slot mas cuando creamos un array, para almacenar allн el 0 indicando que termino.

Ejemplo:
pawn Код:
//Almacenaremos el string "hola" en un array llamado MiArray
new MiArray[5] = {72, 111, 108, 97, 0};//Agregamos el 0 al final indicando que allн termina el texto
Salvedades

Comparaciуn

Si bien aun no hablamos de sentencias, estructuras lуgicas y demбs, es bastante simple de entender y algo bбsico, por lo que cabe destacar esto aquн.
Muchos, seguramente se vieron tentados e intentaron comparar strings de la siguiente forma:
pawn Код:
new array[5] = "Hola";
if(array == "Hola")
El problema con este mйtodo de comparaciуn, es que esta mal. El operador == compara valores numйricos ъnicamente, y los strings, son una cadena de valores.
Para comparar un string deberнamos ir valor por valor, pero esto es algo tedioso, por este motivo hay funciones que nos permiten realizar esto (la funciуn nativa es strcmp, pero
la idea de este tutorial es evitar meterse en detalles sobre funciones nativas y hablar de una forma mas detallada sobre el lenguaje en si).

Asignaciуn

Los siguientes ejemplos son todos anбlogos, es decir son iguales

pawn Код:
new MiArray[5] = {72, 111, 108, 97, 0};
new MiArray[5] = {'H', 'o', 'l', 'a', '\0'};//Al encerrar una letra entre comillas simples, el compilador luego reemplazara a la misma por su valor ascii
new MiArray[5] = "Hola";

Arrays multi-dimensionales:

їQuй es una dimensiуn?
La dimensiуn es un numero el cual indica cuantos indices son necesarios para almacenar/leer un elemento de un array.

їQuй es un array multi-dimensional?
Es un array que contiene a otros arrays. Podrнa graficarse como una matriz en el caso de tener 2 dimensiones, o como un cubo si tuviese 3.

їCuбntas dimensiones existen?
La versiуn de Pawn utilizada por SA-MP soporta hasta 3 dimensiones.

їCуmo crear un array multi-dimensional?
  • Uni-dimensional (1 dimensiуn):
    (Son los que ya vimos antes, pero ahora podemos decir que son uni-dimensionales)

    Ejemplo:
    pawn Код:
    new array[5];//Array uni-dimensional de 5 slots
  • Bi-dimensional (2 dimensiones):

    Ejemplo:
    pawn Код:
    new array[5][5];//Array bi-dimensional de 5x5 slots, es decir por cada slot "primario" podemos almacenar 5 datos, es decir podemos almacenar 25 elementos
  • Tri-dimensional (3 dimensiones):

    Ejemplo:
    pawn Код:
    new array[5][5][5];//Array tri-dimensional de 5x55 slots, es decir por cada slot "primario" tenemos 5 slots secundarios, que a su vez tienen otros 5 slots para almacenar datos.
їCуmo utilizo un array multi-dimensional?
Se utilizan igual que los uni-dimensionales.
  • Uni-dimensional:

    Ejemplo:
    pawn Код:
    new array[3];
    //Asignaciуn:
    array[0] = 1;//Asignamos el valor '1' en el index 0 de nuestro array
    array[1] = 50;//Asignamos el valor '50' en el index 1 de nuestro array
    //Lectura:
    printf("El valor almacenado en el index 0 de array es %i", array[0]);//Accedemos al valor almacenado en el index 0
    Grбficamente:
    Код:
    1 50 0 0 0
  • Bi-dimensional:

    Ejemplo:
    pawn Код:
    new array[5][5];
    //Asignaciуn:
    array[0][1] = 1;//Asignamos el valor '1' en el index 1 respecto del index 0 de nuestro array
    array[0][3] = 5;//Asignamos el valor '5' en el index 3 respecto del index 0 de nuestro array
    array[4][1] = 9;//Asignamos el valor '9' en el index 1 respecto del index 4 de nuestro array
    array[3][2] = 6;//Asignamos el valor '6' en el index 2 respecto del index 3 de nuestro array
    array[3][4] = 8;//Asignamos el valor '8' en el index 4 respecto del index 3 de nuestro array
    //Lectura:
    printf("El valor almacenado en el index 1 respecto del index 0 es %i", array[0][1]);
    Grбficamente:
    Код:
    0 1 0 5 0
    0 0 0 0 0
    0 0 0 0 0
    0 0 6 0 8
    0 9 0 0 0
  • Tri-dimensional:

    Ejemplo:
    pawn Код:
    new array[5][5][5];
    //Asignaciуn:
    array[0][1][0] = 10;//Asignamos el valor '10' en el index 0 respecto del index 1 respecto del index 0 de nuestro array
    //Lectura:
    printf("El valor almacenado en el index 0 respecto del index 1 respecto del index 0 es %i", array[0][1]);
    Grбficamente:
    Es un cubo, por lo cual no se puede graficar aqui, pero pueden ver esta imagen.
Alcance de una variable/array:

їQuй es el alcance de una variable/array?
El alcance (scope en ingles) de una variable/array hace referencia al бrea/entorno dentro de la cual se puede utilizar la misma.
Estos entornos se encuentran definidas por las llaves.


Local
Solo puede ser utilizada dentro del entorno en el cual es declarada(ej.: Callbacks, funciones, if, etc.). Para declarar una variable/array de este tipo, la declaraciуn debe ser realizada dentro del entorno en el que se desea usar la variable/array.

Ejemplo:
pawn Код:
public OnPlayerConnect(playerid)
{
    new
        str[32+MAX_PLAYER_NAME],
        name[MAX_PLAYER_NAME];//declaraciуn de los arrays locales

    GetPlayerName(playerid, name, MAX_PLAYER_NAME);
    format(str, sizeof(str), ">>%s(%i) ha ingresado en el servidor", name, playerid);
    SendClientMessageToAll(0xFFFF00FF, str);

    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    GetPlayerName(playerid, name, MAX_PLAYER_NAME);
    format(str, sizeof(str), ">>%s(%i) ha dejado el servidor", name, playerid);
    SendClientMessageToAll(0xFFFF00FF, str);

    return 1;
}
Este codigo esta mal, pues se utilizan las variables definidas local-mente dentro del callback 'OnPlayerConnect' dentro del callback 'OnPlayerDisconnect'.
Para que el cуdigo funcione correctamente deberнan definirse las variables nuevamente dentro del 2do callback.

Como deberнa ser el cуdigo de arriba para funcionar correctamente:
pawn Код:
public OnPlayerConnect(playerid)
{
    new
        str[36+MAX_PLAYER_NAME],
        name[MAX_PLAYER_NAME];//declaraciуn de los arrays locales

    GetPlayerName(playerid, name, MAX_PLAYER_NAME);
    format(str, sizeof(str), ">>%s(%i) ha ingresado en el servidor.", name, playerid);
    SendClientMessageToAll(0xFFFF00FF, str);

    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    new
        str[27+MAX_PLAYER_NAME],
        name[MAX_PLAYER_NAME];//declaraciуn de los arrays locales

    GetPlayerName(playerid, name, MAX_PLAYER_NAME);
    format(str, sizeof(str), ">>%s(%i) ha dejado el servidor.", name, playerid);
    SendClientMessageToAll(0xFFFF00FF, str);

    return 1;
}

Global
Puede ser utilizada en todo el proyecto. Para declarar una variable/array de este tipo, debe declararse en el entorno global, es decir fuera de cualquier funciуn, callback, etc.

Ejemplo:
pawn Код:
new
    bool:Connected[MAX_PLAYERS];

public OnPlayerConnect(playerid)
{
    Connected[playerid] = true;
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    Connected[playerid] = false;
    return 1;
}

Importante: Tenemos que tener en cuenta, que cuando declaramos una variable/array local, la variable existe dentro de los entornos sucesores, pero no en los ancestros.

Ejemplo:
pawn Код:
MyFuncion()
{
    new var1;
    for(new i; i<5; i++)
    {
        //var1 todavнa existe.
        new var2;
        printf("%i", var2);
        var2++;
        //var2 todavнa existe
    }
    //var1, todavнa existe, pero var2 no existe
}
//var1 no existe.

Operadores

Introducciуn

їQuй es un operador?
Un operador es un sнmbolo que se utiliza en expresiones, o bien para realizar una acciуn (no se preocupen si no saben lo que es una expresiуn, lo veremos luego).

їCuбles son los operadores y cuбl es su forma de uso?

Aritmйticos:
A + B
Retorna la suma de A y B
A - B
Retorna la resta de A y B
A * B
Retorna la multiplicaciуn de A y B
A / B
Retorna la divisiуn de A y B
A % B
Retorna el resto de la divisiуn de A y B
Asignaciуn:
A = B
Asigna en A el valor de B
A ++
Asigna en A el resultado de A+1
A --
Asigna en A el resultado de A-1
A += B
Asigna en A el resultado de A+B
A -= B
Asigna en A el resultado de A-B
A *= B
Asigna a A el resultado de A*B
A /= B
Asigna en A el resultado de A/B
A %= B
Asigna en A el resto de A/B
Racionales(numйricos):
A == B
Retorna verdadero si A es igual B, de lo contrario retorna falso
A != B
Retorna verdadero si A es distinto de B, de lo contrario retorna falso
A < B
Retorna verdadero si A es menor que B, de lo contrario retorna falso
A > B
Retorna verdadero si A es mayor que B, de lo contrario retorna falso
A <= B
Retorna verdadero si A es menor o igual que B, de lo contrario retorna falso
A >= B
Retorna verdadero si A es mayor o igual que B, de lo contrario retorna falso
Racionales(booleanas):
!B
(NOT)
Retorna el valor opuesto de B
A || B
(OR)
Retorna verdadero A o B son verdadero, de lo contrario retorna falso
A && B
(AND)
Retorna verdadero si A y B son verdadero, de lo contrario retorna falso

Caracteres Especiales

Script
\
Indica que la lнnea actual, sigue en la de abajo.
;
Fin de sentencia.
Strings
\a Beep
\b backspace
\e Escape
\n Nueva linea
\r Retorno del caddy
\t Tabulaciуn horizontal
\v Tabulaciуn vertical
\\ Inserta literalmente el sнmbolo '\'
\' Inserta literalmente el sнmbolo "'"
\" Inserta literalmente el sнmbolo '"'
\% Inserta literalmente el sнmbolo '%'
\ddd; cуdigo de caracteres, con el cуdigo en decimal "ddd"
\xhhh; cуdigo de caracteres, con el cуdigo en hexadecimal "hhh"

Sentencias, Expresiones y estructuras (condicionales y no condicionales)

їQuй es una sentencia?
Es la unidad mas pequeсa de cуdigo que puede ser ejecutada, es decir, cada linea de cуdigo es una sentencia.

їQuй es una expresiуn?
Una expresiуn es una combinaciуn de constantes, variables/arrays, funciones, y/o operadores, que son evaluadas segъn los parбmetros indicados (si no entienden, no se preocupen pues al ver los ejemplos sera intuitivo).

їCuбles son las expresiones que existen y cуmo se utilizan?
Existen infinitas expresiones, pues son una combinaciуn de constantes, variables/arrays, funciones, y/o operadores. Para evaluar estas expresiones, existen 16 estructuras condicionales las cuales veremos a lo largo de ese tutorial.

if
Es una de las estructuras mбs importantes y simples, se utiliza para comparar, y segъn el resultado de la comparaciуn, se realiza o no una determinada acciуn.

Ejemplo 1:
pawn Код:
public OnPlayerConnect(playerid)
{
    new
        rnd = random(2);

    if(rnd == 0)
        SendClientMessage(playerid, 0x00FF00FF, "Bienvenido al servidor");//Este cуdigo solo se ejecutara si la variable 'rnd' es igual a 0

    return 1;
}
Ejemplo 2:
pawn Код:
public OnPlayerConnect(playerid)
{
    new
        rnd = random(2);

    if(rnd == 0)
    {
        //Este codigo (siguientes 2 lineas) solo se ejecutara si la variable 'rnd' es igual a 0
        SendClientMessage(playerid, 0xFF0000FF, "Fuera de mi servidor");
        Kick(playerid);
    }

    return 1;
}
Nota: Cuando el cуdigo a ejecutar, si la comparaciуn es verdadera, es 1 sola sentencia (ejemplo 1), no es necesario usar llaves; de lo contrario se deben colocar los mismos (ejemplo 2).

else
Es al igual que 'if' una de las estructuras mбs importantes, y tambiйn una de las mбs utilizadas. Su uso va con la estructura vista anteriormente (sin excepciуn) y ejecuta una acciуn ъnicamente cuando la expresiуn en el if es falsa.

Ejemplo:
pawn Код:
Estado(playerid)
{
    if(IsPlayerConnected(playerid) == 1)
    {
        //Este codigo solo se ejecutara si la funciуn 'IsPlayerConnected' retorna el valor 1 (el jugador cuyo id es el valor de la variable 'playerid' esta conectado).
        printf("El jugador %i estб conectado", playerid);
    }
    else
    {
        //Este codigo solo se ejecutara si la funciуn 'IsPlayerConnected' retorna el valor 0 (el jugador cuyo id es el valor de la variable 'playerid' esta desconectado).
        printf("El jugador %i esta desconectado", playerid);
    }
}
else if
Es una combinaciуn de las 2 estructuras vistas anteriormente.

Ejemplo:
pawn Код:
Dinero(playerid)
{
    new
        money = GetPlayerMoney(playerid);

    if(money >= 10000)
        printf("El jugador %i tiene $10.000 o mas!", playerid);
    else if(0 <= money < 10000)
        printf("El jugador %i tiene entre $0 y $10.000", playerid);
    else
        printf("El jugador %i tiene menos de $0", playerid);
}
//Nota: "else if(0 <= money < 10000)" es equivalente a "else if(0 <= money && money < 10000)"
for
Es una forma de definir un loop(bucle) que consiste en tres pasos. El 1є consiste en la iniciaciуn, el 2є es la comparaciуn y el 3є es la renovaciуn (cada paso se separa por ';').

Ejemplo:
pawn Код:
for(new i; i<100; i++)
{
    printf("Nъmero: %d", i);
}
do
Es otra forma de crear un loop, pero a diferencia del for, este solo consta de un paso, la comparaciуn.

Ejemplo:
pawn Код:
new
    i;

do
{
    printf("Nъmero: %d", i);
    i++;//Dado que solo hay una comparaciуn, debemos ser nosotros quienes modifiquemos el valor del contador
}while(i < 100);
while
Es otra forma de crear un loop muy similar a la anterior.

Ejemplo:
pawn Код:
new
    i;

while(i < 100)
{
    printf("Nъmero: %d", i);
    i++;//Dado que solo hay una comparaciуn, debemos ser nosotros quienes modifiquemos el valor del contador
}
return
Se utiliza para retornar un valor de una funciуn/callback, o bien para salir/interrumpir la ejecuciуn misma (no se ejecutara el cуdigo que este luego de esta estructura).

Ejemplo:
pawn Код:
IsValidPlayer(playerid)
{
    if(playerid == INVALID_PLAYER_ID || !IsPlayerConnected(playerid))
        return false;
    return true;
}
assert
Es similar a if, pero si es falso entonces retorna(fin del callback/funciуn)

Ejemplo:
pawn Код:
public OnFilterScriptInit()
{
    new
        num = random(100);

    assert(num > 50);
    printf("%i", num);

    return 1;
}

//Equivalencia utilizando un if
public OnFilterScriptInit()
{
    new
        num = random(100);

    if(num < 50)
        return;
    printf("%i", num);

    return 1;
}
En el ejemplo dado, si la variable num es menor a 50 entonces escribirб el valor de dicha variable en la consola, de lo contrario retorna.


Funciones

Funciones Simples

їQuй es una funciуn?
Podemos definir a una funciуn como un conjunto de sentencias que son ejecutadas cuando invocamos la funciуn.

їCуmo crear una funciуn?
Una funciуn esta compuesta por 2 partes, la cabecera (header) y el cuerpo (body); el header contiene el inicializador, el tag, el nombre y los parбmetros de la misma. El cuerpo por otro
lado, contiene todo el cуdigo que se ejecuta.

Ejemplo:
pawn Код:
Inicializador Tag:Nombre(parametros)
{
    //Todo lo que este aquн entre las 2 llaves es el cuerpo de la funciуn
}
Inicializador Indica que es una funciуn, puede ser static, stock, public o ninguno (mas adelante veremos que son estos inicializadores
Tag Tipo de funciуn, al igual que las variables si no se indica ninguno, por defecto es entero. Esto indica el valor que retornara la funciуn (si es que retorna algun valor).
Nombre Nombre de la funciуn, utilizado luego para invocarla.
Parametros Indica el nombre que se le dara a las variables que reciban los argumentos enviados.
Funciones sin parбmetros
Son funciones a las cuales no se le pasan argumentos, es decir que realizan ъnicamente una acciуn y siempre la misma.

Ejemplo:
pawn Код:
stock KickAll()
{
    for(new i, j=GetMaxPlayers(); i<j; i++)
        if(IsPlayerConnected(i))
            Kick(i);
}
Esa es una funciуn muy simple que solo kickea a todos los jugadores conectados.

Funciones con parбmetros
Son funciones las cuales reciben argumentos los cuales pueden variar y segъn los mismos puede que la funciуn ejecute diferentes sentencias.

Ejemplo:
pawn Код:
stock GivePlayerMoney(playerid, money)
{
    if(IsPlayerConnected(playerid))
    {
        if(money >= 0)
            GivePlayerMoney(playerid, money);
        else
            GivePlayerMoney(playerid, -money);
    }
}
La funciуn anterior siempre otorgara una cantidad positiva de dinero al jugador.

Funciones con retorno de valores
Las funciones pueden retornar valores, pero el tipo de valor retornado debe ser siempre el mismo y debe coincidir con el tipo de la funciуn.

Existen dos formas de retornar valores (aun que por claridad sugiero utilizar la primera):

Ejemplo:
pawn Код:
stock GetConnectedPlayers()
{
    new
    count;

    for(new i; i<GetMaxPlayers(); i++)
        if(IsPlayerConnected(i))
            count++;

    return count;
}
Ejemplo:
pawn Код:
stock GetConnectedPlayers()
{
    new
    count;

    for(new i; i<GetMaxPlayers(); i++)
        if(IsPlayerConnected(i))
            count++;

    GetConnectedPlayers = count;
}
Ahora voy a mostrar una forma errуnea de retornar valores.
pawn Код:
stock Suma(valor1, valor2)
{
    new str[128];
    if(!IsNumeric(valor1) || !IsNumeric(valor2)){
        str = "ERROR: Los valores deben ser numйricos";
        return str;
    }
    return valor1+valor2;
}
La funciуn Suma, va a generar un error a la hora de compilar, dado que el primer valor que retorna es un string o array, mientras que el segundo es un numero entero.


Callbacks

Si bien puede ser algo confuso y complicado para comenzar, es algo que se utiliza todo el tiempo y es bбsico para scriptear en este lenguaje.

їQuй es un callback?
Un callback es una funciуn la cual es pasada como argumento a otra funciуn para ejecutar (o no) una o mas sentencias. Esto permite la re-utilizaciуn de cуdigo y ejecutar una o mas acciones para
diferentes elementos que son el mismo objeto entre otras cosas. Dicho de otra forma, podrнa decirse que son como 'eventos' (aun que en realidad no lo son) y de esta forma, cuando pasa 'X' llamamos
al callback OnX.

їPara que sirve un callback?
Un callback sirve para ejecutar una o mas sentencias en un determinado momento (cuando dicho callback es llamado); el cуdigo ejecutado puede utilizar los argumentos del callback, los cuales representan
en cierta forma un tipo de objeto, pero no necesariamente el mismo (ej: OnPlayerConnect se llama cuando un jugador se conecta, pero los ids en cada llamado pueden no ser los mismos).

їCуmo utilizo un callback?
Para utilizar una callback, simplemente basta colocar el codigo el cual queremos que se ejecute en cada llamado de la misma dentro de su definiciуn.

їPor quй 'forward' y quй es?
La palabra forward indica al compilador que estamos definiendo una nueva funciуn/callback. El porque es simple, pawn exige que primero se declare y luego se utilice.

їPuedo crear mis propios callbacks?
Si, para esto se requiere declarar el callback y luego realizar una llamada al mismo en el momento que nosotros queramos.

Ejemplo:
pawn Код:
forward OnPlayerCallPlayer(playerid, calledid);//Aquн declaramos nuestro callback

//Definiciуn de nuestro callback y sentencias que ejecutara el mismo
public OnPlayerCallPlayer(playerid, calledid)
{
    SendClientMessage(calledid, -1, "Te estбn llamando!");
    return 1;
}

//En algъn momento dentro de una funciуn o callback realizamos la llamada a nuestro callback con los argumentos que este recibirб
CallLocalFunction("OnPlayerCallPlayer", "ii", playerid, calledid);



Nivel: Medio


Inicializadores
Bueno ahora vamos a avanzar un poco mбs allб de las clбsicas definiciones y vamos a comprender un poco mбs sobre este lenguaje de programaciуn.

stock

їQuй es stock?
stock define una variable/array o funciуn, pero con la particularidad de que si dicha variable/funciуn no es utilizada, entonces se omitirб en la compilaciуn y no ocupara lugar.

їCуmo se utiliza?
La forma de utilizaciуn es la misma que utilizamos normalmente

Ejemplo:
pawn Код:
//Variables/arrays:
stock
    variable,
    array[5];

//Funciones:
stock MiFuncion();
?Para quй se utiliza?
Bбsicamente se utiliza para ahorrar memoria y espacio; pero tambiйn se lo utiliza para evitar advertencias sobre definiciones de elementos que luego no se utilizan.

const

їQuй es const?
Se utiliza para definir constantes. Las constantes son variables/arrays cuyo valor no se modificara.

їCуmo se utiliza?
La forma de utilizaciуn es la misma que utilizamos normalmente, pero debemos especificar el valor cuando creamos la variable/array.

Ejemplo:
pawn Код:
//Variables
const variable = 15;
new const variable = 15;
stock const variable = 30;

//Arrays
const array[5] = "Hola";
new const array[5] = "Hola";
stock const array[] = "Hola";
Nota: Como pueden ver, en la declaraciуn de un array, podemos obviar indicar el tamaсo de la ultima dimensiуn.

їPor quй se utiliza?
Podrбn preguntarse, porque no colocar directamente el valor y utilizar una variable constante. Bueno, la respuesta es que mediante la utilizaciуn de arrays/variables constantes, estos valores
si se repiten solo se almacenan 1 vez en memoria; en cambio si utilizбramos directamente el valor "hola", el mismo estarб en la memoria tantas veces como lo utilicemos. Es decir si usamos "hola"
5 veces en el script, en la memoria estarб 5 veces; ademas es mas rбpido acceder a una variable constante que a un texto.

static

їQuй es static?
Declara una variable/array/funciуn pero con caracterнsticas particulares; la variable/array/funciуn declarada puede utilizarse ъnicamente en el entorno y ademas en el caso de la variable/array, conserva el valor.

Ejemplo:
pawn Код:
main()
{
    MyFunction();
    print("!");
    MyFunction();
    return 1;
}

MyFunction()
{
    static
        j;

    for(new i; i<3; i++)
    {
        printf("%i", j);
        j++;
    }
}
Este cуdigo imprimirб en la consola:
Код:
0
1
2
!
3
4
5
Mientras que si la variable j no fuera estбtica, la salida seria:
Код:
0
1
2
!
0
1
2
En el caso de las funciones estбticas o las variables/arrays globales estбticas, estas solo pueden ser utilizadas en el archivo en el cual fueron declaradas.

enum

їQuй es un enum?
Un enum define una lista de elementos a los cuales se les asigna un numero.

їCуmo se utiliza?
La forma de utilizaciуn es la siguiente:

pawn Код:
enum nombre
{
    elemento_1,
    elemento_2,
    elemento_3,
    ...
    elemento_n
};
Nota: El ultimo elemento no lleva una , al final.

Usos comunes
Tal vez el uso mas comъn que le dan a los enums es para almacenar datos de jugadores u otros.

Ejemplo:
pawn Код:
enum PlayerData
{
    bool:Registrado,
    bool:Logueado,
    Dinero,
    Float:Vida,
    Nombre[MAX_PLAYER_NAME]
};

new PlayerInfo[MAX_PLAYERS][PlayerData];

public OnPlayerConnect(playerid)
{
    PlayerInfo[playerid][Registrado] = false;

    return 1;
}
Algo mбs...
Hasta aquн todo bien, pero quedarse solo con ese uso de enums es algo pobre. Los enums realmente son como una tabla, cada palabra del enum en realidad tiene un valor constante.

Ejemplo:
pawn Код:
const e_VAL1 = 0;
const e_VAL2 = 1;
const e_VAL3 = 2;

new Array[3];

main()
{
    Array[e_VAL1] = 10;
    Array[e_VAL2] = 15;
    Array[e_VAL3] = 120;
}
El cуdigo anterior utilizando enums seria el siguiente:

pawn Код:
enum e_VAL
{
    e_VAL1,
    e_VAL2,
    e_VAL3
};

new Array[3];

main()
{
    Array[e_VAL1] = 10;
    Array[e_VAL2] = 15;
    Array[e_VAL3] = 120;
}
Los dos cуdigos son anбlogos y compilaran perfectamente. De esta forma demostramos que los enums son valores constantes, estos valores son dados por el compilador
automбticamente y comienzan en el 0. Ahora bien, podemos tambiйn ser nosotros quienes coloquemos estos valores.

Ejemplo:
pawn Код:
enum e_TEST
{
    e_UNO = 5,
    e_DOS,
    e_TRES,
    e_CUATRO
};
En el ejemplo anterior, la cuenta comenzara en el numero 5, de esta forma e_DOS es el 6, e_TRES el 4 y asн sucesivamente. Pero tambiйn podemos asignar nosotros los valores que queramos
y no ъnicamente el inicial.

Ejemplo:
pawn Код:
enum e_TEST
{
    e_UNO,//0 pues por defecto la cuenta comienza en 0
    e_DOS,//1 pues el valor se auto-incrementa en 1
    e_TRES = 15,//15 pues asignamos el valor 15
    e_CUATRO,//16 pues el valor se auto-incrementa en 1
    e_CINCO = 60,//60 pues asignamos el valor 60
    e_SEIS[5],//Ahora acб hay una diferencia, esto es un bloque de 5 constantes, entonces e_SEIS tiene los valores del 61 hasta el 65
    e_SIETE//Obtendrб el valor siguiente, es decir 66
};

main()
{
    printf("Size: %d", _:e_TEST);//Printeara en la consola "Size: 67" pues el tamaсo de nuestro enum es 67
}
Ahora bien, tal vez estйn pensando que deberнa haber printeado "Size: 66", pero esto es incorrecto ya que no hablamos del valor mбximo, si no de la cantidad de slots que tiene, y estos
son 0-66, entonces hay 67 slots.

Veamos otro ejemplo:
pawn Код:
enum e_TEST
{
    e_UNO,
    e_DOS = 15,
    e_TRES[5],
    e_CUATRO
};

new
    Test[e_TEST];

main()
{
    Test[e_UNO] = 15;
    Test[e_DOS] = 150;
    Test[e_TRES] = "Hola";
    Test[e_CUATRO] = 5;
    Test[e_TEST:21] = 99;

    printf("%d %d %s %d", Test[e_UNO], Test[e_DOS], Test[e_TRES], Test[e_CUATRO]);//Printeara en consola "15 150 Hola 99"
}
Si esperaban que el cуdigo anterior printeara en el ultimo nъmero el 5 se equivocaron, pues la ultima asignaciуn sobre-escribe dicho valor.

Ahora bien, porque tuve que colocar e_TEST:21 y no simplemente 21? Esto se debe a que los enums tambien son tags.

Ejemplo:
pawn Код:
enum E_TEST
{
    E_UNO,
    E_DOS,
    E_TRES
};

new
    E_TEST:Var,
    Var2;

main()
{
    Var = E_TRES;
    Var2 = E_TRES;//Nos darб una advertencia ya que Var2 es de tipo int y no E_TEST

    printf("Var: %d %d", _:Var, Var2);

    return 1;
}
Nota:El tag _: se utiliza para remover cualquier tag de la variable/array/etc temporalmente y cambiar el mismo a int.


Los enums tambiйn pueden ser anуnimos, es decir no necesariamente tienen que tener un nombre.

Ejemplo:
pawn Код:
enum
{
    E_UNO,
    E_DOS,
    E_TRES
};
Una particularidad es que existen enums de tag fuerte y dйbil.

Ejemplo:
pawn Код:
enum E_TEST_1 //Tag fuerte pues comienza con E mayъscula
{
    E_UNO,
    E_DOS,
    E_TRES
};

enum e_TEST_2 //Tag dйbil pues comienza con e minъscula
{
    e_CUATRO,
    e_CINCO,
    e_SEIS
};

main()
{
    new
        Var;

    Var = E_TEST_1:E_UNO;//Darб una advertencia
    Var = e_TEST_2:e_CUATRO;//No da advertencia

    #pragma unused Var
}

Definiciones

Inicializaciуn
El concepto de inicializaciуn hace referencia al valor que se le da a una variable/array al crearlo. Por defecto en una variable su valor inicial es 0, anбlogamente en un array
cada uno de los slots tambiйn es 0.

їCуmo inicializar una variable?
La inicializaciуn de una variable es realmente muy simple, consiste en setear el valor correspondiente en su creaciуn.

Ejemplo:
pawn Код:
new Variable = 5;
їCуmo inicializar un array?
Es casi lo mismo, de hecho, cuando hablamos de strings vimos algo similar.

Ejemplo:
pawn Код:
new Array[10] = {1, 5, 5, 9, 10, 6, 7, 3, 0, 10};
new Array[2][3] = {{1, 5, 6}, {4, 2, 7}};
new Array[10] = {1, 2, ...};
Ops їQuй son los "..."?
Se lo conoce como el operador elipsis y uno de los usos que tiene es la inicializaciуn de arrays, este operador utiliza los valores anteriores para asignar los valores sucesivos al array hasta completarlo.

Veamos algunos ejemplos anбlogos para comprender mejor su funcionamiento:

Ejemplo:
pawn Код:
new Array[15] = {5, ...};
new Array[15] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
Ejemplo:
pawn Код:
new Array[10] = {0, 1, ...};
new Array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Ejemplo:
pawn Код:
new Array[6] = {1, 5, ...};
new Array[6] = {1, 5, 10, 15, 20, 25};
Ejemplo:
pawn Код:
new Array[10] = {1, 5, 8, ...};
new Array[10] = {1, 5, 8, 11, 14, 17, 20, 23, 26, 29};
Como podemos observar, es una forma muy rбpida de inicializar arrays sin tener que completar todos los valores. Si con los ejemplos no lo vieron, lo explicare:
El operador elipsis lo que hace es en caso de solo haber un nъmero, entonces completa con el mismo hasta el final o bien si hay mas de 1 numero restar los ъltimos 2 entre si y a partir del ultimo obtener el siguiente sumando dicha diferencia.

Ejemplo:
Код:
new Array[5] = {a, b, ...};
new Array[5] = {a, b, b+1*(b-a), b+2*(b-a), b+3*(b-a)};
Strings empaquetados

їQuй son los strings empaquetados?
Los strings empaquetados (packed strings en ingles) son cadenas de texto que guardan 1 carбcter por byte; los strings normales guardan un carбcter por cell (4 ytes), por lo que utilizando strings empaquetados, guardamos bastante espacio.

La trampa
El problema que tienen los strings empaquetados es que como tenemos 1/4 del tamaсo original para guardar los datos, cada carбcter solo puede estar en la tabla ASCII original, o lo que es lo mismo
el valor almacenado no puede salir del rango 0-255. Cualquier valor que este fuera de dicho rango solo saltara y caerб dentro del mismo.

Ejemplo:
Код:
El valor 300 salta y se convierte en 44; esto se debe a que 300 es mayor a 255 entonces el por la forma de almacenar utilizada en los strings empaquetados se pierde informaciуn. Una forma simple de calcular el valor
que se guardara (cuando el valor supera el numero 255) es: valor - 256.
Nota: Los strings empaquetados utilizan la codificaciуn Little Endian para almacenar los datos.

їCуmo se utilizan?
A diferencia de los strings/arrays normales, cuando se definen luego de ingresar el tamaсo se agrega la palabra "char".

Asignaciуn:
Ejemplo:
pawn Код:
new
    StringNormal[5],        //Este es un string de 5 cells o 20 bytes
    StringPacked[5 char];   //Este es un string de 2 cells u 8 bytes

main()
{
    StringNormal = "hola";
    StringPacked = !"hola";//Para indicar que el contenido debe ser empaquetado, colocamos el '!' delante del string.

    StringNormal[0] = 'H';
    StringPacked{0} = 'H';//Notese que utilizamos llaves para acceder y no corchetes.
}
Si se estбn preguntando porque el string empaquetado no es de 5 bytes, esto es porque se redondea al mъltiplo de 4 SUPERIOR mas cercano (1 es 4, 3 es 4, 4 es 8 y asi).

A continuaciуn veremos la lectura de datos, la cual dado que nativamente SA-MP no tiene mucho soporte para estos arrays, se vuelve algo tedioso.

Ejemplo:
pawn Код:
new StringPacked[5 char];

main()
{
    new
        tmp[128];

    strpack(StringPacked, "Hola");
    strunpack(tmp, StringPacked);

    format(tmp, 128, "%s, bienvenidos al servidor", tmp);
    SendClientMessage(playerid, -1, tmp);
}
Nota:Actualmente existe una librerнa (creada por Emmet_) la cual permite utilizar format directamente con strings empaquetados: link.

їCuбndo deben usarse strings empaquetados?
  • Strings utilizados no muy frecuentemente en el script.
  • Strings muy grandes con valores de la tabla ASCII
  • Para reducir la memoria utilizada
  • Siempre que se use un array para almacenar nъmeros y estos sean chicos (valores de 0 a 255)

Operadores

Operadores miscelбneos
{} Asignaciуn del contenido de arrays
defined Retorna "true" si la variable indicada fue definida mediante "#define"
sizeof() Retorna el tamaсo de un array
tagof() Retorna el tag de una variable/array
char Retorna el numero de cells necesario para contener un string empaquetado
Ternario (A) ? (B) : © => Es muy similar a if, else. Si A="true" retorna B, de lo contrario retorna C. Ejemplo:
pawn Код:
printf("Admin: %s", (Sinfo[Admin]) ? ("ON") : ("OFF"));
Si Sinfo[Admin] = true, entonces en la consola aparecerб "Admin: ON", de lo contrario aparecerб "Admin: OFF".

Expresiones

Bucles, switch, saltos y state

switch, case y default
Estas expresiones, van siempre juntas y se utilizan para realizar comparaciones en las cuales se quiere que segъn el valor, se realice una acciуn. Puede ser reemplazada por if, else if, else if, else, pero usando if serнa mбs lenta y menos efectiva.

Ejemplo:
pawn Код:
switch(variable)
{
    case 0:
        print("0");
    case 1:
        print("1");
    case 2:
    {
        print("2");
    }
    case 3, 4:
        print("3 o 4");
    case 5 .. 10:
        print("5 a 10");
    default:
        print("El valor de 'variable' es mayor a 10 o menor a 0");
}
Importante: cuando luego de la expresiуn "case" sigue una sola lнnea, o un if(sin else/else if) la expresiуn puede ir libre de brakets, de lo contrario es necesario colocarlos.

Loops(infinitos)
Bueno, en esta pequeсa parte de este tutorial, explicare como crear loops infinitos de diferentes formas.

Mйtodo 1:
pawn Код:
for(;;)print("Esto es un texto que saldrб repetidamente en la consola");
Mйtodo 2:(tira 1 warning, pero funciona perfecto)
pawn Код:
while(true)print("Esto es un texto que saldrб repetidamente en la consola");
Mйtodo 3:
pawn Код:
new
        bool:var = true;
    do{
        print("Esto es un texto que saldrб repetidamente en la consola");
    }while(var);
Esas son 3 formas de hacer un loop infinito. Hay mas formas pero son todas similares, asн que decidн poner solo esas.

break
Se utiliza para terminar con un bucle.

Ejemplo:
pawn Код:
for(new i; i<10; i++)
    if(Array_N[i] == true)
        break;

continue
Se utiliza para saltar un valor en un bucle.

Ejemplo:
pawn Код:
for(new i; i<10; i++){
    if(i==5)
        continue;

    printf("%i", i);
}
Este ejemplo darб como resultado en la consola:
Код:
0
1
2
3
4
6
7
8
9
goto
Esta expresiуn se utiliza para realizar un sato, para ir a x lugar del cуdigo, previamente definido (NO recomendable ya que se produce lo que se conoce como cуdigo espagueti).

Ejemplo:
pawn Код:
main()
{
    new
        bool:ThisBool;

    principio:

    print("principio");
    ThisBool = ((!random(2)) ? (false) : (true));
    if(ThisBool)
    {
        print("SI");
        goto TEnd;
    }
    else
    {
        print("NO");
        goto principio;
    }


    TEnd:

    print("fin");
}
El ejemplo por ahн no sea muy claro, pero lo que ese cуdigo hace es:
1є definir la variable(tipo boolean).
2є empieza con el bucle, y asigna un valor a la variable (verdadero o falso) segъn el numero obtenido del random
3є compara el contenido de la variable y si es false, vuelve a empezar, de lo contrario termina.


state
Se utiliza para cambiar el estado de un autуmata. Su uso es:
pawn Код:
state nombredelautomata
Si quieren mбs informaciуn sobre esto, les recomiendo mirar este topic de ****** que estб muy bien explicado este tema.


Directivas

Directivas bбsicas

#if, #elseif, #else, #endif
Definiciуn:
Se utiliza para comparar una sentencia.

Ejemplo:
pawn Код:
#if USE_MENU = 1
    print("Menъs: Habilitados");
#elseif USE_MENU = 0
    print("Menъs: Deshabilitados");
#else
    print("Menъs: Error");
#endif

#error
Definiciуn:
Se utiliza para enviar un error durante la compilaciуn.

Ejemplo:
pawn Код:
#if defined EERROR
    #error Mensaje de error.
#endif

#assert
Definiciуn:
Chequea si una comparaciуn devuelve true o false. En caso de ser false, detiene la compilaciуn.

Ejemplo:
pawn Код:
#define PP 6
#assert PP<4
Ese ejemplo enviara un error fatal con el texto "assertion failed: 6<4"

#include
Definiciуn:
Inserta el texto del archivo a incluir en la lнnea en la que se ubica.

Ejemplo:
pawn Код:
#include <a_samp>//carpeta de includes
#include "../include/gl_common"//otra carpeta

#tryinclude
Definiciуn:
Funciona igual que #include, con la diferencia de que si no puede incluir el archivo, no envнa un error.

Ejemplo:
pawn Код:
#tryinclude <a_samp>
#endinput
Definiciуn:
Deja de incluir el archivo que estaba siendo leнdo.

Ejemplo:
pawn Код:
#include <nombre>
#if defined _NOMBRE_INC
    #endinput
#endif
#define _NOMBRE_INC
#define
Definiciуn:
Crea una macro.

Ejemplo:
Constante:
pawn Код:
#define COLOR_RED 0xFF0000FF
#undef
Definiciуn:
Elimina una macro declarada.

Ejemplo:
pawn Код:
#define COLOR_X 0xFFA4B6F9
printf("%d", COLOR_X);
#undef COLOR_X
Si luego de ese cуdigo, intentбramos usar COLOR_X, tendrнamos que definirlo nuevamente, o el compilador, no compilarнa.


Archivos

Introducciуn
Los archivos se utilizan para guardar y leer datos. Estos datos pueden ser cuentas de usuarios, configuraciуn del servidor, autos, etc. La forma mas fбcil de utilizar archivos es utilizando
el formato de texto y no archivos binarios (los cuales veremos luego). La forma de leer/escribir en un archivo funciona mediante un puntero el cual apunta al archivo que abrimos; mediante ese
puntero nosotros podemos leer y escribir a este archivo.

Importante: Ya sea para crear, escribir o leer un archivo, en SA-MP el directorio del mismo debe estar dentro de la carpeta "\scriptfiles\" ubicada en el directorio raнz del servidor.

Creaciуn
Para crear un archivo necesitamos solamente 2 datos, el directorio en el cual crearemos dicho archivo y el nombre de nuestro archivo. Opcionalmente podemos agregarle una extensiуn (recomendado) la cual
nos brinde mбs informaciуn sobre el formato utilizado en dicho archivo. Para la creaciуn de un archivo utilizaremos la funciуn fopen de la siguiente forma:

pawn Код:
new
    File:fhnd;//este sera nuestro puntero al archivo
fhnd = fopen("/Nombre.ext", io_write);//Creamos el archivo
if(fhnd)//El archivo fue creado con йxito
    fclose(fhnd);//Creamos el handle
Nota: Notese que en la ruta del archivo utilizamos '/' y no '\'.

Lectura
Para leer un archivo se necesita el directorio, el nombre del mismo y un array extra para poder almacenar el contenido. La forma mas utilizada para leer de un archivo es hacerlo
linea por linea:

pawn Код:
new
    File:fhnd;

fhnd = fopen("/Nombre.ext", io_read);//Notemos que el archivo debe haberse creado o el servidor podrнa crashear (para evitar esto se puede utilizar io_readwrite)
if(fhnd)
{
    new
        counter,
        buffer[64];

    while(fread(fhnd, buffer))//Leemos linea por linea y almacenamos cada linea leнda en 'buffer'
    {
        printf("Linea %i: %s", counter, buffer);
        counter++;
    }
    fclose(fhnd);
}
Escritura
Para escribir en un archivo se necesita el directorio, el nombre del mismo y ademas el contenido a escribir. Existen 2 formas bбsicas de escritura, sobre-escribiendo todo el contenido o bien escribiendo al final del archivo:

[b]Sobre-escribiendo:
pawn Код:
new
    File:fhnd;

fhnd = fopen("/Nombre.ext", io_write);//El modo io_write creara (si no existe el archivo) o sobre-escribirб su contenido
if(fhnd)
{
    fwrite(fhnd, "Texto a guardar\r\n");//Notemos que \r\n indica que comenzaremos en una nueva linea y movemos el caddy
    fclose(fhnd);
}
Escribiendo al final del archivo:
pawn Код:
new
    File:fhnd;

fhnd = fopen("/Nombre.ext", io_append);//El modo io_write creara (si no existe el archivo) o escribe al final del mismo
if(fhnd)
{
    fwrite(fhnd, "Texto a guardar\r\n");//Notemos que \r\n indica que comenzaremos en una nueva linea y movemos el caddy
    fclose(fhnd);
}

Funciones

Funciones Complejas

Pasar parбmetros como opcionales
Esto es realmente muy simple en realidad, solo debemos agregar '=valor_default' a la variable q queramos que sea opcional y listo.

Ejemplo:
pawn Код:
stock SetPlayerTimeEx(playerid, hora, minutos=0)
{
    SetPlayerTime(playerid, hora, minutos);
    printf("Un admin seteo la hora de %i a %i:%i", playerid, hora, minutos);
}

//Como tiene parбmetros opcionales podemos:
SetPlayerTimeEx(playerid, 12);
Ejemplo:
pawn Код:
stock SetPlayerPosEx(playerid, Float:x, Float:y, Float:z, Float:a=0.0, Float:health=-1.0)
{
    SetPlayerPos(playerid, x, y, z);
    SetPlayerFacingAngle(playerid, a);
    if(health != -1.0)
        SetPlayerHealth(playerid, health);

    return 1;
}

//Si quisiйramos utilizar la funciуn con el parбmetro health pero no el angulo accedemos asн:
SetPlayerPosEx(playerid, 0.0, 0.0, 0.0, .health=100.0);
Pasar parбmetros por valor y por referencia
Parбmetro por valor, a la funciуn le llega una copia del valor. Podemos modificar el mismo pero el original no cambiara.

Ejemplo:
pawn Код:
main()
{
    new
        val_0 = 1,
        val_1 = 3,
        val_2 = Func(val_0, val_1);

    //Si bien Func modifica los valores que le dimos, val_0 y val_1 seguirбn valiendo 1 y 3 respectivamente
    printf("%i %i %i", val_0, val_1, val_2);

}

stock Func(valor_0, valor_1)
{
    valor_0 -= Valor_1 * 5;//modificamos valor_0
    return valor_1 += Valor_0 + Valor_2;
}
Ahora bien, existe una forma de editar los valores que se le asignan a una funciуn. Esto es lo que se conoce como "por referencia". Para hacer esto, solo es necesario agregar
el carбcter '&' delante de la variable que queremos pasar como referencia, de lo contrario (si no lo ponemos), esta variable serб pasada por valor.

Ejemplo:
pawn Код:
main()
{
    new
        val_0 = 1,
        val_1 = 3,
        val_2 = Func(val_0, val_1);

    printf("%i %i %i", val_0, val_1, val_2);

}

stock Func(&valor_0, &valor_1)
{
    valor_0 -= Valor_1 * 5;
    return valor_1 += Valor_0 + Valor_2;
}
Importante: por defecto, los arrays no pueden ser pasados por valor, їQuй quiere decir esto? que si en una funciуn especificamos uno de los parбmetros como array, serб pasado automбticamente por referencia y no por valor. Para pasar un array por valor se debe agregar 'const' delante del mismo.


Parбmetros variables
Para crear una funciуn con parбmetros indefinidos, debemos hacerlo utilizando la elipsis y podemos ayudarnos con otras funciones nativas para saber la cantidad de argumentos y obtener un argumento segъn el index del mismo.

Ejemplo:
pawn Код:
main()
{
    printf("%i", SumaTodo(5, 6, 1, 100, 8));
    printf("%i", SumaTodo(1, 9, 6, 169, 17, 65, 243, 213));
}

stock SumaTodo(...)
{
    new res;
    for(new i; i<numargs(); i++)res += getarg(i);
    return res;
}
Ejemplo:
pawn Код:
//Declaraciуn:
SetPlayerRandomColor(playerid, ...)
{
    new
        rnd,
        count;

    count = numargs() - 1;//numeramos los argumentos.
    rnd = random(count);

    if(!count)
        return SetPlayerColor(playerid, GetPlayerColor(playerid));

    return SetPlayerColor(playerid, getarg((!rnd) ? (1) : (rnd)));
}

//Uso:
SetPlayerColor(playerid, 0xFF0000FF, 0xFFFF00FF, 0x0000FF66, 0x66FFA8FF);



Nivel: Avanzado


Operadores

Operadores de Bits(manipulaciуn)

~A => Retorna el complemento de A.
•A >> B => Retorna el shift aritmйtico de B (hacia la izquierda) sobre A.
•A >>> B => Retorna el shift lуgico de B (hacia la izquierda) sobre A.
•A << B => Retorna el shift de B (hacia la derecha) sobre A.
•A & B => Retorna A "and" B.
•A | B => Retorna A "or" B.
•A ^ B => Retorna A "exclusive or" B.

Operadores de Bits(Asignaciуn)
Esos operadores son iguales a los de asignaciуn comъn, y a estos se les suman los de manipulaciуn de bits (siempre con el signo = despuйs del signo de manipulaciуn).


Nъmeros binarios

Introducciуn
Los nъmeros binarios son nъmeros representados en una forma diferente, mas correctamente en base 2; por otra parte los nъmeros que estamos acostumbrados a manejar son base 10, esto quiere
decir que normalmente utilizamos 10 nъmeros para representar cualquier otro (0-9). Con binario, todo se representa con el 0 y el 1.

Ejemplo:
Код:
Decimal      Binario
0               0
1               1
2               10
3               11
4               100
5               101
6               110
7               111
8               1000
9               1001
10              1010
Importante: Cada posiciуn de un numero binario se conoce como bit y representa una potencia de 2.

Importante: En pawn para indicar que un nъmero es binario se utiliza en prefijo '0b'

Binario a decimal
їCуmo saber que numero se esta representando el binario? Esto es algo realmente simple y es mejor un ejemplo a explicarlo para mayor claridad.

Ejemplo:
Supongamos el numero binario '1100' y queremos saber que nъmero decimal representa.
Код:
Nъmero decimal = 1*(2^3) + 1*(2^2) + 0*(2^1) + 0*(2^0)
Nъmero decimal = 8 + 4 + 0 + 0
Nъmero decimal = 12
Ejemplo:
Supongamos el numero binario '11001011' y queremos saber que nъmero decimal representa.
Код:
Nъmero decimal = 1*(2^7) + 1*(2^6) + 0*(2^5) + 0*(2^4) + 1 *(2^3) + 0 *(2^2) + 1*(2^1) + 1*(2^0)
Nъmero decimal = 128 + 64 + 0 + 0 + 8 + 0 + 2 + 1
Nъmero decimal = 203
Decimal a binario
Para pasar un numero decimal a binario solamente hay que dividir el numero original por 2 y luego el cociente por 2, y asн hasta obtener como dividendo 0 o 1. Una vez que obtuvimos 0 o 1
como dividendo escribimos los restos escribirlos al revйs y ese sera nuestro nъmero binario.

Ejemplo:
Supongamos el numero 25, y queremos saber representarlo en binario:
Код:
25=12*2 + 1
12=6*2 + 0
6=3*2 + 0
3=1*2 + 1
1=0*2 + 1

Una vez que llegamos a obtener el 1 como dividendo (yo hice un paso mas para que se entienda mejor) ya terminamos. Solo nos resta ordenar los restos obtenidos pero en la posiciуn inversa.

En este caso el numero binario que representa al 25 es '11001'
Nъmeros negativos
Tal vez se estйn preguntando como almacenar nъmeros negativos en este sistema binario. Y la forma es muy simple, pawn utiliza un standard en el cual, el bit de mas a la izquierda representa el signo
si dicho bit es 0 entonces el numero es positivo, de lo contrario, este sera negativo (a este bit se lo denomina MSB o most significant bit). De esta forma, como pawn utiliza enteros
de 32 bits, si restamos este bit nos quedan 31 bits para representar cualquier nъmero. Si colocбramos los 31 bits en 1, obtendrнamos el mayor numero posible, el cual es 2,147,483,647. Ahora bien, esto
si hicieran las cuentas, se darнan cuenta que 2^31=2,147,483,648, esto se debe a que dentro de todos los nъmeros que representamos tenemos el 0, entonces el numero mбximo es 2^31-1, por otra parte,
como solo hay un ъnico 0, el menor nъmero posible es -2,147,483,648.

Operaciones con bits

AND (&)
Compara bit a bit y devuelve 1 si ambos son 1, caso contrario 0.

Ejemplo:
Код:
1011010 & 0010010 = 0010010

Para verlo mejor, coloquemos uno sobre el otro
1011010
0010010
------
0010010
OR (|)
Compara bit a bit y devuelve 1 si alguno de los 2 bits es 1, caso contrario 0.

Ejemplo:
Код:
1011010 | 0010010 = 1011010

Para verlo mejor, coloquemos uno sobre el otro
1011010
0010010
------
1011010
XOR (^)
Compara bit a bit y devuelve 1 si SOLO 1 de los 2 bits es 1, caso contrario 0.

Ejemplo:
Код:
1011010 ^ 0010010 = 1001000

Para verlo mejor, coloquemos uno sobre el otro
1011010
0010010
------
1001000
NOT (~)
Invierte todos los 0 y 1 del nъmero.

Ejemplo:
Код:
~0010010 = 1101101

La operaciуn es el equivalente a
1111111 ^ 0010010 (XOR)

Para verlo mejor, coloquemos uno sobre el otro
1111111
0010010
------
1101101
Shifts aritmйticos

Izquierdo (<<)
Mueve cada bit x lugares a la izquierda y se rellena agregando tantos 0 como lugares se muevan los bits.

Ejemplo:
Код:
00000000000000000000000000010000//16
00000000000000000000000000010000 << 2 = 00000000000000000000000001000000//64
Ejemplo:
Код:
11111111111111111111111111110000//-16
11111111111111111111111111110000 << 2 = 11111111111111111111111111000000//-64
Nota: Si prestan atenciуn se darбn cuenta que es aumentar n-veces la potencia del 2.

Derecho (>>)
Mueve cada bit x lugares a la derecha y se agregan x nъmeros a la izquierda, el valor de estos nъmeros es el del MSB para conservar el signo.

Ejemplo:
Код:
00000000000000000000000000010000//16
00000000000000000000000000010000 >> 2 = 00000000000000000000000000000100//4
Ejemplo:
Код:
11111111111111111111111111110000//-16
11111111111111111111111111110000 >> 2 = 11111111111111111111111111111100//-4
Nota: Si prestan atenciуn se darбn cuenta que es restar n-veces la potencia del 2.

Shifts lуgicos

Izquierdo
No existe shift a la izquierda, esto se debe a que seria lo mismo que realizar un shift aritmйtico a la izquierda.

Derecho (>>>)
Podrнa definirse como el opuesto del shift aritmйtico a la izquierda.

Ejemplo:
Код:
00000000000000000000000000010000//16
00000000000000000000000000010000 >> 2 = 00000000000000000000000000000100//4
Ejemplo:
Код:
11111111111111111111111111110000//-16
11111111111111111111111111110000 >> 2 = 00111111111111111111111111111100//1073741820
00000000000000000000000000000000

їPara quй sirven realmente los nъmeros binarios?
Se utilizan principalmente para ahorrar espacio y no desperdiciar memoria.
Pero tambiйn pueden utilizarse para guardar datos en un archivo como veremos mas tarde.


Directivas

Directivas avanzadas

#define
Definiciуn:
Crea una macro. puede ser una funciуn o solo una constante.

Ejemplo:
Constante:
pawn Код:
#define COLOR_RED 0xFF0000FF
Funciуn:
pawn Код:
#define Minutes(%0) (%0)*60*1000
Dado que el tema de las macros es muy amplio, y ya ha sido explicado por ****** les dejo el Link

#pragma
Definiciуn:
Esta directiva, puede tomar muchos valores:

amxlimit (valor):
Setea el valor mбximo del tamaсo que puede alcanzar el archivo .amx del script.

amxram (valor):
Setea el valor mбximo de memoria ram que puede utilizar el archivo .amx del script.

codepage (nombre/valor):
Setea el formato en el que deben codificarse los strings.

ctrlchar (carбcter):
Setea el sнmbolo que indica la continuaciуn una nueva lнnea (por defecto"\").

deprecated (valor):
Setea un sнmbolo que no se puede usar. Si el compilado lo encuentra en el script, sale un warning.

dynamic (valor):
Setea el tamaсo en cells de la memoria asignada para los datos dinбmicos.

Library (nombre):
Especifica el archivo (.dll o .so) del cual obtener las funciones nativas.

pack (0/1):
Cambia el modo de uso de los strings comprimidos y descomprimidos.

tabsize (value):
Setea el valor asignado a cada tabulaciуn. (defecto: .

unused (symbol):
Especifica que no se usara ese sнmbolo.



Final

Espero que les sirva y tengo el post abierto a ediciones si me equivoque en algo y para futuras actualizaciones.
Reply
#2

Solamente excelente, mil gracias.
Reply
#3

Simplemente increible.
Reply
#4

Genial, mi peludo amigo.
Reply
#5

OOO:

No fui el primero que tuvo el honor de leerlo, como dijiste anoche, me considero alguien que no use tanto pawno.

Me has dado un gran empujуn (:

Simplemente, grбcias
Reply
#6

Muy bueno, felicitaciones se nota que pasaste bastante tiempo escribiйndolo. Aunque hasta en la secciуn "Avanzado" no aprendн nada porque ya me sabнa todo, sigue estando bien. xD


EDIT: Pronto mi thread de optimizaciones.
Reply
#7

ЎBien hecho!

Solo te falto dejarnos un enlace para leer el manual del lenguage.
Reply
#8

Quote:
Originally Posted by Miguel
Посмотреть сообщение
ЎBien hecho!

Solo te falto dejarnos un enlace para leer el manual del lenguage.
la verdad es que pense en poner un link al manual, pero no lo puse x varias razones. dejo algunas
Si bien es sierto que el manual ese es muchisimo mas completo que esto, x razones obvias, hay muchas cosas que estan explicadas de una forma confusa, y se hace un poco complicado de entender.

Ahora bien, a aquellos que lo lean, tengan en cuenta que en ese manual se habla de funciones, operadores, directivas, que en algunos casos el compilador que se usa para sa-mp, no soporta. y puede q compile, pero no funcionara.
Reply
#9

Quote:
Originally Posted by the_chaoz
Посмотреть сообщение
tengan en cuenta que en ese manual se habla de funciones, operadores, directivas, que en algunos casos el compilador que se usa para sa-mp, no soporta. y puede q compile, pero no funcionara.
Entonces no es por un lado "razonable" leer y seguir el manual?
Reply
#10

Quote:
Originally Posted by the_chaoz
Посмотреть сообщение
la verdad es que pense en poner un link al manual, pero no lo puse x varias razones. dejo algunas
Si bien es sierto que el manual ese es muchisimo mas completo que esto, x razones obvias, hay muchas cosas que estan explicadas de una forma confusa, y se hace un poco complicado de entender.

Ahora bien, a aquellos que lo lean, tengan en cuenta que en ese manual se habla de funciones, operadores, directivas, que en algunos casos el compilador que se usa para sa-mp, no soporta. y puede q compile, pero no funcionara.
Para eso estб la wiki.
Ah y sobre el tutorial quedу re bien , pero los manuales son para complementar tu tutorial, no todo estб en los manuales.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)