[avoid] puzzlement

The place to post your WML questions and answers.

Moderators: Forum Moderators, Developers

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.
Post Reply
Spannerbag
Posts: 43
Joined: December 18th, 2016, 6:14 pm

[avoid] puzzlement

Post by Spannerbag » August 26th, 2019, 11:49 am

Hi,

I'm STILL (grrr!) trying to complete the last playable scenario of my campaign but it keeps making life interesting.

Latest is some [avoid] behaviour I can't understand.

I set mutliple [avoid]s to prevent the ai entering certain areas yet one (at least) always fails - not sure about the others but I guess they probably fail too.

A south eastern areas (aka "SE enclave") should be avoided by many ai sides.

First I setup a definition of the relevant area:

Code: Select all

# SE enclave locations
#define SE_ENCLAVE_FILTER
x=66-80
y=47-60
terrain=Cvr,Kvr,Hh^Es,Mm,Re^Vyer,Rb,Re^Es
#enddef
This works as expected in a moveto event:

Code: Select all

# SE enclave moveto
  [event]
    name=moveto
    [filter]
      side=1
      [filter_location]
        {SE_ENCLAVE_FILTER}
      [/filter_location]
    [/filter]
    [fire_event]
      name=remove_se_avoid
    [/fire_event]
...(snipped)...
The actual avoid is setup in prestart:

Code: Select all

# Setup initial conditions
  [event]
    name=prestart
...(snipped)...
#
# Avoid SE enclave (id=se)
    [modify_ai]
      [filter_side]
        side=2-7,9
      [/filter_side]
      action=add
      path=aspect[avoid].facet[]
      [facet]
        id=se
        [value]
          {SE_ENCLAVE_FILTER}
        [/value]
      [/facet]
    [/modify_ai]
(I originally used side=2,3,4,5,6,7,9 but tried [filter_side] when that failed.)

Yet a side 4 unit moved into the supposedly off-limits area. :debug/inspect for side 4 reveals:

Code: Select all

[aspect]
	engine="cpp"
	id="avoid"
	invalidate_on_gamestate_change=no
	invalidate_on_minor_gamestate_change=no
	invalidate_on_tod_change=yes
	invalidate_on_turn_start=yes
	name="composite_aspect"
	[facet]
		engine=""
		id="se"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			terrain="Cvr,Kvr,Hh^Es,Mm,Re^Vyer,Rb,Re^Es"
			x="66-80"
			y="47-60"
		[/value]
	[/facet]
	[facet]
		engine=""
		id="elgenefar"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			radius=2
			x=73
			y=2
		[/value]
	[/facet]
	[facet]
		engine=""
		id="arrah"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			radius=2
			x=2
			y=58
		[/value]
	[/facet]
	[facet]
		engine=""
		id="morn"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			radius=2
			x=24
			y=59
		[/value]
	[/facet]
	[default]
		engine="cpp"
		id="default_facet"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			[not]
			[/not]
		[/value]
	[/default]
[/aspect]
The first avoid is the one that doesn't work (the next 3 are where reinforcements appear). I notice that terrain is listed before x,y - but I don't suppose this makes any difference?


I had thought that the clauses

Code: Select all

...
 		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
...
were the problem and actually deleted a prior post. However comparing the above with Heir to the Throne:

Code: Select all

[aspect]
	engine="cpp"
	id="avoid"
	invalidate_on_gamestate_change=no
	invalidate_on_minor_gamestate_change=no
	invalidate_on_tod_change=yes
	invalidate_on_turn_start=yes
	name="composite_aspect"
	[facet]
		engine="cpp"
		id=""
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			x="2-4"
			y="22-24"
		[/value]
	[/facet]
	[facet]
		engine="cpp"
		id=""
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			x="2-4"
			y="22-24"
		[/value]
	[/facet]
	[default]
		engine="cpp"
		id="default_facet"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=yes
		invalidate_on_turn_start=yes
		name="standard_aspect"
		[value]
			[not]
			[/not]
		[/value]
	[/default]
[/aspect]
The same values appear here?

I'd dearly love to finish this scenario before I expire so if anyone has any suggestions, please share!

Many thanks in advance for your time and trouble!
UMC Campaign: After EI
I suspect the universe is simpler than we think and stranger than we can know.

User avatar
Celtic_Minstrel
Developer
Posts: 1529
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: [avoid] puzzlement

Post by Celtic_Minstrel » August 27th, 2019, 4:18 am

I'm a little puzzled by this too, as it was my understanding that it would only take the first avoid facet (the one you say isn't working) while ignoring the rest. Regardless, I'm fairly sure that what you'll need to do to solve this is to somehow merge the avoids into a single filter.

Hopefully mattsc will show up with a better explanation a bit later.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.

Spannerbag
Posts: 43
Joined: December 18th, 2016, 6:14 pm

Re: [avoid] puzzlement

Post by Spannerbag » August 27th, 2019, 9:55 am

Celtic_Minstrel wrote:
August 27th, 2019, 4:18 am
I'm a little puzzled by this too, as it was my understanding that it would only take the first avoid facet (the one you say isn't working) while ignoring the rest. Regardless, I'm fairly sure that what you'll need to do to solve this is to somehow merge the avoids into a single filter.

Hopefully mattsc will show up with a better explanation a bit later.
Thanks for your input - at least I now know it's not me doing something stupid :)
I'm considering various alternatives, but I'm happy with the design and gameplay as they are. The various avoids are removed under different conditions. I could, I suppose, merge them then delete and re-implement (with a reduced filter) whenever one of the avoids needs removing, but it would be klunky. Worth a look tho'...

Again, thanks for your reply.
UMC Campaign: After EI
I suspect the universe is simpler than we think and stranger than we can know.

Spannerbag
Posts: 43
Joined: December 18th, 2016, 6:14 pm

[avoid] puzzlement - update

Post by Spannerbag » August 27th, 2019, 12:46 pm

Hi everyone,

Still not got this working but I've scoped out the behaviour a bit more, it might inform someone cleverer than me regarding possible fixes...

By placing a side 4 unit near a village that should be avoided I now know that the avoid facet invalidates on turn 2.
The unit captures a village further away on turn 1 (presumably because the avoid is in force) then captures the supposedly off-limits village on turn 2.

I have experimented with various settings and here is the relevant section of the current avoid setup:

Code: Select all

[aspect]
	engine="cpp"
	id="avoid"
	invalidate_on_gamestate_change=no
	invalidate_on_minor_gamestate_change=no
	invalidate_on_tod_change=yes
	invalidate_on_turn_start=yes
	name="composite_aspect"
	[facet]
		engine="cpp"
		id="se"
		invalidate_on_gamestate_change=no
		invalidate_on_minor_gamestate_change=no
		invalidate_on_tod_change=no
		invalidate_on_turn_start=no
		name="standard_aspect"
		[value]
			radius=4
			x=77
			y=59
		[/value]
	[/facet]
I did try to change name="standard_aspect" to name="composite_aspect" (with and without double-quote) to match the setting in the parent avoid aspect but this simply produced the error:

Code: Select all

<Lua error>  Mandatory WML child missing yet untested for. Please report.
                    stack traceback:
                            [C]: in field 'add_ai_component'
                            lua/wml/modify_ai.lua:20 in local 'cmd'
                            lua/wml-utils.lua:145 in field 'handle_event_commands'
                            lua/wml-flow.lua:6 in function <lua/wml-flow.lua:5>
If anyone can shed any light on this I'd be really grateful!
In the meantime I'll think of ways to redesign the scenario :(

Thanks in advance for your time and trouble.
UMC Campaign: After EI
I suspect the universe is simpler than we think and stranger than we can know.

mattsc
Posts: 1121
Joined: October 13th, 2010, 6:14 pm
Location: Hidden on the hex behind Fred

Re: [avoid] puzzlement

Post by mattsc » August 27th, 2019, 1:41 pm

I believe that what Celtic_Minstrel says is true, just that it is the last, not the first, facet which is active. As in, whatever facet is added last overwrites all previous ones. The exception to this, and the reason why multiple facets are possible, is when facets only apply at a certain times of day or at certain turns. In that case, the AI uses whatever the last-added facet that is active at the current time is.

So the solution is as Celtic_Minstrel suggests, to combine the filters in the same [avoid] tag, with [or] or similar.

As for your last post, none of the "invalidate_*" settings should matter. They only determine when the internal aspect value needs to be recalculated. As you have a static location filter, that should not matter. Do you set another [avoid] tag at the beginning of Turn 2 that overwrites the previous one? That's the only thing I can think of (other than a bug that we are not aware of). If that's not it, I don't know. I could have a look and see if I can figure it out, if you don't mind sending me a test case (scenario file and start-of-scenario save).

Spannerbag
Posts: 43
Joined: December 18th, 2016, 6:14 pm

Re: [avoid] puzzlement

Post by Spannerbag » August 27th, 2019, 6:06 pm

mattsc wrote:
August 27th, 2019, 1:41 pm
I believe that what Celtic_Minstrel says is true, just that it is the last, not the first, facet which is active. As in, whatever facet is added last overwrites all previous ones. The exception to this, and the reason why multiple facets are possible, is when facets only apply at a certain times of day or at certain turns. In that case, the AI uses whatever the last-added facet that is active at the current time is.

So the solution is as Celtic_Minstrel suggests, to combine the filters in the same [avoid] tag, with [or] or similar.

As for your last post, none of the "invalidate_*" settings should matter. They only determine when the internal aspect value needs to be recalculated. As you have a static location filter, that should not matter. Do you set another [avoid] tag at the beginning of Turn 2 that overwrites the previous one? That's the only thing I can think of (other than a bug that we are not aware of). If that's not it, I don't know. I could have a look and see if I can figure it out, if you don't mind sending me a test case (scenario file and start-of-scenario save).

Thanks ever so much for the clarification.
Being a bit sad I spent a few hours today re-writing the various avoid clauses as separate [modify_side][ai][avoid] clauses which, I thought, from initial testing seemed to work... except that the avoid in question I tested was the last one :doh:
These multiple [avoids]s (I guess) also clobbered performance and the ai made some very peculiar moves.

FWIW the reason I use so many avoids is that throughout the scenario various reinforcements arrive and their starting points, ideally, need to be clear of enemy units (otherwise a newy arrived leader will potentially appear with several enemies nearby and if they are killed it results in defeat...). I fear I'm trying to be too clever... I wanted (and IMHO have largely succeeded) in creating a campaign with different pathways to the final scenario and these previous choices make a big difference to gameplay and what is actually presented to the player. But it means juggling a lot of balls...

I think I will try and wrap up the various avoids into a single tag for each side, but I fear the performance hit might be too much...

Again, many thanks for taking the trouble to explain, it's really appreciated!
UMC Campaign: After EI
I suspect the universe is simpler than we think and stranger than we can know.

Spannerbag
Posts: 43
Joined: December 18th, 2016, 6:14 pm

[avoid] puzzlement - update 2

Post by Spannerbag » August 27th, 2019, 10:47 pm

Hi again,

I think I'm trying to do something that can't be done without a humungous [switch] and/or [if] construct :(

What I've done is to create a variable for each side (called $avoid_clause) but it seems that it isn't possible to "parameterise" [avoid].
I've tried both
[avoid]
$avoid_clause
[/avoid]


and

[avoid]
"$avoid_clause"
[/avoid]


but in both cases I get an error:

Unexpected characters after variable name (expected , or =)

Is there any way to embed a variable within [avoid] or does it have to be a literal?

Thanks in advance!
UMC Campaign: After EI
I suspect the universe is simpler than we think and stranger than we can know.

User avatar
Ravana
Forum Moderator
Posts: 2244
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: [avoid] puzzlement

Post by Ravana » August 27th, 2019, 11:06 pm

[insert_tag] might work.

User avatar
Celtic_Minstrel
Developer
Posts: 1529
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: [avoid] puzzlement - update 2

Post by Celtic_Minstrel » August 28th, 2019, 12:54 am

mattsc wrote:
August 27th, 2019, 1:41 pm
I believe that what Celtic_Minstrel says is true, just that it is the last, not the first, facet which is active. As in, whatever facet is added last overwrites all previous ones. The exception to this, and the reason why multiple facets are possible, is when facets only apply at a certain times of day or at certain turns. In that case, the AI uses whatever the last-added facet that is active at the current time is.
To clarify what I said - yes, the most-recently-added should take priority. For whatever reason I had the impression that new facets are added at the top of the list, so that the first one shown in the inspect dialog would be the one that's actually active. Perhaps I was incorrect on that note though.

The other exception to that rule is when the facets have turn filters (the turns and time_of_day keys in that case it's the most-recently-added facet whose filter matches the current turn that will be active.
Spannerbag wrote:
August 27th, 2019, 10:47 pm
What I've done is to create a variable for each side (called $avoid_clause) but it seems that it isn't possible to "parameterise" [avoid].
I've tried both
[avoid]
$avoid_clause
[/avoid]


and

[avoid]
"$avoid_clause"
[/avoid]


but in both cases I get an error:

Unexpected characters after variable name (expected , or =)

Is there any way to embed a variable within [avoid] or does it have to be a literal?

Thanks in advance!
There is indeed a way to do this, it just doesn't use the $ syntax (as Ravana noted). The following code would do what you want:

Code: Select all

[insert_tag]
	name="avoid"
	variable="avoid_clause"
[/insert_tag]
This is equivalent to an [avoid] tag containing whatever is in the avoid_clause container variable.

Do note that the variable will be substituted immediately, so you'll still need to replace the avoid aspect whenever it changes.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.

Spannerbag
Posts: 43
Joined: December 18th, 2016, 6:14 pm

Re: [avoid] puzzlement - update 2

Post by Spannerbag » August 28th, 2019, 1:46 pm

Celtic_Minstrel wrote:
August 28th, 2019, 12:54 am

Code: Select all

[insert_tag]
	name="avoid"
	variable="avoid_clause"
[/insert_tag]
This is equivalent to an [avoid] tag containing whatever is in the avoid_clause container variable.

Do note that the variable will be substituted immediately, so you'll still need to replace the avoid aspect whenever it changes.
That's brilliant! (Unlike me). Many thanks for your time and trouble.
However :oops:, having rewritten swathes of code several times and fiddled about with the map, I found that any avoid clause seemed to really slow down ai moves and added lots of wait-cursor time with nothing happening on-screen (at least on my elderly laptop). (This last scenario takes place on a large map with 8 enemy sides.)

Purely by chance (rather than clever design on my part) the leader who appears in what is likely to be the most precarious position is the only one who is expendable. Another ai behaviour was fixed by changing the map (it's not as slick now but at least it works). Another avoid was removed by respawning an enemy leader if killed by another (ai) enemy - this would happen under shroud so would be invisible to the player. There is a possibility that in the later stages of the scenario (which I have not yet tested fully) that without other avoids the ai could force a player defeat, but this is unlikely and I could always alert the player to this possibility via dialogue.

If there are no more surprises (hah!) I might, actually, complete this scenario soon-ish (sometime next month with luck). Then there's just the (2 part) epilogue to write, final testing and publish (doubtless after submitting questions about publishing UMC). So maybe it'll be out there by Xmas 2020 :doh: ...

So... I am currently testing a version without avoids. However, if it transpires that I can't get things to work as I want, I can always use [insert_tag] and see if I can tweak performance...

Many, many thanks for your time, trouble and patience! It's really appreciated.
UMC Campaign: After EI
I suspect the universe is simpler than we think and stranger than we can know.

mattsc
Posts: 1121
Joined: October 13th, 2010, 6:14 pm
Location: Hidden on the hex behind Fred

Re: [avoid] puzzlement

Post by mattsc » August 28th, 2019, 7:27 pm

Hmm, I have used [avoid] tags multiple times and never noticed any significant or unusual delays. Would it be possible for you to send me a test case so that I can look into what's happening? (Feel free to do so by PM, so that it won't be a spoiler.) Sometimes there are relatively simple optimizations that can be done to speed up things; on the Wesnoth engine side, I mean, not in your campaign. Even if you decide not to use this, it might still help others in the long run.

Good luck with your campaign. I understand, from my own experience, that sometimes something that you think should be very simple just doesn't work as expected, esp. with the AI. If you'd like any other pointers with that, let me know and maybe I'll be able to help. Of course, as you already discovered, sometimes the "solution" has nothing to do with the AI.

Post Reply