array not arraying [SOLVED]

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
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: array not arraying

Post by Ravana »

When reviewing code we start with more obvious issues. Once those are solved and we still hear code doesnt work, then we might try to run it personally.

But when quick glance already tells that there is no way the code will work, there is no point to set it up in game.
User avatar
Helmet
Posts: 641
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: array not arraying

Post by Helmet »

Ravana wrote: November 21st, 2022, 5:06 pm But when quick glance already tells that there is no way the code will work...
This is the first time I've heard that the code won't work. I thought beetlenaut had provided a solution that I didn't understand.

So the problem is that [foreach] is unable to learn the value of how_frozen within a petrified unit's array, so it doesn't loop like I expect?

And there's no alternative way to test the value of how_frozen using FOR or SWITCH or whatever?

WML can't do that?
Author of:
DIY Campaign, Confederacy of Swamp Creatures: Big Battle 1, Confederacy of Swamp Creatures: Big Battle 2, Frogfolk Delivery Service, The Pool of Ek.
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: array not arraying

Post by Ravana »

For this example ignore the loop and just think of first unit (target_units[0]).
When asking for $target_units[0].id.how_frozen and wanting to get 0 back, you expect array contains element
[target_units]
[id] - more properly accessed with id[0], but it would probably work without index too and return first tag
how_frozen=0
[/id]
[id] - multiple tags can have same name, they are accessed by index
how_frozen=9
[/id]
[/target_units]

However, target_units is made of units, and instead of [id][/id] they have for example $target_units[0].id=Thug-4
[target_units]
id=Ghost-5 - one tag can only have each key once, last one applies
id=Thug-4
[/target_units]
User avatar
Helmet
Posts: 641
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: array not arraying

Post by Helmet »

Ravana wrote: November 21st, 2022, 5:41 pm For this example...
Thanks. I think arrays are partly the source of my confusion. But your post gave me an idea..

I've used [foreach] in the past with hitpoints and it worked. Here it is:

Code: Select all

	[foreach]
		array=target_units
		[do]
			[if]
				[variable]
					name=this_item.hitpoints
					less_than_equal_to=$harm_damage 
				[/variable]
				[then]
This may be a stupid question, but could I use cost= to hold the how_frozen value? Once a unit is on the map, cost is useless. I could use it to hold the frozen values, which are 0-2. Then I could use name=this_item.cost within the [variable] of the [foreach] loop.

Is that a viable workaround to circumvent the problem?
Author of:
DIY Campaign, Confederacy of Swamp Creatures: Big Battle 1, Confederacy of Swamp Creatures: Big Battle 2, Frogfolk Delivery Service, The Pool of Ek.
User avatar
beetlenaut
Developer
Posts: 2813
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: array not arraying

Post by beetlenaut »

Helmet wrote: November 21st, 2022, 5:23 pm This is the first time I've heard that the code won't work. I thought beetlenaut had provided a solution that I didn't understand.
I told you a while ago that, "There may be more problems, but fix the above problems first." You should assume that is true for pretty much every post by one of us.
Helmet wrote: November 21st, 2022, 5:23 pm So the problem is that [foreach] is unable to learn the value of how_frozen within a petrified unit's array, so it doesn't loop like I expect?
I don't know what made you think that, but no, the [foreach] loop should do what you want when its errors are fixed.

I realized that you have another large problem though. You have two new_turn events, and you want one to happen after the other. That's not guaranteed, so they might be happening in the reverse order. You need to combine them into one event with one [foreach]. I'm going to tell you how to make it simpler so it's easier to work with.

Right now, THAWING EVENT uses a lot of code to subtract 1 from how_frozen. This is a waste of time considering that computers are purpose-built to subtract! It should work in one event with one [if] statement in your [foreach]: If how_frozen is greater than 0 then subtract one from it, otherwise unpetrify. (The subtract function is in [set_variable]. Look it up if you're not sure you know how it works.)
Helmet wrote: November 21st, 2022, 6:10 pm This may be a stupid question, but could I use cost= to hold the how_frozen value?
I don't know. That might work, but it would make the code pretty unintelligible, so I wouldn't do it.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
Helmet
Posts: 641
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: array not arraying

Post by Helmet »

beetlenaut wrote: November 21st, 2022, 6:24 pmI realized that you have another large problem though. You have two new_turn events, and you want one to happen after the other. That's not guaranteed, so they might be happening in the reverse order.
Ah. I think reverse order happened a few times, because odd things would randomly happen when play-testing.
beetlenaut wrote: November 21st, 2022, 6:24 pm You need to combine them into one event with one [foreach]. I'm going to tell you how to make it simpler so it's easier to work with...
Thanks, beetlenaut. I did what you said and made one new turn event.

The Giant Rat unpetrifies now, but too quickly -- on the next turn, after being frozen.

Look at this code here. See status=petrified in the [store_unit] filter?

Code: Select all

        [store_unit]
            [filter]
                side=2  # This will store all of the side 2 units in an array.
                status=petrified
            [/filter]
Because of that line, I was able to make [else] simple, because no unit who is not petrified should be within this loop. This is correct, right?

Code: Select all

                    [else]
                        [unpetrify] #                               any unit that is not frozen or thawing will be unpetrified
                            id=$this_item.id
                        [/unpetrify]
                    [/else]
                [/if]
            [/do]
Here is all the code...

Code: Select all

	[event] #                                                       T H A W I N G     E V E N T
		name=new turn
        first_time_only=no
        [store_unit]
            [filter]
                side=2  # This will store all of the side 2 units in an array.
                status=petrified
            [/filter]
            variable=target_units  # "unit" as a variable name is reserved for the unit that triggers an event, so try not to use it for other things.  It could get confusing.
        [/store_unit]
        [foreach]
            array=target_units
            [do]
                [if]
                    [variable]
                        name=this_item.how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
                        greater_than=0
                    [/variable]
                    [then]
                        [set_variable]
                            name=this_item.how_frozen
                            sub=1 #                               unit was frozen, but is now thawing. Unit will unpetrify next turn.
                        [/set_variable]
                    [/then]
                    [else]
                        [unpetrify] #                               any unit that is not frozen or thawing will be unpetrified
                            id=$this_item.id
                        [/unpetrify]
                    [/else]
                [/if]
            [/do]
        [/foreach]
    [/event]

[event]
    name=attacker hits
    first_time_only=no
    [filter_attack]
        special=freezes
    [/filter_attack]

    [modify_unit]
        [filter]
            id=$second_unit.id  # 		an id stores a specific unit in an array.   
        [/filter]
        [set_variable]
            name=how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
            value=2
        [/set_variable]
    [/modify_unit]

    # $second_unit is just a copy of the unit, not the actual unit itself. However, when you use [modify_unit] you update the actual unit, 
    # not the copy, so the copy is now out-of-date. If you want to keep $second_unit accurate you'll need to re-store the unit after modifying it:
    [store_unit]
        [filter]
            id=$second_unit.id
        [/filter]
        variable=second_unit
        id=$second_unit.id
    [/store_unit]

    [message]
        speaker=MyLeader
        message="Modify unit just changed a variable to: " + $second_unit.variables.how_frozen + "."
    [/message]
[/event]
Author of:
DIY Campaign, Confederacy of Swamp Creatures: Big Battle 1, Confederacy of Swamp Creatures: Big Battle 2, Frogfolk Delivery Service, The Pool of Ek.
User avatar
beetlenaut
Developer
Posts: 2813
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: array not arraying

Post by beetlenaut »

Helmet wrote: November 21st, 2022, 7:06 pm The Giant Rat unpetrifies now, but too quickly -- on the next turn, after being frozen.
My guess is that this is because you are using a new_turn event. You should either use a side_2_turn if it only matters for side 2, or use side_turn but check to make sure you only store the units whose turn it is. That way it could work for any side. (There is an automatically-stored $side_number variable that you would need for the second option.)
Helmet wrote: November 21st, 2022, 7:06 pm This is correct, right?
It looks that way.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: array not arraying

Post by Ravana »

> name=this_item.how_frozen
Units do not have attribute named how_frozen, you can inspect and see that unit has container
[variables]
how_frozen=2
[/variables]

That is why we have mentioned unit variables, they are exactly for the purpose of storing any kind of WML inside unit. $target_units[0].variables.how_frozen should contain some value.

You can use [inspect][/inspect] as breakpoint in
[foreach]
array=target_units
[do]
[inspect][/inspect]
I think it will let you see what this_item contains.
User avatar
Helmet
Posts: 641
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: array not arraying

Post by Helmet »

Ravana wrote: November 21st, 2022, 7:38 pm$target_units[0].variables.how_frozen should contain some value.
Is this what you mean?
I used name=$target_units[0].variables.how_frozen.
It didn't work, so I must not be understanding.

Code: Select all

	[event] #                                                       T H A W I N G     E V E N T
		name=new turn
        first_time_only=no
        [store_unit]
            [filter]
                side=2  # This will store all of the side 2 units in an array.
                status=petrified
            [/filter]
            variable=target_units  # "unit" as a variable name is reserved for the unit that triggers an event, so try not to use it for other things.  It could get confusing.
        [/store_unit]
        [foreach]
            array=target_units
            [do]
                [if]
                    [variable]
                        name=$target_units[0].variables.how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
                        greater_than=0
                    [/variable]

                    [then]
                        [set_variable]
                            name=$target_units[i].variables.how_frozen
                            sub=1 #                               unit was frozen, but is now thawing. Unit will unpetrify next turn.
                        [/set_variable]
                    [/then]
                    [else]
                        [unpetrify] #                               any unit that is not frozen or thawing will be unpetrified
                            id=$this_item.id
                        [/unpetrify]
                    [/else]
                [/if]
            [/do]
        [/foreach]
    [/event]
I used :inspect and looked at [target_units][0]. It seems to be a copy of everything for the petrified Giant Rat.

How does a person get the 0 to change to 1, 2 ,3 and so forth, in the event there are multiple petrified units? Apparently you're not supposed to use the default i.
Wiki: index_var: The name of a variable which refers to the index of the current item. Defaults to i. Note that this is just for information purposes and should not be used to access the array from within the loop (any such changes made will not persist).
Author of:
DIY Campaign, Confederacy of Swamp Creatures: Big Battle 1, Confederacy of Swamp Creatures: Big Battle 2, Frogfolk Delivery Service, The Pool of Ek.
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: array not arraying

Post by Ravana »

I mean
[message]
message=$target_units[0].variables.how_frozen
[/message]
It is value of first unit -> unit variable -> how_frozen -> number. So you would get name=2, and variable with name 2 does not exist. Purpose of this line is to show how to access value from unit variable. Once you know what you do works for one unit, you can work on iteration to do it for all units.
User avatar
Helmet
Posts: 641
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: array not arraying

Post by Helmet »

Ravana wrote: November 21st, 2022, 8:14 pmOnce you know what you do works for one unit, you can work on iteration to do it for all units.
That's what I'm trying to do. At one point, I had a small success. This code printed a 2 on the screen:

message="Within the foreach loop the how_frozen variable is " + $target_units[0].variables.how_frozen + "."

I went ahead an inserted the i in place of the 0 in this --> $target_units[0].variables.how_frozen, but nothing happened.

Latest code attempt:

Code: Select all

	[event] #                                                       T H A W I N G     E V E N T
		name=new turn
        first_time_only=no
        [store_unit]
            [filter]
                side=2  # This will store all of the side 2 units in an array.
                status=petrified
            [/filter]
            variable=target_units  # "unit" as a variable name is reserved for the unit that triggers an event, so try not to use it for other things.  It could get confusing.
        [/store_unit]
        [foreach]
            array=target_units
            [do]
                [if]
                    [inspect][/inspect]
                    [variable]
                        name=$target_units[i].variables.how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
                        greater_than=0
                    [/variable]

                    [then]
                        [set_variable]
                            name=$target_units[i].variables.how_frozen
                            sub=1 #                               unit was frozen, but is now thawing. Unit will unpetrify next turn.
                        [/set_variable]
                    [/then]
                    [message]
                        speaker=MyLeader
                        message="Within the foreach loop the how_frozen variable is " + $target_units[i].variables.how_frozen + "."
                    [/message]
                    [else]
                        [message]
                            speaker=MyLeader
                            message="Within the foreach loop the how_frozen variable is " + $target_units[i].variables.how_frozen + "."
                        [/message]
                        [unpetrify] #                               any unit that is not frozen or thawing will be unpetrified
                            id=$this_item.id
                        [/unpetrify]
                    [/else]
                [/if]
            [/do]
        [/foreach]
    [/event]

[event]
    name=attacker hits
    first_time_only=no
    [filter_attack]
        special=freezes
    [/filter_attack]

    [modify_unit]
        [filter]
            id=$second_unit.id  # 		an id stores a specific unit in an array.   
        [/filter]
        [set_variable]
            name=how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
            value=2
        [/set_variable]
    [/modify_unit]

    # $second_unit is just a copy of the unit, not the actual unit itself. However, when you use [modify_unit] you update the actual unit, 
    # not the copy, so the copy is now out-of-date. If you want to keep $second_unit accurate you'll need to re-store the unit after modifying it:
    [store_unit]
        [filter]
            id=$second_unit.id
        [/filter]
        variable=second_unit
        id=$second_unit.id
    [/store_unit]

    [message]
        speaker=MyLeader
        message="Modify unit just changed a variable to: " + $second_unit.variables.how_frozen + "."
    [/message]
[/event]
I have no idea how to debug it. I've attached the campaign, which is just a map where I test new units and debug (lol) code. I'd appreciate it if someone took a crack at fixing the event. The Frostbite is standing right next to the Giant Rat, so attack the Giant Rat and freeze it. The freezing attack does not work on defense (intentionally). This is what I've been trying to do: make a petrified unit become unpetrified two turns after being petrified. This process represents a frozen unit thawing and returning to normal.

ATTACHMENT DELETED
Last edited by Helmet on November 22nd, 2022, 5:23 pm, edited 1 time in total.
Author of:
DIY Campaign, Confederacy of Swamp Creatures: Big Battle 1, Confederacy of Swamp Creatures: Big Battle 2, Frogfolk Delivery Service, The Pool of Ek.
User avatar
beetlenaut
Developer
Posts: 2813
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: array not arraying

Post by beetlenaut »

Helmet wrote: November 21st, 2022, 8:39 pm I'd appreciate it if someone took a crack at fixing the event.
Maybe you don't realize that Ravana or I could fix the event in a jiffy if we wanted to, but we are purposely not doing that! We are trying to teach you WML and to get you to think about the code. You don't seem to be doing that because you should have realized that $target_unit[i].variables.how_frozen is not storing the name of a variable, even if you aren't sure exactly what it does store. (Ravana has told you what's in it now though.)
Helmet wrote: November 21st, 2022, 7:49 pm How does a person get the 0 to change to 1, 2 ,3 and so forth, in the event there are multiple petrified units?
This question does make sense, and tells me that you understand more about arrays than before, so that's good at least. But, the thing is, you have the solution to the question in your code already! You are doing what you need to do in [unpetrify]. Go read [foreach] again if that's still unclear.

You are getting close, and I only counted three changes that you need to make.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: array not arraying

Post by Ravana »

I just realized "unit was frozen, but is now thawing. Unit will unpetrify next turn" part does not work because you set it as if it is normal variable, while it needs to go inside unit like you do with attacker hits event.

Though I am not very confident on my understanding of [foreach] there, I wrote all my code when [while] was the one iteration style used.
User avatar
Helmet
Posts: 641
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: array not arraying

Post by Helmet »

beetlenaut wrote: November 21st, 2022, 8:55 pm You are getting close, and I only counted three changes that you need to make.
:inspect shows that [this_item][0] has the value of how_frozen, which is the value I need to decrease every turn.
this_item.jpg
Here is the latest code. I might have fixed one or two problems, but not three, because it still doesn't work.

Thawing event...

Code: Select all

	[event] #                                                       T H A W I N G     E V E N T
		name=new turn
        first_time_only=no
        [store_unit]
            [filter]
                side=2  # This will store all of the side 2 units in an array.
                status=petrified
            [/filter]
            variable=target_units  # "unit" as a variable name is reserved for the unit that triggers an event, so try not to use it for other things.  It could get confusing.
        [/store_unit]
        [foreach]
            array=target_units
            [do]
                # [inspect][/inspect]
                [if]
                    [variable]
                        name=this_item.how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
                        greater_than=0
                    [/variable]

                    [then]
                        [set_variable]
                            name=this_item.how_frozen
                            sub=1 #                               unit was frozen, but is now thawing. Unit will unpetrify next turn.
                        [/set_variable]
                    [/then]
                    [message]
                        speaker=MyLeader
                        message="Location 1."
                    [/message]
                    [else]
                        [unpetrify] #                               any unit that is not frozen or thawing will be unpetrified
                            id=$this_item.id
                        [/unpetrify]
                    [/else]
                [/if]
            [/do]
        [/foreach]
    [/event]
Freezing event...

Code: Select all

[event]
    name=attacker hits
    first_time_only=no
    [filter_attack]
        special=freezes
    [/filter_attack]

    [modify_unit]
        [filter]
            id=$second_unit.id  # 		an id stores a specific unit in an array.   
        [/filter]
        [set_variable]
            name=how_frozen #              how frozen is the unit on a scale of 0-2       0=not frozen    1=thawing     2=frozen
            value=2
        [/set_variable]
    [/modify_unit]

    # $second_unit is just a copy of the unit, not the actual unit itself. However, when you use [modify_unit] you update the actual unit, 
    # not the copy, so the copy is now out-of-date. If you want to keep $second_unit accurate you'll need to re-store the unit after modifying it:
    [store_unit]
        [filter]
            id=$second_unit.id
        [/filter]
        variable=second_unit
        id=$second_unit.id
    [/store_unit]

    [message]
        speaker=MyLeader
        message="Modify unit just changed a variable to: " + $second_unit.variables.how_frozen + "."
    [/message]
[/event]
Author of:
DIY Campaign, Confederacy of Swamp Creatures: Big Battle 1, Confederacy of Swamp Creatures: Big Battle 2, Frogfolk Delivery Service, The Pool of Ek.
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: array not arraying

Post by Ravana »

You forgot .variables
Post Reply