im working with some perl code, and im really unfamiliar with the language, and I have a situation. I'm working with a package of perl scripts for a game, there are about 4000 of them and counting. They are release constantly, and altering their contents isnt really an option, it would just be too time consuming. That being said, here is an example of one that fits the situation i'm having.

sub EVENT_ITEM {
if($item1=="7880" && $item2=="7879" && $item3=="5192"){
quest::summonitem(4199);
quest::exp(85); }
}

This would normally be executed by the video game that would supply the EVENT_ITEM call, ass well as the summonitem, and exp functions.

I'm simmulating this invlovement on my site. There is a perl script that executes the EVENT_ITEM sub, and there are provodided summonitem and exp functions that instead spit out HTML that is returned to my php for display.

In essence they are able to simmulate game activities on the webpage before they try for real in the game.

The situation im having is with the $item1-$item4. They are hardcoded in the scripts(the ones i can't change). On the site, I will have 4 textboxes where they person can type these values in and submit them to the perl script. The issue is... if the user puts them in the wrong order the conditional wont execute. They might put item# 7880 in the 3rd box... and then it wouldnt function.

my question is this: Is there someway I can load multiple values into $item1-$item4? Something to the effect of an array that will evaluate every single value in a conditional. For instance in my main perl file that will simmulate execution of the EVENT_ITEM could I do something like

$item1=array(7880,7879,5192)
$item2=array(7880,7879,5192)
$item3=array(7880,7879,5192)

So when $item1==7880 it will check all three values before returning its true/false. Anyone got any idea?


Sorry for the length, i know im long winded.

There is probably a cleaner and easier way to do this, but if you include this sub in your perl file somewhere:

sub Compare_Items
{
	($ref_cmplist, $ref_udata) = @_;

	foreach $udata (@{$ref_udata}) {
		$flags{$udata} = false;
		foreach $cmp_item (@{$ref_cmplist}) {
			if ($cmp_item eq $udata) { $flags{$udata} = true; }
		}
	}

	while (($key, $value) = each %flags) {
		if ($value eq false) { $main_flag = false; }
	}

	return $main_flag;
}

Then you can use it by simply checking its return value. First however, there are a couple of things I should mention. There needs to be 2 arrays in order for this to work. The good news, is that this is very flexible, and can handle many arguments (not just limited to item1, item2, etc). This is basically what you need to do... make an array, which is the list of values you want to compare the user entered values against. In your example, that array would need to contain "7880", "7879", and "5192". Then, you need to take the scalars entered by the user (ie: $item1, $item2, $item3) and put those into an array. Then pass both arrays to the sub/function above. It sounds a lot more complicated than it is really. Here is the code that I used, commented and in its entirety (the code is much shorter without all the comments :) ):

$main_flag = true;

$item1 = "7880"; # Input Would Be From Textbox, Not Assigned Like Here
$item2 = "5192"; # Input Would Be From Textbox, Not Assigned Like Here
$item3 = "7879"; # Input Would Be From Textbox, Not Assigned Like Here

# // This Is The List Of Items That You Want 
# // To Compare The User Input Against
push @compare_list, "7880";
push @compare_list, "7879";
push @compare_list, "5192";

# // Here, We Actually Put $item1, $item2 And $item3 
# // Into An Array.... Yeah, It's That Easy
push @userdata, $item1;
push @userdata, $item2;
push @userdata, $item3;


# // Now We Call The Sub, And Pass It References
# // To Both Of The Arrays. When This Line Finishes
# // The Variable "$are_same" Will Be Either True
# // Or False... True If All The Items Match Something
# // From The Other List... False If Even One Does Not
# // Match.
$are_same = &Compare_Items( \@compare_list, \@userdata );

# // Display True Or False To The Screen
# // ie: Do The Items All Match?
# // You Should Probably Test This With 
# // An If, Instead Of Showing Its Value ;-)
print "$are_same\n";

exit; 

sub Compare_Items
{
	($ref_cmplist, $ref_udata) = @_;

	foreach $udata (@{$ref_udata}) {
		$flags{$udata} = false;
		foreach $cmp_item (@{$ref_cmplist}) {
			if ($cmp_item eq $udata) { $flags{$udata} = true; }
		}
	}

	while (($key, $value) = each %flags) {
		if ($value eq false) { $main_flag = false; }
	}

	return $main_flag;
}

let me know if you need further assistance, or if this just doesn't do what you expect or need.

I don't think that would do it. Lemme give you a better example of whats being run here.

$item1=$ARGV[0];
$item2=$ARGV[1];
$item3=$ARGV[2];
$item4=$ARGV[3];
$myscript=$ARGV[3];

my $TheQuest="";

sub WriteIt {
  $TheQuest.=$_[0]."\n";
}

sub exp {
  WriteIt("<br><font color=yellow>You gain experience!!</font>");
}

sub summonitem {
  WriteIt("<br><b>".$myscript." gives you : </b><a href=$main::root_url"."item.php?id=$_[0]>".$_[0]."</a>");
}

eval "require '$myscript'";

EVENT_ITEM();

print $TheQuest;
exit;
}

ok, so i've got the like 4000 files that this gets run on, and the contents will vary greatly. There really isn't any way for me to predict what item numbers are going to be in the game characters file. So i'll give two scenarios.

The player wants to simmulate giving items to King Tormax to see if his quest is working. So they come to my site, and "give" him 3 items to see if his quest is working. The php calls my perl with all the arguments as follow. "'questparser.pl' '7880' '7879' '5192' '0' 'King_Tormax.pl'"

This will end up including the King_Tormax file, which will have the EVENT_ITEM in it, and the calls to item1-item4. In this situation the items are set in the correct order for king tormax's quest file. which is as follows

sub EVENT_ITEM {
if($item1=="7880" && $item2=="7879" && $item3=="5192"){
quest::summonitem(4199);
quest::exp(85); }
}

had they typed the items in a different oder, 7879, 7880, 5192, then the conditional in king tormax's file wouldnt go off. In the actual game the items are handed in all at once, so order is not a factor, and a user wouldnt expect it to be a factor on my site. Furthermore the quest files for each game character aren't written with the arguments in any kind of order. In this example they are in descending order, but its pure coincidence.

Another example is Veltar,

sub EVENT_ITEM {
if($item1=="356" && $item2=="685"){
quest::say("Very well mortal...");
quest::summonitem(376);
quest::exp(1000); }
elseif($item1=="2296" && $item2=="686"){
quest::say("You have done well for me!");
quest::summonitem(377);
quest::exp(1000); }

as you can see, its very chaotic what to expect from the quest files. In game im really not sure how they do it. When you give the items to the game character a window opens up with 4 slots, and you hand the items in, in any order. So i'm not sure how the game server, which is written in c++, calls the perl so that these items are in order. Naturally the say, summonitem, exp functions are all provided by the game server in that case. These are the things i'm simmulating by writing my own functions that output html.

I was wondering if there was some kind of regular expression that could be used to do this. I've never really messed with the stuff, but i've seen items in []'s before. Would something like

$item1="/[".$ARGV[0].",".$ARGV[1].",".$ARGV[2].",".$ARGV[3]."]/"
$item2="/[".$ARGV[0].",".$ARGV[1].",".$ARGV[2].",".$ARGV[3]."]/"
$item3="/[".$ARGV[0].",".$ARGV[1].",".$ARGV[2].",".$ARGV[3]."]/"
$item4="/[".$ARGV[0].",".$ARGV[1].",".$ARGV[2].",".$ARGV[3]."]/"

so when the conditional of $item1=="7880" fires it will check "/[7880,5192,7879,0]/=="7880"

I know none of that is syntactically correct im shooting in the dark =P

I do believe the code I gave you above would work just fine for what you are doing... instead of manually using push to push each item, you would do a for loop and push all of the items that are arguments and that are not the last one (the filename). However, this can be done with grouping in regex similar to this:

$item1 = "Fun";
$retval = ($item1 =~ m/(Fun|Sucky|Cool)/i) ? true : false;

print "$retval\n";

This will set $retval to true or false depending on if $item1 contains any of the words in the group (Fun, Sucky or Cool) or not.

so when the conditional of $item1=="7880" fires it will check "/[7880,5192,7879,0]/=="7880"

Its possible (I think). Using a hash sounds like the better approach. Very simple example:

%item1 = (
   7880 => [7880,7879,5192,0],
   7879 => [7879,7880,5192,0],
   5192 => [5192,7880,7879,0],
);

$item1 = $item1{$ARGV[0]} || die "Usage: no item found\n";

In the above if $ARGV[0] equaled 7880 then $item1 will be a reference to an array : [7880,7879,5192,0]. The first value is:

$item1->[0]

And so on for the other values in the array reference. The concept is pretty straight forward, but the implementation might not be.

Use an perl array:

@array=("1234","4231","5674");
print "$array[0]\n$array[1]\n$array[2]\n";
for $var (@array){
   print "$var\n";
}

You can pass the array to a sub or an object and the sub or or object will get the array in @_ or you can shift it into a local variable.

This article has been dead for over six months. Start a new discussion instead.