private void GenerateTrees([NotNull] Map map)
{
if (map == null)
{
throw new ArgumentNullException("map");
}
int minHeight = args.TreeHeightMin;
int maxHeight = args.TreeHeightMax;
int minTrunkPadding = args.TreeSpacingMin;
int maxTrunkPadding = args.TreeSpacingMax;
const int topLayers = 2;
const double odds = 0.618;
Random rn = new Random();
map.CalculateShadows();
for (int x = 0; x < map.Width; x += rn.Next(minTrunkPadding, maxTrunkPadding + 1))
{
for (int y = 0; y < map.Length; y += rn.Next(minTrunkPadding, maxTrunkPadding + 1))
{
int nx = x + rn.Next(-(minTrunkPadding / 2), (maxTrunkPadding / 2) + 1);
int ny = y + rn.Next(-(minTrunkPadding / 2), (maxTrunkPadding / 2) + 1);
if (nx < 0 || nx >= map.Width || ny < 0 || ny >= map.Length)
{
continue;
}
int nz = map.Shadows[nx, ny];
if ((map.GetBlock(nx, ny, nz) == bGroundSurface) && slopemap[nx, ny] < .5)
{
// Pick a random height for the tree between Min and Max,
// discarding this tree if it would breach the top of the map
int nh;
if ((nh = rn.Next(minHeight, maxHeight + 1)) + nz + nh / 2 > map.Height)
{
continue;
}
// Generate the trunk of the tree
for (int z = 1; z <= nh; z++)
{
map.SetBlock(nx, ny, nz + z, Block.Log);
}
for (int i = -1; i < nh / 2; i++)
{
// Should we draw thin (2x2) or thicker (4x4) foliage
int radius = (i >= (nh / 2) - topLayers) ? 1 : 2;
// Draw the foliage
for (int xoff = -radius; xoff < radius + 1; xoff++)
{
for (int yoff = -radius; yoff < radius + 1; yoff++)
{
// Drop random leaves from the edges
if (rn.NextDouble() > odds && Math.Abs(xoff) == Math.Abs(yoff) && Math.Abs(xoff) == radius)
{
continue;
}
// By default only replace an existing block if its air
if (map.GetBlock(nx + xoff, ny + yoff, nz + nh + i) == Block.Air)
{
map.SetBlock(nx + xoff, ny + yoff, nz + nh + i, Block.Leaves);
}
}
}
}
}
}
}
}