[solved] Using WFL or similar in a filter

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.
Post Reply
white_haired_uncle
Posts: 1231
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

[solved] Using WFL or similar in a filter

Post by white_haired_uncle »

    I'd like store units that have an ability that starts with "regeneration". This is an example which covers two cases I know of, but there could be others, like "regeneration 13" that I don't (perhaps can't) know of".

    Code: Select all

       [store_unit]
                [filter]
                    status=incinerated
                    ability=regenerates
                    [and]
                            [filter_side]
                                side=$side_number
                            [/filter_side]
                    [/and]
                    [or]
                        status=incinerated
                        ability="regnerates 16"
                        [and]
                            [filter_side]
                                side=$side_number
                            [/filter_side]
                        [/and]
                    [/or]
                    ...
                    

    So I'd like to do something like

    Code: Select all

    "(ability.word[0])"=regenerates
    but in an actual valid syntax.

    I think I can see a path to what I want by filtering only by side, and then iterating on that list looking at abilities.regenerate.id, but I was hoping for something a little simpler.
    Last edited by white_haired_uncle on August 2nd, 2023, 7:10 pm, edited 1 time in total.
    Speak softly, and carry Doombringer.
    User avatar
    Ravana
    Forum Moderator
    Posts: 3025
    Joined: January 29th, 2012, 12:49 am
    Location: Estonia
    Contact:

    Re: Using WFL or similar in a filter

    Post by Ravana »

    Probably lua_function is the only clean way to implement this iteration in filters.
    User avatar
    Spannerbag
    Posts: 539
    Joined: December 18th, 2016, 6:14 pm
    Location: Yes

    Re: Using WFL or similar in a filter

    Post by Spannerbag »

    white_haired_uncle wrote: August 2nd, 2023, 4:49 am ...So I'd like to do something like

    Code: Select all

    "(ability.word[0])"=regenerates
    but in an actual valid syntax.
    Eh, not sure this will work but where you filter for ability=regenerates you could try ability_type=regenerates which would filter all units with the [regenerates] ability type?

    If that's not enough you could also try the following (but I suspect it will be horribly inefficient!):

    Code: Select all

            [and]
                ability_type=regenerates
                [filter_wml]
                    glob_on_id=*egenerate*		# Includes Regenerate..., regenerate... etc.
                [/filter_wml]
            [/and]
    
    Not sure on the exact syntax but this does work for me. I tested it with the code below and it worked (I was testing ways to determine what units a leader could currently extra_recruit).

    Code: Select all

    # Our heroes
      [side]
        team_name=Goodies
        user_team_name= _ "Goodies"
        side=1
        x,y=1,1
        id=Goody
        name=_"Goody"
        type=Spearman
        extra_recruit=Mage,Fencer,Cavalryman
        controller=human
        canrecruit=yes
        recruit=Bowman,Spearman
        gold=100
      [/side]
    
    ...
    
    # Turn 1
      [event]
        name=turn 1
         {DEBUG_MSG (_"Testing if filter_wml can split extra recruit value test is extra_recruit=Fencer - will probably fail")}
         [if]
           [have_unit]
             id=Goody
             [filter_wml]
               glob_on_extra_recruit=*Fencer*
             [/filter_wml]
           [/have_unit]
         [then]
    {DEBUG_MSG (_"It worked?!")}
         [/then]
         [else]
    {DEBUG_MSG (_"Fail")}
         [/else]
         [/if]
    
    HTH, cheers!
    --Spannerbag
    SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, v1.16)
    I suspect the universe is simpler than we think and stranger than we can know.
    Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
    white_haired_uncle
    Posts: 1231
    Joined: August 26th, 2018, 11:46 pm
    Location: A country place, far outside the Wire

    Re: Using WFL or similar in a filter

    Post by white_haired_uncle »

    Spannerbag wrote: August 2nd, 2023, 12:52 pm
    HTH, cheers!
    --Spannerbag
    Thanks! That's exactly what I was looking for. I do have other ability types=regenerate (note that's singular) whose id's do not start with "regenerate" and have special requirements (adjacent units or terrain type).

    Here is the solution:

    Code: Select all

                    [or]
                        status=incinerated
                        ability_types=regenerate
                        #ability=regenerates,regenerates 6,regenerates 12,regenerates 15,regenerates  16,regenerates 18,regenerates 20, regenerates 22,regenerates 24,regenerates 40,regenerates 100,regenerates 200
                        [filter_unit]
                            [filter_wml]
                                glob_on_id=*egenerate*
                            [/filter_wml]
                        [/filter_unit]
                        [and]
                            [filter_side]
                                side=$side_number
                            [/filter_side]
                        [/and]
                    [/or]
    I'm curious if the and tags are redundant, but it works and I'm tired of testing.

    And I have NO IDEA where "ability_types" came from. I'm pretty sure I cut/pasted "ability_type=regenerate". But it works. ???
    Speak softly, and carry Doombringer.
    User avatar
    Ravana
    Forum Moderator
    Posts: 3025
    Joined: January 29th, 2012, 12:49 am
    Location: Estonia
    Contact:

    Re: Using WFL or similar in a filter

    Post by Ravana »

    Meaningless keys and tags are usually ignored.
    User avatar
    Spannerbag
    Posts: 539
    Joined: December 18th, 2016, 6:14 pm
    Location: Yes

    Re: Using WFL or similar in a filter

    Post by Spannerbag »

    white_haired_uncle wrote: August 2nd, 2023, 3:18 pm
    Spannerbag wrote: August 2nd, 2023, 12:52 pm
    HTH, cheers!
    --Spannerbag
    Thanks! That's exactly what I was looking for.
    You're very welcome, it's nice to be able to help someone else for a change :)

    white_haired_uncle wrote: August 2nd, 2023, 3:18 pm I do have other ability types=regenerate (note that's singular)...
    Whoops! Apologies for that :oops:

    If all your regenerating units have this ability via the [regenerate] tag (got it right this time :) ) you shouldn't need the filter_wml clause.

    That said, I presume it's possible to implement regeneration via [heals] + affect_self=yes so my original logic was intended to be belt and braces (though it would not find units that used [heals] + affect_self=yes to "regenerate" and had an ability id that was - say - "heal self" rather than some variant of "regenerate").

    white_haired_uncle wrote: August 2nd, 2023, 3:18 pm I'm curious if the and tags are redundant, but it works and I'm tired of testing.
    Know that feeling...

    white_haired_uncle wrote: August 2nd, 2023, 3:18 pm And I have NO IDEA where "ability_types" came from. I'm pretty sure I cut/pasted "ability_type=regenerate". But it works. ???
    Just my tuppence worth but suspect everything is being caught by filter_wml 'cause I'm not sure ability_types will do anything?
    I know you're fed up with testing but you could try using ability_type=regenerate and lose the filter_wml if all your units regenerate via [regenerate]?

    Anyway glad it's working now :D

    Cheers!
    -- Spannerbag
    SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, v1.16)
    I suspect the universe is simpler than we think and stranger than we can know.
    Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
    white_haired_uncle
    Posts: 1231
    Joined: August 26th, 2018, 11:46 pm
    Location: A country place, far outside the Wire

    Re: [solved] Using WFL or similar in a filter

    Post by white_haired_uncle »

    Okay, I take it back, it does not work. I must have only tested the new part to see that it did what I want, but not that it didn't do what I don't want it to.

    There is a status, incinerated, which is much like poison. It should be healed in one of three cases. To make things simple, I've broken them down into separate store_unit/foreach blocks to minimize crosstalk.

    1) Incinerated unit is next to a healer or on a village. This works.

    2) Incinerated unit has a [abilities][regenerate] with id that does not start with "*egenerate" (e.g. id=nature's power). These are separate from item 3, because they have dependencies (e.g. nature's power only regenerates when on forested terrain). These work. I identify them by ability, (e.g. ability=natures power) not by ability_type.

    3) Incinerated unit has a [abilities][regenerate] with id that does start with "*egenerate" (or at least I think it does, the name does, unfortunately in this scenario, maybe because there are like 16 teams, inspect->units core dumps wesnoth). [I suppose I should find/create another scenario to confirm, or maybe I could look in a save?]. I want to identify these by ability type, but only for certain ability type id's so as not to conflict with group #2.

    I'm beginning to wonder if Spannerbag's solution will work for me, and I think I see why it might not. Consider:

    Code: Select all

                       ability_type=regenerate
                            [filter_wml]
                                glob_on_id=*egenerate*
                            [/filter_wml]
     
    If I read that right, it's looking for unit.id="*egenerate*", NOT unit.abilities.regenerate.id="*egenerate*" which is what I need. For laughs, I tried glob_on_abilities.regenerate.id= which didn't work (as I rather suspected).

    Hmm, why does this work

    Code: Select all

    ability=regenerates,regenerates 6,regenerates 12,regenerates 15,regenerates  16,regenerates 18,regenerates 20, regenerates 22,regenerates 24,regenerates 40,regenerates 100,regenerates 200
    while this doesn't

    Code: Select all

    ability=regenerate*
    I can use wildcards with terrain (though they're in a [filter_location]).

    going to try

    Code: Select all

                            ability_type=regenerate   # Has a regeneration ability
                            [not]                     # but not one that has dependendcies
                                ability=natures power,symbiosis 24,symbiosis 36
                            [/not]
     
    Speak softly, and carry Doombringer.
    User avatar
    Celtic_Minstrel
    Developer
    Posts: 2252
    Joined: August 3rd, 2012, 11:26 pm
    Location: Canada
    Contact:

    Re: [solved] Using WFL or similar in a filter

    Post by Celtic_Minstrel »

    Try formula = "find(abilities, word[0] = 'regenerate') != null()".

    That means "search through the list of ability IDs to find one whose first word is regenerate and pass the filter if something was found".

    Note that ability_types will do nothing. Even if you have more than one, you need to use just ability_type.
    white_haired_uncle wrote: August 3rd, 2023, 4:20 pm Hmm, why does this work

    Code: Select all

    ability=regenerates,regenerates 6,regenerates 12,regenerates 15,regenerates  16,regenerates 18,regenerates 20, regenerates 22,regenerates 24,regenerates 40,regenerates 100,regenerates 200
    while this doesn't

    Code: Select all

    ability=regenerate*
    I can use wildcards with terrain (though they're in a [filter_location]).
    Globs are only supported in specific places, and this isn't one of them.
    Author of The Black Cross of Aleron campaign and Default++ era.
    Former maintainer of Steelhive.
    white_haired_uncle
    Posts: 1231
    Joined: August 26th, 2018, 11:46 pm
    Location: A country place, far outside the Wire

    Re: [solved] Using WFL or similar in a filter

    Post by white_haired_uncle »

    Celtic_Minstrel wrote: August 3rd, 2023, 11:36 pm Try formula = "find(abilities, word[0] = 'regenerate') != null()".
    Thanks, I'll have to look at that more closely in the future. WML and I really don't get along well, but that formula make a lot more sense to me.

    In the end, I went with this. I like it because it fails nicely (it handles all regenerators regardless of their ability name, and any that I don't know about default to curing incinerate even if they really shouldn't under the circumstances).

    Code: Select all

                    [store_unit]
                            [filter]
                                    status=incinerated
                                    [filter_side]
                                            side=$side_number
                                    [/filter_side]
                                    [and]
                                            [filter_adjacent]   # Next to healer
                                                    ability=healing
                                                    is_enemy=no
                                            [/filter_adjacent]
                                            [or]
                                                    [filter_location]  # In a village
                                                            terrain=*^V*
                                                    [/filter_location]
                                            [/or]
                                            [or]
                                                    ability_type=regenerate   # Has a regeneration ability
                                                    [not]                     # but not one that has dependencies
                                                            ability=natures power,symbiosis 24,symbiosis 36
                                                    [/not]
                                            [/or]
                                            [or]
                                                    # Faerie Incarnation
                                                    ability=natures power
                                                    [filter_location]
                                                            terrain=*^F*, *^Uf, *^Ufi, *^Fz*
                                                    [/filter_location]
                                            [/or]
                                            [or] # Deathshroom
                                                    ability="symbiosis 24"
               ...
               				
    
    Speak softly, and carry Doombringer.
    User avatar
    Spannerbag
    Posts: 539
    Joined: December 18th, 2016, 6:14 pm
    Location: Yes

    Re: [solved] Using WFL or similar in a filter (edited)

    Post by Spannerbag »

    Hi again,

    I hate to make your life more interesting but I do have another suggestion?
    white_haired_uncle wrote: August 3rd, 2023, 4:20 pm There is a status, incinerated, which is much like poison. It should be healed in one of three cases...

    1) Incinerated unit is next to a healer or on a village. This works.

    2) Incinerated unit has a [abilities][regenerate] with id that does not start with "*egenerate" (e.g. id=nature's power). These are separate from item 3, because they have dependencies (e.g. nature's power only regenerates when on forested terrain). These work. I identify them by ability, (e.g. ability=natures power) not by ability_type.

    3) Incinerated unit has a [abilities][regenerate] with id that does start with "*egenerate" (or at least I think it does, the name does, unfortunately in this scenario, maybe because there are like 16 teams, inspect->units core dumps wesnoth). [I suppose I should find/create another scenario to confirm, or maybe I could look in a save?]. I want to identify these by ability type, but only for certain ability type id's so as not to conflict with group #2.
    ...
    Could you combine 2) and 3) above by adding to the method 2) filter the clause ability_type_active=regenerate?
    Just a thought - and it might simplify
    white_haired_uncle wrote: August 5th, 2023, 11:42 am

    Code: Select all

                    [store_unit]
                            [filter]
                                    status=incinerated
                                    [filter_side]
                                            side=$side_number
                                    [/filter_side]
                                    [and]
                                            [filter_adjacent]   # Next to healer
                                                    ability=healing
                                                    is_enemy=no
                                            [/filter_adjacent]
                                            [or]
                                                    [filter_location]  # In a village
                                                            terrain=*^V*
                                                    [/filter_location]
                                            [/or]
                                            [or]
                                                    ability_type=regenerate   # Has a regeneration ability
                                                    [not]                     # but not one that has dependencies
                                                            ability=natures power,symbiosis 24,symbiosis 36
                                                    [/not]
                                            [/or]
                                            [or]
                                                    # Faerie Incarnation
                                                    ability=natures power
                                                    [filter_location]
                                                            terrain=*^F*, *^Uf, *^Ufi, *^Fz*
                                                    [/filter_location]
                                            [/or]
                                            [or] # Deathshroom
                                                    ability="symbiosis 24"
               ...
    To something like
    Edit: removed ability_type=regenerate as I think ability_type_active=regenerate on its own is enough?

    Code: Select all

                    [store_unit]
                            [filter]
                                    status=incinerated
                                    [filter_side]
                                            side=$side_number
                                    [/filter_side]
                                    [and]
                                            [filter_adjacent]   # Next to healer
                                                    ability=healing
                                                    is_enemy=no
                                            [/filter_adjacent]
                                            [or]
                                                    [filter_location]  # In a village
                                                            terrain=*^V*
                                                    [/filter_location]
                                            [/or]
                                            [or]
    # --- Don't think this is needed ---  ability_type=regenerate                     # Has *any* sort of regeneration ability...
                                                    ability_type_active=regenerate    # ...that is currently active
                                            [/or]
               ...
    But I can well understand the feeling The damn things works well enough. I'm done. :)

    Cheers!
    -- Spannerbag
    SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, v1.16)
    I suspect the universe is simpler than we think and stranger than we can know.
    Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
    white_haired_uncle
    Posts: 1231
    Joined: August 26th, 2018, 11:46 pm
    Location: A country place, far outside the Wire

    Re: [solved] Using WFL or similar in a filter

    Post by white_haired_uncle »

    Well, that does work (just ability_type_active=regenerate), but it seems to cover all possible cases without me having to hardcode anything. I did get to remove 29 lines of code, so I guess I can put up with it.

    Thanks again.
    Speak softly, and carry Doombringer.
    User avatar
    Spannerbag
    Posts: 539
    Joined: December 18th, 2016, 6:14 pm
    Location: Yes

    Re: [solved] Using WFL or similar in a filter

    Post by Spannerbag »

    white_haired_uncle wrote: August 6th, 2023, 10:15 am Well, that does work (just ability_type_active=regenerate), but it seems to cover all possible cases without me having to hardcode anything. I did get to remove 29 lines of code, so I guess I can put up with it.
    :lol:
    white_haired_uncle wrote: August 6th, 2023, 10:15 am Thanks again.
    Glad it worked :D

    Cheers!
    -- Spannerbag
    SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, v1.16)
    I suspect the universe is simpler than we think and stranger than we can know.
    Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
    Post Reply