Jump to content

  •  





Basic Item Trader Script

Posted by GmOcean, in 1. Beginner Scripts 25 November 2014 · 1248 views

Basic Item Trader Script ( 2 Parts )
A basic item trader script. Here we will learn how to give players an item in exchange for other items.

Part 1
Alright, since you're here, I'm goign to assume you completed the previous guide and created a working Healer & Buffer script with a zeny cost. Or, you already know all that.
So let's start off by making our npc header. Don't forget to use those constants for sprite_id. For a list of sprite IDs and their constants check here: Sprite_IDs Credits: Ai4rei. Additonally, the constants for those NPCs are also located in const.txt.

For this npc, I'm going to be using the vending machine sprite and I'm going to name my npc Vending machine. You're free to choose your own sprite and name.
prontera,152,180,4    script    Vending Machine    2_VENDING_MACHINE1,{

So let's start off by making the variables we'll be using for this script. And we're going to place those under the label: OnInit: again. We are also going to be using npc_variables as well. The only difference is that this we're going to be using arrays via the command: setarray <array name>[<first value>],<value>{,<value>...<value>}; and don't forget to end it all with the end; command.
Now, our script is going to give a Player, 1 Valkyrie_Helm for 5 different items. So let's add it in:
OnInit:
    .reward_item = Valkyrie_Helm;
    .reward_amount = 1;
    setarray .request_items[0], Red_Potion, White_Potion, Blue_Potion, Jellopy, Poring_Card;
    setarray .required_amount[0], 10, 5, 1, 1000, 1;
    end;

This tells us, that we're going to be giving a player, 1 Valkyrie helm for 10 Red Potions, 5 White Potions, 1 Blue Potion, 1000 Jellopy and 1 Poring card. Now that's easy!
Now we need to add in all of our mes commands to give our npc some dialogue. But, since this npc is gonna do a bit of talking let's save it's name in a temporary scope_variable:
.@npc_name$ = "[^FF0000 Vending Machine ^000000]";

Now the variable .@npc_name$ holds all that information inside of it. And it's definitely a lot easier to type. So let's add the mes command beneath that with our variable:
mes .@npc_name$;

You'll notice I didn't use any quotation marks for that. This is because we used a string variable. And our string variable already has those quotation marks saved inside of it. Now then, let's add in the rest of the mes commands to let player's know how much 1 valkyrie helm costs. To do that were going to be utilizing the command: getitemname(<item id>) and where it asks for <item_id> we're going to be using our variables. So let's add the following lines in:
mes "I will give you "+ .reward_amount +" "+ getitemname(.reward_item) +",";
mes "for the following items:";
mes ""+ getitemname(.required_items[0]) +" x"+ .required_amount[0] +"";
mes ""+ getitemname(.required_items[1]) +" x"+ .required_amount[1] +"":
mes ""+ getitemname(.required_items[2]) +" x"+ .required_amount[2] +"":
mes ""+ getitemname(.required_items[3]) +" x"+ .required_amount[3] +"":
mes ""+ getitemname(.required_items[4]) +" x"+ .required_amount[4] +"":

See, that wasn't too hard. It's practically the same thing as the reward variables, just with the extra [#] added. Okay, next let's add in our menu. This time we're going to keep it to 2 options, so we're going to make it that if they choose option 2, end the script with close; since we used mes earlier.
if (select("Trade in items", "That's a rip off!") == 2) {
    close;
}

Okay, now that we got that taken care of. We need to add a few checks. The first check being whether or not they have those items. To do that we're going to use the command: countitem(<item id>).
Keep in mind that since we have 5 items to check for, we're going to be utilizing the | | operator. Now this is where things get a little technical, after each | | we're going to add the next check on the line beneath.
We're doing this to keep the script nice and neat. Would you rather look at 5 short lines, or 1 really long line that makes your head turn? So let's stick to 5 short lines.
Let's add our check below the if() statement we did above. It should look something like this:
if ((countitem(.required_items[0]) < .required_amount[0]) ||
    (countitem(.required_items[1]) < .required_amount[1]) ||
    (countitem(.required_items[2]) < .required_amount[2]) ||
    (countitem(.required_items[3]) < .required_amount[3]) ||
    (countitem(.required_items[4]) < .required_amount[4])) {
        mes "You don't have all the required items.";
        close;
}

Now that we added the check to see if they have all the items, it's time to delete those items, and give them the reward! The commands that let us do that are the following respectively: delitem <item id>,<amount>{,<account ID>}; and getitem <item id>,<amount>{,<account ID>};
So let's add that in below our check, and remember to use those variables:
delitem .required_items[0], .required_amount[0];
delitem .required_items[1], .required_amount[1];
delitem .required_items[2], .required_amount[2];
delitem .required_items[3], .required_amount[3];
delitem .required_items[4], .required_amount[4];
getitem .reward_item, .reward_amount;

Okay, now there's only 1 more thing to do, and that's add the last } to the very bottom of our script. After you add that you're done. You now have a working item trader script. It should look something like this:
prontera,154,180,4	script	Vending Machine	2_VENDING_MACHINE1,{
.@npc_name$ = "[^FF0000 Vending Machine ^000000]";
mes .@npc_name$;
mes "I will give you "+ .reward_amount +" "+ getitemname(.reward_item) +",";
mes "for the following items:";
mes ""+ getitemname(.required_items[0]) +" x"+ .required_amount[0] +"";
mes ""+ getitemname(.required_items[1]) +" x"+ .required_amount[1] +"";
mes ""+ getitemname(.required_items[2]) +" x"+ .required_amount[2] +"";
mes ""+ getitemname(.required_items[3]) +" x"+ .required_amount[3] +"";
mes ""+ getitemname(.required_items[4]) +" x"+ .required_amount[4] +"";
if (select("Trade in items", "That's a rip off!") == 2) {
	close;
}
if ((countitem(.required_items[0]) < .required_amount[0]) ||
    (countitem(.required_items[1]) < .required_amount[1]) ||
    (countitem(.required_items[2]) < .required_amount[2]) ||
    (countitem(.required_items[3]) < .required_amount[3]) ||
    (countitem(.required_items[4]) < .required_amount[4])){
        mes "You don't have all the required items.";
	close;
}
delitem .required_items[0], .required_amount[0];
delitem .required_items[1], .required_amount[1];
delitem .required_items[2], .required_amount[2];
delitem .required_items[3], .required_amount[3];
delitem .required_items[4], .required_amount[4];
getitem .reward_item, .reward_amount;
close;

OnInit:
    .reward_item = Valkyrie_Helm;
    .reward_amount = 1;
    setarray .required_items[0], Red_Potion, White_Potion, Blue_Potion, Jellopy, Poring_Card;
    setarray .required_amount[0], 10, 5, 1, 1000, 1;
    end;
}
You just finished making a working item trader npc. But it's not 100% done yet. We need to do a few more things. We'll deal with those in the next lesson. For now look at it, and be proud.

Part 2
Okay, last lesson I mentioned how the script wasn't 100% done yet, because there were a few things we needed to take care of. So let's knock those out.

Firstly, let's start by opening the script from last time:
prontera,154,180,4	script	Vending Machine	2_VENDING_MACHINE1,{
.@npc_name$ = "[^FF0000 Vending Machine ^000000]";
mes .@npc_name$;
mes "I will give you "+ .reward_amount +" "+ getitemname(.reward_item) +",";
mes "for the following items:";
mes ""+ getitemname(.required_items[0]) +" x"+ .required_amount[0] +"";
mes ""+ getitemname(.required_items[1]) +" x"+ .required_amount[1] +"";
mes ""+ getitemname(.required_items[2]) +" x"+ .required_amount[2] +"";
mes ""+ getitemname(.required_items[3]) +" x"+ .required_amount[3] +"";
mes ""+ getitemname(.required_items[4]) +" x"+ .required_amount[4] +"";
if (select("Trade in items", "That's a rip off!") == 2) {
	close;
}
if ((countitem(.required_items[0]) < .required_amount[0]) ||
    (countitem(.required_items[1]) < .required_amount[1]) ||
    (countitem(.required_items[2]) < .required_amount[2]) ||
    (countitem(.required_items[3]) < .required_amount[3]) ||
    (countitem(.required_items[4]) < .required_amount[4])){
        mes "You don't have all the required items.";
	close;
}
delitem .required_items[0], .required_amount[0];
delitem .required_items[1], .required_amount[1];
delitem .required_items[2], .required_amount[2];
delitem .required_items[3], .required_amount[3];
delitem .required_items[4], .required_amount[4];
getitem .reward_item, .reward_amount;
close;

OnInit:
    .reward_item = Valkyrie_Helm;
    .reward_amount = 1;
    setarray .required_items[0], Red_Potion, White_Potion, Blue_Potion, Jellopy, Poring_Card;
    setarray .required_amount[0], 10, 5, 1, 1000, 1;
    end;
}

Alright, now that we opened this up, we need to add a check to make sure the player has enough inventory space, and free-weight to carry the reward.
To do so we need to use the command: checkweight(<item id>,<amount>{,<item id>,<amount>,<item id>,<amount>,...}); Only thin is, we're going to check to see if the command fails using this operator: !
So let's go ahead and add that above the first delitem command:
if (!checkweight(.reward_item, .reward_amount)) {

This tells us that, if true ( if the command fails ) to do something. In our case, we want to just tell the player they don't have enough free-space/weight to receive the item. Then we're going to add a close; command to end the script early. And lastly close the check with }.
So let's go ahead and do that, it should look like this when it's done:
    mes "You don't have enough free inventory space or weight to receive this item.";
    close;
}

Okay, now the script is finished, and you technically don't need to do anything else to it. But, we're here to learn! So we're going to clean up the script a bit using a loop.
The loop we will be using is called: while (<condition>) <statement>; There are other loops that can get the job done, but I feel like this one is best suited since it's simple.
Alright, so go ahead and delete the following from your script:
mes ""+ getitemname(.required_items[0]) +" x"+ .required_amount[0] +"";
mes ""+ getitemname(.required_items[1]) +" x"+ .required_amount[1] +"";
mes ""+ getitemname(.required_items[2]) +" x"+ .required_amount[2] +"";
mes ""+ getitemname(.required_items[3]) +" x"+ .required_amount[3] +"";
mes ""+ getitemname(.required_items[4]) +" x"+ .required_amount[4] +"";

Okay now where those mes commands used to be, we're going to add our loop. We're goign to be using a scope_variable .@ and we're going to compare it to a value we obtain with this command: getarraysize(<array name>).
So go ahead and add the following:
while (.@i < getarraysize(.required_items)) {

Just a note, .@i can be any variable name. It doesn't even need to be a scope_variable. But since we only need the variable for this 1 loop, we use a scope_variable, so it's memory isn't saved once the script ends. However, .@i is most commonly used in cases like these. Now then let's continue.
Beneath that we're going to be adding 1 mes command followed by setting the variable .@i + 1.
On the line after that we're going to close the loop with }. I'm sure you've noticed I keep telling you to close either a script, if() statement, loop and the like with }. This is because we always need to make sure to close a command with a right-curly bracket } whenever a left-curly bracket { is used.

Now, the mes command we're going to use is very similar to the ones we deleted. The only difference is, instead of using [0] or [1] or [2], we'll be replacing that with [.@i] as such:
    mes ""+ getitemname(.required_items[.@i]) +" x"+ .required_amount[.@i] +"";
    ++.@i;
}

Okay since that's done we're about 80% done making this script nice and clean. There is only 1 more thing to do, and that's add 1 more while() loop. But this time, we're going to be replacing those delitem() commands with the loop. The difference is, instead of using .@i we're going to switch it to .@j it is a lower-case J. If you're having a hard time reading that. So taking a look at our previous loop as an example, let's replace those delitem() commands with a loop:
while (.@j < getarraysize(.required_items)) {
    delitem .required_items[.@j], .required_amount[.@j];
    ++.@j;
}

Alright, now your script should look something like this:
prontera,154,180,4	script	Vending Machine	2_VENDING_MACHINE1,{
.@npc_name$ = "[^FF0000 Vending Machine ^000000]";
mes .@npc_name$;
mes "I will give you "+ .reward_amount +" "+ getitemname(.reward_item) +",";
mes "for the following items:";
while (.@i < getarraysize(.required_items)){
    mes ""+ getitemname(.required_items[.@i]) +" x"+ .required_amount[.@i] +"";
    ++.@i;
}
if (select("Trade in items", "That's a rip off!") == 2) {
    close;
}
if ((countitem(.required_items[0]) < .required_amount[0]) ||
    (countitem(.required_items[1]) < .required_amount[1]) ||
    (countitem(.required_items[2]) < .required_amount[2]) ||
    (countitem(.required_items[3]) < .required_amount[3]) ||
    (countitem(.required_items[4]) < .required_amount[4])){
	mes "You don't have all the required items.";
	close;
}
if (!checkweight(.reward_item, .reward_amount)){
    mes "You don't have enough free inventory space or weight to receive this item.";
    close;
}
while (.@j < getarraysize(.required_items)){
    delitem .required_items[.@j], .required_amount[.@j];
    ++.@j;
}
getitem .reward_item, .reward_amount;
close;

OnInit:
    .reward_item = Valkyrie_Helm;
    .reward_amount = 1;
    setarray .required_items[0], Red_Potion, White_Potion, Blue_Potion, Jellopy, Poring_Card;
    setarray .required_amount[0], 10, 5, 1, 1000, 1;
    end;
}
Go ahead and save that, because we are done.