More filter examples

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.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

More filter examples

Post by enclave »

The more I code the more I convince myself that filters may become a nightmare.. I am far from a newbie in WML and I still really often struggle with filters. Sometimes what seems to be simple becomes hours and hours of tests until it actually starts to work right. So I decided the filters deserve a separate topic. The wiki is unfortunately mostly showing very basic filter examples.
If you have examples of filters that are 100% tested and DO work, feel free to post them here, specifying what exactly you are filtering and why (in the top line of your post, ideally written in bold style).
To administrators: if you have any power to add link in wiki for more filter examples, please add the link to this topic specifying that although it is all 100% tested it still MAY contain bugs, so learning from the codes in this topic is at people's own risk, as these examples are created by amateurs like me.

Contents:
1) [store_locations]
a) storing any terrains that are not Impassable (_off^_usr) from a 10x10 field of a map.
b) checking if these hexes contain enough forest
c) if not, then randomly adding some forest to the 10x10 piece.
d) looping that through the map applying to whole map field by field.

2) [abilities] [regenerate] [filter_adjacent]
ship is being repaired by Peasant if he is in village, ship is near village and there is no enemy near the ship.

3) a) [abilities][leadership][filter_adjacent]
b) [set_specials] [damage][filter_adjacent]
very very long code
flank abilities and surrounded.. unit becomes stronger against surrounded unit (more damage), depending on how many units with this ability are used to surround. In turn surrounded unit becomes weaker (less damage), depending on how many units have surrounded him.

4) [filter_vision] example (also has [filter_location] and [store_unit] filters). store only all visible units to current side. killed 3+ hours to try to figure out how to do it right and still dont understand why wose in the woods (hidden) is considered invisible to current side, when it belongs to current side.. but well.. not in a mood to kill 3 more hours trying to figure it out. Hope this example will help somebody :)

5) [filter_vision] example (also has [lift_fog],[reset_fog],[remove_shroud] and [redraw]) allows you to see some other player's map.

6) [store_locations] examples with radius.. also has find_in

7) lua wesnoth.get_locations with "not" in filter.

8)[store_locations] examples with radius.. stores king if he is on keep and then checks if there are any empty castles in his radius

9) [store_locations] basic but with double radius a true nightmare...

10) [set_menu_item] that you can add to your add-on and experiment with filters.. It will visually show you what your filter does or could do...

11) [micro_ai] a very full of complications filter that would make a peasant look for a place to build new village and GO there, with a rule that villages should be at least 3 hex away from each other.

12) a basic lua filter for lua beginners.. (it may seem to be a simple filter, but it's not obvious how to make it work in lua) wesnoth.get_locations and also ipairs
Last edited by enclave on May 16th, 2018, 1:46 pm, edited 15 times in total.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

1) [store_locations]

a) Lets store 10x10 piece of map, but only hexes with grassland and snow, and ignore all hexes with forest.
There are few ways to store 10x10 field of the map.
Way 1 (using coma separated list of x, y values):

Code: Select all

	[store_locations]
        terrain=G*,G*^*,Aa*,Aa*^*
	x=1,2,3,4,5,6,7,8,9,10
	[and]
	y=1,2,3,4,5,6,7,8,9,10
	[/and]
	[not]
	terrain=*^F*
	[/not]
	variable=terrain_cube_10x10
	[/store_locations]
Spoiler:
Way 2 (using dashes -):

Code: Select all

	[store_locations]
        terrain=G*,G*^*,Aa*,Aa*^*
	x=1-10
	y=1-10
	[not]
	terrain=*^F*
	[/not]
	variable=terrain_cube_10x10
	[/store_locations]
This is doing the same thing and it does not even require [and]
Also it is very convenient if we want to do loop with this [store_locations] so this is what we will use in the next step.

b) Now when we stored the 10x10 field of all X between 1 and 10, and all Y values between 1 and 10 We could check if this field of 100 hexes has enough hills or not... keep in mind that you only stored grassland and snow hexes so our example is pointless, as there are 0 hills stored, because we didn't filter them.. To store all hexes we would need to remove terrain=G*,G*^*,Aa*,Aa*^* line or add hills to it like so terrain=G*,G*^*,Aa*,Aa*^*, H*,H*^*
To do this we will use a filter find_in
So we will store all hexes that have Hills H*,H*^* but this time not from the whole map, not from certain x,y ranges, but only from terrain_cube_10x10 array from our previous task. So let's say we check if there is more or less than 10 hills in that 10x10 field on the map..

Code: Select all

[store_locations]
find_in=terrain_cube_10x10
terrain=H*,H*^*
variable=array_with_hills
[/store_locations]
##
[if]
[variable]
name=array_with_hills.length
less_than=10
[/variable]
[then]
So if there is less than 10 hills we can do our next task:
c) randomly add some hills to that 10x10 piece of land..
like so:

Code: Select all

{REPEAT 5 (
{VARIABLE_OP NS_HIT_X rand 1..10}
{VARIABLE_OP NS_HIT_Y rand 1..10}
{MODIFY_TERRAIN Hh $NS_HIT_X $NS_HIT_Y}
)}
[/then]
[/if]
This would add Hills Hh 5 times to random coordinates. The coordinates may repeat, so result may have less than 5 extra hills.. but in my case it doesn't matter.. If it matters for you, you may cycle store locations.. like so:
Spoiler:
c) now if we want to check every 10x10hex of the map if there is enough hills or not, and add them if less than 10, randomly.. it will be a long and complicated code, we would need to do something like that:
Spoiler:
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

2) [abilities] [regenerate] [filter_adjacent]
ship is being repaired by Peasant if he is in village, ship is near village and there is no enemy near the ship.

I will not describe here how [object] [effect] works, but you can always ask if you have questions, I would happily explain.
This is about filters, and I was advised to put some [filter_adjacent] examples, so here is one of them..
We will add [regenerate] ability to a unit and make it work as described above.

Code: Select all

[effect]
					apply_to=new_ability
					[abilities]
				[regenerate]
				id=transport_regenerates
				name= _ "under repair"
				female_name= _ "female^Repairable"
				name_inactive= _ "repairable"
				female_name_inactive= _ "female^Repairable"
				value=14
        description_inactive= _ "The ship will heal itself 14 HP per turn if it is positioned near friendly village with Peasant in it and no enemy units next to ship."	
        description= _ "The ship will heal 14 HP next turn if conditions not change."
        affect_self=yes
[filter]
[filter_adjacent]
adjacent=n,ne,se,s,sw,nw
[filter_location]
terrain=Gg^Vh
[filter]
type=Peasant
[/filter]
[/filter_location]
[/filter_adjacent]
[and]
[not]
[filter_adjacent]
adjacent=n,ne,se,s,sw,nw
is_enemy=true
[filter]
[/filter]
[/filter_adjacent]
[/not]
[/and]
[/filter]
					[/regenerate]
				[/abilities]
				[/effect]			
terrain=Gg^Vh this is only 1 type of villages.. if you want it to apply to all types of villages, use *^V* instead.
type=Peasant may be changed to any unit type, or you may use ability= instead.. this way you may have same unit type with different abilities, so same type units with different abilities some of them could heal the ship, some of them cant.. When you filter ability, you would need to use ability ID and NOT name.
Spoiler:
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

3) a) [abilities][leadership][filter_adjacent]
b) [set_specials] [damage][filter_adjacent]

A very very complicated and long codes.. once applied to a unit the unit array becomes visually split into 2 arrays if you look through :debug :inspect in game. Any questions ask.

Flank abilities.
I wanted to make a code where units surrounded by enemy units would become weaker and get more damage, depending on how many enemy units around.

a) Abilities to become weaker if surrounded by enemy units with ability id=cg_flank
Spoiler:
b) Effect that makes enemy units become stronger against surrounded unit. Similar to backstab or charge attack specials.
Spoiler:
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

4) Store only visible units in radius of 10 hex from selected coordinates $x1 $y1 [filter_vision][filter_location][store_unit]

Code: Select all

[store_unit]
   [filter]
      [filter_location]
         x,y=$x1,$y1  ## instead of $x1 $y1 you can put whatever.. eg. 15 36
         radius=10 ## this is radius from $x1 $y1 coordinates.. 
      [/filter_location]
      [filter_vision]
         visible=yes ## this means it stores only visible units to side below (excluding woses in some cases)
         side=$side_number ## visible to this side.. units not hidden and not in fog..
      [/filter_vision]
   [/filter]
   variable=development_test_array_1 ##name of array to store visible units in range..
[/store_unit]
Last edited by enclave on May 8th, 2017, 4:10 pm, edited 1 time in total.
User avatar
ForestDragon
Posts: 1769
Joined: March 6th, 2014, 1:32 pm
Location: Ukraine

Re: More filter examples

Post by ForestDragon »

If i am not mistaken, the wiki can be edited. You couls (if i am not mistaken) add these examples to the wiki.
My active add-ons: The Great Steppe Era,XP Bank,Alliances Mod,Pestilence,GSE+EoMa,Ogre Crusaders,Battle Royale,EoMaifier,Steppeifier,Hardcoreifier
My inactive add-ons (1.12): Tale of Alan, The Golden Age
Co-creator of Era of Magic
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: More filter examples

Post by Sapient »

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
Celtic_Minstrel
Developer
Posts: 2166
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: More filter examples

Post by Celtic_Minstrel »

Please fix your indentation. It's difficult to read when stuff isn't indented properly. Also, please put code tags around each example.

Your "flanked from two sides" example can be done more simply (in 1.13.x) using the autostored variables and direction operators. You basically only need one filter_adjacent tag, something like this:

Code: Select all

[filter_adjacent]
               adjacent=$this_unit.facing:cw,$this_unit.facing:ccw
               is_enemy=true
               count=2
               ability=cg_flank
[/filter_adjacent]
Your surrounded example looks like it's actually a repeat of the flank example.
Author of The Black Cross of Aleron campaign and Default++ era.
Former maintainer of Steelhive.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

Me? Yes. Thank you! But how is it related to my last post?
Celtic_Minstrel wrote:Please fix your indentation. It's difficult to read when stuff isn't indented properly.
Yeah, I started to indent things in my last post because of others having difficulties. But I have no time to change all my posts dated in the past, sorry. If you feel unhappy with them, please use your privileges of developer to delete them.
Celtic_Minstrel wrote:Also, please put code tags around each example.
Where did I miss them? I'm sometimes not paying enough attention..
Celtic_Minstrel wrote:Your "flanked from two sides" example can be done more simply (in 1.13.x) using the autostored variables and direction operators. You basically only need one filter_adjacent tag, something like this:
Thank you for your example. I hope it actually works when you say it is "something likes this", otherwise it doesn't help anyone here, because this topic is all working and tested examples. So hopefully it works and when people start to play 1.13 some day it will be useful for them, because at the moment I personally don't know a single person playing 1.13 but it's really great that it exists and has so many more features than 1.12!

I really don't understand why you all replied here.. I wish I had so many replies when I'm asking for help with something.
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: More filter examples

Post by Sapient »

enclave wrote:
Me? Yes. Thank you! But how is it related to my last post?
When you said "The wiki is unfortunately mostly showing very basic filter examples," I thought maybe you had not seen that page, because it does have a few complex examples. Also, that would be a logical place to add a link to provide more advanced examples, as you are doing here.



enclave wrote: I really don't understand why you all replied here.. I wish I had so many replies when I'm asking for help with something
.
Haha... there's no need to get defensive. FilterWML and good WML documentation are both interests of mine. We like your idea and are encouraging you to improve and finish what you started.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

Thank you for your support Sapient, I will try my best to improve.
I wouldn't change any wiki with my input examples (like ForestDragon mentioned being possible), because I don't feel confident to do it myself, I still may do mistakes, or my code may not be optimized, or for other reasons related to my relatively low experience in this subject. In my opinion wiki should be written by people who knows the subject perfectly well and there is no place for mistakes etc if it is created to guide others. Forum is rather something that is written by amateurs and can only be taken as advice, not a guide.. If somebody knowledgeable finds my examples trustworthy and well written, please feel free to put them into wiki. I'm happy enough with just being able to find my examples in google search as it has happened to me couple of times, when I was actually able to find something I was looking for (and I wrote it long time ago, just forgot, so I actually managed to help my own self a couple of times).
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

5) [filter_vision] example (also has [lift_fog],[reset_fog],[remove_shroud] and [redraw]) allows you to see some other player's map. Imagine you would like to exchange map with some other player, without becoming allies.. So then that's for you.

Code: Select all

## remove_shroud will remove shroud from side 2, and what was under shroud will become visible for player 1 if you are playing with shroud
[remove_shroud]
   side=1 ## side to which the shroud will disappear and map will be revealed
   [filter_vision]
      visible=yes ## filters visible area (could filter the invisible area..if was no)
      respect_fog=no ## will show the explored map of side2, all hexes he has ever been to, NOT ONLY currently visible hexes
      side=2 ## side which can see these hexes.. removes shroud where player 2 can see
   [/filter_vision]
[/remove_shroud]	
## lift_fog removes fog from player 2 and his land and units become visible to player 1
[lift_fog]
   [filter_side] 
      side=1 ## side to which the fog will disappear and map will be revealed
   [/filter_side]
   [filter_vision]
      visible=yes ## all same as [remove_shroud] code above
      respect_fog=no ## all same as [remove_shroud] code above
      side=2 ## all same as [remove_shroud] code above
   [/filter_vision]
[/lift_fog]	
## the next section with reset_fog is if you want the fog to cover everything again for some reason..
[reset_fog]
   [filter_side] 
      side=1 ## side 1 will have fog everywhere
   [/filter_side]
   [filter_vision] ## should restrict to these, visible to side 2 hexes.. but in practice it didn't work for me
      visible=yes 
      respect_fog=no
      side=2
   [/filter_vision]
   reset_view=yes ## as [filter_vision] didn't work I had to use reset_view which just covers EVERYTHING in fog, there is even a message like "4 friendly units sighted" in green, when u move some units and fog disappears. FUNNY
[/reset_fog]
## and redraw will just remove fog from places that you can see.. 
[redraw]
   side=1 ## applies to your side, side 1
[/redraw]
So result of these codes will be that in the shroud you will see the explored map of player 2, but you will not see what units he has or anything.. I guess we could achieve same effect with just

Code: Select all

[remove_shroud]
   side=1 
   [filter_vision]
      visible=yes 
      respect_fog=no 
      side=2 
   [/filter_vision]
[/remove_shroud]	
but I shown more examples and possibilities.. have fun :)
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

6) [store_locations] with radius and find_in
I still struggle with filters all the time looks like.. took me ages to figure out the filters that would work for these 2 examples:

This one will store everything on map except water and 10 hex radius around leaders.

Code: Select all

[store_locations]
[not]
terrain=W*,W*^*
[/not]
[and]
[not]
	[filter]
	canrecruit=yes
	[/filter]
	radius=10
	[/not]
[/and]
variable=ns_test_locations
[/store_locations]
This one will store land without water in radius of 10 hex around hex with coordinates 11,11

Code: Select all

[store_locations]
x,y=11,11
radius=10
variable=ns_test_locs1
[/store_locations]

[store_locations]
find_in=ns_test_locs1
[not]
terrain=W*,W*^*
[/not]
variable=ns_test_locations
[/store_locations]
I tried 1million ways and nothing except find_in worked for me.. sad that it requires 2 steps..
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: More filter examples

Post by Sapient »

enclave wrote: This one will store everything on map except water and 10 hex radius around leaders.
Your [and] there is redundant. There is no need to wrap the [not] in an [and].
enclave wrote: This one will store land without water in radius of 10 hex around hex with coordinates 11,11.
I tried 1million ways and nothing except find_in worked for me.. sad that it requires 2 steps.
The thing you have to remember is that radius is evaluated last of all. So to force earlier evaluation of radius, wrap it in a subtag such as [and].

Code: Select all

[store_locations]
  [not]
    terrain=W*,W*^*
  [/not]
  [and]
    x,y=11,11
    radius=10
  [/and]
  variable=ns_test_locations
[/store_locations]
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: More filter examples

Post by enclave »

The thing you have to remember is that radius is evaluated last of all. So to force earlier evaluation of radius, wrap it in a subtag such as [and].

Code: Select all

[store_locations]
  [not]
    terrain=W*,W*^*
  [/not]
  [and]
    x,y=11,11
    radius=10
  [/and]
  variable=ns_test_locations
[/store_locations]
I was sure I tried it as well, but looks like not, because your example above worked perfectly.

Why this one below doesn't work? Isn't it quite the same thing? Or radius comes even after all "and"s if not wrapped into an [and] himself?

Code: Select all

[store_locations]
      x,y=11,11
    radius=10
[and]
  [not]
    terrain=W*,W*^*
  [/not]
[/and] 
  variable=ns_test_locations
[/store_locations]
Thanks in advance.
Post Reply