If you have other simple solutions, please feel free to post them in this topic.
This "continent map generator" is a bash script ( created and tested on a Mac. ) Copy the code from this post, or download the attached zip file and decompress it.
Also attached is a functional Freeciv 2.6.4 or later Scenario file including this generated map.
The script uses a simple process to create the map, and it's best shown in the pictures below.
The map starts out as a field of random characters which represent land tiles in Freeciv. Then the horizontal and vertical ocean areas ( the white spaces between and around the rectangles) are imposed. By the way, text characters are usually taller than they are wide, which results in a vertical stretching of what the final map will look like in Freeciv, if using square tiles at least.
The script loops through the map multiple times, top-to-bottom and bottom-to-top, selecting land tiles near ocean ( the white spaces ) to become ocean.
Next is the result of loop 2. If you like big clunky continents, you can change the # in the script to stop at loop 2 or 3.
Below is loop 3's output.
And finally, below loop 4 has finished and I like the continents.
The last step in the script is to add the proper formatting for this map to be used in a Freeciv scenario ".sav" file.
Below is the text of the final map in Freeciv scenario [map] layer format.
Code: Select all
t0000=" "
t0001=" "
t0002=" "
t0003=" g "
t0004=" ggg hgg "
t0005=" gp ggfghmhph "
t0006=" fp pfpfg hg hggpmphph "
t0007=" h p hpggpg phgp hhmgfffphgfm "
t0008=" hmg p gpphgmp fggg pggffgfpfgpf "
t0009=" fgp ghgppphg hfmggg gfgggggpgff "
t0010=" fgf hggghffhg hfgpgghpffpmggf "
t0011=" ggmggh p f fphfgpfpfhppfgp "
t0012=" fp hp gm h hg hgpgg "
t0013=" m g hf f fg "
t0014=" pf "
t0015=" "
t0016=" "
t0017=" "
t0018=" "
t0019=" "
t0020=" "
t0021=" "
t0022=" gf gg f "
t0023=" fgggh gpfg pffg hm p "
t0024=" hfhghghhhgfggfh h h gpp ggh g "
t0025=" mhhhfmfgphpmpghg pggp gmfgg pgpf "
t0026=" phgpfhfhph fgg fhfppp fpfgh gff "
t0027=" hhggpffhpfg ghpg gppf ffpfhg gmp "
t0028=" g gfghfphggh mpfmh hgpppgmpmgf p g "
t0029=" m phh pgh gppp gffpffgf gfpm gp "
t0030=" hf ggpf h fggppfhg g h "
t0031=" f fp p "
t0032=" "
t0033=" "
t0034=" "
t0035=" "
^ Here's a screenshot of that upper-right island in Freeciv 2.6.4 with Amplio 2 (square) tile graphics.
^ And a close-up of the minimap.
^ This picture shows the top of the Freeciv scenario ".sav" file content.
^ And here I had just pasted the new map over the old map in the scenario. Both the old and new maps are 66 x 36 tiles ( you can change the size in the script very easily) so a simple cut-and-paste of the new map over the old map is fine* and after saving the scenario file, it's ready to play.
* = Because none of the other layers has any features at all, no river, no roads, etc.
And finally, below is the full text of the bash script that generated the map.
Code: Select all
#!/usr/bin/env bash
# This line is a comment, the line at the top is not.
# map generator ContinentGen Bash script.sh v1.8
# Declare variables
declare zeroPad="0000" tile test
declare -a terrain_layer terrain_layer_B
declare -i x y c=0 r blanklines maxgap=12
# The map size is determined by the xsize and ysize variables on the next line
declare -i xsize=120 ysize=60
# The # of rectangles is set in the variable rectangles, below.
# Valid values are 1, 2, -2, 4, 6, -6, 8, -8, 9, and 16.
# 2 gives 2 vertical continents, -2 gives 2 horizontal, similar for 6, -6, and 8, -8
declare -i rectangles=8
# maxgap controls how many contiguous blank horizontal lines
# are allowed in the map before looping stops.
# The map dimensions also effect the shape and size of each continent.
if [ ${rectangles} -eq 1 ] ; then
maxgap=12
elif [ ${rectangles} -eq 2 ] ; then
maxgap=10
elif [ ${rectangles} -eq -2 ] ; then
maxgap=10
elif [ ${rectangles} -eq 4 ] ; then
maxgap=10
elif [ ${rectangles} -eq 6 ] ; then
maxgap=10
elif [ ${rectangles} -eq 8 ] ; then
maxgap=7
elif [ ${rectangles} -eq -8 ] ; then
maxgap=7
elif [ ${rectangles} -eq 9 ] ; then
maxgap=12
elif [ ${rectangles} -eq 16 ] ; then
maxgap=12
fi
# Ouput a blank line
echo
# Create terrain layer
for (( y=0 ; y<${ysize} ; y++ )) ; do
for (( x=0 ; x<${xsize} ; x++ )) ; do
r=$(( 1 + RANDOM % 19 ))
# No lake tiles, add them later
if [ ${r} -ge 1 ] && [ ${r} -le 5 ] ; then tile="g" ; fi
if [ ${r} -ge 6 ] && [ ${r} -le 9 ] ; then tile="p" ; fi
if [ ${r} -ge 10 ] && [ ${r} -le 12 ] ; then tile="h" ; fi
if [ ${r} -ge 13 ] && [ ${r} -le 15 ] ; then tile="f" ; fi
if [ ${r} -eq 16 ] ; then tile="m" ; fi
if [ ${r} -eq 17 ] ; then tile="d" ; fi
if [ ${r} -eq 18 ] ; then tile="j" ; fi
if [ ${r} -eq 19 ] ; then tile="s" ; fi
if [ ${rectangles} -eq 1 ] ; then
# No divisions, 1 supercontinent
:
elif [ ${rectangles} -eq 2 ] ; then
# 1 row of ocean vertical middle centerline
if [ ${x} -eq $(( ${xsize} / 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq -2 ] ; then
# 1 row of ocean horizontal middle centerline
if [ ${y} -eq $(( ${ysize} / 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq 4 ] ; then
# 1 column of ocean vertical middle centerine
if [ ${x} -eq $(( ${xsize} / 2 )) ] ; then tile=" " ; fi
# 1 row of ocean horizontal middle centerline
if [ ${y} -eq $(( ${ysize} / 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq 6 ] ; then
# 2 columns of ocean vertical
if [ ${x} -eq $(( ${xsize} / 3 )) ] ; then tile=" " ; fi
if [ ${x} -eq $(( ${xsize} / 3 * 2 )) ] ; then tile=" " ; fi
# 1 row of ocean horizontal middle centerline
if [ ${y} -eq $(( ${ysize} / 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq -6 ] ; then
# 1 column of ocean vertical
if [ ${x} -eq $(( ${xsize} / 2 )) ] ; then tile=" " ; fi
# 2 rows of ocean horizontal
if [ ${y} -eq $(( ${ysize} / 3 )) ] ; then tile=" " ; fi
if [ ${y} -eq $(( ${ysize} / 3 * 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq 8 ] ; then
# 3 columns of ocean vertical
if [ ${x} -eq $(( ${xsize} / 4 )) ] ; then tile=" " ; fi
if [ ${x} -eq $(( ${xsize} / 4 * 2 )) ] ; then tile=" " ; fi
if [ ${x} -eq $(( ${xsize} / 4 * 3 )) ] ; then tile=" " ; fi
# 1 row of ocean horizontal middle centerline
if [ ${y} -eq $(( ${ysize} / 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq -8 ] ; then
# 1 column of ocean vertical middle centerine
if [ ${x} -eq $(( ${xsize} / 2 )) ] ; then tile=" " ; fi
# 3 rows of ocean horizontal middle centerline
if [ ${y} -eq $(( ${ysize} / 4 )) ] ; then tile=" " ; fi
if [ ${y} -eq $(( ${ysize} / 4 * 2 )) ] ; then tile=" " ; fi
if [ ${y} -eq $(( ${ysize} / 4 * 3 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq 9 ] ; then
# 1 column of ocean vertical per 1/3rd of map
if [ ${x} -eq $(( ${xsize} / 3 )) ] ; then tile=" " ; fi
if [ ${x} -eq $(( ( ${xsize} / 3 ) * 2 )) ] ; then tile=" " ; fi
# 1 row of ocean horizontal per 1/3rd of map
if [ ${y} -eq $(( ${ysize} / 3 )) ] ; then tile=" " ; fi
if [ ${y} -eq $(( ( ${ysize} / 3 ) * 2 )) ] ; then tile=" " ; fi
elif [ ${rectangles} -eq 16 ] ; then
# 1 column of ocean vertical per 1/4 of map
if [ ${x} -eq $(( ${xsize} / 4 )) ] ; then tile=" " ; fi
if [ ${x} -eq $(( ( ${xsize} / 4 ) * 2 )) ] ; then tile=" " ; fi
if [ ${x} -eq $(( ( ${xsize} / 4 ) * 3 )) ] ; then tile=" " ; fi
# 1 row of ocean horizontal per 1/4 of map
if [ ${y} -eq $(( ${ysize} / 4 )) ] ; then tile=" " ; fi
if [ ${y} -eq $(( ( ${ysize} / 4 ) * 2 )) ] ; then tile=" " ; fi
if [ ${y} -eq $(( ( ${ysize} / 4 ) * 3 )) ] ; then tile=" " ; fi
fi
# 1 row of ocean at map edges left, right, top, bottom
if [ ${x} -eq 0 ] ; then tile=" " ; fi
if [ ${y} -eq 0 ] ; then tile=" " ; fi
if [ ${x} -eq $(( ${xsize} - 1 )) ] || [ ${y} -eq $(( ${ysize} - 1 )) ] ; then tile=" " ; fi
terrain_layer[${y}]="${terrain_layer[${y}]}${tile}"
done
done
# output original rectangles
echo "Before the loops:"
for ((y=0;y<${ysize};y++)) ; do
echo "t${zeroPad:${#y}}${y}=\"${terrain_layer[${y}]}\""
done
# Now loop top-to-bottom and bottom-to-top through the lines
# and look for land tiles next to ocean
# and change some of the land tiles to ocean too
# and output the map after each loop
# Loops up to 16 times, but stops if there are too many blank lines
for (( loop=1 ; loop<=18 ; loop++ )) ; do
test=""
blanklines=0
echo ; echo
# print loop header with loop #
echo "loop: ${loop}"
for (( z=0; z<${ysize} ; z++ )) ; do
if [ $(( loop % 2 )) -eq 0 ] ; then
# even loop number, loop backward, ysize to 0
y=$(( ysize - z ))
else
# odd loop number, loop forward, 0 to ysize
y=z
fi
terrain_layer_B[${y}]=""
for (( x=0 ; x<${xsize} ; x++ )) ; do
# This is the tile which we might change from land to ocean
tile="${terrain_layer[${y}]:${x}:1}"
# If this tile is not ocean then check the tiles around it
if [ "${tile}" != " " ] ; then
# Next are the 8 tiles of the ring around that tile
# above the tile
if [ "${terrain_layer[$((${y}-1))]:$((${x}-1)):1}" == " " ] ; then c=$((c+1)) ; fi
if [ "${terrain_layer[$((${y}-1))]:${x}:1}" == " " ] ; then c=$((c+1)) ; fi
if [ "${terrain_layer[$((${y}-1))]:$((${x}+1)):1}" == " " ] ; then c=$((c+1)) ; fi
# beside the tile
if [ "${terrain_layer[${y}]:$((${x}-1)):1}" == " " ] ; then c=$((c+1)) ; fi
if [ "${terrain_layer[${y}]:$((${x}+1)):1}" == " " ] ; then c=$((c+1)) ; fi
# below the tile
if [ "${terrain_layer[$((${y}+1))]:$((${x}-1)):1}" == " " ] ; then c=$((c+1)) ; fi
if [ "${terrain_layer[$((${y}+1))]:${x}:1}" == " " ] ; then c=$((c+1)) ; fi
if [ "${terrain_layer[$((${y}+1))]:$((${x}+1)):1}" == " " ] ; then c=$((c+1)) ; fi
if [ "${tile}" != " " ] ; then
# If only 1 neighboring tile is ocean,
# then only a small chance of changing the tile to ocean
if [ "${c}" -eq 1 ] ; then
if [ $(( 1 + RANDOM % 10 )) -ge 9 ] ; then
tile=" "
fi
# If 2 neighboring tiles are ocean, slightly better chance
elif [ "${c}" -eq 2 ] ; then
if [ $(( 1 + RANDOM % 10 )) -ge 8 ] ; then
tile=" "
fi
# If 3 neighboring tiles are ocean, an even better chance
elif [ "${c}" -eq 3 ] ; then
if [ $(( 1 + RANDOM % 10 )) -ge 7 ] ; then
tile=" "
fi
# If more than 3 neighboring tiles are ocean,
# then change this one to ocean too
elif [ "${c}" -gt 3 ] ; then
tile=" "
fi
fi
fi
c=0
terrain_layer_B[${y}]="${terrain_layer_B[${y}]}${tile}"
done
terrain_layer[${y}]="${terrain_layer_B[${y}]}"
# track percentage of map that is land tiles?
# if a significant portion of the map lines are blank on this loop, then break
test="${terrain_layer[${y}]// /}"
if [ "${#test}" -eq 0 ] ; then
blanklines=$(( ${blanklines} + 1 ))
else
blanklines=0
fi
if [ ${blanklines} -gt ${maxgap} ] ; then
echo "Loop ${loop} aborted due to # of blank lines=${blanklines}"
break 3
fi
done
# This would be a good place to add lake tiles
for ((y=0;y<${ysize};y++)) ; do
echo "t${zeroPad:${#y}}${y}=\"${terrain_layer_B[${y}]}\""
done
done
# Print 1 last blank line
echo
exit 0
^ Screenshot of a 120x60 map of 6 horizontally oriented continents, generated by v1.8. Two of the original rectangles separated, and it's now 8 continents and a few small islands.
Update to 1.8: does 1, 2, 4, 6, 8, 9, or 16 continents at a time, some in two orientations. Updated version 1.7 is attached allows 4 or 6 rectangles initially, 1.6 doesn't add lake tiles, does add Jungle and Swamp tiles. 1.5: changed to thinner white lines initially. 1.4 added looping up to 16 times but stops if there are too many blank lines (the land becomes too wispy.) Also displays each loop's output with proper formatting for insertion into Freeciv scenario [map] section -- so you can copy whichever loop's output you like.
That's it.