set_variable nested in "if then" using iteration: provisional results

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.
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Hey,

I have tried absolutely everything (I am a complete WML noob but I have learned a few things in the past couple of days).
It seems every time I try to use "if then", I am not able to create a specials array (I can store them fine as long as I don't use an "if then" but I don't want empty values in my array.

I am creating a convenient way to build amla conditions based on unit meta data and want to "can" easy unit info for other modders to use. My end goal is to be able to create extensible and dynamic amla lookup (but that is getting ahead of myself).

I can't see what I am doing wrong (this is a modification that will use an event to create meta data (for right now I am using on recruit so I can troubleshoot in the inspector easily))

The problem arises:

Code: Select all

[if]
	[variable]
		name=$unit.attack[$j].specials.$specials_categories[$k].category|[$l].id
		not_equals=""
	[/variable]
	[then]
		[color=#BF0000]{VARIABLE s_category "$specials_categories[$k].category"}
		{VARIABLE s_id "$unit.attack[$j].specials.$specials_categories[$k].category|[$l].id"}
		[set_variables]
			name=specials_array
			mode=insert
			[value]
				category=$s_category
				id=$s_id
			[/value]
		[/set_variables]
		{CLEAR_VARIABLE s_category}
		{CLEAR_VARIABLE s_id}[/color]
	[/then]
[/if]

Code: Select all

#textdomain wesnoth-DynAmla

#define unit_quality
[event]
	name=recruit
    first_time_only=no
	
	#store nice list of units attacks
	{VARIABLE i 0}
	[while]
		[variable]
			name="i"
			less_than=$unit.attack.length
		[/variable]
		[do]
			[set_variables]
				name=attack_array
				mode=insert
				[value]
					damage=$unit.attack[$i].damage
					description=$unit.attack[$i].description
					icon=$unit.attack[$i].icon
					name=$unit.attack[$i].name
					number=$unit.attack[$i].number
					range=$unit.attack[$i].range
					type=$unit.attack[$i].type
				[/value]
			[/set_variables]
			#{VARIABLE unit.variables.attack_name_$i| $attack_array[1].specials_0}
		{VARIABLE_OP i add 1}
		[/do]
	[/while]
	{CLEAR_VARIABLE i}
	
	#get all specials categories and ids in order to query based on either sub data or specials meta data
	#create specials category list
	[set_variables]
		name=specials_categories
			[value]
				category="attacks" #0
			[/value]
			[value]
				category="berserk" #1
			[/value]
			[value]
				category="chance_to_hit" #2
			[/value]
			[value]
				category="damage" #3
			[/value]
			[value]
				category="disable" #4
			[/value]
			[value]
				category="drains" #5
			[/value]
			[value]
				category="dummy" #6
			[/value]
			[value]
				category="firststrike" #7
			[/value]
			[value]
				category="heal_on_hit" #8
			[/value]
			[value]
				category="petrifies" #9
			[/value]
			[value]
				category="plague" #10
			[/value]
			[value]
				category="poison" #11
			[/value]
			[value]
				category="slow" #12
			[/value]
			[value]
				category="swarm" #13
			[/value]
	[/set_variables]
	
	#if special exist, get it and store tag name along with id
	{VARIABLE j 0}
	[while]
		[variable]
			name="j"
			less_than=$unit.attack.length
		[/variable]
		[do]
			{VARIABLE k 0}
			[while]
				[variable]
					name="k"
					less_than=$specials_categories.length
				[/variable]
				[do]
					{VARIABLE l 0}
					[while]
						[variable]
							name="l"
							less_than=3
						[/variable]
						[do]
							#use previous sepcials_categories array to check each specials tag category for ids
							[if]
								[variable]
									name=$unit.attack[$j].specials.$specials_categories[$k].category|[$l].id
									not_equals=""
								[/variable]
								[then]
									{VARIABLE s_category "$specials_categories[$k].category"}
									{VARIABLE s_id "$unit.attack[$j].specials.$specials_categories[$k].category|[$l].id"}
									[set_variables]
										name=specials_array
										mode=insert
										[value]
											category=$s_category
											id=$s_id
										[/value]
									[/set_variables]
									{CLEAR_VARIABLE s_category}
									{CLEAR_VARIABLE s_id}
								[/then]
							[/if]
							#check if special id procs using the in game inspector
							{VARIABLE unit.variables.special_id_$j|$k|$l| $unit.attack[$j].specials.$specials_categories[$k].category|[$l].id}
						{VARIABLE_OP l add 1}
						[/do]
					[/while]
					{CLEAR_VARIABLE l}
				{VARIABLE_OP k add 1}
				[/do]
			[/while]
			{CLEAR_VARIABLE k}
		{VARIABLE_OP j add 1}
		[/do]
	[/while]
	{CLEAR_VARIABLE j}
	{CLEAR_VARIABLE specials_categories}
	[unstore_unit]
		variable=unit
	[/unstore_unit]
[/event]
#enddef
Last edited by Celtic_Minstrel on April 2nd, 2018, 4:56 am, edited 2 times in total.
Reason: Remove excessive indentation
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: set_variable nested in "if then" using iteration: provisional results

Post by Ravana »

Based on #create specials category list |[$l] needs to be removed, category is one key, not array.

Evaluating some parts of your condition with some j,k,l might give $unit.attack[0].specials.damage.id, which may return "charge" or empty, which is then interpreted as variable name, which this code does not set. So it returns empty, and condition is false.
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Hey Ravana,

thank you so much for a swift reply. I honestly didn't know how quickly people reply.

What happens in the event if there are two damage tags in the specials array? For a silly example: Say we have a custom unit that is a horse riding assassin that backstabs with a lance while charging, wouldn't I need to iterate as that would mean there are two damage tags within the specials tag (that was what I was trying to account for)?

Item of interest: Per Ravana which is then interpreted as variable name
\tDoes that mean there is some other step that I am missing in order to use it in a conditional properly? I have set full WML in the values section in set_variables to see what the literal code snippit would evaluate to and it looks to me as if the conditional would properly filter. But that one statement from you makes me think that I missed a step.

I have been able to yield a series of unit.variables.special_id_ijk = "" where some unit.variables.special_id_ijk = "specials.<some_tag_in_specials_categories>.id" successfully but that gives me a host of variables with many empty values and includes all specials that the unit has at successfully indexed locations. I have also been able to yield a specials_array with category and id in each index but again yields many empty values (I was hoping to use a conditional to only insert category and id at valid id in the array.
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Ravana wrote: March 31st, 2018, 8:26 pm Based on #create specials category list |[$l] needs to be removed, category is one key, not array.

Evaluating some parts of your condition with some j,k,l might give $unit.attack[0].specials.damage.id, which may return "charge" or empty, which is then interpreted as variable name, which this code does not set. So it returns empty, and condition is false.
Hey I also wanted to note that |[$l] terminates $specials_categories.category| which from what I understand would grab an item from the specials_categories array and substitute it in the dot notation lookup? After the sub that should result in $unit.attack[].specials.<special_type>[].id where <special_type> is the result of specials_categories[].category? I am sorry I have worked with code before but this is the first time I have worked with and interpreted language. The reason I felt that I had to do this is I noticed that specials was a collection of tags of differing type and wanted a dynamic way to grab them.
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

hyper_cubed wrote: April 1st, 2018, 2:18 am
Ravana wrote: March 31st, 2018, 8:26 pm Based on #create specials category list |[$l] needs to be removed, category is one key, not array.

Evaluating some parts of your condition with some j,k,l might give $unit.attack[0].specials.damage.id, which may return "charge" or empty, which is then interpreted as variable name, which this code does not set. So it returns empty, and condition is false.
Hey I also wanted to note that |[$l] terminates $specials_categories.category| which from what I understand would grab an item from the specials_categories array and substitute it in the dot notation lookup? After the sub that should result in $unit.attack[].specials.<special_type>[].id where <special_type> is the result of specials_categories[].category? I am sorry I have worked with code before but this is the first time I have worked with and interpreted language. The reason I felt that I had to do this is I noticed that specials was a collection of tags of differing type and wanted a dynamic way to grab them.
I attached examples of the issue.
This resulted from using the in game inspector on a fresh recruit (orcish assassin) As expected I found where I can correctly record category and id (I just did a set_variable without a conditional and then threw the conditional in the [value] tag to evaluate exactly what is happening. The attached images outline my issue, what I have written looks like it should work (as you can see in the conditional report in the inspector, but when I try to actually use it as code it doesn't do anything.
Attachments
Example_Of_True.PNG
Example_of_False.PNG
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: set_variable nested in "if then" using iteration: provisional results

Post by Ravana »

From first image you see it looks for variable called poison (in my example charge). That variable is not set from the code you included.

I guess that $l part might be needed then.

Basically, [variable] name=$... is usually incorrect, that only makes sense when entire variable name is dynamic.
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: set_variable nested in "if then" using iteration: provisional results

Post by Sapient »

I'm not sure if this is related to your problem or not, but instead of not_equals="" you should write not_equals="$empty". Attributes with empty string values are often (but not always) ignored.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Sapient wrote: April 1st, 2018, 2:39 pm I'm not sure if this is related to your problem or not, but instead of not_equals="" you should write not_equals="$empty". Attributes with empty string values are often (but not always) ignored.
I had no idea how to represent and empty, thank you so very much (I was worried about that).

I implemented the empty and attempted to do what Ravanna suggested with setting a variable to use in the conditional. I commented out the troubleshooting code that I used yesterday to print a pseudo "readout" of what should be happing (left it in there to show what I am doing. After doing all the things I am still only able to populate a specials array with set_variable and not the "if then" clause.

Is there some sort of trick that I need to do with _main.cfg that allows the wesnoth engine to properly parse macros? That is the only line of reasoning that I have to follow right now.

Code: Select all

#get all specials categories and ids in order to query based on either sub data or specials meta data
	#create specials category list
	[set_variables]
		name=specials_categories
			[value]
				category="attacks" #0
			[/value]
			[value]
				category="berserk" #1
			[/value]
			[value]
				category="chance_to_hit" #2
			[/value]
			[value]
				category="damage" #3
			[/value]
			[value]
				category="disable" #4
			[/value]
			[value]
				category="drains" #5
			[/value]
			[value]
				category="dummy" #6
			[/value]
			[value]
				category="firststrike" #7
			[/value]
			[value]
				category="heal_on_hit" #8
			[/value]
			[value]
				category="petrifies" #9
			[/value]
			[value]
				category="plague" #10
			[/value]
			[value]
				category="poison" #11
			[/value]
			[value]
				category="slow" #12
			[/value]
			[value]
				category="swarm" #13
			[/value]
	[/set_variables]
	
	#if special exist, get it and store tag name along with id
	{VARIABLE j 0}
	[while]
		[variable]
			name="j"
			less_than=$unit.attack.length
		[/variable]
		[do]
			{VARIABLE k 0}
			[while]
				[variable]
					name="k"
					less_than=$specials_categories.length
				[/variable]
				[do]
					{VARIABLE l 0}
					[while]
						[variable]
							name="l"
							less_than=3
						[/variable]
						[do]
							{VARIABLE specials_category_content "$specials_categories[$k].category"}
							{VARIABLE special_id_content "$unit.attack[$j].specials.$specials_categories[$k].category|[$l].id"}
							#use previous specials_categories array to check each specials tag category for ids
							[if]
								[variable]
									name="$special_id_content"
									not_equals="$empty"
								[/variable]
								[then]
									[set_variables]
										name=specials_array
										mode=insert
										[value]
											category="$specials_category_content|"
											id="$special_id_content|"
										[/value]
									[/set_variables]
									{VARIABLE_OP special_idx add 1}
								[/then]
							[/if]
							#[set_variables]
							#	name=specials_array
							#	mode=insert
							#	[value]
							#		category=$specials_category_content
							#		id=$special_id_content
							#			[if]
							#				[variable]
							#					name=$special_id_content
							#					not_equals=$empty
							#				[/variable]
							#				[then]
							#					[set_variables]
							#						name=specials_array
							#						mode=insert
							#						[value]
							#							category=$specials_category_content
							#							id=$special_id_content
							#						[/value]
							#					[/set_variables]
							#					{VARIABLE_OP special_idx add 1}
							#				[/then]
							#			[/if]
							#	[/value]
							#[/set_variables]
							{CLEAR_VARIABLE specials_category_content}
							{CLEAR_VARIABLE special_id_content}
							#check if special id procs using the in game inspector
							{VARIABLE unit.variables.special_id_$j|$k|$l| $unit.attack[$j].specials.$specials_categories[$k].category|[$l].id}
						{VARIABLE_OP l add 1}
						[/do]
					[/while]
					{CLEAR_VARIABLE l}
				{VARIABLE_OP k add 1}
				[/do]
			[/while]
			{CLEAR_VARIABLE k}
		{VARIABLE_OP j add 1}
		[/do]
	[/while]
	{CLEAR_VARIABLE j}
	{CLEAR_VARIABLE specials_categories}
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: set_variable nested in "if then" using iteration: provisional results

Post by Ravana »

You still try to read variable "poison", which still is empty.
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Ravana wrote: April 1st, 2018, 3:54 pm You still try to read variable "poison", which still is empty.

Hey Ravanna,

Firstly, thank you for your attention. I really appreciate it.

It would be empty most of the time (I am trying to filter those out using a conditional in order to only add valid items in the array), however the iteration will eventually pick up a valid id if the unit has a weapon special (this is why I am so confused, as once it did pick one up, the conditional should do it's thing).

So my problem isn't picking up valid IDs, it is getting the [set_variables][values][/values][/set_variables] that resides whithin the condtional to execute once a valid id is in the queue.

Wouldn't a specials tag be
[poison]
id=poison
.
.
.
.
[/poison]
?
You could have a poison tag on the same unit that had a silly tag that looked like this:
[poison]
id=ungodlybloodofdemons
.
.
.
.
[/poison]
I have the loop to iterate 3 times for each category in order to pick up on at least three ids of the same type that are different (I will make the 3 number more dynamic once I can actually get my array to populate properly.

I noticed that for example:
HORSEMAN
[damage]
id=charge
.
.
.
.
[/damage]
THIEF
[damage]
id=backstab
.
.
.
.
[/damage]
They have the same category of special but different ids.
I want to believe the creators probably did this because they knew that modders would create a heck ton of weapon specials and that is what I am trying to pick up (for example in LOTI, you can have around 5 weapon specials on the same attack).
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: set_variable nested in "if then" using iteration: provisional results

Post by Ravana »

It would be empty most of the time
Where you set variable called poison?
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Sapient wrote: April 1st, 2018, 2:39 pm I'm not sure if this is related to your problem or not, but instead of not_equals="" you should write not_equals="$empty". Attributes with empty string values are often (but not always) ignored.
I have come across a bit of a curiosity.
I created a test. First I created an if then statement with simple conditional around a known and successful [set_variables] tag that is inside a while do statement. Success.

Then I took that same while do statement that contained the [set_variables] and inverted it, I put the if then statement inside of the while do and let that control the [set_variables]. Failure.

Is there an engine limitation with putting (while condition do, if condition then, set_variables) type procedure?
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Ravana wrote: April 1st, 2018, 4:34 pm It would be empty most of the time
Where you set variable called poison?
Where you would normally use $unit.attack[].specials.<category>[].id to get the id of a special I used another array to iterate through all 13 possible categories in order to dynamically populate <category> I am approaching it thus because I don't want to hard code $unit.attack[].specials.poison[].id. Eventually you would get to the poison category and at that point the at attack 2 for special <poison> with id=poison, it should resolve as true.

Say we have a crazy god unit that can poison, poison_undead, charge, backstab (all with attack # 2 and nothing for attack # 1 (maybe attack 1 is a wet noodle)) then we should have
attack[0]
[attack]
[specials]
[/specials]
[/attack]
attack[1]
[attack]
[specials]
[poison]
id=poison
.
.
[/poison]
[poison]
id=poison_undead
.
.
[/poison]
[damage]
id=charge
.
.
[/damage]
[damage]
id=backstab
.
.
[/damage]
[/specials]
[/attack]
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: set_variable nested in "if then" using iteration: provisional results

Post by Ravana »

All those are somewhere on inner levels. But you ask toplevel variable like poison, poison_undead, charge... And those remain empty.
hyper_cubed
Posts: 33
Joined: March 31st, 2018, 7:52 pm
Location: USA

Re: set_variable nested in "if then" using iteration: provisional results

Post by hyper_cubed »

Ravana wrote: April 1st, 2018, 5:37 pm All those are somewhere on inner levels. But you ask toplevel variable like poison, poison_undead, charge... And those remain empty.
I'm not sure how to disagree as I am very new at this and find it difficult to gainsay more experienced individuals, but when I look at the gamestate inspect it shows that I have to drill passed "attacks", "specials", and then I can crack into the individual specials categories (if there were two [poision] tags then it would make me thing that I would treat that as an array within the specials container that resides within the attacks container.

Attached is what I see for the orcish assassin unit.
Attachments
Specials_Tags.PNG
Drilldown.PNG
Post Reply