Advanced WML

From The Battle for Wesnoth Wiki

Advanced WML

Store Reachable Locations

Obsolete Wesnoth 1.9.2 added the [store_reachable_locations] tag.

#define STORE_REACHABLE_LOCATIONS ORIGIN COST_INFO TOTAL_MOVES RESULT 
       {VARIABLE SRL_reach_list.hexes.x ${ORIGIN}.x}
       {VARIABLE SRL_reach_list.hexes.y ${ORIGIN}.y}
       {VARIABLE {RESULT}.x ${ORIGIN}.x}
       {VARIABLE {RESULT}.y ${ORIGIN}.y}
       {VARIABLE SRL_i 0}
       [while]
           [variable]
               name=SRL_i
               less_than={TOTAL_MOVES}
           [/variable]
           [do]
               {FOREACH {COST_INFO} SRL_j}
               {VARIABLE SRL_tmp ${COST_INFO}[$SRL_j].cost}
               {VARIABLE_OP SRL_tmp add $SRL_i}
               [if]
                   [variable]
                       name=SRL_tmp
                       less_than_equal_to={TOTAL_MOVES}
                   [/variable]
                   [then]
                       [store_locations]
                           [filter_adjacent]
                               find_in=SRL_reach_list[$SRL_i].hexes
                           [/filter_adjacent]
                           [insert_tag]
                               name=and
                               variable={COST_INFO}[$SRL_j].filter_location
                           [/insert_tag]
                           [not]
                               find_in={RESULT}
                           [/not]
                           [or]
                               find_in=SRL_reach_list[$SRL_tmp].hexes
                           [/or]
                           variable=SRL_reach_list[$SRL_tmp].hexes
                       [/store_locations]
                   [/then]
               [/if]
               {NEXT j}
               {CLEAR_VARIABLE SRL_reach_list[$SRL_i].hexes}
               {VARIABLE_OP SRL_i add 1}
               [store_locations]
                   find_in=SRL_reach_list[$SRL_i].hexes
                   [or]
                       find_in={RESULT}
                   [/or]
                   variable={RESULT}
               [/store_locations]
           [/do]
       [/while]
       {CLEAR_VARIABLE SRL_reach_list}
       {CLEAR_VARIABLE SRL_i}
       {CLEAR_VARIABLE SRL_j}
       {CLEAR_VARIABLE SRL_tmp}
#enddef

Note: This only works in 1.5 and later versions.

  • {TOTAL_MOVES} is the maximum number of movement points that may be spent for the calculation of reach. Example: "5"
  • {ORIGIN} is the name of a starting location variable or unit variable. Example: "second_unit"
  • {RESULT} is the name of a result variable that will contain the reachable locations. Example: "reachable_locs"
  • {COST_INFO} is the name of a special array variable that you have to construct before calling the macro. This is an example of how to build a move cost array "move_costs":
       [set_variables]
           name=move_costs
           [literal]
               cost=1
               [filter_location]
                   terrain=Re,Gg,C*,K*,*^V*
               [/filter_location]
           [/literal]
           [literal]
               cost=2
               [filter_location]
                   terrain=Gs^Fp,Hh,Ss,Ww
               [/filter_location]
           [/literal]
       [/set_variables]

Force Injured Units to Retreat

This may be obsolete, in Wesnoth 1.14 consider using Micro AIs instead, particularly the Hunter and Goto ones.

#define RETREAT_WHEN_INJURED CONDITION SIDE FILTER HOW_INJURED SEARCH_RADIUS
    # This macro should be used at the scenario level. It defines a pair of
    # events that enforce behavior for injured units matching the given FILTER
    # that belong to the given SIDE. These units are forced to retreat to the
    # nearest allied village, and then forcibly restrained there until they
    # are no longer injured. The definition of "injured" is controlled by the
    # HOW_INJURED parameter: a unit counts as injured when its maximum
    # hitpoints divided by its current hitpoints is greater than HOW_INJURED
    # (using integer division). So set HOW_INJURED to 1 to have a unit retreat
    # when at 1/2 health or less, to 2 for 1/3 health, etc. Finer-grained
    # control over this is extremely difficult (although a pure hitpoints-based
    # method would be easy). The events defined only fire when the given
    # CONDITION is met, so this macro can be restricted in scope to only
    # certain turns. Also, a search for nearby villages is limited to the given
    # SEARCH_RADIUS, after which all villages on the map are considered.
    [event]
        name=side turn
        first_time_only=no
        [if]
            [variable]
                name=side_number
                equals={SIDE}
            [/variable]
            [and]
                {CONDITION}
            [/and]
            [then]
                [clear_variable]
                    name=retreat_when_injured_units
                [/clear_variable]
                [store_unit]
                    variable=retreat_when_injured_units
                    [filter]
                        side={SIDE}
                        [and] # Match the given filter
                            {FILTER}
                        [/and]
                        [not] # Not already resting in a village
                            [filter_location]
                                terrain=*^V*
                            [/filter_location]
                        [/not]
                        [and] # Injured
                            formula="(max_hitpoints / hitpoints) > {HOW_INJURED}"
                        [/and]
                    [/filter]
                [/store_unit]
                {FOREACH retreat_when_injured_units retreat_when_injured_units_index}
                    [set_variable]
                        name=retreat_when_injured_id
                        to_variable=retreat_when_injured_units[$retreat_when_injured_units_index].id
                    [/set_variable]
                    [set_variable]
                        name=retreat_when_injured_x
                        to_variable=retreat_when_injured_units[$retreat_when_injured_units_index].x
                    [/set_variable]
                    [set_variable]
                        name=retreat_when_injured_y
                        to_variable=retreat_when_injured_units[$retreat_when_injured_units_index].y
                    [/set_variable]
                    # Find a nearby village in the city (that's unoccupied).
                    {FIND_NEARBY (terrain=*^V*
                                  [not]
                                      [filter]
                                      [/filter]
                                  [/not]
                                  [and]
                                      [not]
                                          find_in=retreat_when_injured_destinations
                                      [/not]
                                  [/and]) $retreat_when_injured_x $retreat_when_injured_y {SEARCH_RADIUS}}
                    {SET_DESTINATION id=$retreat_when_injured_id $nearby_locations[0].x $nearby_locations[0].y}
                    [store_locations]
                        variable=retreat_when_injured_destinations
                        mode=append
                        x=$nearby_locations[0].x
                        y=$nearby_locations[0].y
                    [/store_locations]
                    {DEBUG ("$retreat_when_injured_id is forced to retreat from ($retreat_when_injured_x, $retreat_when_injured_y) to ($nearby_locations[0].x, $nearby_locations[0].y) and is the $retreat_when_injured_units_index|th unit to retreat this turn.")}
                    [event] # Force the unit to stop once it arrives
                        name=moveto
                        delayed_variable_substitution=no
                        [filter]
                            id=$retreat_when_injured_id
                            x=$nearby_locations[0].x
                            y=$nearby_locations[0].y
                        [/filter]
                        {DEBUG ("Injured unit $retreat_when_injured_id reached village at ($nearby_locations[0].x, $nearby_locations[0].y).")}
                        {SET_PROPERTY (id=$retreat_when_injured_id) moves 0}
                        {DEBUG ("Injured unit $retreat_when_injured_id has $unit.moves moves left")}
                    [/event]
                {NEXT retreat_when_injured_units_index}
                [clear_variable]
                    name=retreat_when_injured_id,retreat_when_injured_x,retreat_when_injured_y,retreat_when_injured_destinations,nearby_locations
                [/clear_variable]
            [/then]
        [/if]
    [/event]

    # This event prevents retreated injured units from going back into battle.
    [event]
        name=turn refresh
        first_time_only=no
        [if]
            [variable]
                name=side_number
                equals={SIDE}
            [/variable]
            [then]
                [store_unit] # Find units that still need to rest
                    variable=retreat_when_injured_resting_units
                    [filter]
                        find_in=retreat_when_injured_units
                        formula="(max_hitpoints / hitpoints) > {HOW_INJURED}"
                        [filter_location]
                            terrain=*^V*
                        [/filter_location]
                    [/filter]
                [/store_unit]
                {FOREACH retreat_when_injured_resting_units retreat_when_injured_resting_units_index}
                    [set_variable]
                        name=retreat_when_injured_resting_id
                        to_variable=retreat_when_injured_resting_units[$retreat_when_injured_resting_units_index].id
                    [/set_variable]
                    {DEBUG ("Forcing unit $retreat_when_injured_resting_id to rest (the $retreat_when_injured_resting_units_index|th this turn).")}
                    {SET_PROPERTY id=retreat_when_injured_resting_id moves 0} # They rest!
                {NEXT retreat_when_injured_resting_units_index}
                [clear_variable]
                    name=retreat_when_injured_resting_units,retreat_when_injured_resting_id
                [/clear_variable]
                [store_unit] # Find trapped units...
                    variable=retreat_when_injured_trapped_units
                    [filter]
                        find_in=retreat_when_injured_units
                        formula="(max_hitpoints / hitpoints) > {HOW_INJURED}"
                        [and]
                            [filter_adjacent]
                                count=2
                                adjacent=ne,sw
                                is_enemy=yes
                            [/filter_adjacent]
                            [or]
                                [filter_adjacent]
                                    count=2
                                    adjacent=nw,se
                                    is_enemy=yes
                                [/filter_adjacent]
                            [/or]
                            [or]
                                [filter_adjacent]
                                    count=2
                                    adjacent=n,s
                                    is_enemy=yes
                                [/filter_adjacent]
                            [/or]
                        [/and]
                    [/filter]
                [/store_unit]
                {FOREACH retreat_when_injured_trapped_units retreat_when_injured_trapped_units_index}
                    [set_variable]
                        name=retreat_when_injured_trapped_id
                        to_variable=retreat_when_injured_trapped_units[$retreat_when_injured_trapped_units_index].id
                    [/set_variable]
                    {DEBUG ("Preventing unit $retreat_when_injured_trapped_id from attacking.")}
                    {SET_PROPERTY id=retreat_when_injured_trapped_id attacks_left 0} # No attacking for you
                {NEXT retreat_when_injured_trapped_units_index}
                [clear_variable]
                    name=retreat_when_injured_trapped_units,retreat_when_injured_trapped_id
                [/clear_variable]
            [/then]
        [/if]
    [/event]
#enddef

See Also

This page was last edited on 2 July 2019, at 21:03.