Random terrain generator


Technology


So, the first encounter of We Be Goblins says it takes place in a swamp. And rather than a neat, orderly, you know, color-by-numbers swamp, I decided to make my own random marsh generator

It's a perl script, takes 'moor' or 'swamp' as the first input, the width in squares as input 2, and the length in squares as input 3. I tried really hard to make it look plausible from the Environment section in the PRD. Let me know if

a) it doesn't produce realistic-looking swamp or moor terrain, or
b) if anyone wants more of these. Each of the others would be an equal challenge, I think

Code in a text editor spoo~ooky:

#!/usr/bin/perl
$marsh_category = $ARGV[0];
$width = $ARGV[1];
$length = $ARGV[2];

$shallow_bog_chance = 0;
$deep_bog_chance = 0;
$light_undergrowth_chance = 0;
$heavy_undergrowth_chance = 0;

if ($marsh_category =~ /moor/)
{
$shallow_bog_chance = 20;
$deep_bog_chance = 5;
$light_undergrowth_chance = 30;
$heavy_undergrowth_chance = 10;
}
elsif ($marsh_category =~ /swamp/)
{
$shallow_bog_chance = 40;
$deep_bog_chance = 20;
$light_undergrowth_chance = 20;
$heavy_undergrowth_chance = 20;
}

for (my $i = 0; $i < $width; $i++)
{
for (my $j = 0; $j < $length; $j++)
{
$marsh[$i][$j] = "";
$bog_roll = int(rand(100)) + 1;
$undergrowth_roll = int(rand(100)) + 1;
if ($bog_roll <= ($shallow_bog_chance + $deep_bog_chance) &&
$undergrowth_roll <= ($light_undergrowth_chance + $heavy_undergrowth_chance))
{
$sub_roll = rand();
$sub_chance_bog = ($shallow_bog_chance + $deep_bog_chance) / ($shallow_bog_chance + $deep_bog_chance + $light_undergrowth_chance + $heavy_undergrowth_chance);
if ($sub_roll <= $sub_chance_bog)
{
placeBog($i, $j);
}
else
{
placeUndergrowth($i, $j);
}
}
elsif ($bog_roll <= ($shallow_bog_chance + $deep_bog_chance))
{
placeBog($i, $j);
}
elsif ($undergrowth_roll <= ($light_undergrowth_chance + $heavy_undergrowth_chance))
{
placeUndergrowth($i, $j);
}
else
{
$marsh[$i][$j] = "..";
}
}
}
for (my $i = 0; $i < $width; $i++)
{
for (my $j = 0; $j < $length; $j++)
{
if ($marsh[$i][$j] =~ m/DB/)
{
replaceTerrain($i + 1, $j, "DB");
replaceTerrain($i, $j + 1, "DB");
replaceTerrain($i + 1, $j + 1, "DB");
$i++;
$j++;
}
if ($i >= $width ||
$j >= $length)
{
last;
}
if ($marsh[$i][$j] =~ m/HU/)
{
replaceTerrain($i + 1, $j, "HU");
replaceTerrain($i, $j + 1, "HU");
replaceTerrain($i + 1, $j + 1, "HU");
$i++;
$j++;
}
if ($i >= $width ||
$j >= $length)
{
last;
}
}
if ($i >= $width)
{
last;
}
}
for ($i = 0; $i < $width; $i++)
{
for ($j = 0; $j < $length; $j++)
{
print $marsh[$i][$j] . " ";
}
print "\n\n";
}
print "SB: Shallow Bog\n";
print "DB: Deep Bog\n";
print "LU: Light Undergrowth\n";
print "HU: Heavy Undergrowth\n";

sub replaceTerrain
{
$starting_i = $_[0];
$starting_j = $_[1];
$terrain_to_find = $_[2];
if ($starting_i > $width ||
$starting_j > $length)
{
return;
}
for (my $i = $starting_i; $i < $width; $i++)
{
for (my $j = $starting_j; $j < $length; $j++)
{
if ($marsh[$i][$j] =~ m/$terrain_to_find/)
{
$temp = $marsh[$i][$j];
$marsh[$i][$j] = $marsh[$starting_i][$starting_j];
$marsh[$starting_i][$starting_j] = $temp;
return;
}
}
}
}

sub placeBog
{
$x = $_[0];
$y = $_[1];
$sub_roll = rand();
if ($sub_roll <= ($shallow_bog_chance / ($shallow_bog_chance + $deep_bog_chance)))
{
$marsh[$x][$y] = "SB";
}
else
{
$marsh[$x][$y] = "DB";
}
}

sub placeUndergrowth
{
$x = $_[0];
$y = $_[1];
$sub_roll = rand();
if ($sub_roll <= $light_undergrowth_chance / ($light_undergrowth_chance + $heavy_undergrowth_chance))
{
$marsh[$x][$y] = "LU";
}
else
{
$marsh[$x][$y] = "HU";
}
}


I've meant to get around to doing something like this some day. (Swipes code.) Although, I wasn't going to use perl, myself.

Producing realistic terrain will be ... tricky. You'd need something smarter. Even sticking with what the Core Rulebook says, "[d]eep bog squares are usually clustered together and surrounded by an irregular ring of shallow bog squares."

But I don't mean to be discouraging; I would like to see more of these.


Hey, I know it's not perfect. For deep bog and heavy undergrowth, the code tries to clump them together into 10x10 units. I figure the 'irregular rings' will work themselves out. This tends to group such clumps into the top part of the map, and from there you can switch around your bog clumps by hand into something more even-looking.

One nice thing about forest and marsh is that there aren't any 'straight' features, just clumps. I figure I'll have to do something fancy with hilly terrain to keep it from being like cottage cheese bumpy.

Hmm, if I ported this code into javascript, I could host it on my site. I'll think about it...


I went ahead and wrote a forest generator. Again, it takes 3 inputs, one for forest density, one for height, and one for width. And again, it's written in perl.

The big problem with the forest generation rules is that there's too much stuff! For medium and dense forest, there's stuff in like every square, which if you're drawing the map by hand is just no fun. If you end up printing out map squares, that's a different thing, Anyway, sparse forest still works okay, you can just hand spruce (ha!) it up with dense trees and heavy undergrowth.

forest.pl:

#!/usr/bin/perl
$forest_category = $ARGV[0];
$width = $ARGV[1];
$length = $ARGV[2];

$typical_tree_chance = 0;
$massive_tree_chance = 0;
$light_undergrowth_chance = 0;
$heavy_undergrowth_chance = 0;

if ($forest_category =~ m/sparse/)
{
$typical_tree_chance = 50;
$light_undergrowth_chance = 50;
}
elsif ($forest_category =~ m/medium/)
{
$typical_tree_chance = 70;
$massive_tree_chance = 10;
$light_undergrowth_chance = 70;
$heavy_undergrowth_chance = 20;
}
elsif ($forest_category =~ m/dense/)
{
$typical_tree_chance = 80;
$massive_tree_chance = 20;
$light_undergrowth_chance = 50;
$heavy_undergrowth_chance = 50;
}

for (my $i = 0; $i < $width; $i++)
{
for (my $j = 0; $j < $length; $j++)
{
$forest[$i][$j] = "";
$tree_roll = int(rand(100)) + 1;
$undergrowth_roll = int(rand(100)) + 1;
if ($tree_roll <= $typical_tree_chance &&
$undergrowth_roll <= $light_undergrowth_chance)
{
$forest[$i][$j] = "TU";
}
elsif ($tree_roll <= ($typical_tree_chance + $massive_tree_chance))
{
placeTree($i, $j);
}
elsif ($undergrowth_roll <= ($light_undergrowth_chance + $heavy_undergrowth_chance))
{
placeUndergrowth($i, $j);
}
else
{
$forest[$i][$j] = "..";
}
}
}
for (my $i = 0; $i < $width; $i++)
{
for (my $j = 0; $j < $length; $j++)
{
if ($forest[$i][$j] =~ m/HU/)
{
replaceTerrain($i + 1, $j, "HU");
replaceTerrain($i, $j + 1, "HU");
replaceTerrain($i + 1, $j + 1, "HU");
$i++;
$j++;
}
if ($i >= $width ||
$j >= $length)
{
last;
}
}
if ($i >= $width)
{
last;
}
}
for (my $i = 0; $i < $width; $i++)
{
for (my $j = 0; $j < $length; $j++)
{
if ($forest[$i][$j] =~ m/MT/)
{
if ($i - 1 >= 0)
{

clearUndergrowth($i - 1, $j - 1) if ($j - 1 >= 0);
clearUndergrowth($i - 1, $j);
clearUndergrowth($i - 1, $j + 1) if ($j + 1 < $length);
}
clearUndergrowth($i, $j - 1) if ($j - 1 >= 0);
clearUndergrowth($i, $j + 1) if ($j + 1 < $length);
if ($i + 1 < $width)
{
clearUndergrowth($i + 1, $j - 1) if ($j - 1 >= 0);
clearUndergrowth($i + 1, $j);
clearUndergrowth($i + 1, $j + 1) if ($j + 1 < $length);
}
}
}
}
for ($i = 0; $i < $width; $i++)
{
for ($j = 0; $j < $length; $j++)
{
print $forest[$i][$j] . " ";
}
print "\n\n";
}
print "TT: Typical Tree\n";
print "MT: Massive Tree\n";
print "LU: Light Undergrowth\n";
print "HU: Heavy Undergrowth\n";
print "TU: Typical Tree, Light Undergrowth\n";

sub clearUndergrowth
{
$x = $_[0];
$y = $_[1];
$sub_roll = int(rand(100)) + 1;
if ($sub_roll <= 50)
{
$forest[$x][$y] = ".." if ($forest[$x][$y] =~ m/LU|HU/);
$forest[$x][$y] = "TT" if ($forest[$x][$y] =~ m/TU/);
}
}

sub replaceTerrain
{
$starting_i = $_[0];
$starting_j = $_[1];
$terrain_to_find = $_[2];
if ($starting_i > $width ||
$starting_j > $length)
{
return;
}
for (my $i = $starting_i; $i < $width; $i++)
{
for (my $j = $starting_j; $j < $length; $j++)
{
if ($forest[$i][$j] =~ m/$terrain_to_find/)
{
$temp = $forest[$i][$j];
$forest[$i][$j] = $forest[$starting_i][$starting_j];
$forest[$starting_i][$starting_j] = $temp;
return;
}
}
}
}

sub placeTree
{
$x = $_[0];
$y = $_[1];
$sub_roll = rand();
if ($sub_roll <= ($typical_tree_chance / ($typical_tree_chance + $massive_tree_chance)))
{
$forest[$x][$y] = "TT";
}
else
{
$forest[$x][$y] = "MT";
}
}

sub placeUndergrowth
{
$x = $_[0];
$y = $_[1];
$sub_roll = rand();
if ($sub_roll <= $light_undergrowth_chance / ($light_undergrowth_chance + $heavy_undergrowth_chance))
{
$forest[$x][$y] = "LU";
}
else
{
$forest[$x][$y] = "HU";
}
}

Community / Forums / Gamer Life / Entertainment / Technology / Random terrain generator All Messageboards

Want to post a reply? Sign in.
Recent threads in Technology