Error with nested FOREACH in an IF + CODE block

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

Post Reply
User avatar
Warklaw
Cave Troll
Posts: 28
Joined: Wed Oct 27, 2010 4:31 pm
Location: Minneapolis, MN

Error with nested FOREACH in an IF + CODE block

Post by Warklaw »

I was curious if anyone could help me out. I am encountering an error that I can't seem to resolve directly.

Here is the error I am receiving:
 Error in roll for IF option.       Statement options (if any): h, IF(response == 0), CODE       Statement Body (first 200 characters): { [h, FOREACH(food, foodArray), CODE: { [h: foodGroup = json.get(food,"group")] [h, IF(foodGroup == "Fruit"), CODE: { [h: fruit
When I try to run this code:

Code: Select all

<!-- Check to see if they are sure --->
[h: warnText = "<html><FONT COLOR = red><b>Scary warning message!<BR>You should read this!</b></FONT></html>"]
[h: respList = "Yes,No"]

[h: success = input(
"junkVar||"+ warnText +"|LABEL|TEXT=FALSE",
"response |"+ respList +"| Are you sure you want to continue?| RADIO| ORIENT=H"
)]
[h: abort(success)]

<!-- Create an JSON array to play with -->
[h: foodArray = "[]"]
[h: fruitArray = "[]"]
[h: meatArray = "[]"]

[h: newFood1 = json.set("","ID",1,"group","Fruit","name","Apple")]
[h: newFood2 = json.set("","ID",2,"group","Fruit","name","Banana")]
[h: newFood3 = json.set("","ID",3,"group","Fruit","name","Kumkwat")]
[h: newFood4 = json.set("","ID",4,"group","Meat","name","Beef")]
[h: newFood5 = json.set("","ID",5,"group","Meat","name","Pork")]

[h: foodArray = json.append(foodArray,newFood1)]
[h: foodArray = json.append(foodArray,newFood2)]
[h: foodArray = json.append(foodArray,newFood3)]
[h: foodArray = json.append(foodArray,newFood4)]
[h: foodArray = json.append(foodArray,newFood5)]

<!-- Use the input to determine code to run -->
[h, IF(response == 0), CODE:
{
   <!-- Seperate the good groups -->
   [h, FOREACH(food, foodArray), CODE:
   {
      [h: foodGroup = json.get(food,"group")]
      [h, IF(foodGroup == "Fruit"), CODE:
      {
          [h: fruitArray = json.append(fruitArray,food)]
      }]
      [h, IF(foodGroup == "Meat"), CODE:
      {
          [h: meatArray = json.append(meatArray,food)]
      }]
    }]
   [h: output =  "Meat: "+ meatArray +"<BR>Fruit: "+ fruitArray]
};
{
   [h: output = "User aborted process"]
}]

<!-- Output results -->
[r: output]
I know the code INSIDE and before the IF statement is correct as I have run the code without the IF statement (included below) and it runs fine (though obviously it does not branch).

Code: Select all

<!-- Check to see if they are sure --->
[h: warnText = "<html><FONT COLOR = red><b>Scary warning message!<BR>You should read this!</b></FONT></html>"]
[h: respList = "Yes,No"]

[h: success = input(
"junkVar||"+ warnText +"|LABEL|TEXT=FALSE",
"response |"+ respList +"| Are you sure you want to continue?| RADIO| ORIENT=H"
)]
[h: abort(success)]

<!-- Create an JSON array to play with -->
[h: foodArray = "[]"]
[h: fruitArray = "[]"]
[h: meatArray = "[]"]

[h: newFood1 = json.set("","ID",1,"group","Fruit","name","Apple")]
[h: newFood2 = json.set("","ID",2,"group","Fruit","name","Banana")]
[h: newFood3 = json.set("","ID",3,"group","Fruit","name","Kumkwat")]
[h: newFood4 = json.set("","ID",4,"group","Meat","name","Beef")]
[h: newFood5 = json.set("","ID",5,"group","Meat","name","Pork")]

[h: foodArray = json.append(foodArray,newFood1)]
[h: foodArray = json.append(foodArray,newFood2)]
[h: foodArray = json.append(foodArray,newFood3)]
[h: foodArray = json.append(foodArray,newFood4)]
[h: foodArray = json.append(foodArray,newFood5)]

<!-- Removed branching statement -->

   <!-- Seperate the good groups -->
   [h, FOREACH(food, foodArray), CODE:
   {
      [h: foodGroup = json.get(food,"group")]
      [h, IF(foodGroup == "Fruit"), CODE:
      {
          [h: fruitArray = json.append(fruitArray,food)]
      }]
      [h, IF(foodGroup == "Meat"), CODE:
      {
          [h: meatArray = json.append(meatArray,food)]
      }]
    }]
   [h: output =  "Meat: "+ meatArray +"<BR>Fruit: "+ fruitArray]

<!-- Removed branching statement -->

<!-- Output results -->
[r: output]
I know I can get a simular result using a assert() instead of the IF statement, but I would rather have the error in the chat appear from the "user" running the macro than the system.

Code: Select all

<!-- Check to see if they are sure --->
[h: warnText = "<html><FONT COLOR = red><b>Scary warning message!<BR>You should read this!</b></FONT></html>"]
[h: respList = "Yes,No"]

[h: success = input(
"junkVar||"+ warnText +"|LABEL|TEXT=FALSE",
"response |"+ respList +"| Are you sure you want to continue?| RADIO| ORIENT=H"
)]
[h: abort(success)]

<!-- Create an JSON array to play with -->
[h: foodArray = "[]"]
[h: fruitArray = "[]"]
[h: meatArray = "[]"]

[h: newFood1 = json.set("","ID",1,"group","Fruit","name","Apple")]
[h: newFood2 = json.set("","ID",2,"group","Fruit","name","Banana")]
[h: newFood3 = json.set("","ID",3,"group","Fruit","name","Kumkwat")]
[h: newFood4 = json.set("","ID",4,"group","Meat","name","Beef")]
[h: newFood5 = json.set("","ID",5,"group","Meat","name","Pork")]

[h: foodArray = json.append(foodArray,newFood1)]
[h: foodArray = json.append(foodArray,newFood2)]
[h: foodArray = json.append(foodArray,newFood3)]
[h: foodArray = json.append(foodArray,newFood4)]
[h: foodArray = json.append(foodArray,newFood5)]

<!-- Removed branching statement inserted assert statement -->
<!-- If user selected 'No' abort process, notify user -->
[h: assert(response == 0,"<b>Carbs are bad... M'kay!.<b>",0)]

   <!-- Seperate the good groups -->
   [h, FOREACH(food, foodArray), CODE:
   {
      [h: foodGroup = json.get(food,"group")]
      [h, IF(foodGroup == "Fruit"), CODE:
      {
          [h: fruitArray = json.append(fruitArray,food)]
      }]
      [h, IF(foodGroup == "Meat"), CODE:
      {
          [h: meatArray = json.append(meatArray,food)]
      }]
    }]
   [h: output =  "Meat: "+ meatArray +"<BR>Fruit: "+ fruitArray]

<!-- Removed branching statement -->

<!-- Output results -->
[r: output]
I am at a loss for what is wrong. Any help would be greatly appreciated.

User avatar
jfrazierjr
Deity
Posts: 5176
Joined: Tue Sep 11, 2007 7:31 pm

Re: Error with nested FOREACH in an IF + CODE block

Post by jfrazierjr »

Nesting. You can only go 2 levels deep with [CODE:] as clearly stated on the wiki. When you find yourself going more than one level deep with multiple statements, it's time for you to break out to a seperate [macro:]
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: Error with nested FOREACH in an IF + CODE block

Post by Azhrei »

Or in a lot of cases you can restructure the code to avoid the nesting limit.

User avatar
Warklaw
Cave Troll
Posts: 28
Joined: Wed Oct 27, 2010 4:31 pm
Location: Minneapolis, MN

Re: Error with nested FOREACH in an IF + CODE block

Post by Warklaw »

Noted, I will review both those options. Thanks.

User avatar
Warklaw
Cave Troll
Posts: 28
Joined: Wed Oct 27, 2010 4:31 pm
Location: Minneapolis, MN

Re: Error with nested FOREACH in an IF + CODE block

Post by Warklaw »

Or in a lot of cases you can restructure the code to avoid the nesting limit.
Azhrei, was this what you were thinking?

Code: Select all

<!-- Check to see if they are sure --->
[h: warnText = "<html><FONT COLOR = red><b>Scary warning message!<BR>You should read this!</b></FONT></html>"]
[h: respList = "Yes,No"]

[h: success = input(
"junkVar||"+ warnText +"|LABEL|TEXT=FALSE",
"response |"+ respList +"| Are you sure you want to continue?| RADIO| ORIENT=H"
)]
[h: abort(success)]

<!-- Create an JSON array to play with -->
[h: foodArray = "[]"]
[h: fruitArray = "[]"]
[h: meatArray = "[]"]

[h: newFood1 = json.set("","ID",1,"group","Fruit","name","Apple")]
[h: newFood2 = json.set("","ID",2,"group","Fruit","name","Banana")]
[h: newFood3 = json.set("","ID",3,"group","Fruit","name","Kumkwat")]
[h: newFood4 = json.set("","ID",4,"group","Meat","name","Beef")]
[h: newFood5 = json.set("","ID",5,"group","Meat","name","Pork")]

[h: foodArray = json.append(foodArray,newFood1)]
[h: foodArray = json.append(foodArray,newFood2)]
[h: foodArray = json.append(foodArray,newFood3)]
[h: foodArray = json.append(foodArray,newFood4)]
[h: foodArray = json.append(foodArray,newFood5)]

<!-- Use the input to determine code to run -->
[h, IF(response == 0), CODE:
{
   <!-- Seperate the good groups -->
   [h, FOREACH(food, foodArray), CODE:
   {
      [h: foodGroup = json.get(food,"group")]
      [h: fruitArray = IF(foodGroup == "Fruit", json.append(fruitArray,food), fruitArray)]
      [h: meatArray = IF(foodGroup == "Meat", json.append(meatArray,food), meatArray)]
    }]
   [h: output =  "Meat: "+ meatArray +"<BR>Fruit: "+ fruitArray]
};
{
   [h: output = "User aborted process"]
}]

<!-- Output results -->
[r: output]
@jfrazierjr, thanks for calling out the part about two levels in the CODE wiki that I must have skimmed and did not comprehend a thousand times. Hopefully it sets in this time. I am pretty familiar with calling other macros and can think of a couple ways to do it here.

@Azhrei,thanks for the nudge! :D

User avatar
CoveredInFish
Demigod
Posts: 3104
Joined: Mon Jun 29, 2009 10:37 am
Location: Germany
Contact:

Re: Error with nested FOREACH in an IF + CODE block

Post by CoveredInFish »

Btw you can use [if:] without [code:]. No need to use Wiki: if()-function here (although you use it well).

This would work as well

Code: Select all

[h, IF(foodGroup == "Fruit"): fruitArray = json.append(fruitArray,food)]

User avatar
Warklaw
Cave Troll
Posts: 28
Joined: Wed Oct 27, 2010 4:31 pm
Location: Minneapolis, MN

Re: Error with nested FOREACH in an IF + CODE block

Post by Warklaw »

Thanks for that! I like that a lot better than if(), way more clean, which is part of my problem in over using CODE. I personally like the CODE block because for me it seems more organized.

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: Error with nested FOREACH in an IF + CODE block

Post by Azhrei »

Warklaw wrote:@Azhrei,thanks for the nudge! :D
Yes, in this case that's one way of reorganizing the code. Different goals will require different types of restructuring but it is always possible. (I seem to remember a proof of that statement being presented in college. Maybe it was in my Logic class, or maybe it was in some programming course...)

User avatar
Bone White
Great Wyrm
Posts: 1124
Joined: Tue Aug 23, 2011 11:41 am
Location: Cornwall, UK

Re: Error with nested FOREACH in an IF + CODE block

Post by Bone White »

Usually I find I can conserve code blocks by putting together complex boolean arguments for if functions.

For example:

Code: Select all

If school = invocation then
  If level = 1 then
    Foreach spell in list do
      If spelltype = damage then
        Add to Array
      Else
        Nothing
Could be converted to.

Code: Select all

If (school = invocation) && (level = 1) then
  Foreach spell in list do
    If spelltype = damage then
      Add to Array
    Else
      Nothing
Or if you notice a better way:

Code: Select all

Foreach spell in list do
  If (school = invocation) && (level = 1) && (spelltype = damage) then
    Add to Array
  Else
    Nothing
I hope this makes sense with my pseudo code.

Post Reply

Return to “Macros”