[Tutorial] Converting strcmp(+strtok) to dcmd/zcmd(+sscanf)
#1

Converting STRCMP & STRTOK to ZCMD/DCMD & SScanF
Why am I making this?

Because most "noobs" don't know how to convert and because there's no tutorial on this yet AFAIK.
NOTE: ZCMD is the fastest command processor, so I recommend using it!


How:

STRCMP to DCMD&ZCMD:

This is really easy. The only differences are that zcmd and dcmd got "params".
Let's convert this easy command:

pawn Код:
if( !strcmp( cmdtext, "/suicide", true ))
{
    new
        szMessage[ 54 ],
        pName[ MAX_PLAYER_NAME ];
    GetPlayerName( playerid, pName, sizeof( pName ));
    format( szMessage, sizeof( szMessage ), "(%i)%s just commited suicide.", playerid, pName );
    SendClientMessageToAll( 0xFFFFFFFF, szMessage );
    SetPlayerHealth( playerid, 0.0 );
    return true;
}
First of all, for both ZCMD and DCMD, the command doesn't go under OnPlayerCommandText, but as a individual function. Cut it out, and paste outside any callback. On the bottom would be an example of where you can paste it.

Then, if you want DCMD, you need to put a line inside OnPlayerCommandText (zcmd doesn't require this)

pawn Код:
dcmd(command_name_here, length_of_command_excluding_the_slash, cmdtext);
Example:
pawn Код:
dcmd(suicide, 7, cmdtext); //suicide is the command, it's length is 7.
Next, we're going to start on the command itself.
Change:
pawn Код:
if( !strcmp( cmdtext, "/suicide", true ))
To:
pawn Код:
//dcmd:
dcmd_suicide(playerid, params[])
//zcmd:
CMD:suicide(playerid, params[])
When you don't use "params", DCMD will give you a warning, zcmd wont.
To get rid of this warning, put
pawn Код:
#pragma unused params
after the bracket, like this:
pawn Код:
dcmd_mycommand(playerid, params[])
{
    #pragma unused params
    //rest of code
Let's take a look at our command now:

DCMD
pawn Код:
//onplayercommandtext
dcmd(suicide, 7, cmdtext);
pawn Код:
dcmd_suicide(playerid, params[] )
{
    #pragma unused params
    new
        szMessage[ 54 ],
        pName[ MAX_PLAYER_NAME ];
    GetPlayerName( playerid, pName, sizeof( pName ));
    format( szMessage, sizeof( szMessage ), "(%i)%s just commited suicide.", playerid, pName );
    SendClientMessageToAll( 0xFFFFFFFF, szMessage );
    SetPlayerHealth( playerid, 0.0 );
    return true;
}
ZCMD
pawn Код:
CMD:suicide(playerid, params[])
{
    new
        szMessage[ 54 ],
        pName[ MAX_PLAYER_NAME ];
    GetPlayerName( playerid, pName, sizeof( pName ));
    format( szMessage, sizeof( szMessage ), "(%i)%s just commited suicide.", playerid, pName );
    SendClientMessageToAll( 0xFFFFFFFF, szMessage );
    SetPlayerHealth( playerid, 0.0 );
    return true;
}
That was easy, wasn't it?
Now let's try converting a command using strtok into dcmd/zcmd & sscanf!

Let's use this vehicle command for an example
pawn Код:
if( !strcmp( cmd, "/v", true ))
{
    new
        tmp[ 128 ],
        vID,
        pID,
        Float:x,
        Float:y,
        Float:z;
    tmp = strtok(cmdtext, idx);
    if( !strlen( tmp ))
        return SendClientMessage( playerid, 0xFFFF00FF, ”USAGE: /v [playerid] [vehicleid]);
    pID = strval( tmp );
    tmp = strtok(cmdtext, idx);
    if( !strlen( tmp ))
        return SendClientMessage( playerid, 0xFFFF00FF, ”USAGE: /v [playerid] [vehicleid]);
    vID = strval( tmp );
    if( vID < 400 || vID > 611 )
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid vehicle model!);
    else if( !IsPlayerConnected( pID ))
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid ID!);
    GetPlayerPos( pID, x, y, z );
    GetXYInFrontOfPlayer( pID, x, y );
    CreateVehicle( vID, x, y, z+0.5, 0.0, -1, -1, -1 );
    return true;
}
This command spawns a vehicle with the desired model infront of the player with the desired playerid.
NOTE: I'm not making efficient code, but I'm not trying to either.

To convert this, we need to do the basics first.
If you use dcmd add
pawn Код:
dcmd(v, 1, cmdtext);
Then move the command out from OnPlayerCommandText, and change the first line so it works with zcmd and dcmd (as we did above).

After we've done that, we start converting the strtok to sscanf.
The code so far looks like this:
pawn Код:
dcmd_v(playerid, params[]) //or CMD:v(playerid, params[]) if you use zcmd
{
    new
        tmp[ 128 ],
        vID,
        pID,
        Float:x,
        Float:y,
        Float:z;
    tmp = strtok(cmdtext, idx);
    if( !strlen( tmp ))
        return SendClientMessage( playerid, 0xFFFF00FF, ”USAGE: /v [playerid] [vehicleid]);
    pID = strval( tmp );
    tmp = strtok(cmdtext, idx);
    if( !strlen( tmp ))
        return SendClientMessage( playerid, 0xFFFF00FF, ”USAGE: /v [playerid] [vehicleid]);
    vID = strval( tmp );
    if( vID < 400 || vID > 611 )
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid vehicle model!);
    else if( !IsPlayerConnected( pID ))
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid ID!);
    GetPlayerPos( pID, x, y, z );
    GetXYInFrontOfPlayer( pID, x, y );
    CreateVehicle( vID, x, y, z+0.5, 0.0, -1, -1, -1 );
    return true;
}
Now let's start converting!

First of all, we don't need the variable called "tmp" anymore, so delete that.
Text, delete the part starting at "tmp = strtok(cmdtext, idx);" all the way down to the second "vID = strval( tmp );",
leaving us with this code:

pawn Код:
dcmd_v(playerid, params[]) //or CMD:v(playerid, params[]) if you use zcmd
{
    new
        vID,
        pID,
        Float:x,
        Float:y,
        Float:z;
   
    if( vID < 400 || vID > 611 )
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid vehicle model!);
    else if( !IsPlayerConnected( pID ))
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid ID!);
    GetPlayerPos( pID, x, y, z );
    GetXYInFrontOfPlayer( pID, x, y );
    CreateVehicle( vID, x, y, z+0.5, 0.0, -1, -1, -1 );
    return true;
}
If you want to check out the syntax on sscanf, search for it here on the forums, as I won't tell you how to do it.

Ok, first of all, we need to add the sscanf line, which is constructed fairly easy:
pawn Код:
if( sscanf( params, "ii", pID, vID )) //will return true if _NOT_ both parameters are typed in.
    return SendClientMessage( playerid, 0xFFFF00FF, "USAGE: /v [playerid] [vehicleid]" );
Notice that these lines, does the same as the whole part we deleted from the strtok code, which obviously is easier and much faster.
And since those lines is all you need, you are already done!

Our code atm:
pawn Код:
dcmd_v(playerid, params[]) //or CMD:v(playerid, params[]) if you use zcmd
{
    new
        vID,
        pID,
        Float:x,
        Float:y,
        Float:z;
    if( sscanf( params, "ii", pID, vID ))
        return SendClientMessage( playerid, 0xFFFF00FF, "USAGE: /v [playerid] [vehicleid]" );
    if( vID < 400 || vID > 611 )
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid vehicle model!);
    else if( !IsPlayerConnected( pID ))
        return SendClientMessage( playerid, 0xFF0000FF, ”Invalid ID!);
    GetPlayerPos( pID, x, y, z );
    GetXYInFrontOfPlayer( pID, x, y );
    CreateVehicle( vID, x, y, z+0.5, 0.0, -1, -1, -1 );
    return true;
}
Note that you won't need "#pragma unused params" when using dcmd, since "params" is being used.

I told you that I won't explain the sscanf part, but I decided I did a quick explanation:
The sscanf param check always starts with
pawn Код:
if( sscanf( params
What comes after depends on the command.
In my example, we use two integers as params.
Integers are represented by either "i" or "d", and that is why I put "ii" in the sscanf line.
What comes after "ii" is the variables you use to store those integer values.
In my example, that is pID and vID.

Other representants are

s - string
u - user (playerid or (part of) name)
f - float
x - hex

There are more, but those you have to check up yourself.
Go to: https://sampwiki.blast.hk/wiki/Fast_Commands for more info about dcmd and sscanf.

I hope this "tutorial" helped you converting commands.
Good luck & Have fun!
Reply
#2

great work,
you should explain how to do a command with multiple parameters, I seen there were a few people wondering about that.
Reply
#3

Not an option, since this is a converting tutorial, not a sscanf tutorial.
I added the link to the wiki page for dcmd & sscanf.

EDIT: Ty for the feedback, btw.
Reply
#4

Nice work, your indentation is a bit... over the top, though.
Reply
#5

Define "over the top".
Everybody has their own ways, and I like it my way.
Reply
#6

Quote:
Originally Posted by LarzI
Посмотреть сообщение
Define "over the top".
Everybody has their own ways, and I like it my way.
True, and I used to follow that style of indentation... but it is kind of hard to interpret, with spaces literally everywhere.
Reply
#7

I use spaces so the code won't be so "packed", and imho easier to edit.
Much more easy to read too.
You may not like it, but I do. This isn't a C&P tutorial, it's a watch and learn. People make it their own way.

EDIT: Ty for the feedback, btw.
Reply
#8

Nice done, but wasen't sscanf 'U' for ID or NPC, and 'R' for players only.

And I use your way of indendation aswell, I agree its much easier to read.
Reply
#9

Quote:
Originally Posted by playbox12
Посмотреть сообщение
Nice done, but wasen't sscanf 'U' for ID or NPC, and 'R' for players only.

And I use your way of indendation aswell, I agree its much easier to read.
According to ****** and personal experiences, 'u' = playerid or (part of)playername, but can also be NPC, which I don't know anything about.. yet.
Reply
#10

Quote:
Originally Posted by LarzI
Посмотреть сообщение
According to ****** and personal experiences, 'u' = playerid or (part of)playername, but can also be NPC, which I don't know anything about.. yet.
Then, why using 'u' I don't think you want to assign anything to a NPC ;P, but its a bit offtopic, so lets just stop it
Reply
#11

I don't use 'u' in here...
But yeah, let's just stop it ^^ OT discussion goes in PMs c:
Reply
#12

Quote:
Originally Posted by LarzI
View Post
DCMD
pawn Code:
//onplayercommandtext
dcmd( suicide, 7, cmdtext );
I use the same style of indentation like you, and noticed this will output an error if you put those spaces, unless you modify the dcmd define accordingly.
________
BMW CONCEPT 5 SERIES GRAN TURISMO HISTORY
Reply
#13

Quote:
Originally Posted by [NoV]LaZ
View Post
I use the same style of indentation like you, and noticed this will output an error if you put those spaces, unless you modify the dcmd define accordingly.
Ty for noticing that!
I actually know it, it's the same for the definition of functions and callbacks (and foreach) too.

Fixing it now
Reply
#14

It gives me warning like this when I change from strcmp to zcmd

E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\pawno\include\dutils.inc(285) : warning 219: local variable "tmp" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\pawno\include\dutils.inc(449) : warning 219: local variable "tmp" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\pawno\include\dini.inc(46) : warning 219: local variable "tmp" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\pawno\include\dini.inc(54) : warning 219: local variable "tmp" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1105) : warning 219: local variable "tmp" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1150) : error 010: invalid function or declaration
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1155) : error 017: undefined symbol "cmdtext"
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1163) : error 017: undefined symbol "cmdtext"
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1210) : warning 209: function "cmd_afk" should return a value
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1225) : warning 209: function "cmd_back" should return a value
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(123 : error 021: symbol already defined: "cmd_uzi"
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1904) : warning 219: local variable "pName" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(1936) : warning 219: local variable "pName" shadows a variable at a preceding level
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(2903) : warning 203: symbol is never used: "cmd"
E:\SA-MP Stuff\[Ask] Yourself\Ask FightClub GrAvE Zone\gamemodes\W9X.pwn(2903) : warning 203: symbol is never used: "idx"
Pawn compiler 3.2.3664 Copyright © 1997-2006, ITB CompuPhase


4 Errors.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)