Aprender pawn
(nivel
bsico/medio/avanza
do)
Introduccin
Haca rato que no creaba ningn tutorial, y tena 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 ms nuevos a dar
sus primeros pasos con este lenguaje de programacin de scripts
llamado pawn. Y a aquellos que saben un poco, a que sigan aprendiendo
cosas nuevas, o a recordar cosas que se haban olvidado.
Este tutorial va a ir desde lo ms bsico, hasta cosas no tan bsicas
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 Bsico/Nulo, Medio y
Avanzado. Cada nivel consta con conocimientos acorde al nivel
propuesto, pero les sugiero a aquellos que no han ledo demasiado
sobre pawn, que lean desde el principio, aun que tengan los
conocimientos, porque lo que se dice en el nivel bsico, se da por
entendido en los dems 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:
Introduccin
Forma de uso
Indice:
Nivel: Bsico/Nulo
o Variables y Arrays
Primeros pasos con variables y arrays
Qu es una variable?
Para qu sirve una variable?
Cmo defino una variable?
Cmo utilizo una variable?
Qu es un tag y cules existen?
Cmo definimos una variable con un tag?
Qu es un array?
Cmo defino un array?
Cmo utilizo un array?
Cuales son los tags de los arrays?
Podemos definir arrays con tags? Y si es as Cules
son los tags de los arrays?
Un 'tipo' de array particular, los strings
Qu es un string?
Cmo guardo un string?
Salvedades
Comparacin
Asignacin
Arrays multi-dimensionales
Qu es una dimensin?
Qu es un array multi-dimensional?
Cuntas dimensiones existen?
Cmo crear un array multi-dimensional?
Cmo utilizo un array multi-dimensional?
Alcance de una variable/array
Qu es el alcance de una variable/array?
Local
Global
o Operadores
Introduccin
Qu es un operador?
Cules son los Operadores y cul es su forma de uso?
o Caracteres Especiales
Script
Strings
o Sentencias, Expresiones y estructuras (condicionales y no
condicionales)
Qu es una sentencia?
Qu es una expresin?
Cules son las expresiones que existen y cmo se utilizan?
if, else, combinacin (else if), assert, for, do, while y return
o Funciones
Funciones Simples
Qu es una funcin?
Cmo crear una funcin?
Funciones sin parmetros
Funciones con parmetros
Funciones con retorno de valores
o Callbacks
Qu es un callback?
Para qu sirve un callback?
Cmo utilizo un callback?
Por qu 'forward' y qu es?
Puedo crear mis propios callbacks?
Nivel: Medio
o Inicializadores
stock
Qu es stock?
Cmo se utiliza?
Para qu se utiliza?
const
Qu es const?
Cmo se utiliza?
Por qu se utiliza?
static
Qu es static?
enum
Qu es un enum?
Cmo se utiliza?
Usos comunes
Algo ms...
o Definiciones
Inicializacin
Cmo inicializar una variable?
Cmo inicializar un array?
Ops Qu son los "..."?
Strings empaquetados
Qu son los strings empaquetados?
La trampa
Cmo se utilizan?
Cundo deben usarse strings empaquetados?
o Operadores
Operadores miselaneos
{}
defined
sizeof
tagof
char
Ternario
o Expresiones
Bucles, switch, saltos, sleep
switch, case y default
break
continue
goto
sleep
state
Loops(infinitos)
o Directivas
Directivas bsicas
#if, #elseif, #else, #endif
#error
#assert
#include
#tryinclude
#endinput
#define
#undef
o Archivos
Introduccin
Creacin
Lectura
Escritura
o Funciones
Funciones Complejas
Parmetros opcionales
Parmetros por valor y por referencia
Parmetros variables
Nivel: Avanzado
o Operadores
Operadores de Bits(manipulacin)
Operadores de Bits(Asignacin)
o Nmeros binarios[/b]
Introduccin
Binario a Decimal
Decimal a binario
Nmeros negativos
Operaciones con bits
AND (&)
OR (|)
XOR (^)
NOT (~)
Shifts aritmticos
Izquierdo
Derecho
Shifts lgicos
Izquierdo
Derecho
Para qu sirven realmente los nmeros binarios?
o Directivas
Directivas avanzadas
#define
#pragma
amxlimit
amxram
codepage
ctrlchar
deprecated
dynamic
Library
pack
tabsize
unused
Final
Nivel: Bsico/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 ejecucin del mismo, para almacenar informacin, que luego
usaremos para almacenar algn 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).
Cmo defino una variable?
Para definir una variable en pawn, la forma ms simple es utilizar
"new" y se utiliza de la siguiente forma.
Code:
new MiVariable;
Esa sentencia define "MiVariable" como una variable de tipo entero (en
ingles integer).
Cmo 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:
Code:
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:
Code:
El valor de MiVariable es 15.
Entonces en las variables solo podemos almacenar nmeros enteros?
Por el momento diremos que no, para poder almacenar otros datos como
por ejemplo nmeros decimales, utilizaremos 'Tags'.
Qu es un tag y cules existen?
Un tag es un pedacito de cdigo, 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 nmeros enteros y nmeros con coma
Almacena el handle de un archivo abierto (no se preocupen de que es un
File
handle, luego lo explicare)
bool Almacena true o false (verdadero o falso)
int Almacena nmeros enteros (Este es el tag por defecto utilizado en pawn)
Cmo definimos una variable con un tag?
Para definir una variable taggeada (con un tag), lo vamos a hacer de
la siguiente forma:
Code:
new tag:Nombre;
Ejemplos
Code:
Float new Float:MiFloat;
Code:
File new File:MiFile;
Code:
Bool new bool:MyBool;
Code:
Integer new MiInteger;
Qu es un array?
Un array es como si definiramos muchas variables y las uniramos
todas, de esta forma tendramos una sucesin de variables, en las
cuales podramos almacenar varios datos (1 dato por variable).
Cmo defino un array?
La forma de definir un array es muy sencilla, de hecho es casi igual
que definir una variable.
Ejemplo:
Code:
new MiArray[4];
Como pueden ver, solo varia [n]; en este caso, n=4. Pero... Qu
representa 'n'? 'n' representa el tamao de ese array, es decir la
cantidad de datos que podemos almacenar.
Cmo utilizo un array?
Para utilizar un array, lo que hacemos es almacenar o leer los datos
indicando la posicin que ocupa el mismo (Las posiciones o indices
comienzan en 0 y van hasta n-1).
Ejemplo:
Code:
new MiArray[3];
//Asignacin:
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 definicin.
Ejemplo:
Code:
new Array[5];
Array[5] = 4;//esto causara un error, dado que el ndex mximo de
Array es 4
Ejemplo 2:
Code:
new MiArray[4];
//Asignacin
MiArray = {1, 5, 8, 10};//Realizamos una asignacin 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 asignacin mltiple, 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 Cules son los tags de
los arrays?
Los mismos tags que tienen las variables, y se los especifica de igual
forma:
Code:
new tag:nombre[tamao];
Ahora que ms o menos tenemos idea de cmo se declara una variable y
un array, un caso algo ms 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 nmeros (y en los arrays se almacenan nmeros nicamente) Cmo
podemos almacenar estos caracteres?
Hace mucho tiempo se decidi que se creara una tabla de cdigos,
donde a cada carcter se le asignara un numero que lo representaba, a
esta tabla se la llamo tabla ASCII.
Cmo guardo un string?
Para almacenar un string solo basta convertir la cadena y guardarla en
el array que queremos.
Ejemplo:
Code:
//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 maysculas y minsculas)
Ahora bien, logramos almacenar un string en el array como queramos,
pero tenemos un nuevo problema, dado que los arrays se guardan en la
memoria seguidos, como sabra el compilador como dejar de leer?
Es decir, supongamos el siguiente ejemplo:
Code:
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 convencin la cual
indica que todos los strings deben terminar
en el carcter 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:
Code:
//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
Comparacin
Si bien aun no hablamos de sentencias, estructuras lgicas y dems, es
bastante simple de entender y algo bsico, por lo que cabe destacar
esto aqu.
Muchos, seguramente se vieron tentados e intentaron comparar strings
de la siguiente forma:
Code:
new array[5] = "Hola";
if(array == "Hola")
El problema con este mtodo de comparacin, es que esta mal. El
operador == compara valores numricos nicamente, y los strings, son
una cadena de valores.
Para comparar un string deberamos ir valor por valor, pero esto es
algo tedioso, por este motivo hay funciones que nos permiten realizar
esto (la funcin 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).
Asignacin
Los siguientes ejemplos son todos anlogos, es decir son iguales
Code:
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 dimensin?
La dimensin 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. Podra graficarse como una
matriz en el caso de tener 2 dimensiones, o como un cubo si tuviese 3.
Cuntas dimensiones existen?
La versin de Pawn utilizada por SA-MP soporta hasta 3 dimensiones.
Cmo crear un array multi-dimensional?
Uni-dimensional (1 dimensin):
(Son los que ya vimos antes, pero ahora podemos decir que son uni-
dimensionales)
Ejemplo:
Code:
new array[5];//Array uni-dimensional de 5 slots
Bi-dimensional (2 dimensiones):
Ejemplo:
Code:
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:
Code:
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.
Cmo utilizo un array multi-dimensional?
Se utilizan igual que los uni-dimensionales.
Uni-dimensional:
Ejemplo:
Code:
new array[3];
//Asignacin:
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
Grficamente:
Code:
1 50 0 0 0
Bi-dimensional:
Ejemplo:
Code:
new array[5][5];
//Asignacin:
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]);
Grficamente:
Code:
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:
Code:
new array[5][5][5];
//Asignacin:
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]);
Grficamente:
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 declaracin debe ser realizada dentro
del entorno en el que se desea usar la variable/array.
Ejemplo:
Code:
public OnPlayerConnect(playerid)
{
new
str[32+MAX_PLAYER_NAME],
name[MAX_PLAYER_NAME];//declaracin 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 cdigo funcione correctamente deberan definirse las
variables nuevamente dentro del 2do callback.
Como debera ser el cdigo de arriba para funcionar correctamente:
Code:
public OnPlayerConnect(playerid)
{
new
str[36+MAX_PLAYER_NAME],
name[MAX_PLAYER_NAME];//declaracin 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];//declaracin 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 funcin, callback, etc.
Ejemplo:
Code:
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:
Code:
MyFuncion()
{
new var1;
for(new i; i<5; i++)
{
//var1 todava existe.
new var2;
printf("%i", var2);
var2++;
//var2 todava existe
}
//var1, todava existe, pero var2 no existe
}
//var1 no existe.
Operadores
Introduccin
Qu es un operador?
Un operador es un smbolo que se utiliza en expresiones, o bien para
realizar una accin (no se preocupen si no saben lo que es una
expresin, lo veremos luego).
Cules son los operadores y cul es su forma de uso?
Aritmticos:
A+B Retorna la suma de A y B
A-B Retorna la resta de A y B
A*B Retorna la multiplicacin de A y B
A/B Retorna la divisin de A y B
A%B Retorna el resto de la divisin de A y B
Asignacin:
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(numricos):
Retorna verdadero si A es igual B, de lo contrario retorna
A == B
falso
Retorna verdadero si A es distinto de B, de lo contrario
A != B
retorna falso
Retorna verdadero si A es menor que B, de lo contrario
A<B
retorna falso
Retorna verdadero si A es mayor que B, de lo contrario
A>B
retorna falso
Retorna verdadero si A es menor o igual que B, de lo
A <= B
contrario retorna falso
Retorna verdadero si A es mayor o igual que B, de lo
A >= B
contrario retorna falso
Racionales(booleanas):
!B
Retorna el valor opuesto de B
(NOT)
A || B Retorna verdadero A o B son verdadero, de lo contrario
(OR) retorna falso
A && B Retorna verdadero si A y B son verdadero, de lo contrario
(AND) retorna falso
Caracteres Especiales
Script
\ Indica que la lnea actual, sigue en la de abajo.
; Fin de sentencia.
Strings
\a Beep
\b backspace
\e Escape
\n Nueva linea
\r Retorno del caddy
\t Tabulacin horizontal
\v Tabulacin vertical
\\ Inserta literalmente el smbolo '\'
\' Inserta literalmente el smbolo "'"
\" Inserta literalmente el smbolo '"'
\% Inserta literalmente el smbolo '%'
\ddd; cdigo de caracteres, con el cdigo en decimal "ddd"
\xhhh; cdigo de caracteres, con el cdigo en hexadecimal "hhh"
Sentencias, Expresiones y estructuras (condicionales
y no condicionales)
Qu es una sentencia?
Es la unidad mas pequea de cdigo que puede ser ejecutada, es decir,
cada linea de cdigo es una sentencia.
Qu es una expresin?
Una expresin es una combinacin de constantes, variables/arrays,
funciones, y/o operadores, que son evaluadas segn los parmetros
indicados (si no entienden, no se preocupen pues al ver los ejemplos
sera intuitivo).
Cules son las expresiones que existen y cmo se utilizan?
Existen infinitas expresiones, pues son una combinacin 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 ms importantes y simples, se utiliza para
comparar, y segn el resultado de la comparacin, se realiza o no una
determinada accin.
Ejemplo 1:
Code:
public OnPlayerConnect(playerid)
{
new
rnd = random(2);
if(rnd == 0)
SendClientMessage(playerid, 0x00FF00FF, "Bienvenido al
servidor");//Este cdigo solo se ejecutara si la variable 'rnd' es
igual a 0
return 1;
}
Ejemplo 2:
Code:
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 cdigo a ejecutar, si la comparacin 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 ms importantes, y tambin
una de las ms utilizadas. Su uso va con la estructura vista
anteriormente (sin excepcin) y ejecuta una accin nicamente cuando
la expresin en el if es falsa.
Ejemplo:
Code:
Estado(playerid)
{
if(IsPlayerConnected(playerid) == 1)
{
//Este codigo solo se ejecutara si la funcin
'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 funcin
'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 combinacin de las 2 estructuras vistas anteriormente.
Ejemplo:
Code:
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 iniciacin, el 2 es la comparacin y el 3 es la
renovacin (cada paso se separa por ';').
Ejemplo:
Code:
for(new i; i<100; i++)
{
printf("Nmero: %d", i);
}
do
Es otra forma de crear un loop, pero a diferencia del for, este solo
consta de un paso, la comparacin.
Ejemplo:
Code:
new
i;
do
{
printf("Nmero: %d", i);
i++;//Dado que solo hay una comparacin, 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:
Code:
new
i;
while(i < 100)
{
printf("Nmero: %d", i);
i++;//Dado que solo hay una comparacin, debemos ser nosotros
quienes modifiquemos el valor del contador
}
return
Se utiliza para retornar un valor de una funcin/callback, o bien para
salir/interrumpir la ejecucin misma (no se ejecutara el cdigo que
este luego de esta estructura).
Ejemplo:
Code:
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/funcin)
Ejemplo:
Code:
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 funcin?
Podemos definir a una funcin como un conjunto de sentencias que son
ejecutadas cuando invocamos la funcin.
Cmo crear una funcin?
Una funcin esta compuesta por 2 partes, la cabecera (header) y el
cuerpo (body); el header contiene el inicializador, el tag, el nombre
y los parmetros de la misma. El cuerpo por otro
lado, contiene todo el cdigo que se ejecuta.
Ejemplo:
Code:
Inicializador Tag:Nombre(parametros)
{
//Todo lo que este aqu entre las 2 llaves es el cuerpo de la
funcin
}
Indica que es una funcin, puede ser static, stock, public o ninguno
Inicializador
(mas adelante veremos que son estos inicializadores
Tipo de funcin, al igual que las variables si no se indica ninguno, por
Tag defecto es entero. Esto indica el valor que retornara la funcin (si es
que retorna algun valor).
Nombre Nombre de la funcin, utilizado luego para invocarla.
Indica el nombre que se le dara a las variables que reciban los
Parametros
argumentos enviados.
Funciones sin parmetros
Son funciones a las cuales no se le pasan argumentos, es decir que
realizan nicamente una accin y siempre la misma.
Ejemplo:
Code:
stock KickAll()
{
for(new i, j=GetMaxPlayers(); i<j; i++)
if(IsPlayerConnected(i))
Kick(i);
}
Esa es una funcin muy simple que solo kickea a todos los jugadores
conectados.
Funciones con parmetros
Son funciones las cuales reciben argumentos los cuales pueden variar y
segn los mismos puede que la funcin ejecute diferentes sentencias.
Ejemplo:
Code:
stock GivePlayerMoney(playerid, money)
{
if(IsPlayerConnected(playerid))
{
if(money >= 0)
GivePlayerMoney(playerid, money);
else
GivePlayerMoney(playerid, -money);
}
}
La funcin 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 funcin.
Existen dos formas de retornar valores (aun que por claridad sugiero
utilizar la primera):
Ejemplo:
Code:
stock GetConnectedPlayers()
{
new
count;
for(new i; i<GetMaxPlayers(); i++)
if(IsPlayerConnected(i))
count++;
return count;
}
Ejemplo:
Code:
stock GetConnectedPlayers()
{
new
count;
for(new i; i<GetMaxPlayers(); i++)
if(IsPlayerConnected(i))
count++;
GetConnectedPlayers = count;
}
Ahora voy a mostrar una forma errnea de retornar valores.
Code:
stock Suma(valor1, valor2)
{
new str[128];
if(!IsNumeric(valor1) || !IsNumeric(valor2)){
str = "ERROR: Los valores deben ser numricos";
return str;
}
return valor1+valor2;
}
La funcin 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 bsico para scriptear en este lenguaje.
Qu es un callback?
Un callback es una funcin la cual es pasada como argumento a otra
funcin para ejecutar (o no) una o mas sentencias. Esto permite la re-
utilizacin de cdigo y ejecutar una o mas acciones para
diferentes elementos que son el mismo objeto entre otras cosas. Dicho
de otra forma, podra 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 cdigo 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).
Cmo 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 definicin.
Por qu 'forward' y qu es?
La palabra forward indica al compilador que estamos definiendo una
nueva funcin/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:
Code:
forward OnPlayerCallPlayer(playerid, calledid);//Aqu declaramos
nuestro callback
//Definicin de nuestro callback y sentencias que ejecutara el mismo
public OnPlayerCallPlayer(playerid, calledid)
{
SendClientMessage(calledid, -1, "Te estn llamando!");
return 1;
}
//En algn momento dentro de una funcin 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 ms all de las clsicas
definiciones y vamos a comprender un poco ms sobre este lenguaje de
programacin.
stock
Qu es stock?
stock define una variable/array o funcin, pero con la particularidad
de que si dicha variable/funcin no es utilizada, entonces se omitir
en la compilacin y no ocupara lugar.
Cmo se utiliza?
La forma de utilizacin es la misma que utilizamos normalmente
Ejemplo:
Code:
//Variables/arrays:
stock
variable,
array[5];
//Funciones:
stock MiFuncion();
?Para qu se utiliza?
Bsicamente se utiliza para ahorrar memoria y espacio; pero tambin 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.
Cmo se utiliza?
La forma de utilizacin es la misma que utilizamos normalmente, pero
debemos especificar el valor cuando creamos la variable/array.
Ejemplo:
Code:
//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 declaracin de un array, podemos obviar
indicar el tamao de la ultima dimensin.
Por qu se utiliza?
Podrn preguntarse, porque no colocar directamente el valor y utilizar
una variable constante. Bueno, la respuesta es que mediante la
utilizacin de arrays/variables constantes, estos valores
si se repiten solo se almacenan 1 vez en memoria; en cambio si
utilizramos 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
rpido acceder a una variable constante que a un texto.
static
Qu es static?
Declara una variable/array/funcin pero con caractersticas
particulares; la variable/array/funcin declarada puede utilizarse
nicamente en el entorno y ademas en el caso de la variable/array,
conserva el valor.
Ejemplo:
Code:
main()
{
MyFunction();
print("!");
MyFunction();
return 1;
}
MyFunction()
{
static
j;
for(new i; i<3; i++)
{
printf("%i", j);
j++;
}
}
Este cdigo imprimir en la consola:
Code:
0
1
2
!
3
4
5
Mientras que si la variable j no fuera esttica, la salida seria:
Code:
0
1
2
!
0
1
2
En el caso de las funciones estticas o las variables/arrays globales
estticas, 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.
Cmo se utiliza?
La forma de utilizacin es la siguiente:
Code:
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 comn que le dan a los enums es para almacenar
datos de jugadores u otros.
Ejemplo:
Code:
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 ms...
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:
Code:
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 cdigo anterior utilizando enums seria el siguiente:
Code:
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 cdigos son anlogos y compilaran perfectamente. De esta forma
demostramos que los enums son valores constantes, estos valores son
dados por el compilador
automticamente y comienzan en el 0. Ahora bien, podemos tambin ser
nosotros quienes coloquemos estos valores.
Ejemplo:
Code:
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 tambin
podemos asignar nosotros los valores que queramos
y no nicamente el inicial.
Ejemplo:
Code:
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 tamao de nuestro enum es 67
}
Ahora bien, tal vez estn pensando que debera haber printeado "Size:
66", pero esto es incorrecto ya que no hablamos del valor mximo, si
no de la cantidad de slots que tiene, y estos
son 0-66, entonces hay 67 slots.
Veamos otro ejemplo:
Code:
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 cdigo anterior printeara en el ultimo nmero el 5
se equivocaron, pues la ultima asignacin 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:
Code:
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 tambin pueden ser annimos, es decir no necesariamente
tienen que tener un nombre.
Ejemplo:
Code:
enum
{
E_UNO,
E_DOS,
E_TRES
};
Una particularidad es que existen enums de tag fuerte y dbil.
Ejemplo:
Code:
enum E_TEST_1 //Tag fuerte pues comienza con E mayscula
{
E_UNO,
E_DOS,
E_TRES
};
enum e_TEST_2 //Tag dbil pues comienza con e minscula
{
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
Inicializacin
El concepto de inicializacin hace referencia al valor que se le da a
una variable/array al crearlo. Por defecto en una variable su valor
inicial es 0, anlogamente en un array
cada uno de los slots tambin es 0.
Cmo inicializar una variable?
La inicializacin de una variable es realmente muy simple, consiste en
setear el valor correspondiente en su creacin.
Ejemplo:
Code:
new Variable = 5;
Cmo inicializar un array?
Es casi lo mismo, de hecho, cuando hablamos de strings vimos algo
similar.
Ejemplo:
Code:
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 inicializacin de arrays, este operador utiliza los valores
anteriores para asignar los valores sucesivos al array hasta
completarlo.
Veamos algunos ejemplos anlogos para comprender mejor su
funcionamiento:
Ejemplo:
Code:
new Array[15] = {5, ...};
new Array[15] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
Ejemplo:
Code:
new Array[10] = {0, 1, ...};
new Array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Ejemplo:
Code:
new Array[6] = {1, 5, ...};
new Array[6] = {1, 5, 10, 15, 20, 25};
Ejemplo:
Code:
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 rpida 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 nmero,
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:
Code:
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 carcter por byte; los strings normales guardan un
carcter 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 tamao original para guardar los datos, cada carcter 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:
Code:
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 informacin. 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 codificacin Little Endian
para almacenar los datos.
Cmo se utilizan?
A diferencia de los strings/arrays normales, cuando se definen luego
de ingresar el tamao se agrega la palabra "char".
Asignacin:
Ejemplo:
Code:
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 estn preguntando porque el string empaquetado no es de 5 bytes,
esto es porque se redondea al mltiplo de 4 SUPERIOR mas cercano (1 es
4, 3 es 4, 4 es 8 y asi).
A continuacin veremos la lectura de datos, la cual dado que
nativamente SA-MP no tiene mucho soporte para estos arrays, se vuelve
algo tedioso.
Ejemplo:
Code:
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 librera (creada por Emmet_) la cual
permite utilizar format directamente con strings empaquetados: link.
Cundo 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 nmeros y estos sean chicos
(valores de 0 a 255)
Operadores
Operadores miscelneos
{} Asignacin del contenido de arrays
defined Retorna "true" si la variable indicada fue definida mediante "#define"
sizeof() Retorna el tamao de un array
tagof() Retorna el tag de una variable/array
Retorna el numero de cells necesario para contener un string
char
empaquetado
(A) ? (B) : (C) => Es muy similar a if, else. Si A="true" retorna B, de lo
contrario retorna C. Ejemplo:
Code:
Ternario 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 segn el valor, se realice
una accin. Puede ser reemplazada por if, else if, else if, else, pero
usando if sera ms lenta y menos efectiva.
Ejemplo:
Code:
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 expresin "case" sigue una sola lnea,
o un if(sin else/else if) la expresin puede ir libre de brakets, de
lo contrario es necesario colocarlos.
Loops(infinitos)
Bueno, en esta pequea parte de este tutorial, explicare como crear
loops infinitos de diferentes formas.
Mtodo 1:
Code:
for(;;)print("Esto es un texto que saldr repetidamente en la
consola");
Mtodo 2:(tira 1 warning, pero funciona perfecto)
Code:
while(true)print("Esto es un texto que saldr repetidamente en la
consola");
Mtodo 3:
Code:
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:
Code:
for(new i; i<10; i++)
if(Array_N[i] == true)
break;
continue
Se utiliza para saltar un valor en un bucle.
Ejemplo:
Code:
for(new i; i<10; i++){
if(i==5)
continue;
printf("%i", i);
}
Este ejemplo dar como resultado en la consola:
Code:
0
1
2
3
4
6
7
8
9
goto
Esta expresin se utiliza para realizar un sato, para ir a x lugar del
cdigo, previamente definido (NO recomendable ya que se produce lo que
se conoce como cdigo espagueti).
Ejemplo:
Code:
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 cdigo hace es:
1 definir la variable(tipo boolean).
2 empieza con el bucle, y asigna un valor a la variable (verdadero o
falso) segn 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 autmata. Su uso es:
Code:
state nombredelautomata
Si quieren ms informacin sobre esto, les recomiendo mirar este
topic de y_less que est muy bien explicado este tema.
Directivas
Directivas bsicas
#if, #elseif, #else, #endif
Definicin:
Se utiliza para comparar una sentencia.
Ejemplo:
Code:
#if USE_MENU = 1
print("Mens: Habilitados");
#elseif USE_MENU = 0
print("Mens: Deshabilitados");
#else
print("Mens: Error");
#endif
#error
Definicin:
Se utiliza para enviar un error durante la compilacin.
Ejemplo:
Code:
#if defined EERROR
#error Mensaje de error.
#endif
#assert
Definicin:
Chequea si una comparacin devuelve true o false. En caso de ser
false, detiene la compilacin.
Ejemplo:
Code:
#define PP 6
#assert PP<4
Ese ejemplo enviara un error fatal con el texto "assertion failed:
6<4"
#include
Definicin:
Inserta el texto del archivo a incluir en la lnea en la que se ubica.
Ejemplo:
Code:
#include <a_samp>//carpeta de includes
#include "../include/gl_common"//otra carpeta
#tryinclude
Definicin:
Funciona igual que #include, con la diferencia de que si no puede
incluir el archivo, no enva un error.
Ejemplo:
Code:
#tryinclude <a_samp>
#endinput
Definicin:
Deja de incluir el archivo que estaba siendo ledo.
Ejemplo:
Code:
#include <nombre>
#if defined _NOMBRE_INC
#endinput
#endif
#define _NOMBRE_INC
#define
Definicin:
Crea una macro.
Ejemplo:
Constante:
Code:
#define COLOR_RED 0xFF0000FF
#undef
Definicin:
Elimina una macro declarada.
Ejemplo:
Code:
#define COLOR_X 0xFFA4B6F9
printf("%d", COLOR_X);
#undef COLOR_X
Si luego de ese cdigo, intentramos usar COLOR_X, tendramos que
definirlo nuevamente, o el compilador, no compilara.
Archivos
Introduccin
Los archivos se utilizan para guardar y leer datos. Estos datos pueden
ser cuentas de usuarios, configuracin del servidor, autos, etc. La
forma mas fcil 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 raz del servidor.
Creacin
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 extensin (recomendado) la cual
nos brinde ms informacin sobre el formato utilizado en dicho
archivo. Para la creacin de un archivo utilizaremos la funcin fopen
de la siguiente forma:
Code:
new
File:fhnd;//este sera nuestro puntero al archivo
fhnd = fopen("/[Link]", 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:
Code:
new
File:fhnd;
fhnd = fopen("/[Link]", io_read);//Notemos que el archivo debe
haberse creado o el servidor podra 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 leda 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 bsicas de
escritura, sobre-escribiendo todo el contenido o bien escribiendo al
final del archivo:
[b]Sobre-escribiendo:
Code:
new
File:fhnd;
fhnd = fopen("/[Link]", 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:
Code:
new
File:fhnd;
fhnd = fopen("/[Link]", 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 parmetros 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:
Code:
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 parmetros opcionales podemos:
SetPlayerTimeEx(playerid, 12);
Ejemplo:
Code:
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 quisiramos utilizar la funcin con el parmetro health pero no
el angulo accedemos as:
SetPlayerPosEx(playerid, 0.0, 0.0, 0.0, .health=100.0);
Pasar parmetros por valor y por referencia
Parmetro por valor, a la funcin le llega una copia del valor.
Podemos modificar el mismo pero el original no cambiara.
Ejemplo:
Code:
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
seguirn 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 funcin. Esto es lo que se conoce como "por referencia". Para
hacer esto, solo es necesario agregar
el carcter '&' delante de la variable que queremos pasar como
referencia, de lo contrario (si no lo ponemos), esta variable ser
pasada por valor.
Ejemplo:
Code:
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 funcin especificamos uno de los
parmetros como array, ser pasado automticamente por referencia y no
por valor. Para pasar un array por valor se debe agregar 'const'
delante del mismo.
Parmetros variables
Para crear una funcin con parmetros indefinidos, debemos hacerlo
utilizando la elipsis y podemos ayudarnos con otras funciones nativas
para saber la cantidad de argumentos y obtener un argumento segn el
index del mismo.
Ejemplo:
Code:
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:
Code:
//Declaracin:
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(manipulacin)
~A => Retorna el complemento de A.
A >> B => Retorna el shift aritmtico de B (hacia la izquierda) sobre
A.
A >>> B => Retorna el shift lgico 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(Asignacin)
Esos operadores son iguales a los de asignacin comn, y a estos se
les suman los de manipulacin de bits (siempre con el signo = despus
del signo de manipulacin).
Nmeros binarios
Introduccin
Los nmeros binarios son nmeros representados en una forma diferente,
mas correctamente en base 2; por otra parte los nmeros que estamos
acostumbrados a manejar son base 10, esto quiere
decir que normalmente utilizamos 10 nmeros para representar cualquier
otro (0-9). Con binario, todo se representa con el 0 y el 1.
Ejemplo:
Code:
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 posicin de un numero binario se conoce como bit y
representa una potencia de 2.
Importante: En pawn para indicar que un nmero es binario se utiliza
en prefijo '0b'
Binario a decimal
Cmo 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 nmero
decimal representa.
Code:
Nmero decimal = 1*(2^3) + 1*(2^2) + 0*(2^1) + 0*(2^0)
Nmero decimal = 8 + 4 + 0 + 0
Nmero decimal = 12
Ejemplo:
Supongamos el numero binario '11001011' y queremos saber que nmero
decimal representa.
Code:
Nmero 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)
Nmero decimal = 128 + 64 + 0 + 0 + 8 + 0 + 2 + 1
Nmero 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 revs y ese sera
nuestro nmero binario.
Ejemplo:
Supongamos el numero 25, y queremos saber representarlo en binario:
Code:
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 posicin inversa.
En este caso el numero binario que representa al 25 es '11001'
Nmeros negativos
Tal vez se estn preguntando como almacenar nmeros 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 nmero. Si colocramos los 31 bits en 1, obtendramos el
mayor numero posible, el cual es 2,147,483,647. Ahora bien, esto
si hicieran las cuentas, se daran cuenta que 2^31=2,147,483,648, esto
se debe a que dentro de todos los nmeros que representamos tenemos el
0, entonces el numero mximo es 2^31-1, por otra parte,
como solo hay un nico 0, el menor nmero 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:
Code:
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:
Code:
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:
Code:
1011010 ^ 0010010 = 1001000
Para verlo mejor, coloquemos uno sobre el otro
1011010
0010010
------
1001000
NOT (~)
Invierte todos los 0 y 1 del nmero.
Ejemplo:
Code:
~0010010 = 1101101
La operacin es el equivalente a
1111111 ^ 0010010 (XOR)
Para verlo mejor, coloquemos uno sobre el otro
1111111
0010010
------
1101101
Shifts aritmticos
Izquierdo (<<)
Mueve cada bit x lugares a la izquierda y se rellena agregando tantos
0 como lugares se muevan los bits.
Ejemplo:
Code:
00000000000000000000000000010000//16
00000000000000000000000000010000 << 2 =
00000000000000000000000001000000//64
Ejemplo:
Code:
11111111111111111111111111110000//-16
11111111111111111111111111110000 << 2 =
11111111111111111111111111000000//-64
Nota: Si prestan atencin se darn cuenta que es aumentar n-veces la
potencia del 2.
Derecho (>>)
Mueve cada bit x lugares a la derecha y se agregan x nmeros a la
izquierda, el valor de estos nmeros es el del MSB para conservar el
signo.
Ejemplo:
Code:
00000000000000000000000000010000//16
00000000000000000000000000010000 >> 2 =
00000000000000000000000000000100//4
Ejemplo:
Code:
11111111111111111111111111110000//-16
11111111111111111111111111110000 >> 2 =
11111111111111111111111111111100//-4
Nota: Si prestan atencin se darn cuenta que es restar n-veces la
potencia del 2.
Shifts lgicos
Izquierdo
No existe shift a la izquierda, esto se debe a que seria lo mismo que
realizar un shift aritmtico a la izquierda.
Derecho (>>>)
Podra definirse como el opuesto del shift aritmtico a la izquierda.
Ejemplo:
Code:
00000000000000000000000000010000//16
00000000000000000000000000010000 >> 2 =
00000000000000000000000000000100//4
Ejemplo:
Code:
11111111111111111111111111110000//-16
11111111111111111111111111110000 >> 2 =
00111111111111111111111111111100//1073741820
00000000000000000000000000000000
Para qu sirven realmente los nmeros binarios?
Se utilizan principalmente para ahorrar espacio y no desperdiciar
memoria.
Pero tambin pueden utilizarse para guardar datos en un archivo como
veremos mas tarde.
Directivas
Directivas avanzadas
#define
Definicin:
Crea una macro. puede ser una funcin o solo una constante.
Ejemplo:
Constante:
Code:
#define COLOR_RED 0xFF0000FF
Funcin:
Code:
#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
Definicin:
Esta directiva, puede tomar muchos valores:
amxlimit (valor):
Setea el valor mximo del tamao que puede alcanzar el archivo .amx
del script.
amxram (valor):
Setea el valor mximo 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 (carcter):
Setea el smbolo que indica la continuacin una nueva lnea (por
defecto"\").
deprecated (valor):
Setea un smbolo que no se puede usar. Si el compilado lo encuentra en
el script, sale un warning.
dynamic (valor):
Setea el tamao en cells de la memoria asignada para los datos
dinmicos.
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 tabulacin. (defecto: .
unused (symbol):
Especifica que no se usara ese smbolo.
Final