Saltar al contenido
  • Global

    Global

    Chatroom Rules

    • NO SE DA SOPORTE EN CHATBOX
    • NO SPAM
    • NO FLOOD

Aprender pawn (nivel basico/medio/avanzado)


Publicaciones recomendadas

  • Usuario
Publicado (editado)
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 Código:
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 Código:
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:

Código:
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 Código:
new tag:Nombre;

Ejemplos Float

pawn Código:
new Float:MiFloat;

File

pawn Código:
new File:MiFile;

Bool

pawn Código:
new bool:MyBool;

Integer

pawn Código:
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 Código:
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 Código:
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 Código:
new Array[5];
Array[5] = 4;//esto causara un error, dado que el índex máximo de Array es 4

Ejemplo 2:

pawn Código:
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 Código:
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 Código:
//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 Código:
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 Código:
//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 Código:
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 Código:
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 Código:
    new array[5];//Array uni-dimensional de 5 slots
  • Bi-dimensional (2 dimensiones):

    Ejemplo:
    pawn Código:
    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 Código:
    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 Código:
    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:
    Código:
    1 50 0 0 0
  • Bi-dimensional:

    Ejemplo:
    pawn Código:
    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:
    Código:
    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 Código:
    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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
stock GetConnectedPlayers()
{
new
count;

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

return count;
}

Ejemplo:

pawn Código:
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 Código:
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 Código:
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 Código:
//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 Código:
//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 Código:
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:

Código:
0
1
2
!
3
4
5

Mientras que si la variable j no fuera estática, la salida seria:

Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
enum
{
E_UNO,
E_DOS,
E_TRES
};

Una particularidad es que existen enums de tag fuerte y débil.

Ejemplo:

pawn Código:
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 Código:
new Variable = 5;

¿Cómo inicializar un array?
Es casi lo mismo, de hecho, cuando hablamos de strings vimos algo similar.

Ejemplo:

pawn Código:
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 Código:
new Array[15] = {5, ...};
new Array[15] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};

Ejemplo:

pawn Código:
new Array[10] = {0, 1, ...};
new Array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

Ejemplo:

pawn Código:
new Array[6] = {1, 5, ...};
new Array[6] = {1, 5, 10, 15, 20, 25};

Ejemplo:

pawn Código:
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:

Código:
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:

Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
for(; ;)print("Esto es un texto que saldrá repetidamente en la consola");

Método 2:(tira 1 warning, pero funciona perfecto)

pawn Código:
while(true)print("Esto es un texto que saldrá repetidamente en la consola");

Método 3:

pawn Código:
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 Código:
for(new i; i<10; i++)
if(Array_N == true)
break;

continue
Se utiliza para saltar un valor en un bucle.

Ejemplo:

pawn Código:
for(new i; i<10; i++){
if(i==5)
continue;

printf("%i", i);
}

Este ejemplo dará como resultado en la consola:

Código:
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 Código:
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 Código:
state nombredelautomata

Si quieren más información sobre esto, les recomiendo mirar este topic de y_less 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 Código:
#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 Código:
#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 Código:
#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 Código:
#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 Código:
#tryinclude <a_samp>

#endinput
Definición:
Deja de incluir el archivo que estaba siendo leído.

Ejemplo:

pawn Código:
#include <nombre>
#if defined _NOMBRE_INC
#endinput
#endif
#define _NOMBRE_INC

#define
Definición:
Crea una macro.

Ejemplo:
Constante:

pawn Código:
#define COLOR_RED 0xFF0000FF

#undef
Definición:
Elimina una macro declarada.

Ejemplo:

pawn Código:
#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 Código:
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 Código:
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:

Sobre-escribiendo:

pawn Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
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 Código:
//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:

Código:
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.

Código:
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.

Código:
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:

Código:
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:

Código:
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:

Código:
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:

Código:
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:

Código:
~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:

Código:
00000000000000000000000000010000//16
00000000000000000000000000010000 << 2 = 00000000000000000000000001000000//64

Ejemplo:

Código:
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:

Código:
00000000000000000000000000010000//16
00000000000000000000000000010000 >> 2 = 00000000000000000000000000000100//4

Ejemplo:

Código:
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:

Código:
00000000000000000000000000010000//16
00000000000000000000000000010000 >> 2 = 00000000000000000000000000000100//4

Ejemplo:

Código:
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 Código:
#define COLOR_RED 0xFF0000FF

Función:

pawn Código:
#define Minutes(%0) (%0)*60*1000

Dado que el tema de las macros es muy amplio, y ya ha sido explicado por Y_Less 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: cool.gif.

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.

 

Fuente: SA-MP Forums

Creador: TheChaoz

Editado por NeuZz
  • Usuario
Publicado

aportazo, excelente estimado, la paciencia para crear esto te felicito

Hay una confusión don gabo, lo hizo TheChaoz de samp forums xd

 

La cuestión es que yo aprendí de esta guía, me pareció un buen aporte al foro :)

  • Usuario
Publicado

Genial! Ya antes eh visto esta guía y me parece una de las mejores guías para Pawno Scripting es un aportaso pero por mas que la allá hecho él gracias por traerla acá. Añadilo a un credito o algo

Si eres tan bueno en Scripting SA-MP porque no hiciste un servidor (?

  • Usuario
Publicado

Genial! Ya antes eh visto esta guía y me parece una de las mejores guías para Pawno Scripting es un aportaso pero por mas que la allá hecho él gracias por traerla acá. Añadilo a un credito o algo

Si eres tan bueno en Scripting SA-MP porque no hiciste un servidor (?

Nunca dije que fuera bueno, solo se el lenguaje xD

 

Los créditos siempre estuvieron ahí, y la pagina a la que nombras es incorrecta.

 

8Pf5T.png

 

Y si tuve un server, era oficial de aca xDD

  • Usuario
Publicado (editado)

aps no habia visto los creditos, en mis tiempos habia q puro aprender de samp wiki y nada mas

Editado por GaBO
  • 2 years later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Invitado
Responder a este tema...

×   Pegar como texto enriquecido.   Pegar como texto sin formato

  Only 75 emoji are allowed.

×   Tu enlace se ha incrustado automáticamente..   Mostrar como un enlace en su lugar

×   Se ha restaurado el contenido anterior.   Limpiar editor

×   No se pueden pegar imágenes directamente. Carga o inserta imágenes desde la URL.

  • Explorando recientemente   0 miembros

    • No hay usuarios registrados viendo esta página.
×
×
  • Crear nuevo...