SA-MP Forums Archive
[Tutorial] Full usage of dcmd (updated) - Printable Version

+- SA-MP Forums Archive (https://sampforum.blast.hk)
+-- Forum: SA-MP Scripting and Plugins (https://sampforum.blast.hk/forumdisplay.php?fid=8)
+--- Forum: Scripting Help (https://sampforum.blast.hk/forumdisplay.php?fid=12)
+---- Forum: Tutorials (https://sampforum.blast.hk/forumdisplay.php?fid=70)
+---- Thread: [Tutorial] Full usage of dcmd (updated) (/showthread.php?tid=243191)



Full usage of dcmd (updated) - Rivera - 21.03.2011

Introduction

Hi all! This is my updated tutorial about dcmd. I must say that I made everything wrong the last tutorial, but thanks to Y_Less now I am ready for a full tutorial.

First of all you must know what's dcmd. dcmd is the most professional command executing processor. I must say that it isn't the fastest. Most of people say that zcmd and ycmd are faster, but I stay with dcmd because it's easy, and I learned that better that any other command processor. Well, the reason why you should learn dcmd is that it's more useful and it can handle more commands. Like most of the great scripters said, some guys that have learned how to script with strtok, dini and dcmd should stay this way, because that's the way they used to script. Of course, with passing time, they can improve their scripts. I don't want useless comments with "ycmd or zcmd is faster" or whatever. This tutorial is for who wants to use dcmd like me, so I hope you enjoy .

Defines and plugins

This command processor can be used with the easy strcmp or strtok, but the easiest way of using it is sscanf. sscanf is the easiest-using plugin, and it's more professional that strtok or dini. Now, for the defines. There's a difference between zcmd and dcmd. zcmd needs to be downloaded and included, but dcmd needs only a long line define :

pawn Code:
#define dcmd(%1,%2,%3) if ((strcmp((%3)[1], #%1, true, (%2)) == 0) && ((((%3)[(%2) + 1] == 0) && (dcmd_%1(playerid, "")))||(((%3)[(%2) + 1] == 32) && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1
Now, for sscanf. It can be downloaded here. The 'include' folder must be sent to /pawno/includes and in your GM or filterscript you should include it:

pawn Code:
#include <sscanf2>
server.cfg :

pawn Code:
plugins sscanf
Now, this is all ready and you should begin scripting with dcmd.

How to make clean commands

Well, making clean commands with dcmd is very easy because of its new features. Of course, sscanf helps even more with the easy scripting. To make a command you should follow these easy steps:

1.) The first step. You need to define your command under OnPlayerCommandText. For example, we want to add a /pay command. The word "pay" has three characters, "p" "a" "y", so we should add a '3', and an usual 'cmdtext' as the last parameter. The command should look like this:

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}
So that's the beginning...

2.) The second step. We need to create the command with an easy lines. These lines should use sscanf, and to be more clear I will add an example.


pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}

dcmd_pay(playerid, params[])
{
    // that's where our command lines should be added
    return 1;
}
About the 'return 1'. sscanf must always return a true value, so there are two ways of returning commands with sscanf.

First:
pawn Code:
return 1;
Second:
pawn Code:
return true;
These ways should work, so you can chose the most practice and professional way which is the first one.

3.) The third step. This step consists in making the command executable, so we can add a function. Without this function, this will be useless. Now, we want to give money to a player, so we need his ID and a value. The 'value' in cash is an integer, so we should write it with 'i' or 'd'. If you need help with the parameters, check the Fast Commands page. So, the command should compile like this:

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}

dcmd_pay(playerid, params[])
{
    new pID, value; // pID = our target's ID and value = the value in cash
    if(sscanf(params, "ui", pID, value)) return SendClientMessage(playerid, -1, "Syntax error: /pay [playerid/Part of name] [amount]");
    return 1;
}
Now, if the player types the command wrong, I added the SendClientMessage line so the server sends a message to the player that he typed the command wrong. Now, we want to check if the id of the player is wrong. This is an easy way too

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}

dcmd_pay(playerid, params[])
{
    new pID, value;
    if(sscanf(params, "ui", pID, value)) return SendClientMessage(playerid, -1, "Syntax error: /pay [playerid/Part of name] [amount]");
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found");
    return 1;
}
This is the easiest way, because 'else if' will check if the id is wrong, and it will send the message that we want.

Now, for the command itself. We want to add some lines, to make the command more professional. That's where dcmd really helps. I will explain some things. When you transfer money to another player, the target gets the message "xxxx transfered you xxxx money", and the sender will get another message "You transfered xxxx money to xxxx". For this, we need both player's names, and a very easy function named 'format'. The correct usage is just like this:

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}

dcmd_pay(playerid, params[])
{
    new pID, value;
    if(sscanf(params, "ui", pID, value)) return SendClientMessage(playerid, -1, "Syntax error: /pay [playerid/Part of name] [amount]");
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found");
    else
    {
        new pName[MAX_PLAYER_NAME], tName[MAX_PLAYER_NAME], string[128]; // pName = sender name; tName = target name; string... i will explain later
        GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
        GetPlayerName(pID, tName, MAX_PLAYER_NAME);
    }
    return 1;
}
Now, the first GetPlayerName defines the sender's name, while the second defines the target's name. Now we want to add sentences to send to both of the players. For the sentences we will weed the defined 'string'. Of course we should format the string, so it can help us in sending the names as messages. That's the correct usage of 'format':

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}

dcmd_pay(playerid, params[])
{
    new pID, value;
    if(sscanf(params, "ui", pID, value)) return SendClientMessage(playerid, -1, "Syntax error: /pay [playerid/Part of name] [amount]");
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found");
    else
    {
        new pName[MAX_PLAYER_NAME], tName[MAX_PLAYER_NAME], string[128];
        GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
        GetPlayerName(pID, tName, MAX_PLAYER_NAME);
        format(string, sizeof(string), "You transfered $%i to %s (%i)", value, tName, pID);
        SendClientMessage(playerid, -1, string);
        format(string, sizeof(string), "You got $%i by %s (%i)", value, pName, playerid);
        SendClientMessage(pID, -1, string);
    }
    return 1;
}
Now, the first 'format' will send the message to the sender, we said that 'i' stands for integer. The money and the ID are integers, so we added %i for both of them. The name of a player is a string, because has many characters, so we added a %s. Now, we want to add the command itself. We should send money to the target and take it from the sender. For this, we will add two easy lines, and that's when our command ends:

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    return 1;
}

dcmd_pay(playerid, params[])
{
    new pID, value;
    if(sscanf(params, "ui", pID, value)) return SendClientMessage(playerid, -1, "Syntax error: /pay [playerid/Part of name] [amount]");
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found");
    else
    {
        new pName[MAX_PLAYER_NAME], tName[MAX_PLAYER_NAME], string[128];
        GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
        GetPlayerName(pID, tName, MAX_PLAYER_NAME);
        format(string, sizeof(string), "You transfered $%i to %s (%i)", value, tName, pID);
        SendClientMessage(playerid, -1, string);
        format(string, sizeof(string), "You got $%i by %s (%i)", value, pName, playerid);
        SendClientMessage(pID, -1, string);
        GivePlayerMoney(pID, value); // sends the money to the target
        GivePlayerMoney(playerid, - value); // takes the money from the sender
    }
    return 1;
}
Compile, no error.

How to make multiple commands

Well, let's say that we need to add more commands in dcmd. This is a big difference from zcmd. We should add every new command under OnPlayerCommandText... Why?! Well, every time we do a new command we need to define it. We have worked with the command /pay. Now, let's make a /slay admin-only command. For this, we will need and 'else if' new line, as well as new functions:

pawn Code:
else if(!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "You have no access to this command);
the '!IsPlayerAdmin' will check if the player is a rcon admin or no. For other types of admin, like admin lv5 or whatever you will need an admin system, or GM. Now, we shall add our new command's define under OnPlayerCommandText like this:

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext); // our previous command
    dcmd(slay, 4, cmdtext); // our new slay command , 's' 'l' 'a' 'y' = 4 (characters)
    // new command define here
    // new command define here...
    return 1;
}
Now, we wanna add the new command as we added before. This time, our command must be written under the other command, so /slay under /pay (this is not too important, but it's more easy to find your commands like this). So that's the way it compiles:

pawn Code:
public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(pay, 3, cmdtext);
    dcmd(slay, 4, cmdtext);
    // new command define here
    // new command define here
    return 1;
}

dcmd_pay(playerid, params[])
{
    new pID, value;
    if(sscanf(params, "ui", pID, value)) return SendClientMessage(playerid, -1, "Syntax error: /pay [playerid/Part of name] [amount]");
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found");
    else
    {
        new pName[MAX_PLAYER_NAME], tName[MAX_PLAYER_NAME], string[128];
        GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
        GetPlayerName(pID, tName, MAX_PLAYER_NAME);
        format(string, sizeof(string), "You transfered $%i to %s (%i)", value, tName, pID);
        SendClientMessage(playerid, -1, string);
        format(string, sizeof(string), "You got $%i by %s (%i)", value, pName, playerid);
        SendClientMessage(pID, -1, string);
        GivePlayerMoney(pID, value);
        GivePlayerMoney(playerid, - value);
    }
    return 1;
}

dcmd_slay(playerid, params[])
{
    // command lines here...
    return 1;
}
Now, we have to do things exactly as the first command, but in this case we don't need an integer, we just need the player's id. id = 'u', so we will use the 'u' character for this command:

pawn Code:
dcmd_slay(playerid, params[])
{
    new pID;
    if(sscanf(params, "u", pID)) return SendClientMessage(playerid, -1, "Syntax error: /slay [playerid/Part of name]");
    return 1;
}
Now, the 'else if' lines.
Notice: The 'else if' lines are very important and you should use them in every command you script. They make the command more professional by avoiding bugs or errors.

For this command we need two 'else if' lines... The first to check if the target's id is wrong and the second to check if the player is rcon admin.

pawn Code:
dcmd_slay(playerid, params[])
{
    new pID;
    if(sscanf(params, "u", pID)) return SendClientMessage(playerid, -1, "Syntax error: /slay [playerid/Part of name]");
    else if(!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "You are not a rcon admin"); // the rcon admin line (very important for admin commands)
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found"); // the invalid target id line (very important too to avoid errors/bugs)
    else
    {
        // now the command's executing lines will be added here
    }
    return 1;
}
Now, we need the target's name and the player who types the cmd's name. We will follow the steps like in the /pay command that I have showed

pawn Code:
dcmd_slay(playerid, params[])
{
    new pID;
    if(sscanf(params, "u", pID)) return SendClientMessage(playerid, -1, "Syntax error: /slay [playerid/Part of name]");
    else if(!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "You are not a rcon admin");
    else if(pID == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Player Not Found");
    else
    {
        new pName[MAX_PLAYER_NAME], tName[MAX_PLAYER_NAME], string[128];
        GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
        GetPlayerName(pID, tName, MAX_PLAYER_NAME);
        format(string, sizeof(string), "You got slayed by admin %s", pName);
        SendClientMessage(pID, -1, string);
        format(string, sizeof(string), "You slayed %s", tName);
        SendClientMessage(playerid, -1, string);
        SetPlayerHealth(pID, 0); // this is the 'command' itself. This line slays the target, the other lines are just for dialog, so the command looks more professional!
    }
    return 1;
}
That's all!
If you want to add another command just add it below OnPlayerCommandText... like I have showed.

I hope you liked this tutorial, as I thought that it's very useful for newbies! Please rate & comment

The End


Re: Full usage of dcmd (updated) - Stigg - 22.03.2011

Not bad at all, nice one fella. Usefull for those who take the dcmd route.


Re: Full usage of dcmd (updated) - Rivera - 22.03.2011

Thanks bro!

It's my first tutorial so I hope that any newbie understands what's dcmd and sscanf at all


Re: Full usage of dcmd (updated) - Rivera - 23.03.2011

Quote:

dcmd route.

dcmd and sscanf

just a small question... why when we type dcmd it gets red? I mean, I didn't made in red with a color define in forum, it auto gets red


Re: Full usage of dcmd (updated) - Davz*|*Criss - 23.03.2011

Nice Tutorial Though, keep it up.


Re: Full usage of dcmd (updated) - wups - 23.03.2011

Quote:
Originally Posted by Rivera
View Post
just a small question... why when we type dcmd it gets red? I mean, I didn't made in red with a color define in forum, it auto gets red
Because you searched dcmd earlyer.

Anyway, dcmd sucks.


Re: Full usage of dcmd (updated) - Rivera - 24.03.2011

Quote:

Anyway, dcmd sucks.

Nice comment...

lol... anyway this is just for beginners so I think they can get what's dcmd at all