Log in

View Full Version : Need some perl array help


Valdaun
10-17-2009, 09:18 PM
I am trying to make a very simple and scalable quest script utilizing arrays of item turnin + rewards. I have it working now, but I am positive I can simplify this just a tad more, hence my post.

Below are some code snippets showing how I am doing it now, then I will ask my questions after the code.

First I define the item turnin + reward array at the top of the .pl file (this particular quest "upgrades" a few old world weapons to fabled status):


my %turnins = (
1 => { "item" => 5401, "reward" => 68259 }, #Mithril 2 hander & fabled
2 => { "item" => 5403, "reward" => 68260 }, #Ghoulbane & fabled
3 => { "item" => 5500, "reward" => 68263 }, #SS of Ykesha & fabled
4 => { "item" => 5412, "reward" => 68262 } #Razing Sword of Skarlon
);

my $max_turnins = 4; # must manually set to highest number above
my $cost = 22503; # blue diamond (dropped)
my $cost_link = quest::varlink($cost);


Then in the hailing portion of the script, this is an example of how I use the array and some say + item links:


$client->Message(315, "At this time, I am able to convert a $cost_link along
with the basic version of any of these weapons into their fabled counterparts:");

# loop through item + reward array and send a list of items to client
for (my $i = 1; $i <= $max_turnins; $i++)
{
my $link = quest::varlink($turnins{$i}{"item"});
$client->Message(315, "$link")
}


Lastly, here is what I am using to actually check for the turnins:


my $gaveitem = 0;

# loop through item + reward array looking for a match
for (my $i = 1; $i <= $max_turnins; $i++)
{
# hand out the goods on a match of item + cost
if (plugin::check_handin(\%itemcount, $turnins{$i}{"item"} => 1, $cost => 1))
{
$gaveitem = 1;
quest::summonitem($turnins{$i}{"reward"});
}
}

# if there were no matches, give back what was turned in
if ($gaveitem == 0)
{
plugin::return_items(\%itemcount);
}


Questions -

So the main thing I would like to change is to not have to specify the array index numbers myself, but I do not know enough about perl syntax to know how to do this.

I would then like to know how I can get a count of the number of items in the array. That way I don't have to create the $max_turnins variable.

Lastly, perhaps this would be easier to accomplish using foreach to automatically go through the whole array? So if anyone has an example that could replicate what I am doing above with foreach that would be very helpful. :)

joligario
10-17-2009, 09:45 PM
If I am reading you right, I think you might be looking for $itemcount

Valdaun
10-17-2009, 10:11 PM
Sorry, I guess I wasn't totally clear. I need a way to have perl tell me how many entries are in my $turnins array I create at the beginning. That way I don't need to manually create another variable for that number myself. (4 in this case, since I have 4 item + reward entries in my example array) In PHP I could use the count() function to do this:


$max_turnins = count($turnins);


$itemcount is something else, and you can see I do use that too. :)

Thanks though

Kobaz
10-17-2009, 11:39 PM
couldn't you use the ids of the turn-ins as keys to a hash that has the fabled item-id and costs in another hash? Then you wouldn't need an integer index, or a loop.

pfyon
10-18-2009, 12:08 AM
Not a lot of experience with perl either, but you just want to know the length of the array? A quick google got me this blog posting with 3 ways to determine the number of elements in an array: http://www.devdaily.com/blog/post/perl/how-determine-size-number-elements-length-perl-array .


A frequently asked question Perl question is "How do I determine the size of a Perl array?", or the equivalent "How do I determine how many elements are in a Perl array?"

There are at least three different ways to do determine the length of a Perl array. The easiest way to demonstrate this is with some sample source code:

#----------------------------#
# create a simple Perl array #
#----------------------------#
@foods = qw(burgers fries shakes);

#------------------------------------------------------#
# three different ways to get the size of a Perl array #
#------------------------------------------------------#

# 1) implicit scalar conversion:
$size1 = @foods;

# 2) explicit scalar conversion:
$size2 = scalar @foods;

# 3) index of the last element in the array, plus one:
$size3 = $#foods + 1;

printf("The sizes are %d, %d, and %d\n", $size1, $size2, $size3);

which has the corresponding output:

The sizes are 3, 3, and 3

Valdaun
10-18-2009, 12:21 AM
Those are promising and exactly what I want; unfortunately, either it doesn't work for multidimensional arrays, or the way perl and the emulator interact doesn't allow that syntax. I had previously tried the $#array method before, but additionally tried the other two just now and no go. :(

Kobaz
10-19-2009, 04:18 PM
Do the following work?


my %turnins = (
5401, 68259 , #Mithril 2 hander & fabled
5403, 68260 , #Ghoulbane & fabled
5500, 68263 , #SS of Ykesha & fabled
5412, 68262 #Razing Sword of Skarlon
);

my $cost = 22503; # blue diamond (dropped)
my $cost_link = quest::varlink($cost);



$client->Message(315, "At this time, I am able to convert a $cost_link along
with the basic version of any of these weapons into their fabled counterparts:");
my $key = 0;
# loop through item + reward array and send a list of items to client
foreach $key (sort keys %turnins)
{
my $link = quest::varlink($turnins{$key});
$client->Message(315, "$link")
}



my $gaveitem = 0;
my $key = 0;
# loop through item + reward array looking for a match
foreach $key (sort keys %turnins)
{
# hand out the goods on a match of item + cost
if (plugin::check_handin(\%itemcount, $turnins{$key} => 1, $cost => 1))
{
$gaveitem = 1;
quest::summonitem($turnins{$key}}{"reward"});
}
}

# if there were no matches, give back what was turned in
if ($gaveitem == 0)
{
plugin::return_items(\%itemcount);
}

Kobaz
10-19-2009, 05:12 PM
aargh typo:



$gaveitem = 1;
quest::summonitem($turnins{$key});

Valdaun
10-23-2009, 12:42 PM
Thank you for that! You got me exactly where I wanted to get to, though I took a slightly different approach for the array.

Using the quest turnin item ID as the primary index in my array was just the ticket.

I'll put up the whole quest in another post, but here's the interesting snippets of the finished product:

Array creation:


my %fabled_turnins = (
5401 => { "cost" => $rare_cost, "reward" => 68259 }, #Mithril 2 hander & fabled
5403 => { "cost" => $rare_cost, "reward" => 68260 }, #Ghoulbane & fabled
5500 => { "cost" => $rare_cost, "reward" => 68263 }, #SS of Ykesha & fabled
5412 => { "cost" => $rare_cost, "reward" => 68262 } #Razing Sword of Skarlon & fabled
);


And from EVENT_ITEM:

foreach $item_id (sort keys %fabled_turnins)
{
$cost = $fabled_turnins{$item_id}{"cost"};
$reward = $fabled_turnins{$item_id}{"reward"};

# hand out the goods on a match of item + cost
if (plugin::check_handin(\%itemcount, $item_id => 1, $cost => 1))
{
quest::summonitem($reward);
}
}