Macro FOREACH to tag [foreach]

The place to post your WML questions and answers.

Moderator: Forum Moderators

Forum rules
  • Please use [code] BBCode tags in your posts for embedding WML snippets.
  • To keep your code readable so that others can easily help you, make sure to indent it following our conventions.
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Macro FOREACH to tag [foreach]

Post by Toranks »

I'm trying to redo some foreach with macro to accommodate the new tag and avoid deprecated warning messages, and I found this nesting too complex to get right without errors. Could someone help me with adapting this? It will serve for me as a base to do the rest (less complex) without errors.
This event gives to any healer 1 experience points for each friendly unit around him with at least 1 HP less than the maximum.

Code: Select all

[event]
    name=turn_end
    id=aww_05_trigger_healing_xp
    first_time_only=no
    [filter_condition]
        {AWW_ENABLED_FEATURE_05}
    [/filter_condition]

    [store_unit]
        variable=healer_units
        [filter]
            ability_type=heals
        [/filter]
    [/store_unit]

    {FOREACH healer_units h}
        {VARIABLE sum_healing_xp 0}

        [store_unit]
            variable=patient_units
            [filter]
                [filter_adjacent]
                    x,y=$healer_units[$h].x,$healer_units[$h].y
                    is_enemy=no
                [/filter_adjacent]
            [/filter]
        [/store_unit]
        {FOREACH patient_units p}
            [if]
                {VARIABLE_CONDITIONAL patient_units[$p].hitpoints less_than $patient_units[$p].max_hitpoints}
                [then]
                    {VARIABLE_OP sum_healing_xp add 1}
                [/then]
            [/if]
        {NEXT p}
        {CLEAR_VARIABLE patient_units}

        [if]
            {VARIABLE_CONDITIONAL sum_healing_xp greater_than 0}
            [then]
                [if]
                    {VARIABLE_CONDITIONAL sum_healing_xp greater_than $aww_05_healing_xp}
                    [then]
                        {VARIABLE sum_healing_xp $aww_05_healing_xp}
                    [/then]
                [/if]

                {VARIABLE_OP healer_units[$h].experience add $sum_healing_xp}

                [unstore_unit]
                    variable=healer_units[$h]
                [/unstore_unit]

            [/then]
        [/if]

    {NEXT h}
    {CLEAR_VARIABLE healer_units,sum_healing_xp}
[/event]
Last edited by Toranks on November 29th, 2022, 9:25 am, edited 1 time in total.
User avatar
Ravana
Forum Moderator
Posts: 2949
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Ravana »

Start from inside,

Code: Select all

        {FOREACH patient_units p}
            [if]
                {VARIABLE_CONDITIONAL patient_units[$p].hitpoints less_than $patient_units[$p].max_hitpoints}
                [then]
                    {VARIABLE_OP sum_healing_xp add 1}
                [/then]
            [/if]
        {NEXT p}
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Toranks »

Ravana wrote: November 28th, 2022, 10:10 am Start from inside,
That doesn't help much xD
Changing what you say, the code still works:

Code: Select all

			[foreach]
				array=patient_units
				variable=patients
				[do]
					[if]
						{VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints}
						[then]
							{VARIABLE_OP sum_healing_xp add 1}
						[/then]
					[/if]			
				[/do]
			[/foreach]
But when I try to change the first FOREACH, stop working at all, doesn't give any XP:

Code: Select all

	[foreach]
		array=healer_units
		variable=healers
		index_var=h
		[do]
			{VARIABLE sum_healing_xp 0}
			[store_unit]
				variable=patient_units
				[filter]
					[filter_adjacent]
						x,y=$healers.x,$healers.y
						is_enemy=no
					[/filter_adjacent]
				[/filter]
			[/store_unit]
			[foreach]
				array=patient_units
				variable=patients
				[do]
					[if]
						{VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints}
						[then]
							{VARIABLE_OP sum_healing_xp add 1}
						[/then]
					[/if]			
				[/do]
			[/foreach]
			{CLEAR_VARIABLE patient_units}
			[if]
				{VARIABLE_CONDITIONAL sum_healing_xp greater_than 0}
				[then]
					[if]
						{VARIABLE_CONDITIONAL sum_healing_xp greater_than $aww_05_healing_xp}
						[then]
							{VARIABLE sum_healing_xp $aww_05_healing_xp}
						[/then]
					[/if]

					{VARIABLE_OP $healers.experience add $sum_healing_xp}

					[unstore_unit]
						variable=healer_units[$h]
					[/unstore_unit]

					#{AWW_FLOAT_TEXT_CURRENT_SIDE_UNIT $sum_healing_xp {AWW_COLOR_XP}}
				[/then]
			[/if]
		[/do]
	[/foreach]
    {CLEAR_VARIABLE healer_units,sum_healing_xp}
What am I doing wrong? I have a dozen attempts with different ways of doing it and nothing
gnombat
Posts: 682
Joined: June 10th, 2010, 8:49 pm

Re: Macro FOREACH to tag [foreach]

Post by gnombat »

Surely this line can't be right?

Code: Select all

{VARIABLE_OP $healers.experience add $sum_healing_xp}
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Toranks »

gnombat wrote: November 28th, 2022, 8:01 pm Surely this line can't be right?

Code: Select all

{VARIABLE_OP $healers.experience add $sum_healing_xp}
If I've replaced {VARIABLE_CONDITIONAL patient_units[$p].hitpoints less_than $patient_units[$p].max_hitpoints} with {VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints} and works, why {VARIABLE_OP healer_units[$h].experience add $sum_healing_xp} replaced with {VARIABLE_OP $healers.experience add $sum_healing_xp} doesn't?
gnombat
Posts: 682
Joined: June 10th, 2010, 8:49 pm

Re: Macro FOREACH to tag [foreach]

Post by gnombat »

VARIABLE_OP needs to have just the name of the variable (without $).
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Toranks »

Nothing with {VARIABLE_OP healers.experience add $sum_healing_xp}, still doesn't receive any XP
User avatar
Ravana
Forum Moderator
Posts: 2949
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Ravana »

[variable]name= wants name of variable. [set_variable]name= wants name of variable. VARIABLE, VARIABLE_OP and similar might save you few closing tags of typing, but if they make you misunderstand your code its better to not use them so much.
gnombat
Posts: 682
Joined: June 10th, 2010, 8:49 pm

Re: Macro FOREACH to tag [foreach]

Post by gnombat »

Toranks wrote: November 28th, 2022, 8:48 pm Nothing with {VARIABLE_OP healers.experience add $sum_healing_xp}, still doesn't receive any XP
You probably need to use the same variable inside [unstore_unit] too.
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Toranks »

The problem is that among dozens of tries I tried with and without $,

Code: Select all

 {VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints} 
works (I can guarantee that, after many tries).
So I assumed that on {VARIABLE_OP healers.experience add $sum_healing_xp} I need to put $ too. But none works, with or without $ on any combination possible. I'm doing anything wrong not related with that $ thing.

Note: What I understand of $ is that it means something like "the value of such variable", and without $ means the variable itself. So, on variables with only 1 content (not arrays), with or without $ are synonyms. Maybe I misunderstood, but like I said, I've already tried all the combinations and I can't get it to work.

About [unstore_unit], this is for unstore that:

Code: Select all

    [store_unit]
        variable=healer_units
        [filter]
            ability_type=heals
        [/filter]
    [/store_unit]
that is at the start of the event, to list all healer-capable units on the map. And I need to unstore one by one as I give them XP. I need to unstore healer_units[$i] (on this case I use index_var=h, just for make the code more readable for me) so healers_unit[$h]. What I'm doing wrong here?
gnombat
Posts: 682
Joined: June 10th, 2010, 8:49 pm

Re: Macro FOREACH to tag [foreach]

Post by gnombat »

Toranks wrote: November 29th, 2022, 2:36 am The problem is that among dozens of tries I tried with and without $,

Code: Select all

 {VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints} 
works (I can guarantee that, after many tries).
So I assumed that on {VARIABLE_OP healers.experience add $sum_healing_xp} I need to put $ too. But none works, with or without $ on any combination possible. I'm doing anything wrong not related with that $ thing.
Actually, now that I look at that line, I think you need to change that one too. It should be:

Code: Select all

{VARIABLE_CONDITIONAL patients.hitpoints less_than $patients.max_hitpoints}
So I think the complete code is this:

Code: Select all

    [foreach]
        array=healer_units
        variable=healers
        index_var=h
        [do]
        {VARIABLE sum_healing_xp 0}

        [store_unit]
            variable=patient_units
            [filter]
                [filter_adjacent]
                    x,y=$healers.x,$healers.y
                    is_enemy=no
                [/filter_adjacent]
            [/filter]
        [/store_unit]
        [foreach]
            array=patient_units
            variable=patients
            [do]
            [if]
                {VARIABLE_CONDITIONAL patients.hitpoints less_than $patients.max_hitpoints}
                [then]
                    {VARIABLE_OP sum_healing_xp add 1}
                [/then]
            [/if]
            [/do]
        [/foreach]

        {CLEAR_VARIABLE patient_units}

        [if]
            {VARIABLE_CONDITIONAL sum_healing_xp greater_than 0}
            [then]
                [if]
                    {VARIABLE_CONDITIONAL sum_healing_xp greater_than $aww_05_healing_xp}
                    [then]
                        {VARIABLE sum_healing_xp $aww_05_healing_xp}
                    [/then]
                [/if]

                {VARIABLE_OP healers.experience add $sum_healing_xp}

                [unstore_unit]
                    variable=healers
                [/unstore_unit]

                #{AWW_FLOAT_TEXT_CURRENT_SIDE_UNIT $sum_healing_xp {AWW_COLOR_XP}}
            [/then]
        [/if]

        [/do]
    [/foreach]
    {CLEAR_VARIABLE healer_units,sum_healing_xp}
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Toranks »

Finally!!! I tried exactly what you send to me at least 4 times yesterday except for the unstore_unit and it didn't occur to me that the problem was in the unstore_unit
Thanks!

[unstore_unit]
variable=healers
[/unstore_unit]


Edit: Reading better, appears that store_unit and unstore_unit are completely independent process, I've never used unstore_unit before, always modify_unit and object, it's the first time I learn about it. And is mandatory to update the unit to reflects the XP change.
User avatar
Lord-Knightmare
Discord Moderator
Posts: 2340
Joined: May 24th, 2010, 5:26 pm
Location: Somewhere in the depths of Irdya, gathering my army to eventually destroy the known world.
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Lord-Knightmare »

Toranks wrote: November 28th, 2022, 3:39 am I'm trying to redo some foreach with macro to accommodate the new tag and avoid deprecated warning messages, and I found this nesting too complex to get right without errors. Could someone help me with adapting this? It will serve for me as a base to do the rest (less complex) without errors.
This event gives to any healer 1 experience points for each unit around him with at least 1 HP less than the maximum.

Code: Select all

[event]
    name=turn_end
    id=aww_05_trigger_healing_xp
    first_time_only=no
    [filter_condition]
        {AWW_ENABLED_FEATURE_05}
    [/filter_condition]

    [store_unit]
        variable=healer_units
        [filter]
            ability_type=heals
        [/filter]
    [/store_unit]

    {FOREACH healer_units h}
        {VARIABLE sum_healing_xp 0}

        [store_unit]
            variable=patient_units
            [filter]
                [filter_adjacent]
                    x,y=$healer_units[$h].x,$healer_units[$h].y
                    is_enemy=no
                [/filter_adjacent]
            [/filter]
        [/store_unit]
        {FOREACH patient_units p}
            [if]
                {VARIABLE_CONDITIONAL patient_units[$p].hitpoints less_than $patient_units[$p].max_hitpoints}
                [then]
                    {VARIABLE_OP sum_healing_xp add 1}
                [/then]
            [/if]
        {NEXT p}
        {CLEAR_VARIABLE patient_units}

        [if]
            {VARIABLE_CONDITIONAL sum_healing_xp greater_than 0}
            [then]
                [if]
                    {VARIABLE_CONDITIONAL sum_healing_xp greater_than $aww_05_healing_xp}
                    [then]
                        {VARIABLE sum_healing_xp $aww_05_healing_xp}
                    [/then]
                [/if]

                {VARIABLE_OP healer_units[$h].experience add $sum_healing_xp}

                [unstore_unit]
                    variable=healer_units[$h]
                [/unstore_unit]

            [/then]
        [/if]

    {NEXT h}
    {CLEAR_VARIABLE healer_units,sum_healing_xp}
[/event]
This looks nifty. I might adapt it to Lua and ship into the RPG I am coding. I feel like in RPG, healers are not given enough XP to level so maybe they can benefit from this.
Creator of "War of Legends"
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
User avatar
Ravana
Forum Moderator
Posts: 2949
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Ravana »

Toranks wrote: November 29th, 2022, 2:36 am The problem is that among dozens of tries I tried with and without $,

Code: Select all

 {VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints} 
works (I can guarantee that, after many tries).
It doesnt work. If your tests worked, it was only because test coverage was low. Possibly you tested only optimistic case. This condition is always true.
User avatar
Celtic_Minstrel
Developer
Posts: 2166
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: Macro FOREACH to tag [foreach]

Post by Celtic_Minstrel »

Toranks wrote: November 29th, 2022, 2:36 am Note: What I understand of $ is that it means something like "the value of such variable", and without $ means the variable itself.
This is sort of correct.
Toranks wrote: November 29th, 2022, 2:36 am So, on variables with only 1 content (not arrays), with or without $ are synonyms.
This is completely wrong. There's no case where the $ doesn't change the meaning.

Without the $ is indeed the "name of the variable", but that's only if it's used in places that expect the name of a variable, such as the "name" key in tags like [variable] or [set_variable]. Other than that, if you want the value of a variable, you need to use $.

If you use $ in a place that needs a variable name, then it's not operating on that variable at all. It's operating on a variable named after the content of that variable. For example, consider the following code:

Code: Select all

[set_variable]
	name=$my_var
	value=4
[/set_variable]
# The below is the same but as a macro
{VARIABLE $my_var value 4}
If the variable "my_var" happens to contain the value "something", then this command doesn't do anything to the "my_var". Instead, it sets the "something" variable to 4. If you don't use $ there, it sets the "my_var" variable to 4.

So, taking the example you showed:
Toranks wrote: November 29th, 2022, 2:36 am The problem is that among dozens of tries I tried with and without $,

Code: Select all

 {VARIABLE_CONDITIONAL $patients.hitpoints less_than $patients.max_hitpoints} 
works (I can guarantee that, after many tries).
So I assumed that on {VARIABLE_OP healers.experience add $sum_healing_xp} I need to put $ too. But none works, with or without $ on any combination possible. I'm doing anything wrong not related with that $ thing.
This code does not compare the patient's hitpoints to the patient's maximum hitpoints. If the patient have 4 hit points, then this compares the value of the variable called "4" to the value of the patient's hitpoints. Since there probably isn't a variable called "4", from what I recall, it'll be considered as if it has a value of 0, so the comparison will always be true. Unless you're doing something unusual, the variable name should not have a $, so the correct code is:

Code: Select all

 {VARIABLE_CONDITIONAL patients.hitpoints less_than $patients.max_hitpoints} 
(By the way, since it's a plural name, is that an array variable? If that's the case you should really write patients[0].whatever instead of patients.whatever. The two are equivalent, but the first form makes it clear that you know it's an array.)
Author of The Black Cross of Aleron campaign and Default++ era.
Former maintainer of Steelhive.
Post Reply