The foreach statement is used to evaluate (run) some code for every element in an array (see the tutorial for more info on arrays, which are just lists of things.) Some typical uses are doing something to everyone in a room, or everyone in a group, or all of a mob's enemies in the room. It can also be used to go through a list and check for something, e.g. checking if someone is carrying a certain item.
The foreach statement takes three arguments: the array that it will cycle over, a loop variable (more on this below), and the code to execute for each item in the list. The loop variable is a shorthand notation of the current item being cycled over, and must take the form of a digit 1-9 after % (%1, %2, etc.) The loop variable cannot duplicate a variable that is already defined in the currently executing MUDL function, so for instance if you had two foreach loops and the first one used %1 for the loop variable, the second one would have to use %2 or %7 or something.
Example 1: checking inventory for an item number 1000set_attr( 'got_it', 'no' ), foreach( inventory(%a), %1, if ( vnum(%1) = 1000, set_attr( 'got_it', 'yes' ) ) ),This code will end up setting the KVP attribute 'got_it' to 'yes' if the actor, %a, has a loaf of bread (item 1000) in his inventory or 'no' if he doesn't. Here
inventory(%a)is the list to cycle through (see inventory for more information on that) and the actor %a is the fellow who issued the command that triggered this MUDL code to start executing.
%1is the "loop variable" that will represent the item in %a's inventory that is currently being cycled through. The code executed for each different inventory item %1 is
if ( vnum(%1) = 1000, set_attr( 'got_it', 'yes' ) )which sees if that particular item is vnum 1000, and if it is, sets 'got_it' to 'yes' using the set_attr function. More help is also available on the if statement. Example 2: damaging everybody in the room
foreach( char_in_room(room(%a)), %2, ( msg_character( %2, 'Flames from a vent in the floor roast you!' ), damage( %2, 2d6 ) ) )
NOTE: it makes code more readable if you put matched opening and closing parentheses in the same column, like I did in this example.
Here, the list is
char_in_room(room(%a))the loop variable is
%2instead of %1 (for no particular reason - you can pick which number you want to use for the loop variable, in the range 1 - 9) and the code executed for each character in the room is
( msg_character( %2, 'Flames from a vent in the floor roast you!' ), damage( %2, 2d6 ) )which issues a message to the character and also some damage. Example 3: possibly paralyzing each of a mob's enemies
foreach( group(target(%c)), %1, if ( room(%1) == room(%c) AND can_see(%1, %c), ( msg_character( %1, 'A purple ray shoots out of $N's eyes at you!', %c ), if ( saves(%1,'spell'), msg_character( %1, 'You shake off the effects!' ), ( msg_character( %1, 'You are paralyzed!' ), affect( %1, 'paralysis', 'duration = 20 level = 45'), msg_everyone_else( %1, '$n freezes!' ) ) ) ) ) )This more complicated example cycles over
group(target(%c))with each member of the target group being referred to as
%1and for each of them, executing the code
if ( room(%1) == room(%c) AND can_see(%c, %1), ( msg_character( %1, 'A purple ray shoots out of $N's eyes at you!', %c ), if ( saves(%1,'spell'), msg_character( %1, 'You shake off the effects!' ), ( msg_character( %1, 'You are paralyzed!' ), affect( %1, 'paralysis', 'duration=20 level=45'), msg_everyone_else( %1, '$n freezes!' ) ) ) ) )which says, "if this person %1 is in my room and I can see him, then issue the "shoots..." message and if he doesn't make his saving throw, paralyze him for 20 ticks then issue more appropriate messages." Note that "saves" is not currently a defined MUDL function, and so presumably would be something the user had to write.