Difference between revisions of "FloodWML"

From The Battle for Wesnoth Wiki
(Everythin about floods)
m (Ranking terrain codes)
 
(13 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
'''FloodWML works for 1.9 and above'''
 +
 
== Usage ==
 
== Usage ==
You can find sources at the bottom of the page. It's too long to include it here.
+
You can find sources at the bottom of the page. It's too long to include here.
NOTE: these macros are performing lots of complex calculations thus they are quite slow. They can make your scenario lag and so make a serious blow especially on older machines. To make sure you've minimized the negative effects, please read the Optimization section below.
 
  
To create a flood:
+
'''NOTE: these macros are performing lots of complex calculations thus they are quite slow. They can make your scenario lag and thus create an unwelcome user experience, especially on older machines. To make sure you've minimized the negative effects, please read the Optimization section below.'''
 +
 
 +
=== Create flood ===
 
  {CREATE_FLOOD "1,1;2,3" "ne,n" "Gg>Ww;Gs>Wwt" awesome_flood}
 
  {CREATE_FLOOD "1,1;2,3" "ne,n" "Gg>Ww;Gs>Wwt" awesome_flood}
Where "1,1;2,3" is a semicolon separated list of coordinate pairs where the flood starts from, "ne,n" is a comma separated list of directions in which the flood will spread, "Gg>Ww;Gs>Wwt" is a semicolon separated list of transformations where a>b means that the hexes with the terrain code a will be converted to b, and finally awesome_flood is the variable to store the current state of the flood in (but you might better think about it as the flood's id).
+
Where "1,1;2,3" is a semicolon separated list of coordinate pairs from which the flood starts, "ne,n" is a comma separated list of directions in which the flood will spread, "Gg>Ww;Gs>Wwt" is a semicolon separated list of transformations where a>b means that the hexes with the terrain code a will be converted to b, and finally awesome_flood is the variable that stores the current state of the flood (you might better think about it as the flood's id).
  
To spread a flood by one hex:
+
=== Spread flood ===
 
  {SPREAD_FLOOD awesome_flood}
 
  {SPREAD_FLOOD awesome_flood}
Where awesome_flood is the flood's id :)
+
Where awesome_flood is the flood's id :). This will spread the flood by one hex. If a hex with a unit is flooded, an event named 'submerged' will be fired. Example
 +
#kill all sunken spearmen
 +
[event]
 +
  name=submerged
 +
  [filter]
 +
    type=Spearman
 +
  [/filter]
 +
 +
  [kill]
 +
    id=$unit.id
 +
    animate=yes
 +
  [/kill]
 +
[/event]
  
To modify a flood's data:
+
=== Modify flood data ===
 
  {SET_FLOOD_DIRECTIONS "se,s" awesome_flood}
 
  {SET_FLOOD_DIRECTIONS "se,s" awesome_flood}
 
  {SET_FLOOD_TERRAIN_TABLE "Gg>Wwg;Gs>Ww" awesome_flood}
 
  {SET_FLOOD_TERRAIN_TABLE "Gg>Wwg;Gs>Ww" awesome_flood}
 
  {SET_FLOOD_SOURCE "3,3;5,4;6,6" awesome_flood}
 
  {SET_FLOOD_SOURCE "3,3;5,4;6,6" awesome_flood}
One note: all of these macros replace current data in awesome_flood, so old information is lost. This is especially important for SET_FLOOD_SOURCE because that alters the list of hexes which are currently form the first wave of the flood. So if you call it, the original flood will stop and a new one will start from "3,3;5,4;6,6" or whatever you specify.
+
Note: all of these macros replace current data in awesome_flood, so old information is lost. This is especially important for SET_FLOOD_SOURCE because it alters the list of current hexes from the first wave of the flood. When you call it, the original flood will stop and a new one will start from "3,3;5,4;6,6" or whatever you specify.
  
 
== Optimization ==
 
== Optimization ==
  
 
=== When to do it? ===
 
=== When to do it? ===
The part consuming up most of the macro's run time is choosing the appropriate terrain type to convert the original to. If you have a wide-spreading flood, this will have to be done for many hexes. Conclusively, if you have a big flood with a big terrain table, it's likely that you'll have to optimize it.
+
The part consuming most of the macro's run time is choosing the appropriate terrain type to convert. If you have a wide-spreading flood, this will have to be done for many hexes. Consequently, if you have a big flood with a big terrain table, it's likely that you'll have to optimize it.
  
 
=== Ranking terrain codes ===
 
=== Ranking terrain codes ===
When searching for the matching terrain code for a specific hex, the algorithm will iterate through the terrain table's elements in the order you gave them, and quits the iteration when the appropriate string is found. If you put the more often terrains to the front, you can achieve radical performance improvements.
+
When searching for the matching terrain code for a specific hex, the algorithm will iterate through the terrain table's elements in the order you give them, and quit the iteration when the appropriate string is found. If you put the more abundant terrains to the front, you can achieve radical performance improvements.
  
 
=== Switching terrain table ===
 
=== Switching terrain table ===
Sometimes it's hard decide which code to put first because different ones are common in the different stages of the flood. For example, an avalanche starts at a mountain, where there are mostly hills, but it reaches the plains where it founds more of flat terrain. In this case, it's the best to completely replace the terrain table with the SET_FLOOD_TERRAIN_TABLE macro, so you can give higher rankings to the new common terrains.
+
Sometimes it's hard to decide which code to put first because different ones are common in different stages of the flood. For example, an avalanche starts at a mountain, where there are mostly hills, but it reaches the plains where it finds more flat terrain. In this case, it's best to completely replace the terrain table with the SET_FLOOD_TERRAIN_TABLE macro, so you can give higher rankings to the new common terrains.
  
 
== Tips & Tricks ==
 
== Tips & Tricks ==
  
 
=== Two-wave flood ===
 
=== Two-wave flood ===
It's not unimaginable that you want to make your flood heterogeneous - for example, shallow water on the edges and deep water in the middle. You can't do this with one flood - but you can with two! You set up the first one just as normal, and the second one in a way that that it converts shallow water to deep (in this example). You start to spread the second with a delay so that the first wave will be ahead.
+
It's not unimaginable that you want to make your flood heterogeneous - for example, shallow water on the edges and deep water in the middle. You can't do this with one flood - but you can with two! You set up the first one just as normal, and the second one in a way that it converts shallow water to deep (in this example). You start to spread the second with a delay so the first wave will remain ahead.
  
 
=== Avoiding obstacles ===
 
=== Avoiding obstacles ===
Imagine that you have a little stream which spreads straight to south and can transform green grass to shallow water. So what does happen if it accidentally meets a mountain? It stops. Well, we don't want that - but neither to convert the mountain to anything else. So we can add this to the terrain table:
+
Imagine you have a little stream which spreads straight south and can transform green grass to shallow water. So what happens if it accidentally meets a mountain? It stops. Well, we don't want that - but neither do we want to convert the mountain to anything else. So we can add to the terrain table:
 
  Mm>Mm
 
  Mm>Mm
This won't change the mountains type (more precisely, it will be changed from Mm to Mm), but the flood won't regard it as an obstacle anymore. Our example stream will continue on the other side of the mountain hex.
+
This won't change the mountain's type (more precisely, it will be changed from Mm to Mm), and the flood won't regard it as an obstacle anymore. Our stream will continue flowing on the other side of the mountain hex.
  
 
== Source Code ==
 
== Source Code ==
+
 
 
  #define INVERT_DIRECTIONS DIRECTIONS OUT_VAR
 
  #define INVERT_DIRECTIONS DIRECTIONS OUT_VAR
#a macro to change directions to their opposites (n->s, sw->ne, etc)
+
    #a macro to change directions to their opposites (n->s, sw->ne, etc)
#DIRECTIONS is a comma-separated list of directions
+
    #DIRECTIONS is a comma-separated list of directions
#OUT_VAR is the variable to write the output in. Output is an array
+
    #OUT_VAR is the variable to write the output in.
#which contains the inverted directions in the order they were given
 
#in DIRECTIONS. The values are stores in the 'direction' key.
 
 
   
 
   
 
  [set_variables]
 
  [set_variables]
 +
    name=TMP_inverted_directions
 +
    [split]
 +
      list={DIRECTIONS}
 +
      separator=","
 +
      key=direction
 +
      remove_empty=yes
 +
    [/split]
 +
[/set_variables]
 +
 +
{FOREACH TMP_inverted_directions TMP_ID_i}
 +
        [set_variable]
 +
                name=TMP_inverted_directions[$TMP_ID_i].direction
 +
                value="-" + $TMP_inverted_directions[$TMP_ID_i].direction
 +
        [/set_variable]
 +
{NEXT TMP_ID_i}
 +
 +
{CLEAR_VARIABLE {OUT_VAR}}
 +
 +
[set_variable]
 
  name={OUT_VAR}
 
  name={OUT_VAR}
  [split]
+
  [join]
  list={DIRECTIONS}
+
  variable=TMP_inverted_directions
 
  separator=","
 
  separator=","
 
  key=direction
 
  key=direction
remove_empty=yes
+
  [/join]
  [/split]
+
  [/set_variable]
[/set_variables]
 
   
 
{FOREACH {OUT_VAR} TMP_ID_i}
 
[if]
 
[variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
equals="n"
 
[/variable]
 
[then]
 
[set_variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
value="s"
 
[/set_variable]
 
[/then]
 
[else]
 
[if]
 
[variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
equals="s"
 
[/variable]
 
[then]
 
[set_variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
value="n"
 
[/set_variable]
 
[/then]
 
[else]
 
[if]
 
[variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
equals="se"
 
[/variable]
 
[then]
 
[set_variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
value="nw"
 
[/set_variable]
 
[/then]
 
[else]
 
[if]
 
[variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
equals="nw"
 
[/variable]
 
[then]
 
[set_variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
value="se"
 
[/set_variable]
 
[/then]
 
[else]
 
[if]
 
[variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
equals="ne"
 
[/variable]
 
[then]
 
[set_variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
value="sw"
 
[/set_variable]
 
[/then]
 
[else]
 
[if]
 
[variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
equals="sw"
 
[/variable]
 
[then]
 
[set_variable]
 
name={OUT_VAR}[$TMP_ID_i].direction
 
value="ne"
 
[/set_variable]
 
[/then]
 
[/if]
 
[/else]
 
[/if]
 
[/else]
 
[/if]
 
[/else]
 
[/if]
 
[/else]
 
[/if]
 
[/else]
 
[/if]
 
{NEXT TMP_ID_i}
 
 
   
 
   
 +
{CLEAR_VARIABLE TMP_inverted_directions}
 
  #enddef
 
  #enddef
 
   
 
   
  #define STORE_FLOODABLE_LOCATIONS SOURCE_X SOURCE_Y DIRECTIONS TERRAINS OUT_VAR
+
  #define STORE_FLOODABLE_LOCATIONS SOURCE DIRECTIONS TERRAINS OUT_VAR
#stores hexes of type TERRAINS whose neighbour in one of DIRECTIONS directions is one of SOURCE_X ; SOURCE_Y
+
    #stores hexes of type TERRAINS whose neighbour in one of DIRECTIONS directions can be found in SOURCE
#SOURCE_X & SOURCE_Y comma-separated list of coordinates
+
    #SOURCE an array of locations
#DIRECTIONS an array of directions, values stored in the 'direction' key (same as the output format of INVERT_DIRECTIONS)
+
    #DIRECTIONS is a list of directions
#TERRAINS comma-separated list of terrain codes
+
    #TERRAINS comma-separated list of terrain codes
#OUT_VAR the variable to write the output in
+
    #OUT_VAR the variable to write the output in
#
+
    #
#NOTE: this macro is in fact used to store the hexes of type TERRAINS which are neighbours of SOURCE_X ; SOURCE_Y in
+
    #NOTE: this macro is in fact used to store the hexes of type TERRAINS which are neighbours of SOURCE in
#certain directions, but we achieve that by inverting those directions outside of this macro. See INVERT_DIRECTIONS.
+
    #certain directions, but we achieve that by inverting those directions outside of this macro. See INVERT_DIRECTIONS.
 
   
 
   
 
  [store_locations]
 
  [store_locations]
variable={OUT_VAR}
+
    variable={OUT_VAR}
 
   
 
   
terrain={TERRAINS}
+
    terrain={TERRAINS}
 
[filter_adjacent_location]
 
adjacent=${DIRECTIONS}[0].direction
 
x={SOURCE_X}
 
y={SOURCE_Y}
 
[/filter_adjacent_location]
 
[or]
 
terrain={TERRAINS}
 
 
[filter_adjacent_location]
 
adjacent=${DIRECTIONS}[1].direction
 
x={SOURCE_X}
 
y={SOURCE_Y}
 
[/filter_adjacent_location]
 
[or]
 
terrain={TERRAINS}
 
 
[filter_adjacent_location]
 
adjacent=${DIRECTIONS}[2].direction
 
x={SOURCE_X}
 
y={SOURCE_Y}
 
[/filter_adjacent_location]
 
[or]
 
terrain={TERRAINS}
 
 
[filter_adjacent_location]
 
adjacent=${DIRECTIONS}[3].direction
 
x={SOURCE_X}
 
y={SOURCE_Y}
 
[/filter_adjacent_location]
 
[or]
 
terrain={TERRAINS}
 
 
[filter_adjacent_location]
 
adjacent=${DIRECTIONS}[4].direction
 
x={SOURCE_X}
 
y={SOURCE_Y}
 
[/filter_adjacent_location]
 
[or]
 
terrain={TERRAINS}
 
 
[filter_adjacent_location]
 
adjacent=${DIRECTIONS}[5].direction
 
x={SOURCE_X}
 
y={SOURCE_Y}
 
[/filter_adjacent_location]
 
[/or]
 
[/or]
 
[/or]
 
[/or]
 
[/or]
 
 
   
 
   
 +
    [filter_adjacent_location]
 +
      adjacent={DIRECTIONS}
 +
  find_in={SOURCE}
 +
    [/filter_adjacent_location]
 
  [/store_locations]
 
  [/store_locations]
 
  #enddef
 
  #enddef
Line 216: Line 116:
 
  #define SPLIT_PAIRS PAIRS SEP1 SEP2 OUT_VAR
 
  #define SPLIT_PAIRS PAIRS SEP1 SEP2 OUT_VAR
 
  [set_variables]
 
  [set_variables]
name=TMP_pairs
+
    name=TMP_pairs
[split]
+
    [split]
list={PAIRS}
+
      list={PAIRS}
key=pair
+
      key=pair
separator={SEP1}
+
      separator={SEP1}
remove_empty=true
+
      remove_empty=true
[/split]
+
    [/split]
 
  [/set_variables]
 
  [/set_variables]
 
   
 
   
 
  {FOREACH TMP_pairs TMP_SP_i}
 
  {FOREACH TMP_pairs TMP_SP_i}
[set_variables]
+
    [set_variables]
name=TMP_splitted
+
      name=TMP_splitted
[split]
+
      [split]
list=$TMP_pairs[$TMP_SP_i].pair
+
          list=$TMP_pairs[$TMP_SP_i].pair
separator={SEP2}
+
          separator={SEP2}
key=value
+
          key=value
[/split]
+
      [/split]
[/set_variables]
+
    [/set_variables]
 
   
 
   
[set_variable]
+
    [set_variable]
name={OUT_VAR}[$TMP_SP_i].value1
+
      name={OUT_VAR}[$TMP_SP_i].value1
value=$TMP_splitted[0].value
+
      value=$TMP_splitted[0].value
[/set_variable]
+
    [/set_variable]
[set_variable]
+
    [set_variable]
name={OUT_VAR}[$TMP_SP_i].value2
+
      name={OUT_VAR}[$TMP_SP_i].value2
value=$TMP_splitted[1].value
+
      value=$TMP_splitted[1].value
[/set_variable]
+
    [/set_variable]
 
  {NEXT TMP_SP_i}
 
  {NEXT TMP_SP_i}
 
   
 
   
Line 251: Line 151:
 
  #define FLOOD_SINGLE_HEX X Y TERRAIN_TABLE
 
  #define FLOOD_SINGLE_HEX X Y TERRAIN_TABLE
 
  [store_locations]
 
  [store_locations]
variable=TMP_current_hex
+
    variable=TMP_current_hex
x={X}
+
    x={X}
y={Y}
+
    y={Y}
 
  [/store_locations]
 
  [/store_locations]
 
   
 
   
 
  {FOREACH {TERRAIN_TABLE} FSH_i}
 
  {FOREACH {TERRAIN_TABLE} FSH_i}
[if]
+
    [if]
[variable]
+
      [variable]
name=TMP_current_hex.terrain
+
          name=TMP_current_hex.terrain
equals=${TERRAIN_TABLE}[$FSH_i].value1
+
          equals=${TERRAIN_TABLE}[$FSH_i].value1
[/variable]
+
      [/variable]
[then]
+
      [then]
{MODIFY_TERRAIN ${TERRAIN_TABLE}[$FSH_i].value2 {X} {Y}}
+
          {MODIFY_TERRAIN ${TERRAIN_TABLE}[$FSH_i].value2 {X} {Y}}
[set_variable]
+
          [set_variable]
name=FSH_i
+
            name=FSH_i
value=${TERRAIN_TABLE}.length
+
            value=${TERRAIN_TABLE}.length
[/set_variable]
+
          [/set_variable]
[/then]
+
      [/then]
[/if]
+
    [/if]
 
  {NEXT FSH_i}
 
  {NEXT FSH_i}
 
   
 
   
Line 279: Line 179:
 
  {SPLIT_PAIRS {TERRAIN_TABLE} ";" ">" {DATA_VAR}.terrain_table}
 
  {SPLIT_PAIRS {TERRAIN_TABLE} ";" ">" {DATA_VAR}.terrain_table}
 
  [set_variable]
 
  [set_variable]
name={DATA_VAR}.floodable_terrains
+
    name={DATA_VAR}.floodable_terrains
[join]
+
    [join]
variable={DATA_VAR}.terrain_table
+
      variable={DATA_VAR}.terrain_table
separator=","
+
      separator=","
key=value1
+
      key=value1
[/join]
+
    [/join]
 
  [/set_variable]
 
  [/set_variable]
 
  #enddef
 
  #enddef
Line 295: Line 195:
 
  {SPLIT_PAIRS {SOURCE} ";" "," TMP_source_coordinates}
 
  {SPLIT_PAIRS {SOURCE} ";" "," TMP_source_coordinates}
 
  [set_variable]
 
  [set_variable]
name={DATA_VAR}.fields_x
+
    name=TMP_fields_x
[join]
+
    [join]
variable=TMP_source_coordinates
+
      variable=TMP_source_coordinates
key=value1
+
      key=value1
separator=","
+
      separator=","
[/join]
+
    [/join]
 
  [/set_variable]
 
  [/set_variable]
 
  [set_variable]
 
  [set_variable]
name={DATA_VAR}.fields_y
+
    name=TMP_fields_y
[join]
+
    [join]
variable=TMP_source_coordinates
+
      variable=TMP_source_coordinates
key=value2
+
      key=value2
separator=","
+
      separator=","
[/join]
+
    [/join]
 
  [/set_variable]
 
  [/set_variable]
 +
 +
[store_locations]
 +
variable={DATA_VAR}.fields
 +
x=$TMP_fields_x
 +
y=$TMP_fields_y
 +
[/store_locations]
 
  #enddef
 
  #enddef
 
   
 
   
 
  #define CREATE_FLOOD SOURCE DIRECTIONS TERRAIN_TABLE DATA_VAR
 
  #define CREATE_FLOOD SOURCE DIRECTIONS TERRAIN_TABLE DATA_VAR
 
  [clear_variable]
 
  [clear_variable]
name={DATA_VAR}
+
    name={DATA_VAR}
 
  [/clear_variable]
 
  [/clear_variable]
 
   
 
   
Line 323: Line 229:
 
   
 
   
 
  #define SPREAD_FLOOD DATA_VAR
 
  #define SPREAD_FLOOD DATA_VAR
  {STORE_FLOODABLE_LOCATIONS ${DATA_VAR}.fields_x ${DATA_VAR}.fields_y {DATA_VAR}.directions ${DATA_VAR}.floodable_terrains TMP_floodable}
+
  {STORE_FLOODABLE_LOCATIONS {DATA_VAR}.fields ${DATA_VAR}.directions ${DATA_VAR}.floodable_terrains {DATA_VAR}.fields}
 
   
 
   
  {FOREACH TMP_floodable TMP_SF_i}
+
  {FOREACH {DATA_VAR}.fields TMP_SF_i}
{FLOOD_SINGLE_HEX $TMP_floodable[$TMP_SF_i].x $TMP_floodable[$TMP_SF_i].y {DATA_VAR}.terrain_table}
+
    {FLOOD_SINGLE_HEX ${DATA_VAR}.fields[$TMP_SF_i].x ${DATA_VAR}.fields[$TMP_SF_i].y {DATA_VAR}.terrain_table}
 
  {NEXT TMP_SF_i}
 
  {NEXT TMP_SF_i}
 
  [redraw][/redraw]
 
  [redraw][/redraw]
 
   
 
   
  [set_variable]
+
  [store_unit]
  name={DATA_VAR}.fields_x
+
  variable=TMP_submerged_units
  [join]
+
  [filter]
  variable=TMP_floodable
+
  [filter_location]
key=x
+
find_in={DATA_VAR}.fields
  separator=","
+
  [/filter_location]
  [/join]
+
  [/filter]
  [/set_variable]
+
  [/store_unit]
  [set_variable]
+
   
name={DATA_VAR}.fields_y
+
{FOREACH TMP_submerged_units TMP_SF_i}
  [join]
+
  [fire_event]
  variable=TMP_floodable
+
  [primary_unit]
  key=y
+
id=$TMP_submerged_units[$TMP_SF_i].id
  separator=","
+
  [/primary_unit]
  [/join]
+
  name=submerged
  [/set_variable]
+
  [/fire_event]
 +
  {NEXT TMP_SF_i}
 +
 +
{CLEAR_VARIABLE TMP_submerged_units}
 +
 
  #enddef
 
  #enddef
 +
 +
== See Also ==
 +
* [[UsefulWMLFragments]]
 +
* [[ReferenceWML]]
 +
 +
 +
[[Category: UsefulWMLFragments]]

Latest revision as of 03:15, 11 April 2013

FloodWML works for 1.9 and above

Usage

You can find sources at the bottom of the page. It's too long to include here.

NOTE: these macros are performing lots of complex calculations thus they are quite slow. They can make your scenario lag and thus create an unwelcome user experience, especially on older machines. To make sure you've minimized the negative effects, please read the Optimization section below.

Create flood

{CREATE_FLOOD "1,1;2,3" "ne,n" "Gg>Ww;Gs>Wwt" awesome_flood}

Where "1,1;2,3" is a semicolon separated list of coordinate pairs from which the flood starts, "ne,n" is a comma separated list of directions in which the flood will spread, "Gg>Ww;Gs>Wwt" is a semicolon separated list of transformations where a>b means that the hexes with the terrain code a will be converted to b, and finally awesome_flood is the variable that stores the current state of the flood (you might better think about it as the flood's id).

Spread flood

{SPREAD_FLOOD awesome_flood}

Where awesome_flood is the flood's id :). This will spread the flood by one hex. If a hex with a unit is flooded, an event named 'submerged' will be fired. Example

#kill all sunken spearmen
[event]
  name=submerged
  [filter]
    type=Spearman
  [/filter]

  [kill]
    id=$unit.id
    animate=yes
  [/kill]
[/event]

Modify flood data

{SET_FLOOD_DIRECTIONS "se,s" awesome_flood}
{SET_FLOOD_TERRAIN_TABLE "Gg>Wwg;Gs>Ww" awesome_flood}
{SET_FLOOD_SOURCE "3,3;5,4;6,6" awesome_flood}

Note: all of these macros replace current data in awesome_flood, so old information is lost. This is especially important for SET_FLOOD_SOURCE because it alters the list of current hexes from the first wave of the flood. When you call it, the original flood will stop and a new one will start from "3,3;5,4;6,6" or whatever you specify.

Optimization

When to do it?

The part consuming most of the macro's run time is choosing the appropriate terrain type to convert. If you have a wide-spreading flood, this will have to be done for many hexes. Consequently, if you have a big flood with a big terrain table, it's likely that you'll have to optimize it.

Ranking terrain codes

When searching for the matching terrain code for a specific hex, the algorithm will iterate through the terrain table's elements in the order you give them, and quit the iteration when the appropriate string is found. If you put the more abundant terrains to the front, you can achieve radical performance improvements.

Switching terrain table

Sometimes it's hard to decide which code to put first because different ones are common in different stages of the flood. For example, an avalanche starts at a mountain, where there are mostly hills, but it reaches the plains where it finds more flat terrain. In this case, it's best to completely replace the terrain table with the SET_FLOOD_TERRAIN_TABLE macro, so you can give higher rankings to the new common terrains.

Tips & Tricks

Two-wave flood

It's not unimaginable that you want to make your flood heterogeneous - for example, shallow water on the edges and deep water in the middle. You can't do this with one flood - but you can with two! You set up the first one just as normal, and the second one in a way that it converts shallow water to deep (in this example). You start to spread the second with a delay so the first wave will remain ahead.

Avoiding obstacles

Imagine you have a little stream which spreads straight south and can transform green grass to shallow water. So what happens if it accidentally meets a mountain? It stops. Well, we don't want that - but neither do we want to convert the mountain to anything else. So we can add to the terrain table:

Mm>Mm

This won't change the mountain's type (more precisely, it will be changed from Mm to Mm), and the flood won't regard it as an obstacle anymore. Our stream will continue flowing on the other side of the mountain hex.

Source Code

#define INVERT_DIRECTIONS DIRECTIONS OUT_VAR
   #a macro to change directions to their opposites (n->s, sw->ne, etc)
   #DIRECTIONS is a comma-separated list of directions
   #OUT_VAR is the variable to write the output in.

[set_variables]
   name=TMP_inverted_directions
   [split]
      list={DIRECTIONS}
      separator=","
      key=direction
      remove_empty=yes
   [/split]
[/set_variables]

{FOREACH TMP_inverted_directions TMP_ID_i}
        [set_variable]
                name=TMP_inverted_directions[$TMP_ID_i].direction
                value="-" + $TMP_inverted_directions[$TMP_ID_i].direction
        [/set_variable]
{NEXT TMP_ID_i}

{CLEAR_VARIABLE {OUT_VAR}}

[set_variable]
	name={OUT_VAR}
	[join]
		variable=TMP_inverted_directions
		separator=","
		key=direction
	[/join]
[/set_variable]

{CLEAR_VARIABLE TMP_inverted_directions}
#enddef

#define STORE_FLOODABLE_LOCATIONS SOURCE DIRECTIONS TERRAINS OUT_VAR
   #stores hexes of type TERRAINS whose neighbour in one of DIRECTIONS directions can be found in SOURCE
   #SOURCE an array of locations
   #DIRECTIONS is a list of directions
   #TERRAINS comma-separated list of terrain codes
   #OUT_VAR the variable to write the output in
   #
   #NOTE: this macro is in fact used to store the hexes of type TERRAINS which are neighbours of SOURCE in
   #certain directions, but we achieve that by inverting those directions outside of this macro. See INVERT_DIRECTIONS.

[store_locations]
   variable={OUT_VAR}

   terrain={TERRAINS}

   [filter_adjacent_location]
      adjacent={DIRECTIONS}
	  find_in={SOURCE}
   [/filter_adjacent_location]
[/store_locations]
#enddef


#define SPLIT_PAIRS PAIRS SEP1 SEP2 OUT_VAR
[set_variables]
   name=TMP_pairs
   [split]
      list={PAIRS}
      key=pair
      separator={SEP1}
      remove_empty=true
   [/split]
[/set_variables]

{FOREACH TMP_pairs TMP_SP_i}
   [set_variables]
      name=TMP_splitted
      [split]
         list=$TMP_pairs[$TMP_SP_i].pair
         separator={SEP2}
         key=value
      [/split]
   [/set_variables]

   [set_variable]
      name={OUT_VAR}[$TMP_SP_i].value1
      value=$TMP_splitted[0].value
   [/set_variable]
   [set_variable]
      name={OUT_VAR}[$TMP_SP_i].value2
      value=$TMP_splitted[1].value
   [/set_variable]
{NEXT TMP_SP_i}

{CLEAR_VARIABLE TMP_pairs}
{CLEAR_VARIABLE TMP_splitted}
#enddef

#define FLOOD_SINGLE_HEX X Y TERRAIN_TABLE
[store_locations]
   variable=TMP_current_hex
   x={X}
   y={Y}
[/store_locations]

{FOREACH {TERRAIN_TABLE} FSH_i}
   [if]
      [variable]
         name=TMP_current_hex.terrain
         equals=${TERRAIN_TABLE}[$FSH_i].value1
      [/variable]
      [then]
         {MODIFY_TERRAIN ${TERRAIN_TABLE}[$FSH_i].value2 {X} {Y}}
         [set_variable]
            name=FSH_i
            value=${TERRAIN_TABLE}.length
         [/set_variable]
      [/then]
   [/if]
{NEXT FSH_i}


{CLEAR_VARIABLE TMP_current_hex}
#enddef

#define SET_FLOOD_TERRAIN_TABLE TERRAIN_TABLE DATA_VAR
{SPLIT_PAIRS {TERRAIN_TABLE} ";" ">" {DATA_VAR}.terrain_table}
[set_variable]
   name={DATA_VAR}.floodable_terrains
   [join]
      variable={DATA_VAR}.terrain_table
      separator=","
      key=value1
   [/join]
[/set_variable]
#enddef

#define SET_FLOOD_DIRECTIONS DIRECTIONS DATA_VAR
{INVERT_DIRECTIONS {DIRECTIONS} {DATA_VAR}.directions}
#enddef

#define SET_FLOOD_SOURCE SOURCE DATA_VAR
{SPLIT_PAIRS {SOURCE} ";" "," TMP_source_coordinates}
[set_variable]
   name=TMP_fields_x
   [join]
      variable=TMP_source_coordinates
      key=value1
      separator=","
   [/join]
[/set_variable]
[set_variable]
   name=TMP_fields_y
   [join]
      variable=TMP_source_coordinates
      key=value2
      separator=","
   [/join]
[/set_variable]

[store_locations]
	variable={DATA_VAR}.fields
	x=$TMP_fields_x
	y=$TMP_fields_y
[/store_locations]
#enddef

#define CREATE_FLOOD SOURCE DIRECTIONS TERRAIN_TABLE DATA_VAR
[clear_variable]
   name={DATA_VAR}
[/clear_variable]

{SET_FLOOD_SOURCE {SOURCE} {DATA_VAR}}
{SET_FLOOD_TERRAIN_TABLE {TERRAIN_TABLE} {DATA_VAR}}
{SET_FLOOD_DIRECTIONS {DIRECTIONS} {DATA_VAR}}
#enddef

#define SPREAD_FLOOD DATA_VAR
{STORE_FLOODABLE_LOCATIONS {DATA_VAR}.fields ${DATA_VAR}.directions ${DATA_VAR}.floodable_terrains {DATA_VAR}.fields}

{FOREACH {DATA_VAR}.fields TMP_SF_i}
   {FLOOD_SINGLE_HEX ${DATA_VAR}.fields[$TMP_SF_i].x ${DATA_VAR}.fields[$TMP_SF_i].y {DATA_VAR}.terrain_table}
{NEXT TMP_SF_i}
[redraw][/redraw]

[store_unit]
	variable=TMP_submerged_units
	[filter]
		[filter_location]
			find_in={DATA_VAR}.fields
		[/filter_location]
	[/filter]
[/store_unit]

{FOREACH TMP_submerged_units TMP_SF_i}
	[fire_event]
		[primary_unit]
			id=$TMP_submerged_units[$TMP_SF_i].id
		[/primary_unit]
		name=submerged
	[/fire_event]
{NEXT TMP_SF_i}

{CLEAR_VARIABLE TMP_submerged_units}

#enddef

See Also

This page was last edited on 11 April 2013, at 03:15.