409 lines
9.6 KiB
C++
409 lines
9.6 KiB
C++
#include <tuple>
|
|
#include <vector>
|
|
|
|
// Generate a world using a seed.
|
|
|
|
void generate_world(world* out, unsigned int seed)
|
|
{
|
|
// Use rand() and RAND_MAX for white noise.
|
|
|
|
srand(seed);
|
|
|
|
// Use FastNoise for fractal Simplex noise.
|
|
|
|
FastNoise noise;
|
|
|
|
noise.SetSeed(seed);
|
|
|
|
noise.SetNoiseType(FastNoise::SimplexFractal);
|
|
|
|
noise.SetFractalOctaves(4);
|
|
|
|
// A small easter egg: sometimes mushroom worlds will spawn!
|
|
|
|
bool mushroom_world = rand() % 1024 == 0;
|
|
|
|
// Generate the base terrain.
|
|
|
|
float frequency = 4.0f;
|
|
|
|
for (float x = 0.0f; x < float(out->x_res); x += 1.0f)
|
|
for (float y = 0.0f; y < float(out->y_res); y += 1.0f)
|
|
for (float z = 0.0f; z < float(out->z_res); z += 1.0f)
|
|
{
|
|
if (y / float(out->y_res) + noise.GetValueFractal(x * frequency, y * frequency, z * frequency) * 0.40f > 0.5f)
|
|
{
|
|
out->set_id(int(x), int(y), int(z), id_stone);
|
|
}
|
|
}
|
|
|
|
// Set the highground blocks.
|
|
|
|
for (float x = 0.0f; x < float(out->x_res); x += 1.0f)
|
|
for (float z = 0.0f; z < float(out->z_res); z += 1.0f)
|
|
for (float y = 0.0f; y < float(out->y_res); y += 1.0f)
|
|
{
|
|
if (out->get_id(int(x), int(y), int(z)) != id_air)
|
|
{
|
|
if (y / float(out->y_res) > 0.6f)
|
|
{
|
|
if (noise.GetValueFractal(x * frequency, y * frequency) >= -0.2f)
|
|
{
|
|
out->set_id_safe(int(x), int(y), int(z), id_sand);
|
|
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 1, int(z), id_sandstone);
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 2, int(z), id_sandstone);
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 3, int(z), id_sandstone);
|
|
}
|
|
else
|
|
{
|
|
out->set_id_safe(int(x), int(y), int(z), id_gravel);
|
|
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 1, int(z), id_gravel);
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 2, int(z), id_gravel);
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 3, int(z), id_gravel);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mushroom_world)
|
|
{
|
|
out->set_id_safe(int(x), int(y), int(z), id_mycelium);
|
|
}
|
|
else
|
|
{
|
|
out->set_id_safe(int(x), int(y), int(z), id_grass);
|
|
}
|
|
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 1, int(z), id_dirt);
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 2, int(z), id_dirt);
|
|
out->set_id_safe_if_not_air(int(x), int(y) + 3, int(z), id_dirt);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Add water and beaches.
|
|
|
|
for (float x = 0.0f; x < float(out->x_res); x += 1.0f)
|
|
for (float y = 0.0f; y < float(out->y_res); y += 1.0f)
|
|
for (float z = 0.0f; z < float(out->z_res); z += 1.0f)
|
|
{
|
|
if (y / float(out->y_res) > 0.5f)
|
|
{
|
|
if (out->get_id(int(x), int(y), int(z)) == id_air)
|
|
{
|
|
out->set_id(int(x), int(y), int(z), id_water);
|
|
}
|
|
else if (out->get_id(int(x), int(y), int(z)) == id_grass || out->get_id(int(x), int(y), int(z)) == id_mycelium)
|
|
{
|
|
out->set_id(int(x), int(y), int(z), id_sand);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Plant trees.
|
|
|
|
if (mushroom_world)
|
|
{
|
|
goto done_trees;
|
|
}
|
|
|
|
for (int i = 0; i < out->x_res * out->z_res / 32; i++)
|
|
{
|
|
tree:
|
|
|
|
int x = rand() % out->x_res;
|
|
int z = rand() % out->z_res;
|
|
|
|
block_id tree_leaf;
|
|
|
|
block_id tree_log;
|
|
|
|
if (rand() % 3 == 0)
|
|
{
|
|
tree_leaf = id_birch_leaves;
|
|
|
|
tree_log = id_birch_log;
|
|
}
|
|
else
|
|
{
|
|
tree_leaf = id_oak_leaves;
|
|
|
|
tree_log = id_oak_log;
|
|
}
|
|
|
|
// Find the highest layer.
|
|
|
|
for (int y = 0; y < out->y_res; y++)
|
|
{
|
|
if (out->get_id(x, y, z) != id_air)
|
|
{
|
|
// Okay, found something that is not air.
|
|
|
|
if (out->get_id(x, y, z) == id_grass)
|
|
{
|
|
// It's grass, we may plant a tree if there are enough
|
|
// blocks available above the grass.
|
|
|
|
if (rand() % 2 == 0)
|
|
{
|
|
// Original tree.
|
|
|
|
if (!out->in_bounds(x, y - 6, z))
|
|
{
|
|
goto tree;
|
|
}
|
|
|
|
// This is the trunk.
|
|
|
|
out->set_id_safe_if_air(x, y - 1, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 2, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 3, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 4, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 5, z, tree_log);
|
|
|
|
// This is the cross at the top.
|
|
|
|
out->set_id_safe_if_air(x, y - 6, z, tree_leaf);
|
|
|
|
out->set_id_safe_if_air(x - 1, y - 6, z, tree_leaf);
|
|
out->set_id_safe_if_air(x + 1, y - 6, z, tree_leaf);
|
|
|
|
out->set_id_safe_if_air(x, y - 6, z - 1, tree_leaf);
|
|
out->set_id_safe_if_air(x, y - 6, z + 1, tree_leaf);
|
|
|
|
// This is the square at the layer second from the
|
|
// top.
|
|
|
|
for (int j = -1; j <= 1; j++)
|
|
{
|
|
for (int k = -1; k <= 1; k++)
|
|
{
|
|
if (j == 0 && k == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out->set_id_safe_if_air(x + j, y - 5, z + k, tree_leaf);
|
|
}
|
|
}
|
|
|
|
// These are the squares at the third and fourth
|
|
// layer from the top.
|
|
|
|
for (int j = -2; j <= 2; j++)
|
|
{
|
|
for (int k = -2; k <= 2; k++)
|
|
{
|
|
if (j == 0 && k == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out->set_id_safe_if_air(x + j, y - 4, z + k, tree_leaf);
|
|
out->set_id_safe_if_air(x + j, y - 3, z + k, tree_leaf);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Rounded tree.
|
|
|
|
if (!out->in_bounds(x, y - 7, z))
|
|
{
|
|
goto tree;
|
|
}
|
|
|
|
// This is the trunk.
|
|
|
|
out->set_id_safe_if_air(x, y - 1, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 2, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 3, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 4, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 5, z, tree_log);
|
|
out->set_id_safe_if_air(x, y - 6, z, tree_log);
|
|
|
|
// This is the cross at the top.
|
|
|
|
out->set_id_safe_if_air(x, y - 7, z, tree_leaf);
|
|
|
|
out->set_id_safe_if_air(x - 1, y - 7, z, tree_leaf);
|
|
out->set_id_safe_if_air(x + 1, y - 7, z, tree_leaf);
|
|
|
|
out->set_id_safe_if_air(x, y - 7, z - 1, tree_leaf);
|
|
out->set_id_safe_if_air(x, y - 7, z + 1, tree_leaf);
|
|
|
|
// This is the square at the layer second from the
|
|
// top.
|
|
|
|
for (int j = -1; j <= 1; j++)
|
|
{
|
|
for (int k = -1; k <= 1; k++)
|
|
{
|
|
if (j == 0 && k == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out->set_id_safe_if_air(x + j, y - 6, z + k, tree_leaf);
|
|
}
|
|
}
|
|
|
|
// These are the squares at the third and fourth
|
|
// layer from the top.
|
|
|
|
for (int j = -2; j <= 2; j++)
|
|
{
|
|
for (int k = -2; k <= 2; k++)
|
|
{
|
|
if (j == 0 && k == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out->set_id_safe_if_air(x + j, y - 5, z + k, tree_leaf);
|
|
out->set_id_safe_if_air(x + j, y - 4, z + k, tree_leaf);
|
|
}
|
|
}
|
|
|
|
// This is the square at the fifth layer from the top.
|
|
// It has it's corners removed.
|
|
|
|
for (int j = -2; j <= 2; j++)
|
|
{
|
|
for (int k = -2; k <= 2; k++)
|
|
{
|
|
if (j == 0 && k == 0)
|
|
{
|
|
continue;
|
|
}
|
|
else if ((j == 2 && k == 2) || (j == 2 && k == -2) || (j == -2 && k == 2) || (j == -2 && k == -2))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out->set_id_safe_if_air(x + j, y - 3, z + k, tree_leaf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
done_trees:
|
|
|
|
// Plant large mushrooms.
|
|
|
|
int mushroom_count = out->x_res * out->z_res / 1024;
|
|
|
|
if (mushroom_world)
|
|
{
|
|
mushroom_count = out->z_res * out->z_res / 32;
|
|
}
|
|
|
|
for (int i = 0; i < mushroom_count; i++)
|
|
{
|
|
mushroom:
|
|
|
|
int x = rand() % out->x_res;
|
|
int z = rand() % out->z_res;
|
|
|
|
for (int y = 0; y < out->y_res; y++)
|
|
{
|
|
if (out->get_id(x, y, z) != id_air)
|
|
{
|
|
// Okay, found something that is not air.
|
|
|
|
if (out->get_id(x, y, z) == id_grass || out->get_id(x, y, z) == id_mycelium)
|
|
{
|
|
// It's grass, we may plant a mushroom if there are enough
|
|
// blocks available above the grass.
|
|
|
|
if (!out->in_bounds(x, y - 6, z))
|
|
{
|
|
goto mushroom;
|
|
}
|
|
|
|
if (rand() % 5 != 0)
|
|
{
|
|
// Red mushroom. This is the trunk.
|
|
|
|
out->set_id_safe_if_air(x, y - 1, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 2, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 3, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 4, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 5, z, id_mushroom_stem);
|
|
|
|
// These are the five squares.
|
|
|
|
for (int j = -1; j <= 1; j++)
|
|
{
|
|
for (int k = -1; k <= 1; k++)
|
|
{
|
|
// Top square.
|
|
|
|
out->set_id_safe_if_air(x + j, y - 6, z + k, id_red_mushroom_block);
|
|
|
|
// Left square.
|
|
|
|
out->set_id_safe_if_air(x - 2, y - 4 + j, z + k, id_red_mushroom_block);
|
|
|
|
out->set_id_safe_if_air(x - 1, y - 4 + j, z + k, id_air);
|
|
|
|
// Right square.
|
|
|
|
out->set_id_safe_if_air(x + 2, y - 4 + j, z + k, id_red_mushroom_block);
|
|
|
|
out->set_id_safe_if_air(x + 1, y - 4 + j, z + k, id_air);
|
|
|
|
// Front square.
|
|
|
|
out->set_id_safe_if_air(x + k, y - 4 + j, z - 2, id_red_mushroom_block);
|
|
|
|
out->set_id_safe_if_air(x + k, y - 4 + j, z - 1, id_air);
|
|
|
|
// Back square.
|
|
|
|
out->set_id_safe_if_air(x + k, y - 4 + j, z + 2, id_red_mushroom_block);
|
|
|
|
out->set_id_safe_if_air(x + k, y - 4 + j, z + 1, id_air);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Brown mushroom. This is the trunk.
|
|
|
|
out->set_id_safe_if_air(x, y - 1, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 2, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 3, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 4, z, id_mushroom_stem);
|
|
out->set_id_safe_if_air(x, y - 5, z, id_mushroom_stem);
|
|
|
|
for (int j = -3; j <= 3; j++)
|
|
{
|
|
for (int k = -3; k <= 3; k++)
|
|
{
|
|
if ((j == 3 && k == 3) || (j == 3 && k == -3) || (j == -3 && k == 3) || (j == -3 && k == -3))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out->set_id_safe_if_air(x + j, y - 6, z + k, id_brown_mushroom_block);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Propagate skylight.
|
|
|
|
propagate_skylight(out);
|
|
} |