FloodWML
Usage
You can find sources at the bottom of the page. It's too long to include it here.
To create a 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).
To spread a flood by one hex:
{SPREAD_FLOOD awesome_flood}
Where awesome_flood is the flood's id :)
To modify a flood's 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}
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.
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. Output is an array
#which contains the inverted directions in the order they were given
#in DIRECTIONS. The values are stores in the 'direction' key.
[set_variables]
name={OUT_VAR}
[split]
list={DIRECTIONS}
separator=","
key=direction
remove_empty=yes
[/split]
[/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}
#enddef
#define STORE_FLOODABLE_LOCATIONS SOURCE_X SOURCE_Y DIRECTIONS TERRAINS OUT_VAR
#stores hexes of type TERRAINS whose neighbour in one of DIRECTIONS directions is one of SOURCE_X ; SOURCE_Y
#SOURCE_X & SOURCE_Y comma-separated list of coordinates
#DIRECTIONS an array of directions, values stored in the 'direction' key (same as the output format of INVERT_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_X ; SOURCE_Y 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}[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]
[/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={DATA_VAR}.fields_x
[join]
variable=TMP_source_coordinates
key=value1
separator=","
[/join]
[/set_variable]
[set_variable]
name={DATA_VAR}.fields_y
[join]
variable=TMP_source_coordinates
key=value2
separator=","
[/join]
[/set_variable]
#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_x ${DATA_VAR}.fields_y {DATA_VAR}.directions ${DATA_VAR}.floodable_terrains TMP_floodable}
{FOREACH TMP_floodable TMP_SF_i}
{FLOOD_SINGLE_HEX $TMP_floodable[$TMP_SF_i].x $TMP_floodable[$TMP_SF_i].y {DATA_VAR}.terrain_table}
{NEXT TMP_SF_i}
[redraw][/redraw]
[set_variable]
name={DATA_VAR}.fields_x
[join]
variable=TMP_floodable
key=x
separator=","
[/join]
[/set_variable]
[set_variable]
name={DATA_VAR}.fields_y
[join]
variable=TMP_floodable
key=y
separator=","
[/join]
[/set_variable]
#enddef