Useful Functions

@KoczkaHUN: I assume you're not familiar with the [ pawn ] tags?
pawn Код:
#define IncreasePVar(%0,%1,%2) SetPVarInt(%0, %1, GetPVarInt(%0, %1) + %2)
#define DecreasePVar(%0,%1,%2) IncreasePVar(%0, %1, -(%2))
Also, are you aware the the DecreasePVar is slower now? Because it now must replace 3 strings instead of 1. As you (may) know, macro's literally replaces texts (only while compiling - not visual in the pwn like CTRL+H). It's now gonna do this:

2- 'DecreasePVar' is a defined macro, so change 'DecreasePVar' for 'IncreasePVar(*, *, -(*))'
3- Change 'IncreasePVar' for 'SetPVarInt(*, *, GetPVarInt(*, *) + *);' (cuz it was also a defined macro)
4- Compile the output (which is now: 'SetPVarInt(playerid, varname[], GetPVarInt(playerid, varname[]) +- value);'

While it would do this when you have this code: #define DecreasePVar(%0,%1,%2) SetPVarInt(%0, %1, GetPVarInt(%0) - %2);

1- Change 'DecreasePVar' for 'SetPVarInt(*, *, GetPVarInt(*) - *);'
2- Compile the output (which is now: See above)

It's not a big deal, but it is slower. I'd rather use the second one. But, for something like this, I wouldn't use them both. I'd go for the literally functions, since I never use PVars: Those are slower (I ever saw a trustable source who'd benchmarked this). The only handy things is that it can hold bigger strings (I read it in the same topic).
More information about what I've told about (the Pre-Processor): https://sampforum.blast.hk/showthread.php?tid=166680

- Kevin

p.s.
Please say it if I'm wrong: As far as I understood and read about in different topics (especially ******' one), it works like this :P
Reply

Quote:
Originally Posted by Kwarde
Посмотреть сообщение
@KoczkaHUN: I assume you're not familiar with the [ pawn ] tags?
Why?

Quote:
Originally Posted by Kwarde
Посмотреть сообщение
Also, are you aware the the DecreasePVar is slower now? Because it now must replace 3 strings instead of 1. As you (may) know, macro's literally replaces texts (only while compiling - not visual in the pwn like CTRL+H). It's now gonna do this:
Yes, I know, but it is only slow on compile. You can do IncreasePVar(playerid, szVariable, -1); to have the same effect like DecreasePVar. The only reason I have made IncreasePVar as the main function, because it is more common to have that. E.g we don't have TakePlayerMoney, but we have GivePlayerMoney, which can do the same effect with negative values.

BTW, we could do this function with stocks, then you would not have to worry about compile speed, but execution speed would be slower (not significantly, PVars are slow enough to be a reason to don't use it)

For now:
pawn Код:
#define IncreasePVarInt(%0,%1,%2) SetPVarInt(%0, %1, GetPVarInt(%0, %1) + %2)
#define DecreasePVarInt(%0,%1,%2) SetPVarInt(%0, %1, GetPVarInt(%0, %1) - %2)
#define IncreasePVarFloat(%0,%1,%2) SetPVarFloat(%0, %1, GetPVarFloat(%0, %1) + %2)
#define DecreasePVarFloat(%0,%1,%2) SetPVarFloat(%0, %1, GetPVarFloat(%0, %1) - %2)
Reply

memset

Very fast way to fill an array/string using a neat assembly instruction to do the dirty work. Usage example:
pawn Код:
new
    string[128]
;

// Fill the whole string with spaces
// NOTE: "sizeof(x) - 1" must be used on strings to preserve the last NULL character!
memset(string, ' ', sizeof(string) - 1);

// Put 20 "@" characters in the beginning of the string
memset(string, '@', 20);

// Put 5 "X" characters at index 5
memset(string[5], 'X', 5);

print(string);
Its real power is in larger arrays:
pawn Код:
new
    somePlayerArray[MAX_PLAYERS]
;

START_BENCH(2000);
{
    // Fill the array with the value 500
    memset(somePlayerArray, 500);
}
FINISH_BENCH("memset player array");

// Output: Bench for memset player array: executes, by average, 613.08 times/ms.
For testing purposes I made another function that looped through the array and set each slot, it executed only 44 times/ms!

pawn Код:
stock memset(aArray[], iValue, iSize = sizeof(aArray)) {
    new
        iAddress
    ;
   
    // Store the address of the array
    #emit LOAD.S.pri 12
    #emit STOR.S.pri iAddress
   
    // Convert the size from cells to bytes
    iSize *= 4;
   
    // Loop until there is nothing more to fill
    while (iSize > 0) {
        // I have to do this because the FILL instruction doesn't accept a dynamic number.
        if (iSize >= 4096) {
            #emit LOAD.S.alt iAddress
            #emit LOAD.S.pri iValue
            #emit FILL 4096
       
            iSize    -= 4096;
            iAddress += 4096;
        } else if (iSize >= 1024) {
            #emit LOAD.S.alt iAddress
            #emit LOAD.S.pri iValue
            #emit FILL 1024

            iSize    -= 1024;
            iAddress += 1024;
        } else if (iSize >= 256) {
            #emit LOAD.S.alt iAddress
            #emit LOAD.S.pri iValue
            #emit FILL 256

            iSize    -= 256;
            iAddress += 256;
        } else if (iSize >= 64) {
            #emit LOAD.S.alt iAddress
            #emit LOAD.S.pri iValue
            #emit FILL 64

            iSize    -= 64;
            iAddress += 64;
        } else if (iSize >= 16) {
            #emit LOAD.S.alt iAddress
            #emit LOAD.S.pri iValue
            #emit FILL 16

            iSize    -= 16;
            iAddress += 16;
        } else {
            #emit LOAD.S.alt iAddress
            #emit LOAD.S.pri iValue
            #emit FILL 4

            iSize    -= 4;
            iAddress += 4;
        }
    }
   
    // aArray is used, just not by its symbol name
    #pragma unused aArray
}
Reply

LOAD.S.pri will load the value at the current function's offset adjusted by the 1st parameter (12, in this case).
Each function has what's called a function frame, where the parameters start at offset 12 (param 1 is 12, param 2 is 16, etc.). All parameters are 4 bytes because the value in the function frame is an address pointing to the value.

At least that's how I think it is, I might be off with some terminology as I haven't read very much on this.

alt and pri are what's called registers, it's basically a temporary storage for memory. So the only difference between, for example, LOAD.S.pri and LOAD.S.alt is where it will store what it loads.
Reply

The offset is in bytes - so there's 12 (3 cells might be what you were thinking of). I think 8 is the number of parameters, and 0 is the pointer to the previous function's frame.

Yes, there are only two registers and I believe those are stored in the processor's cache.

Also, in this case the best way to learn is analyze ******'s code and utilize the Implementer’s Guide.
Reply

I just don't get that #emit. So, all data and addresses are stored on some stack/heap, right? And with #emit you control that data?
Reply

pawn Код:
stock PutPlayerInVehicleEmptySlot( vehicleid, playerid )
{
    new
        bool: bNonAvailable[ 4 ], count = -1
    ;
    foreach(Player, iPlayer)
    {
        if( IsPlayerInVehicle( iPlayer, vehicleid ) )
        {
            new
                iVehicle = GetPlayerVehicleSeat( iPlayer )
            ;
            if( iVehicle >= 0 && iVehicle <= 3 ) bNonAvailable[ iVehicle ] = true;
        }
    }
    for( new i; i < sizeof( bNonAvailable ); i++ )
    {
        if( !bNonAvailable[ i ] ) count = i, PutPlayerInVehicle( playerid, vehicleid, i );
    }
    return count;
}
quick function, can be useful
Reply

Quote:
Originally Posted by Lorenc_
Посмотреть сообщение
pawn Код:
stock PutPlayerInVehicleEmptySlot( vehicleid, playerid )
{
    new
        bool: bNonAvailable[ 4 ], count = -1
    ;
    foreach(Player, iPlayer)
    {
        if( IsPlayerInVehicle( iPlayer, vehicleid ) )
        {
            new
                iVehicle = GetPlayerVehicleSeat( iPlayer )
            ;
            if( iVehicle >= 0 && iVehicle <= 3 ) bNonAvailable[ iVehicle ] = true;
        }
    }
    for( new i; i < sizeof( bNonAvailable ); i++ )
    {
        if( !bNonAvailable[ i ] ) count = i, PutPlayerInVehicle( playerid, vehicleid, i );
    }
    return count;
}
quick function, can be useful
Uhm, you know some vehicles are 2-seated. And some have more than 4(like buses). This needs a GetVehicleSeatCount.
Reply

@[HLF]Southclaw

Was too lazy to make defines.. (Cause I would have to explain a bit more about placing and using them) But yeah, it's better, added now. Thanks
Reply

This is just a loop for variable argument functions, less typing is the only advantage for using it.

First argument is just an identifier for a new variable that will hold the index of the argument.
Second argument is the amount of function parameters that precede the variable arguments (0 for none).

pawn Код:
#define va_loop(%0,%1)\
    new _n_va_args=numargs();\
        for(new %0=%1;%0<_n_va_args;++%0)
Example

pawn Код:
foo(oneplayer, twoplayer, ...)
{
    SendClientMessage(oneplayer, 0xff0000AA, "foo");
    SendClientMessage(twoplayer, 0xff0000AA, "foo");
   
    va_loop(i, 2)//first arguement is a new var (index of argument) - second is the amount of params that precede the variable args
    {
        SendClientMessage(getarg(i),  0xff0000AA, "foo");
    }
}

//call the function
foo(1, 2, 3, 4, 5, 6, 7);
Reply

I use this and works fine

pawn Код:
#define IsValidVehicle(%1) \
    (!!GetVehicleModel(%1))
Reply

Quote:
Originally Posted by the_chaoz
View Post
pawn Code:
IsPointInPlayerScreen(playerid, Float:x, Float:y, Float:z)
{
    new Float:P[3], Float:Dist;
    GetPlayerPos(playerid, P[0], P[1], P[2]);
    if(z-P[2]>15.0 || P[2]-z>15.0)return 0;
    Dist = floatsqroot(floatpower((P[0]-x), 2)+floatpower((P[1]-y), 2)+floatpower((P[2]-z), 2));
    if(Dist>100.0)return 0;
    new Float:cV[3], Float:cP[3], Float:T[3], Float:Ar;
    GetPlayerCameraPos(playerid, cP[0], cP[1], cP[2]);
    GetPlayerCameraFrontVector(playerid, cV[0], cV[1], cV[2]);
    T[0] = cV[0]*Dist+cP[0];
    T[1] = cV[1]*Dist+cP[1];
    T[2] = cV[2]*Dist+cP[2];
    if(z-T[2]>10.5 || T[2]-z>10.5)return 0;
    if(Dist<7.0)return 1;
    Ar=atan2((P[1]-T[1]), (P[0]-T[0]));
    if(Ar-45.0<(atan2((P[1]-y), (P[0]-x)))<Ar+45.0)return 1;
    return 0;
}
RyDeR` or anyone thinking of improving this function?
Reply

Why, is there something wrong with it as it is?
Reply

it's a little buggy, test it and see
Reply

Some time ago I was searching for convert timestamp to date and the only way that I found was use a plugin.

I found this on Pawn source, I think that it can be useful to someone else(be aware of your time zone).

pawn Code:
stock timestamptodate(sec1970,&year=0,&month=0,&day=0,&hour=0,&minute=0,&second=0) //By CompuPhase
{
    #define SECONDS_PER_MINUTE  60
    #define SECONDS_PER_HOUR        3600
    #define SECONDS_PER_DAY     86400
    #define SECONDS_PER_YEAR    31556952    /* based on 365.2425 days per year */
    new monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    new days, seconds;

    /* find the year */
    for (year = 1970; ; year += 1) {
    days = 365 + _:((year & 0x03) == 0); /* clumsy "leap-year" routine, fails for 2100 */
    seconds = days * SECONDS_PER_DAY;
    if (seconds > sec1970)
      break;
    sec1970 -= seconds;
    } /* if */

    /* find the month */
    for (month = 1; ; month += 1) {
    days = monthdays[month - 1];
    seconds = days * SECONDS_PER_DAY;
    if (seconds > sec1970)
      break;
    sec1970 -= seconds;
    } /* if */

    /* find the day */
    for (day = 1; sec1970 >= SECONDS_PER_DAY; day += 1)
    sec1970 -= SECONDS_PER_DAY;

    /* find the hour */
    for (hour = 0; sec1970 >= SECONDS_PER_HOUR; hour += 1)
    sec1970 -= SECONDS_PER_HOUR;

    /* find the minute */
    for (minute = 0; sec1970 >= SECONDS_PER_MINUTE; minute += 1)
    sec1970 -= SECONDS_PER_MINUTE;

    /* remainder is the number of seconds */
    second = sec1970;
}
Reply

Quote:
Originally Posted by Kar
Посмотреть сообщение
it's a little buggy, test it and see
can you tell me more about the bug, i may can fix it.
Reply

pawn Код:
stock Ip_To_Int(const IP_[]) {
    new B_[1], C_ = 1, P_ = 0;
    B_{0} = strval(IP_[0]);
    do { if(IP_[P_] == '.') B_{C_++} = strval(IP_[P_ + 1]); } while(IP_[++P_])
    return B_[0];
}
Edit:
pawn Код:
stock Ip_To_Integer(const IP_[]) {
    new B_[1], C_ = 1, P_ = 0;
    B_{0} = strval(IP_[0]);
    while(IP_[++P_]) { if(IP_[P_] == '.') B_{C_++} = strval(IP_[P_ + 1]); }
    return B_[0];
}
Reply

Convert Seconds to MilleSeconds - Support two langs!

i'm maked this function in php,
after i'm make in version pawn.

Code:
pawn Code:
static stock Convert(numero, tempo, bool:prin)
{
    /*
            Coloque 1 caso queira em inglкs,
            coloque 2 caso queira em portuguкs.
           
            change to 1 if want in inglese,
            change to 2 if want in portuguкs.
           
    */

    #define iLANG 1
   
   
    static
        var_tempo = 0,
        var_saida = 0,
        string[50] = EOS,
        out[50]    = EOS
    ;
   
    #if iLANG == 1
    {
        switch(tempo)
        {
            case 0: var_tempo = 1000,               string = "Seconds(s)";
             case 1: var_tempo = 60000,             string = "Minute(s)";
             case 2: var_tempo = 3600000,           string = "Hor(s)";
             case 3: var_tempo = 86400000,          string = "Day(s)";
             case 4: var_tempo = 86400000,          string = "Week(s)";
             case 5: var_tempo = 2592000000,        string = "Month(s)";
             case 6: var_tempo = 2592000000 * 12,   string = "Year(s)";
             default: var_tempo = 5;
        }
    }
    #endif
    #if iLANG == 2
    {
        switch(tempo)
        {
            case 0: var_tempo = 1000,               string = "Segundo(s)";
            case 1: var_tempo = 60000,              string = "Minuto(s)";
            case 2: var_tempo = 3600000,            string = "Hora(s)";
            case 3: var_tempo = 86400000,           string = "Dia(s)";
            case 4: var_tempo = 86400000,           string = "Semana(s)";
            case 5: var_tempo = 2592000000,         string = "Mes(es)";
            case 6: var_tempo = 2592000000 * 12,    string = "Ano(s)";
            default: var_tempo = 5;
        }
    }
    #endif
    if(var_tempo != 5)
    {
        var_saida =  numero * var_tempo;
        format(out, sizeof(out),"%d %s", var_tempo, var_saida);
    }
    else
    {
        out = "Tempo invбlido";
    }
    if(prin)
    {
        print(out);
    }
    return out;
}
Reply

A VERY simple define:

pawn Код:
#define fopen_append(%0) fopen(%0, fexist(%0) ? io_append : io_write)

//Use:
stock Log(text[])
{
    new File:LOG = fopen_append("logs.txt");
    fwrite(LOG, text);
    fwrite(LOG, "\r\n");
    fclose(LOG);
}
And a simple stock:
pawn Код:
stock fappend(file_path[], string[], bool:new_line = true)
{
    new filemode:io_mode = fexist(file_path) ? io_append : io_write;
    new File:IO = fopen(file_path, io_mode);
    if(!IO) return false;
    if(new_line && _:io_mode == 3) if(!fwrite(IO, "\r\n")) return false;
    if(!fwrite(IO, string)) return false;
    fclose(IO);
    return true;
}

//Use:
fappend("MyLogs.txt", "Hello there!");
fappend("MyLogs.txt", "My name is foobar! :D");
fappend("MyLogs.txt", " (Joking)", false);
Reply

how to remove weapon of player:
pawn Код:
#define RemoveWeapon(%0, %1)  SetPlayerAmmo(%0, %1, 0)
Use:
pawn Код:
RemoveWeapon(playerid, 38); // remove the minigun.
Reply


Forum Jump:


Users browsing this thread: 47 Guest(s)