How does one filter units based on traits

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
Col Lightbeam
Posts: 46
Joined: November 18th, 2008, 1:01 am

How does one filter units based on traits

Post by Col Lightbeam »

Where would I find help in making an event filter that works for all units only in one type of terrain (I already know mostly how to do this) at the beginning of each turn (I think I could do this without help) and NOT (I think I could do this without help) if they have "X" trait (this is the part that seems the biggest issue)?
Mix Era Of Magic, Era of Myths, and Extended Era and you get all my favorite teams on one group! and ULTIMATE POWER!!!!!!!!!!!!

Also in the programming industry... later.
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: How does one filter units based on traits

Post by zookeeper »

A StandardUnitFilter for filtering for a trait:

Code: Select all

[filter_wml]
    [modifications]
        [trait]
            id=strong
        [/trait]
    [/modifications]
[/filter_wml]
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: How does one filter units based on traits

Post by Sapient »

We really should add this to the SUF so it is easier to check traits and weapon specials by id. Although for weapon specials it may be better to add a full blown [filter_weapon] rather than a top-level special= check.

Unfortunately I don't have my computer set up for building the code right now, but it should be an Easy Coding Task.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
User avatar
Col Lightbeam
Posts: 46
Joined: November 18th, 2008, 1:01 am

Re: How does one filter units based on traits

Post by Col Lightbeam »

What did I do wrong with this bit of code?

Code: Select all

###voiddeath###
[event]
name=new turn
first_time_only=no

[have_unit]
side=$side_number
x,y=$x1,$y1
[/have_unit]

[filter_location]
terrain="Xv"
[/filter_location]

[not]
[filter_wml]
    [modifications]
        [trait]
            id=spacewalker
        [/trait]
    [/modifications]
[/filter_wml]
[/not]

[kill]
x=$x1
y=$y1
animate=no
[/kill]
[/event]
What the apparent result is that the turns accelerate, and both leaders die on turn 1.

Nevermind...

I forgot one set of

Code: Select all

[filter][/filter]
it seems.

Now, it is this and it appears not to work anymore...

Code: Select all

###voiddeath###
[event]
name=new turn
first_time_only=no


[filter]
[have_unit]
side=$side_number
x,y=$x1,$y1
[/have_unit]

[filter_location]
terrain="Xv"
[/filter_location]
[/filter]
[not]
[filter_wml]
    [modifications]
        [trait]
            id=spacewalker
        [/trait]
    [/modifications]
[/filter_wml]
[/not]

[kill]
x=$x1
y=$y1
animate=no
[/kill]
[/event]
What did I do wrong?
Last edited by Col Lightbeam on August 30th, 2010, 9:31 pm, edited 1 time in total.
Mix Era Of Magic, Era of Myths, and Extended Era and you get all my favorite teams on one group! and ULTIMATE POWER!!!!!!!!!!!!

Also in the programming industry... later.
User avatar
Dixie
Posts: 1757
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: How does one filter units based on traits

Post by Dixie »

First off, [have_unit] makes no sense by itself, it needs to be in a [if], and it will eventually be followed by a [then]. Look a some exemples from mainline, there are plenty.

Second, [filter_location] and [filter_wml] should be inside your [have_unit]

Third, I really doubt there is a x1 and y1 in a new turn event, since this event doesn't necessarily concern a unit in particular (contrarily to attacker hits, for instance). You will need to store the concerned unit, and then use that stored version to kill it. In fact, you can probably skip the whole [if] and [have_unit] part if you just go with an efficient [store_unit].
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth
User avatar
Col Lightbeam
Posts: 46
Joined: November 18th, 2008, 1:01 am

Re: How does one filter units based on traits

Post by Col Lightbeam »

I tried what you said and it just caused the effect of the first set of code in my last post
this is the code I tried:

Code: Select all

###voiddeath###
[event]
name=new turn
first_time_only=no

[store_unit]
[filter]
x=$x1
y=$y1
[/filter]
[filter_location]
terrain="Xv"
[/filter_location]
[filter_wml]
[not]
    [modifications]
        [trait]
            id=spacewalker
        [/trait]
    [/modifications]
[/not]
[/filter_wml]
kill=yes
mode=replace
variable=worker
[/store_unit]
[/event]
I got it to delay accl turns and loss of units until after there was a unit that fulfilled the conditions by

Code: Select all

###voiddeath###
[event]
name=new turn
first_time_only=no

[if]
[have_unit]
[filter]
x=$x1
y=$y1
[/filter]
[filter_location]
terrain="Xv"
[/filter_location]
[filter_wml]
[not]
    [modifications]
        [trait]
            id=spacewalker
        [/trait]
    [/modifications]
[/not]
[/filter_wml]
[/have_unit]
[then]
[store_unit]
kill=yes
[/store_unit]
[/then]
[/if]
[/event]
Now how do you get it to only destroy units that fill that condition?
And thanks for that tip about

Code: Select all

mode=replace
Last edited by Col Lightbeam on August 30th, 2010, 11:20 pm, edited 2 times in total.
Mix Era Of Magic, Era of Myths, and Extended Era and you get all my favorite teams on one group! and ULTIMATE POWER!!!!!!!!!!!!

Also in the programming industry... later.
User avatar
Pentarctagon
Project Manager
Posts: 5564
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: How does one filter units based on traits

Post by Pentarctagon »

fyi, the mode=replace line is redundant since replace is the default value anyway. also, it seems that x1 and y1 do exist in a new turn event, however their values are both -999, which could explain why nothing is happening.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
Col Lightbeam
Posts: 46
Joined: November 18th, 2008, 1:01 am

Re: How does one filter units based on traits

Post by Col Lightbeam »

I got it to work except it seems to ignore the filter of

Code: Select all

[not]
    [modifications]
        [trait]
            id=spacewalker
        [/trait]
    [/modifications]
[/not]
Mix Era Of Magic, Era of Myths, and Extended Era and you get all my favorite teams on one group! and ULTIMATE POWER!!!!!!!!!!!!

Also in the programming industry... later.
User avatar
Dixie
Posts: 1757
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: How does one filter units based on traits

Post by Dixie »

Your code is so, so wrong. I suggest you give this a good read. Also, follow the link to standard unit filter, because it has great wisdom to share with you, and you could use it. And get rid of x1 and y1, they make no sense used there. If you really must, you can use "$this_unit.x,$this_unit.y", but it is pointless.

Ideally, you would also clear the variable the units are stored into.
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth
User avatar
Col Lightbeam
Posts: 46
Joined: November 18th, 2008, 1:01 am

Re: How does one filter units based on traits

Post by Col Lightbeam »

Dixie wrote:Your code is so, so wrong. I suggest you give this a good read. Also, follow the link to standard unit filter, because it has great wisdom to share with you, and you could use it. And get rid of x1 and y1, they make no sense used there. If you really must, you can use "$this_unit.x,$this_unit.y", but it is pointless.

Ideally, you would also clear the variable the units are stored into.
I guess this is one reason why some people aren't good at advice...

You say "Your code is so, so wrong" and yet give little thought to explaining it. I WAS and still AM at the suggested places and you seem to imply that
"StandardUnitFilter
From Wesnoth

From FilterWML, this is the standard way of filtering units.

When a unit filter is applied to a map, first it applies to all units on the field, based on their coordinates. Next it applies to units in the recall list. This is important to remember as it means, for example, that the tag [kill] can be used to kill units in the recall list.

You can access the filtered unit within the filter as the $this_unit variable, see SingleUnitWML for the possible content of these variables

The term StandardUnitFilter means that the set of such keys and tags (see below) can appear at that point. Often a StandardUnitFilter needs to be included in a [filter] tag. But many tags take the StandardUnitFilter directly as an argument, like [kill] and [have_unit].


The following attributes and sub-tags are allowed:

* id: unit matches the given description. This is the same as id in the [unit] tag. Note that it is independent of a unit's user-visible name, which can be internationalized independent of this. See SingleUnitWML.
* speaker: alias for description
* type: matches the unit's type name (can be a list of types)
* race: the race of the unit type.
Mainline races are listed in data/core/units.cfg
* ability: unit has an ability with the given id; see AbilitiesWML
* side: the unit is on the given side (can be a list)
* has_weapon: the unit has a weapon with the given name
* canrecruit: yes if the unit can recruit (i.e. is a leader)
* gender: female if the unit is female rather than the default of male
* role: the unit has been assigned the given role; see [role], InternalActionsWML
* level: the level of the unit
* defense: current defense of the unit on current tile (chance to hit %, like in movement type definitions)
* movement_cost: current movement cost of the unit on current tile
* x,y: the position of the unit. Note: there is a special case for units on the recall list such that x,y="recall,recall"
* find_in: name of an array or container variable; if present, the unit will not match unless it is also found stored in the variable
* [filter_vision]: this tests whether or not the unit is currently visible
o visible: yes or no, default yes. In Wesnoth 1.6.4 "yes" filters for units (visible or invisible) in visible locations. Filtering for unit (in)visibility requires "no".
o viewing_side: the side(s) which you are checking if they are able to see (or not see) the unit. All sides listed here must pass the test. If no side is listed, it will check the visibility all enemy sides.
* [filter_wml]: this is WML level filter for the unit. In it, you can filter on anything that is in the WML description of a unit. This description can be found in any savegame also in SingleUnitWML.
* [and]: an extra unit filter. Unless the unit also matches the [and] filter, then it will not count as a match. Note: [and],[or], and [not] filters are considered after the containing filter; they are then processed in the order encountered.
* [or]: an extra unit filter. If a unit matches the [or] filter, then it will count as a match regardless of conditions in previous filters or the containing filter.
* [not]: an extra unit filter. If a unit matches the [not] filter, then that unit will not be considered a match by the containing filter.
* [filter_adjacent]: standard unit filter; if present the correct number of adjacent units must match this filter
o count: a number, range, or comma separated range; default "1-6"
o adjacent: a comma separated list of directions; default "n,ne,se,s,sw,nw"
o is_enemy: a boolean specifying whether the adjacent unit must be an enemy or an ally (optional)
* [filter_location]: StandardLocationFilter - the tile that the unit is standing on matches the location filter.
* formula: FormulaAI like formula returning a boolean. The unit filtered is an implicit variable in the call.
* lua_function: the name of a Lua function in the global environment that takes a unit as an argument and returns true if the given unit matches the filter. StandardUnitFilter
From Wesnoth

From FilterWML, this is the standard way of filtering units.

When a unit filter is applied to a map, first it applies to all units on the field, based on their coordinates. Next it applies to units in the recall list. This is important to remember as it means, for example, that the tag [kill] can be used to kill units in the recall list.

You can access the filtered unit within the filter as the $this_unit variable, see SingleUnitWML for the possible content of these variables

The term StandardUnitFilter means that the set of such keys and tags (see below) can appear at that point. Often a StandardUnitFilter needs to be included in a [filter] tag. But many tags take the StandardUnitFilter directly as an argument, like [kill] and [have_unit].


The following attributes and sub-tags are allowed:

* id: unit matches the given description. This is the same as id in the [unit] tag. Note that it is independent of a unit's user-visible name, which can be internationalized independent of this. See SingleUnitWML.
* speaker: alias for description
* type: matches the unit's type name (can be a list of types)
* race: the race of the unit type.
Mainline races are listed in data/core/units.cfg
* ability: unit has an ability with the given id; see AbilitiesWML
* side: the unit is on the given side (can be a list)
* has_weapon: the unit has a weapon with the given name
* canrecruit: yes if the unit can recruit (i.e. is a leader)
* gender: female if the unit is female rather than the default of male
* role: the unit has been assigned the given role; see [role], InternalActionsWML
* level: the level of the unit
* defense: current defense of the unit on current tile (chance to hit %, like in movement type definitions)
* movement_cost: current movement cost of the unit on current tile
* x,y: the position of the unit. Note: there is a special case for units on the recall list such that x,y="recall,recall"
* find_in: name of an array or container variable; if present, the unit will not match unless it is also found stored in the variable
* [filter_vision]: this tests whether or not the unit is currently visible
o visible: yes or no, default yes. In Wesnoth 1.6.4 "yes" filters for units (visible or invisible) in visible locations. Filtering for unit (in)visibility requires "no".
o viewing_side: the side(s) which you are checking if they are able to see (or not see) the unit. All sides listed here must pass the test. If no side is listed, it will check the visibility all enemy sides.
* [filter_wml]: this is WML level filter for the unit. In it, you can filter on anything that is in the WML description of a unit. This description can be found in any savegame also in SingleUnitWML.
* [and]: an extra unit filter. Unless the unit also matches the [and] filter, then it will not count as a match. Note: [and],[or], and [not] filters are considered after the containing filter; they are then processed in the order encountered.
* [or]: an extra unit filter. If a unit matches the [or] filter, then it will count as a match regardless of conditions in previous filters or the containing filter.
* [not]: an extra unit filter. If a unit matches the [not] filter, then that unit will not be considered a match by the containing filter.
* [filter_adjacent]: standard unit filter; if present the correct number of adjacent units must match this filter
o count: a number, range, or comma separated range; default "1-6"
o adjacent: a comma separated list of directions; default "n,ne,se,s,sw,nw"
o is_enemy: a boolean specifying whether the adjacent unit must be an enemy or an ally (optional)
* [filter_location]: StandardLocationFilter - the tile that the unit is standing on matches the location filter.
* formula: FormulaAI like formula returning a boolean. The unit filtered is an implicit variable in the call.
* lua_function: the name of a Lua function in the global environment that takes a unit as an argument and returns true if the given unit matches the filter. "
would help me somehow without directing me to any specific place. This is kind of like saying as a person's lawyer in response to a question concerning problems with court logic "It is in here" and handing him or her a law book. Please, if you are to give suggestions, at least help by saying how your logic is superior (in other words why you are right and I am wrong) and how to correct that. You may think that you ARE being helpful, but it seems to me you are just handing me a law book (extreme example but sufficient I think) and say "It is in here". Certainly a computer could in theory read through the law book and mix and match looking for the problem, but that takes a very smart computer and I am nowhere near at putting different combinations together and seeing results quickly.

Now to give Dixie some credit, He did help me reduce lines of code for an older problem I had with his suggestion.

(By the way I was looking for [switch] which works almost like the Select Case for Visual basic for praychance)

Soo, if one is to act and talk superior, please act and talk superior in a helpful way... Like including answers to "How" and "Why"
Mix Era Of Magic, Era of Myths, and Extended Era and you get all my favorite teams on one group! and ULTIMATE POWER!!!!!!!!!!!!

Also in the programming industry... later.
itota
Posts: 68
Joined: April 3rd, 2010, 5:27 am

Re: How does one filter units based on traits

Post by itota »

* [filter_wml]: this is WML level filter for the unit. In it, you can filter on anything that is in the WML description of a unit. This description can be found in any savegame also in SingleUnitWML.
but perfect description cannot be found there. this seems to be a problem of the page.

(sorry if this post of mine is not to the point)
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: How does one filter units based on traits

Post by Sapient »

Don't put the [not] inside the [filter_wml] since it just does blind WML matching... put it outside wrapping it instead. The [and] [or] [not] tags are not allowed anywhere you might want them, but only where explicitly stated in the Reference.

Also, I agree it would be nice if people refrained from posting unhelpful or discouraging comments. I think what they were trying to say is that you are placing tags in places where they make sense to you (based on other situations) but not where the reference explicitly states they are allowed.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: How does one filter units based on traits

Post by silene »

Sapient wrote:Don't put the [not] inside the [filter_wml] since it just does blind WML matching... put it outside wrapping it instead. The [and] [or] [not] tags are not allowed anywhere you might want them, but only where explicitly stated in the Reference.
[not] works fine inside [filter_wml]. [and] and [or] don't.
User avatar
Ken_Oh
Moderator Emeritus
Posts: 2178
Joined: February 6th, 2006, 4:03 am
Location: Baltimore, Maryland, USA

Re: How does one filter units based on traits

Post by Ken_Oh »

Heh, yeah, I was about to get confused here for a minute.
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: How does one filter units based on traits

Post by Sapient »

Hmmm... well that's rather counter-intuitive and undocumented.
Anyways I wouldn't rely on such a behavior because if it is undocumented and counter-intuitive then it is likely be removed in a future version.

Back to your problem, this looks bad:
[store_unit]
kill=yes
[/store_unit]

It should warn you that [store_unit] requires a [filter], if it ever tried to execute that line.

There may be other bugs as well.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
Post Reply