[Tutorial] Pawn Elipse.
#1

Pawn Elipse.
Por rjjj ou Ken



Neste tutorial darei explicaзхes relacionadas ao entendimento da declaraзгo Elipse, as "reticкncias" do Pawn (...) .


Obs: "Argumento" = Valor passado a um parвmetro de uma funзгo durante a chamada da mesma.



Bem, a Elipse pode aparecer em diferentes tipos de cуdigos, mas й notбvel que em todas as suas apariзхes, ela tem a funзгo de equivaler б vбrios elementos .




pawn Код:
new x[7] = {2, 3, 5, ...};


No caso acima:



x[0] й igual б 2 (pois 2 foi o primeiro definido na estrutura, por isso ele й o valor da parte da array que tem index 0 (primeira parte da array).
x[1] й igual б 3 (pois 3 foi o segundo definido na estrutura, por isso ele й o valor da parte da array que tem index 1 (segunda parte da array).
x[2] й igual б 5 (pois 5 foi o terceiro definido na estrutura, por isso ele й o valor da parte da array que tem index 2 (terceira parte da array).



Mas qual seria o valor de x[3] (sendo que й na posiзгo 3 onde estб a Elipse) ? seria 5? seria 3 ? ou seria 0 ?



Vamos descobrir isso e muito mais .





1 - Elipse na inicializaзгo de variбveis arrays.



Na criaзгo de uma variбvel array, podemos optar por definir o valor que serб armazenado por cada cell da array usando a estrutura:


pawn Код:
new x[4] = {/*valores*/};


Como demonstrei no comeзo do tutorial .



Nesse caso, a Elipse pode aparecer como um dos valores, e quando isso acontecer, provocarб diferentes efeitos:




* Efeito quando apenas uma ъnica "parte da array" for definida e logo apуs for seguida de Elipse:


Exemplos:


pawn Код:
new x[4] = {4, ...};  //1є caso
new y[6] = {-1, ...}; //2є caso
new z[3] = {67, ...}; //3° caso

Em cada um dos casos acima, a Elipse farб com que todos os outros elementos da variбvel array sejam iguais ao primeiro.


No 1є caso, alйm do primeiro elemento (x[0]) adquirir valor 4 (que foi definido pelo programador), a Elipse farб com que todos os outros elementos (x[1], x[2], etc) tornem-se 4.




* Efeito quando mais de uma "parte da array" for definida e, logo apуs, tudo for seguido de Elipse:


pawn Код:
new a[10] = {4, 5, 6, 8, ...};  //1є caso
new b[44] = {1, 4, ...}; //2є caso
new c[32] = {5, 9, ...}; //3° caso

Nesses casos, os dois ъltimos valores definidos dentro da estrutura {/*valores*/} constituirгo uma progressгo aritmйtica (P.A) na qual esses dois valores serгo o primeiro e o segundo termo da sequencia numйrica .


Em outras palavras, se temos:


Код:
new a[10] = {4, 5, 6, 8, ...};

O 6 e o 8 constituiraзгo uma P.A de razгo 2 (para se achar a razгo, subtrai-se um termo da P.A pelo termo anterior б este), ou seja, que terб seus valores crescendo de 2 em 2 .


pawn Код:
//P.A formada:
 
6, 8, 10, 12, 14, 16,...  // e vai crescendo.... atй que a ъltima cell da array seja ocupada por um valor :D

Portanto, a Elipse farб com que a variбvel array que citei antes seja :


pawn Код:
new a[10] = {4, 5, 6, 8, 10, 12, 14, 16, 19, 21}; //Parou de crescer no 21, por que um valor foi atribuнdo б "a[9]" (ъltima parte da array).





2 - Elipse como parвmetros de funзхes.




Se temos uma funзгo:


pawn Код:
stock LOL(...)
{
    return 1;
}

Podemos chamб-la com quantos parвmetros quisermos:


pawn Код:
LOL(1, 3, 5, 7);

LOL(1,5);

LOL("!");


Muitos jб devem ter visto a native da funзгo format :


pawn Код:
native format(output[], len, const format[], {Float,_}:...);

Vejam que a Elipse aparece como o ъltimo parвmetro , isso explica por que podemos colocar incontбveis sнmbolos no ъltimo parвmetro do format quando o chamamos.




* getarg(argid)



A funзгo getarg(argid) retorna o valor de um argumento. Sendo assim pode-se usб-la para obter o que for colocado no lugar da Elipse .


Exemplo:


Se temos uma funзгo:


pawn Код:
stock xD(...)
{
    printf("ARG 1: %i    ARG 2: %i    ARG 3: %i", getarg(0), getarg(1), getarg(2));
    return 1;
}

Quando a chamarmos dessa forma:


pawn Код:
xD(30, 40, 50);

O seguinte texto serб imprimido :


pawn Код:
"ARG 1: 30    ARG 2: 40    ARG 3: 50"


Exceзгo:


Se a funзгo fosse assim :

pawn Код:
stock xD(...)
{
    printf("ARG 1: %s    ARG 2: %s    ARG 3: %s", getarg(0), getarg(1), getarg(2));
    return 1;
}
E tivйssemos chamado a funзгo com vбrias strings no lugar da Elipse :

pawn Код:
xD("abc", "def", "ghi");
O que seria imprimido seria uma fusгo das iniciais de cada string:

pawn Код:
"ARG 1: a    ARG 2: da    ARG 3: gda"

Isso ocorre devido б um conflito entre a Elipse (que equivale б vбrios nъmeros em sequencia), a string (que equivale б vбrios nъmeros tambйm) e o getarg (que pode retornar apenas um nъmero da Elipse, que se for composta de ainda mais nъmeros (string) deixa tudo tenso)) .




* numargs()



A funзгo numargs() retorna a quantidade de argumentos passados a uma funзгo .


Exemplo: Se temos a funзгo:


pawn Код:
stock Total(...)
{
    printf("Total de Argumentos: %d", numargs());
    return 1;
}
E a chamamos desta forma:

pawn Код:
Total(15, 45, 90); //3 argumentos
Isto serб imprimido

pawn Код:
"Total de Argumentos: 3"



* setarg(argid, index, valor)


A funзгo setarg(argid, index, valor) muda o valor de um argumento. Retorna 0 se o argumento for invбlido.



Exemplo: Se temos a funзгo:


pawn Код:
stock Go(...)
{
    setarg(0, 0, 5); //O Segundo parametro deve ser sempre 0 quando o que estiver no lugar da Elipse nгo for uma parte de uma array
    printf("ARG 1: %d", getarg(0));
    return 1;
}
E a chamamos desta forma:

pawn Код:
Go(3);

O valor imprimido nгo serб 3, e sim 5.





3 - Curiosidades.




O ъnico mйtodo atual de se criar a famosa funзгo SendClientMessageEx (que envia uma mensagem ao jogador, jб formatada) funcionando 100% й atravйs de #defines :



pawn Код:
#define SendClientMessageEx(%0, %1, %2); new x[128]; format(x,128,%2), SendClientMessage(%0, %1, %2);


Isso por que "misteriosamente" a exceзгo das strings em Elipse (que ocorre a fusгo das iniciais, etc) nгo se aplica б Elipse do format, pois o mesmo consegue muito bem ter strings como parвmetros finais .



Entretanto, o SendClientMessageEx pode ser criado de uma maneira bem otimizada, ficando quase idкntico ao mesmo se tivesse sido criado atravйs de uma stock com Elipse, desta forma:



pawn Код:
new x[128]; //Sendo x uma variбvel global, vбrias variбveis nгo precisam ser criadas a cada uso da funзгo
#define SendClientMessageEx(%0, %1, %2); \
format(x,128,%2), SendClientMessage(%0, %1, %2);



E й isso, dъvidas ? Perguntem .



Espero ter ajudado .
Reply
#2

Sempre com уtimos tutoriais. Parabйns.
Reply
#3

Quote:
Originally Posted by rjjj
Посмотреть сообщение
...

O ъnico mйtodo atual de se criar a famosa funзгo SendClientMessageEx (que envia uma mensagem ao jogador, jб formatada) funcionando 100% й atravйs de #defines :
bom trabalho porem sim existe maneira de fazer o SendClientMessage sem precisar de define ...

Estб aqui uma versao alterada por ****** do original codigo do Zeex

pawn Код:
#define BYTES_PER_CELL 4

stock CPF(playerid, color, fstring[], {Float, _}:...)
{
    // This is the number of parameters which are not variable that are passed
    // to this function (i.e. the number of named parameters).
    static const
        STATIC_ARGS = 3;
    // Get the number of variable arguments.
    new
        n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL;
    if (n)
    {
        new
            message[128],
            arg_start,
            arg_end;
       
        // Load the real address of the last static parameter. Do this by
        // loading the address of the last known static parameter and then
        // adding the value of [FRM].
        #emit CONST.alt        fstring
        #emit LCTRL          5
        #emit ADD
        #emit STOR.S.pri        arg_start
       
        // Load the address of the last variable parameter. Do this by adding
        // the number of variable parameters on the value just loaded.
        #emit LOAD.S.alt        n
        #emit ADD
        #emit STOR.S.pri        arg_end
       
        // Push the variable arguments. This is done by loading the value of
        // each one in reverse order and pushing them. I'd love to be able to
        // rewrite this to use the values of pri and alt for comparison,
        // instead of having to constantly load and reload two variables.
        do
        {
            #emit LOAD.I
            #emit PUSH.pri
            arg_end -= BYTES_PER_CELL;
            #emit LOAD.S.pri      arg_end
        }
        while (arg_end > arg_start);
       
        // Push the static format parameters.
        #emit PUSH.S          fstring
        #emit PUSH.C          128
        #emit PUSH.ADR         message
       
        // Now push the number of arguments passed to format, including both
        // static and variable ones and call the function.
        n += BYTES_PER_CELL * 3;
        #emit PUSH.S          n
        #emit SYSREQ.C         format
       
        // Remove all data, including the return value, from the stack.
        n += BYTES_PER_CELL;
        #emit LCTRL          4
        #emit LOAD.S.alt        n
        #emit ADD
        #emit SCTRL          4
       
        return SendClientMessage(playerid, color, message);
        //return print(message);
    }
    else
    {
        return SendClientMessage(playerid, color, fstring);
        //return print(fstring);
    }
}
Porem nem eu a uso pois ja existe a maneira do define... :3
Reply
#4

[ame]http://www.youtube.com/watch?v=DgqOEsX74T0[/ame]
Reply
#5

@Viniborn

Muito Obrigado ! .



@SlashPT


Bem, eu cheguei a testar alguns dos projetos que postaram aqui no fуrum e sempre tinha algum problema em relaзгo б maneira que o format utiliza .


Esse que vocк postou tentei usar mas ele crashou o Filterscript que uso pra testes ,quando iniciei o server (defini BYTES_PER_CELL igual б 4, o tamanho de uma cell em bytes) .


Bem, mas talvez usando format pelo #emit realmente dк para burlar os errors que o compilador gera quando colocamos assim dentro de uma funзгo com Elipse com argumento, por exemplo:


Код:
new string[100];
format(string, sizeof(string), ...);
Mas nгo deve valer a pena bater cabeзa com isso , pois jб temos a modo #define que й 100% funcional .




@Rodox_Mortein

Spam ? .
Reply
#6

estranho pois comigo nao crashou testei agora mesmo que ate me tinha esquecido de definir a Byte por cell e apуs definir deu certinho, e pelo que ouvi falar nao da problemas.

O problema й que й muito lento acho que percebes porque... xD
Reply
#7

Testei, e nгo crashou tambйm...
Reply
#8

@Rodox_Mortein


Exemplifiquei bastante para que ficasse fбcil de entender .


Se vocк tiver um bom conhecimento sobre variбveis arrays, acho que pode entender o tutorial sу vendo os exemplos .


Tambйm tentei usar os termos conhecidos aqui no fуrum (como "array", por exemplo), para facilitar o entendimento .




@SlashPT


.




@[S]trong


Й, bem estranho , testei no lvdm tambйm e crashou, talvez seja aquilo do tamanho de uma cell бs vezes mudar de sistema operacional pra sistema operacional .



Muito obrigado б todos que aprovaram o Tutorial !
Reply
#9

Bom tutorial, eu acabei de ligar o SAMP-SERVER.exe usando ela e nгo deu crash, mas como vocк falou, deve ser o sistema operacional.
Reply
#10

Quote:
Originally Posted by Rodox_Mortein
Посмотреть сообщение
Eu tambem ??
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)