PDA

View Full Version : Nested coupled foreach loops


Asylum
10-15-2014, 05:28 PM
I have searched the forums, though not exhaustively, for help on this topic but this was the only thread close to what I want to accomplish:

http://www.eqemulator.org/forums/showthread.php?t=31777

I am trying to create nested foreach loops where the inner loop simultaneously reads two @lists containing 8 items each. Here's what I have so far, and can't figure out how to reference the $item (@itemlist). Any help would be appreciated. Thanks.


sub EVENT_SPAWN {
$npc->TempName("");
quest::settimer("armor", 30);
}

sub EVENT_TIMER {
if ($timer eq "armor") {
my @clientlist = $entity_list->GetClientList();
my @slotlist = (2,7,9,10,12,17,18,19);
my @itemlist = (0000,0000,0000,0000,0000,0000,0000,0000);
foreach $ent (@clientlist) {
foreach $slot (@slotlist) {
if (plugin::check_hasitemequipped($ent, $slot, $item)) { #usage plugin::check_hasitemequipped($client, slotid, itemid)
$ent->Message(315, "Your armor protects you from harm.");
}
else {
my $eid = $ent->GetID(); #Get this client's Entity_ID
$ent->CastSpell(7026,$eid); #casts Aura of Crimson Mists IV
my $h_ent_name = $ent->GetCleanName();
quest::ze(4, "$h_ent_name suffers in the throes of anguish.");
}
}
}
}
}


the plugin I created is as follows:


#checks to see if player has item equipped
#usage plugin::check_hasitemequipped($client, slotid, itemid); #just input numbers for slotid and itemid

#Item slotid #'s
#1 LEar
#2 Head - visible
#3 Face
#4 REar
#5 Neck
#6 Shoulder
#7 Arms - visible
#8 Back
#9 LWrist - visible
#10 RWrist - visible
#11 Range
#12 Hands - visible
#13 Primary Slot - visible
#14 Secondary Slot - visible
#15 LFinger
#16 RFinger
#17 Chest - visible
#18 Legs - visible
#19 Feet - visible
#20 Belt
#21 Ammo

sub check_hasitemequipped { #Check for item $itmchk in slot $slotid
my $client = shift;
my $slotid = shift;
my $itmchk = shift;
my $itemid = $client->GetItemIDAt($slotid);
if($itemid1==$itmchk) {
return 1;
}
return 0;
}

1;

Asylum
10-15-2014, 05:39 PM
Update: perhaps?


sub EVENT_SPAWN {
$npc->TempName("");
quest::settimer("armor", 30);
}

sub EVENT_TIMER {
if ($timer eq "armor") {
my @clientlist = $entity_list->GetClientList();
my @slotlist = (2,7,9,10,12,17,18,19);
my @itemlist = (0000,0000,0000,0000,0000,0000,0000,0000);
foreach $ent (@clientlist) {
foreach $slot (@slotlist) {
if (plugin::check_hasitemequipped($ent, $slot, $itemlist[$a])) { #usage plugin::check_hasitemequipped($client, slotid, itemid)
$a++;
$ent->Message(315, "Your armor protects you from harm.");
}
else {
my $eid = $ent->GetID(); #Get this client's Entity_ID
$ent->CastSpell(7026,$eid); #casts Aura of Crimson Mists IV
my $h_ent_name = $ent->GetCleanName();
quest::ze(4, "$h_ent_name suffers in the throes of anguish.");
}
}
}
}
}

Kingly_Krab
10-15-2014, 06:43 PM
Try this for the NPC: sub EVENT_SPAWN {
$npc->TempName("");
quest::settimer("armor", 30);
}

sub EVENT_TIMER {
if ($timer eq "armor") {
my @clientlist = $entity_list->GetClientList();
my @itemlist = (0000,0000,0000,0000,0000,0000,0000,0000);
foreach $c (@clientlist) {
if (plugin::check_hasitemequipped($c, @itemlist)) {
$c->Message(315, "Your armor protects you from harm.");
}
else {
$c->CastSpell(7026, $c->GetID());
quest::ze(4, $c->GetCleanName() . " suffers in the throes of anguish.");
}
}
}
}Try this for the plugin: sub check_hasitemequipped {
my $client = shift;
my @itemlist = shift;
foreach $item (@itemlist) {
for ($i = 0; $i <= 22; $i++) {
if ($i == 22) {
$i == 9999;
}
if ($client->GetItemIDAt($i) == $item) {
return 1;
}
}
}
return 0;
}

EDIT: Slot information can be found here (http://wiki.eqemulator.org/p?slots).

Asylum
10-15-2014, 06:51 PM
I see you've avoided the nested loops by shifting one iteration to the plugin; good idea. Now to tweak allowing bracers in either left or right slots (9 or 10).

I would want to limit the checked slots to visible slots (2,7,9,10,12,17,18,19), so the 1->22 $i++ iteration would need changing.

Thanks Kingly_Krab

p.s. This can also be utilized to accomplish the "remove weapon or armor" emotes and checks during MPG trials.

Kingly_Krab
10-15-2014, 07:01 PM
Okay, I'd like to see how you're going to use this. Unless you're just using it for the MPG trials.

Asylum
10-15-2014, 07:52 PM
No, the MPG trials were an afterthought use. I plan on utilizing this check to implement a way to force usage of "resist gear" beyond the simple type resist checks. I.e., if you equip (not just own) 3 of 8 pieces of this gear, you only get hit with 5 of the 8 iterations of a DD, for example; whereas if you have the entire set on (lore to be added) the DD does not harm you.

I'll post the event when completed. Thanks again.

Asylum
10-15-2014, 08:54 PM
Results of testing:

Trying your suggested code for npc and plugin, the code merely checks for the proper item on the client's head (the lowest value slot in which an item can appear from the @itemlist). If that passes, returns a 1 and check ends. If that fails, returns a 0 and check ends. I.e., the for loop 1-22 is not executing past a true


if ($client->GetItemIDAt($i) == $item) {
return 1;
}


as none of the other sent items in @itemlist are numerically correct to correspond with $i, returning a 0.

My quest continues...

Uleat
10-15-2014, 09:39 PM
I'm probably missing something...

my @itemlist = (0000,0000,0000,0000,0000,0000,0000,0000);


Wouldn't any item found in any checked slot return 0?

0000 (as @item) != {>0 .. <= ceiling} (as $client->GetItemIDAt($i))

Asylum
10-15-2014, 09:44 PM
Yes, the actual numbers for the items are not 0000, those were just placeholders when I began thinking of this script at work today. I have decided to axe the plugin and do it manually and it works perfectly, only I still have the explicit right versus left wrists to tackle. Finally, I need to get it working as a loop to have the ill effects count the number of correct/missing items of the 8.

This works as intended for checking all 8 visible armor items:


sub EVENT_SPAWN {
$npc->TempName("");
quest::settimer("armor", 30);
}

sub EVENT_TIMER {
if ($timer eq "armor") {
my @clientlist = $entity_list->GetClientList();
foreach $ent (@clientlist) {
if ($ent->GetItemIDAt(2) == 2298 && $ent->GetItemIDAt(7) == 2372 && $ent->GetItemIDAt(9) == 2376 && $ent->GetItemIDAt(10) == 31891 && $ent->GetItemIDAt(12) == 2377 && $ent->GetItemIDAt(17) == 2370 && $ent->GetItemIDAt(18) == 2378 && $ent->GetItemIDAt(19) == 2379) {
$ent->Message(315, "Your armor protects you from harm.");
}
else {
$ent->CastSpell(7026,$ent->GetID()); #casts Aura of Crimson Mists IV
quest::ze(4, $ent->GetCleanName() . " suffers in the throes of anguish.");
}
}
}
}


Hint: the item numbers are unique to my server, who knows what they are on other servers.

Kingly_Krab
10-15-2014, 10:14 PM
If you HAVE you do your if statement that way, try this. (Spacing should not look like this, this is just for looks.)

if ($ent->GetItemIDAt(2) == 2298
&& $ent->GetItemIDAt(7) == 2372
&& (($ent->GetItemIDAt(9) == 2376 && $ent->GetItemIDAt(10) == 31891)
|| ($ent->GetItemIDAt(9) == 2376 && $ent->GetItemIDAt(10) == 2376)
|| ($ent->GetItemIDAt(9) == 31891 && $ent->GetItemIDAt(10) == 2376)
|| ($ent->GetItemIDAt(9) == 31891 && $ent->GetItemIDAt(10) == 31891))
&& $ent->GetItemIDAt(12) == 2377
&& $ent->GetItemIDAt(17) == 2370
&& $ent->GetItemIDAt(18) == 2378
&& $ent->GetItemIDAt(19) == 2379)

Asylum
10-16-2014, 01:28 PM
Next question: is there a function or call that accomplishes the following, or can one of you experts create one to look into an item's file and find the assigned weapon type by value? I imagine it would mirror the function of
quest::isdisctome(item_id) # Checks if 'item_id' is a discipline tome.


#usage quest::isweapon_type($itemid, type) where you choose the value for slash, blunt, et cetera

$itemid = $client->GetItemIDAt(13); #Gets itemid in primary
if (quest::isweapon_type($itemid, type)) { # Checks if $itemid is a type weapon
effect;
}
else {
other effect;
}