Add mapgen parameters to set the range of the random number of randomwalk caves per mapchunk, and to set the proportion that are flooded with liquids. Default values are, for now, unchanged from the previous hardcoded values. Add parameters to allow small randomwalk caves Disabled by default for now as they have never been present in the non-mgv6 mapgens.
577 lines
22 KiB
C++
577 lines
22 KiB
C++
/*
|
|
Minetest
|
|
Copyright (C) 2017-2019 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
|
|
Copyright (C) 2017-2019 paramat
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
|
|
#include <cmath>
|
|
#include "mapgen.h"
|
|
#include "voxel.h"
|
|
#include "noise.h"
|
|
#include "mapblock.h"
|
|
#include "mapnode.h"
|
|
#include "map.h"
|
|
#include "content_sao.h"
|
|
#include "nodedef.h"
|
|
#include "voxelalgorithms.h"
|
|
//#include "profiler.h" // For TimeTaker
|
|
#include "settings.h" // For g_settings
|
|
#include "emerge.h"
|
|
#include "dungeongen.h"
|
|
#include "cavegen.h"
|
|
#include "mg_biome.h"
|
|
#include "mg_ore.h"
|
|
#include "mg_decoration.h"
|
|
#include "mapgen_carpathian.h"
|
|
|
|
|
|
FlagDesc flagdesc_mapgen_carpathian[] = {
|
|
{"caverns", MGCARPATHIAN_CAVERNS},
|
|
{"rivers", MGCARPATHIAN_RIVERS},
|
|
{NULL, 0}
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
MapgenCarpathian::MapgenCarpathian(MapgenCarpathianParams *params, EmergeManager *emerge)
|
|
: MapgenBasic(MAPGEN_CARPATHIAN, params, emerge)
|
|
{
|
|
base_level = params->base_level;
|
|
river_width = params->river_width;
|
|
river_depth = params->river_depth;
|
|
valley_width = params->valley_width;
|
|
|
|
spflags = params->spflags;
|
|
cave_width = params->cave_width;
|
|
large_cave_depth = params->large_cave_depth;
|
|
lava_depth = params->lava_depth;
|
|
small_cave_num_min = params->small_cave_num_min;
|
|
small_cave_num_max = params->small_cave_num_max;
|
|
large_cave_num_min = params->large_cave_num_min;
|
|
large_cave_num_max = params->large_cave_num_max;
|
|
large_cave_flooded = params->large_cave_flooded;
|
|
cavern_limit = params->cavern_limit;
|
|
cavern_taper = params->cavern_taper;
|
|
cavern_threshold = params->cavern_threshold;
|
|
dungeon_ymin = params->dungeon_ymin;
|
|
dungeon_ymax = params->dungeon_ymax;
|
|
|
|
grad_wl = 1 - water_level;
|
|
|
|
//// 2D Terrain noise
|
|
noise_filler_depth = new Noise(¶ms->np_filler_depth, seed, csize.X, csize.Z);
|
|
noise_height1 = new Noise(¶ms->np_height1, seed, csize.X, csize.Z);
|
|
noise_height2 = new Noise(¶ms->np_height2, seed, csize.X, csize.Z);
|
|
noise_height3 = new Noise(¶ms->np_height3, seed, csize.X, csize.Z);
|
|
noise_height4 = new Noise(¶ms->np_height4, seed, csize.X, csize.Z);
|
|
noise_hills_terrain = new Noise(¶ms->np_hills_terrain, seed, csize.X, csize.Z);
|
|
noise_ridge_terrain = new Noise(¶ms->np_ridge_terrain, seed, csize.X, csize.Z);
|
|
noise_step_terrain = new Noise(¶ms->np_step_terrain, seed, csize.X, csize.Z);
|
|
noise_hills = new Noise(¶ms->np_hills, seed, csize.X, csize.Z);
|
|
noise_ridge_mnt = new Noise(¶ms->np_ridge_mnt, seed, csize.X, csize.Z);
|
|
noise_step_mnt = new Noise(¶ms->np_step_mnt, seed, csize.X, csize.Z);
|
|
if (spflags & MGCARPATHIAN_RIVERS)
|
|
noise_rivers = new Noise(¶ms->np_rivers, seed, csize.X, csize.Z);
|
|
|
|
//// 3D terrain noise
|
|
// 1 up 1 down overgeneration
|
|
noise_mnt_var = new Noise(¶ms->np_mnt_var, seed, csize.X, csize.Y + 2, csize.Z);
|
|
|
|
//// Cave noise
|
|
MapgenBasic::np_cave1 = params->np_cave1;
|
|
MapgenBasic::np_cave2 = params->np_cave2;
|
|
MapgenBasic::np_cavern = params->np_cavern;
|
|
MapgenBasic::np_dungeons = params->np_dungeons;
|
|
}
|
|
|
|
|
|
MapgenCarpathian::~MapgenCarpathian()
|
|
{
|
|
delete noise_filler_depth;
|
|
delete noise_height1;
|
|
delete noise_height2;
|
|
delete noise_height3;
|
|
delete noise_height4;
|
|
delete noise_hills_terrain;
|
|
delete noise_ridge_terrain;
|
|
delete noise_step_terrain;
|
|
delete noise_hills;
|
|
delete noise_ridge_mnt;
|
|
delete noise_step_mnt;
|
|
if (spflags & MGCARPATHIAN_RIVERS)
|
|
delete noise_rivers;
|
|
|
|
delete noise_mnt_var;
|
|
}
|
|
|
|
|
|
MapgenCarpathianParams::MapgenCarpathianParams():
|
|
np_filler_depth (0, 1, v3f(128, 128, 128), 261, 3, 0.7, 2.0),
|
|
np_height1 (0, 5, v3f(251, 251, 251), 9613, 5, 0.5, 2.0),
|
|
np_height2 (0, 5, v3f(383, 383, 383), 1949, 5, 0.5, 2.0),
|
|
np_height3 (0, 5, v3f(509, 509, 509), 3211, 5, 0.5, 2.0),
|
|
np_height4 (0, 5, v3f(631, 631, 631), 1583, 5, 0.5, 2.0),
|
|
np_hills_terrain (1, 1, v3f(1301, 1301, 1301), 1692, 5, 0.5, 2.0),
|
|
np_ridge_terrain (1, 1, v3f(1889, 1889, 1889), 3568, 5, 0.5, 2.0),
|
|
np_step_terrain (1, 1, v3f(1889, 1889, 1889), 4157, 5, 0.5, 2.0),
|
|
np_hills (0, 3, v3f(257, 257, 257), 6604, 6, 0.5, 2.0),
|
|
np_ridge_mnt (0, 12, v3f(743, 743, 743), 5520, 6, 0.7, 2.0),
|
|
np_step_mnt (0, 8, v3f(509, 509, 509), 2590, 6, 0.6, 2.0),
|
|
np_rivers (0, 1, v3f(1000, 1000, 1000), 85039, 5, 0.6, 2.0),
|
|
np_mnt_var (0, 1, v3f(499, 499, 499), 2490, 5, 0.55, 2.0),
|
|
np_cave1 (0, 12, v3f(61, 61, 61), 52534, 3, 0.5, 2.0),
|
|
np_cave2 (0, 12, v3f(67, 67, 67), 10325, 3, 0.5, 2.0),
|
|
np_cavern (0, 1, v3f(384, 128, 384), 723, 5, 0.63, 2.0),
|
|
np_dungeons (0.9, 0.5, v3f(500, 500, 500), 0, 2, 0.8, 2.0)
|
|
{
|
|
}
|
|
|
|
|
|
void MapgenCarpathianParams::readParams(const Settings *settings)
|
|
{
|
|
settings->getFlagStrNoEx("mgcarpathian_spflags", spflags, flagdesc_mapgen_carpathian);
|
|
|
|
settings->getFloatNoEx("mgcarpathian_base_level", base_level);
|
|
settings->getFloatNoEx("mgcarpathian_river_width", river_width);
|
|
settings->getFloatNoEx("mgcarpathian_river_depth", river_depth);
|
|
settings->getFloatNoEx("mgcarpathian_valley_width", valley_width);
|
|
|
|
settings->getFloatNoEx("mgcarpathian_cave_width", cave_width);
|
|
settings->getS16NoEx("mgcarpathian_large_cave_depth", large_cave_depth);
|
|
settings->getS16NoEx("mgcarpathian_lava_depth", lava_depth);
|
|
settings->getU16NoEx("mgcarpathian_small_cave_num_min", small_cave_num_min);
|
|
settings->getU16NoEx("mgcarpathian_small_cave_num_max", small_cave_num_max);
|
|
settings->getU16NoEx("mgcarpathian_large_cave_num_min", large_cave_num_min);
|
|
settings->getU16NoEx("mgcarpathian_large_cave_num_max", large_cave_num_max);
|
|
settings->getFloatNoEx("mgcarpathian_large_cave_flooded", large_cave_flooded);
|
|
settings->getS16NoEx("mgcarpathian_cavern_limit", cavern_limit);
|
|
settings->getS16NoEx("mgcarpathian_cavern_taper", cavern_taper);
|
|
settings->getFloatNoEx("mgcarpathian_cavern_threshold", cavern_threshold);
|
|
settings->getS16NoEx("mgcarpathian_dungeon_ymin", dungeon_ymin);
|
|
settings->getS16NoEx("mgcarpathian_dungeon_ymax", dungeon_ymax);
|
|
|
|
settings->getNoiseParams("mgcarpathian_np_filler_depth", np_filler_depth);
|
|
settings->getNoiseParams("mgcarpathian_np_height1", np_height1);
|
|
settings->getNoiseParams("mgcarpathian_np_height2", np_height2);
|
|
settings->getNoiseParams("mgcarpathian_np_height3", np_height3);
|
|
settings->getNoiseParams("mgcarpathian_np_height4", np_height4);
|
|
settings->getNoiseParams("mgcarpathian_np_hills_terrain", np_hills_terrain);
|
|
settings->getNoiseParams("mgcarpathian_np_ridge_terrain", np_ridge_terrain);
|
|
settings->getNoiseParams("mgcarpathian_np_step_terrain", np_step_terrain);
|
|
settings->getNoiseParams("mgcarpathian_np_hills", np_hills);
|
|
settings->getNoiseParams("mgcarpathian_np_ridge_mnt", np_ridge_mnt);
|
|
settings->getNoiseParams("mgcarpathian_np_step_mnt", np_step_mnt);
|
|
settings->getNoiseParams("mgcarpathian_np_rivers", np_rivers);
|
|
settings->getNoiseParams("mgcarpathian_np_mnt_var", np_mnt_var);
|
|
settings->getNoiseParams("mgcarpathian_np_cave1", np_cave1);
|
|
settings->getNoiseParams("mgcarpathian_np_cave2", np_cave2);
|
|
settings->getNoiseParams("mgcarpathian_np_cavern", np_cavern);
|
|
settings->getNoiseParams("mgcarpathian_np_dungeons", np_dungeons);
|
|
}
|
|
|
|
|
|
void MapgenCarpathianParams::writeParams(Settings *settings) const
|
|
{
|
|
settings->setFlagStr("mgcarpathian_spflags", spflags, flagdesc_mapgen_carpathian, U32_MAX);
|
|
|
|
settings->setFloat("mgcarpathian_base_level", base_level);
|
|
settings->setFloat("mgcarpathian_river_width", river_width);
|
|
settings->setFloat("mgcarpathian_river_depth", river_depth);
|
|
settings->setFloat("mgcarpathian_valley_width", valley_width);
|
|
|
|
settings->setFloat("mgcarpathian_cave_width", cave_width);
|
|
settings->setS16("mgcarpathian_large_cave_depth", large_cave_depth);
|
|
settings->setS16("mgcarpathian_lava_depth", lava_depth);
|
|
settings->setU16("mgcarpathian_small_cave_num_min", small_cave_num_min);
|
|
settings->setU16("mgcarpathian_small_cave_num_max", small_cave_num_max);
|
|
settings->setU16("mgcarpathian_large_cave_num_min", large_cave_num_min);
|
|
settings->setU16("mgcarpathian_large_cave_num_max", large_cave_num_max);
|
|
settings->setFloat("mgcarpathian_large_cave_flooded", large_cave_flooded);
|
|
settings->setS16("mgcarpathian_cavern_limit", cavern_limit);
|
|
settings->setS16("mgcarpathian_cavern_taper", cavern_taper);
|
|
settings->setFloat("mgcarpathian_cavern_threshold", cavern_threshold);
|
|
settings->setS16("mgcarpathian_dungeon_ymin", dungeon_ymin);
|
|
settings->setS16("mgcarpathian_dungeon_ymax", dungeon_ymax);
|
|
|
|
settings->setNoiseParams("mgcarpathian_np_filler_depth", np_filler_depth);
|
|
settings->setNoiseParams("mgcarpathian_np_height1", np_height1);
|
|
settings->setNoiseParams("mgcarpathian_np_height2", np_height2);
|
|
settings->setNoiseParams("mgcarpathian_np_height3", np_height3);
|
|
settings->setNoiseParams("mgcarpathian_np_height4", np_height4);
|
|
settings->setNoiseParams("mgcarpathian_np_hills_terrain", np_hills_terrain);
|
|
settings->setNoiseParams("mgcarpathian_np_ridge_terrain", np_ridge_terrain);
|
|
settings->setNoiseParams("mgcarpathian_np_step_terrain", np_step_terrain);
|
|
settings->setNoiseParams("mgcarpathian_np_hills", np_hills);
|
|
settings->setNoiseParams("mgcarpathian_np_ridge_mnt", np_ridge_mnt);
|
|
settings->setNoiseParams("mgcarpathian_np_step_mnt", np_step_mnt);
|
|
settings->setNoiseParams("mgcarpathian_np_rivers", np_rivers);
|
|
settings->setNoiseParams("mgcarpathian_np_mnt_var", np_mnt_var);
|
|
settings->setNoiseParams("mgcarpathian_np_cave1", np_cave1);
|
|
settings->setNoiseParams("mgcarpathian_np_cave2", np_cave2);
|
|
settings->setNoiseParams("mgcarpathian_np_cavern", np_cavern);
|
|
settings->setNoiseParams("mgcarpathian_np_dungeons", np_dungeons);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// Lerp function
|
|
inline float MapgenCarpathian::getLerp(float noise1, float noise2, float mod)
|
|
{
|
|
return noise1 + mod * (noise2 - noise1);
|
|
}
|
|
|
|
// Steps function
|
|
float MapgenCarpathian::getSteps(float noise)
|
|
{
|
|
float w = 0.5f;
|
|
float k = std::floor(noise / w);
|
|
float f = (noise - k * w) / w;
|
|
float s = std::fmin(2.f * f, 1.f);
|
|
return (k + s) * w;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void MapgenCarpathian::makeChunk(BlockMakeData *data)
|
|
{
|
|
// Pre-conditions
|
|
assert(data->vmanip);
|
|
assert(data->nodedef);
|
|
assert(data->blockpos_requested.X >= data->blockpos_min.X &&
|
|
data->blockpos_requested.Y >= data->blockpos_min.Y &&
|
|
data->blockpos_requested.Z >= data->blockpos_min.Z);
|
|
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
|
|
data->blockpos_requested.Y <= data->blockpos_max.Y &&
|
|
data->blockpos_requested.Z <= data->blockpos_max.Z);
|
|
|
|
this->generating = true;
|
|
this->vm = data->vmanip;
|
|
this->ndef = data->nodedef;
|
|
|
|
v3s16 blockpos_min = data->blockpos_min;
|
|
v3s16 blockpos_max = data->blockpos_max;
|
|
node_min = blockpos_min * MAP_BLOCKSIZE;
|
|
node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
|
|
full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
|
|
full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
|
|
|
|
// Create a block-specific seed
|
|
blockseed = getBlockSeed2(full_node_min, seed);
|
|
|
|
// Generate terrain
|
|
s16 stone_surface_max_y = generateTerrain();
|
|
|
|
// Create heightmap
|
|
updateHeightmap(node_min, node_max);
|
|
|
|
// Init biome generator, place biome-specific nodes, and build biomemap
|
|
if (flags & MG_BIOMES) {
|
|
biomegen->calcBiomeNoise(node_min);
|
|
generateBiomes();
|
|
}
|
|
|
|
// Generate tunnels, caverns and large randomwalk caves
|
|
if (flags & MG_CAVES) {
|
|
// Generate tunnels first as caverns confuse them
|
|
generateCavesNoiseIntersection(stone_surface_max_y);
|
|
|
|
// Generate caverns
|
|
bool near_cavern = false;
|
|
if (spflags & MGCARPATHIAN_CAVERNS)
|
|
near_cavern = generateCavernsNoise(stone_surface_max_y);
|
|
|
|
// Generate large randomwalk caves
|
|
if (near_cavern)
|
|
// Disable large randomwalk caves in this mapchunk by setting
|
|
// 'large cave depth' to world base. Avoids excessive liquid in
|
|
// large caverns and floating blobs of overgenerated liquid.
|
|
generateCavesRandomWalk(stone_surface_max_y,
|
|
-MAX_MAP_GENERATION_LIMIT);
|
|
else
|
|
generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
|
|
}
|
|
|
|
// Generate the registered ores
|
|
m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
|
|
|
|
// Generate dungeons
|
|
if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
|
|
full_node_max.Y <= dungeon_ymax)
|
|
generateDungeons(stone_surface_max_y);
|
|
|
|
// Generate the registered decorations
|
|
if (flags & MG_DECORATIONS)
|
|
m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
|
|
|
|
// Sprinkle some dust on top after everything else was generated
|
|
if (flags & MG_BIOMES)
|
|
dustTopNodes();
|
|
|
|
// Update liquids
|
|
updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
|
|
|
|
// Calculate lighting
|
|
if (flags & MG_LIGHT) {
|
|
calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
|
|
full_node_min, full_node_max);
|
|
}
|
|
|
|
this->generating = false;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
int MapgenCarpathian::getSpawnLevelAtPoint(v2s16 p)
|
|
{
|
|
// If rivers are enabled, first check if in a river channel
|
|
if (spflags & MGCARPATHIAN_RIVERS) {
|
|
float river = std::fabs(NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed)) -
|
|
river_width;
|
|
if (river < 0.0f)
|
|
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
|
|
}
|
|
|
|
float height1 = NoisePerlin2D(&noise_height1->np, p.X, p.Y, seed);
|
|
float height2 = NoisePerlin2D(&noise_height2->np, p.X, p.Y, seed);
|
|
float height3 = NoisePerlin2D(&noise_height3->np, p.X, p.Y, seed);
|
|
float height4 = NoisePerlin2D(&noise_height4->np, p.X, p.Y, seed);
|
|
|
|
float hterabs = std::fabs(NoisePerlin2D(&noise_hills_terrain->np, p.X, p.Y, seed));
|
|
float n_hills = NoisePerlin2D(&noise_hills->np, p.X, p.Y, seed);
|
|
float hill_mnt = hterabs * hterabs * hterabs * n_hills * n_hills;
|
|
|
|
float rterabs = std::fabs(NoisePerlin2D(&noise_ridge_terrain->np, p.X, p.Y, seed));
|
|
float n_ridge_mnt = NoisePerlin2D(&noise_ridge_mnt->np, p.X, p.Y, seed);
|
|
float ridge_mnt = rterabs * rterabs * rterabs * (1.0f - std::fabs(n_ridge_mnt));
|
|
|
|
float sterabs = std::fabs(NoisePerlin2D(&noise_step_terrain->np, p.X, p.Y, seed));
|
|
float n_step_mnt = NoisePerlin2D(&noise_step_mnt->np, p.X, p.Y, seed);
|
|
float step_mnt = sterabs * sterabs * sterabs * getSteps(n_step_mnt);
|
|
|
|
float valley = 1.0f;
|
|
float river = 0.0f;
|
|
|
|
if ((spflags & MGCARPATHIAN_RIVERS) && node_max.Y >= water_level - 16) {
|
|
river = std::fabs(NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed)) - river_width;
|
|
if (river <= valley_width) {
|
|
// Within river valley
|
|
if (river < 0.0f) {
|
|
// River channel
|
|
valley = river;
|
|
} else {
|
|
// Valley slopes.
|
|
// 0 at river edge, 1 at valley edge.
|
|
float riversc = river / valley_width;
|
|
// Smoothstep
|
|
valley = riversc * riversc * (3.0f - 2.0f * riversc);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool solid_below = false;
|
|
u8 cons_non_solid = 0; // consecutive non-solid nodes
|
|
|
|
for (s16 y = water_level; y <= water_level + 32; y++) {
|
|
float mnt_var = NoisePerlin3D(&noise_mnt_var->np, p.X, y, p.Y, seed);
|
|
float hill1 = getLerp(height1, height2, mnt_var);
|
|
float hill2 = getLerp(height3, height4, mnt_var);
|
|
float hill3 = getLerp(height3, height2, mnt_var);
|
|
float hill4 = getLerp(height1, height4, mnt_var);
|
|
|
|
float hilliness = std::fmax(std::fmin(hill1, hill2), std::fmin(hill3, hill4));
|
|
float hills = hill_mnt * hilliness;
|
|
float ridged_mountains = ridge_mnt * hilliness;
|
|
float step_mountains = step_mnt * hilliness;
|
|
|
|
s32 grad = 1 - y;
|
|
|
|
float mountains = hills + ridged_mountains + step_mountains;
|
|
float surface_level = base_level + mountains + grad;
|
|
|
|
if ((spflags & MGCARPATHIAN_RIVERS) && river <= valley_width) {
|
|
if (valley < 0.0f) {
|
|
// River channel
|
|
surface_level = std::fmin(surface_level,
|
|
water_level - std::sqrt(-valley) * river_depth);
|
|
} else if (surface_level > water_level) {
|
|
// Valley slopes
|
|
surface_level = water_level + (surface_level - water_level) * valley;
|
|
}
|
|
}
|
|
|
|
if (y < surface_level) { //TODO '<=' fix from generateTerrain()
|
|
// solid node
|
|
solid_below = true;
|
|
cons_non_solid = 0;
|
|
} else {
|
|
// non-solid node
|
|
cons_non_solid++;
|
|
if (cons_non_solid == 3 && solid_below)
|
|
return y - 1;
|
|
}
|
|
}
|
|
|
|
return MAX_MAP_GENERATION_LIMIT; // No suitable spawn point found
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
int MapgenCarpathian::generateTerrain()
|
|
{
|
|
MapNode mn_air(CONTENT_AIR);
|
|
MapNode mn_stone(c_stone);
|
|
MapNode mn_water(c_water_source);
|
|
|
|
// Calculate noise for terrain generation
|
|
noise_height1->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_height2->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_height3->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_height4->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_hills_terrain->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_ridge_terrain->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_step_terrain->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_hills->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_ridge_mnt->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_step_mnt->perlinMap2D(node_min.X, node_min.Z);
|
|
noise_mnt_var->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
|
|
if (spflags & MGCARPATHIAN_RIVERS)
|
|
noise_rivers->perlinMap2D(node_min.X, node_min.Z);
|
|
|
|
//// Place nodes
|
|
const v3s16 &em = vm->m_area.getExtent();
|
|
s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
|
|
u32 index2d = 0;
|
|
|
|
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
|
// Hill/Mountain height (hilliness)
|
|
float height1 = noise_height1->result[index2d];
|
|
float height2 = noise_height2->result[index2d];
|
|
float height3 = noise_height3->result[index2d];
|
|
float height4 = noise_height4->result[index2d];
|
|
|
|
// Rolling hills
|
|
float hterabs = std::fabs(noise_hills_terrain->result[index2d]);
|
|
float n_hills = noise_hills->result[index2d];
|
|
float hill_mnt = hterabs * hterabs * hterabs * n_hills * n_hills;
|
|
|
|
// Ridged mountains
|
|
float rterabs = std::fabs(noise_ridge_terrain->result[index2d]);
|
|
float n_ridge_mnt = noise_ridge_mnt->result[index2d];
|
|
float ridge_mnt = rterabs * rterabs * rterabs *
|
|
(1.0f - std::fabs(n_ridge_mnt));
|
|
|
|
// Step (terraced) mountains
|
|
float sterabs = std::fabs(noise_step_terrain->result[index2d]);
|
|
float n_step_mnt = noise_step_mnt->result[index2d];
|
|
float step_mnt = sterabs * sterabs * sterabs * getSteps(n_step_mnt);
|
|
|
|
// Rivers
|
|
float valley = 1.0f;
|
|
float river = 0.0f;
|
|
|
|
if ((spflags & MGCARPATHIAN_RIVERS) && node_max.Y >= water_level - 16) {
|
|
river = std::fabs(noise_rivers->result[index2d]) - river_width;
|
|
if (river <= valley_width) {
|
|
// Within river valley
|
|
if (river < 0.0f) {
|
|
// River channel
|
|
valley = river;
|
|
} else {
|
|
// Valley slopes.
|
|
// 0 at river edge, 1 at valley edge.
|
|
float riversc = river / valley_width;
|
|
// Smoothstep
|
|
valley = riversc * riversc * (3.0f - 2.0f * riversc);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialise 3D noise index and voxelmanip index to column base
|
|
u32 index3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
|
|
u32 vi = vm->m_area.index(x, node_min.Y - 1, z);
|
|
|
|
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1;
|
|
y++,
|
|
index3d += ystride,
|
|
VoxelArea::add_y(em, vi, 1)) {
|
|
if (vm->m_data[vi].getContent() != CONTENT_IGNORE)
|
|
continue;
|
|
|
|
// Combine height noises and apply 3D variation
|
|
float mnt_var = noise_mnt_var->result[index3d];
|
|
float hill1 = getLerp(height1, height2, mnt_var);
|
|
float hill2 = getLerp(height3, height4, mnt_var);
|
|
float hill3 = getLerp(height3, height2, mnt_var);
|
|
float hill4 = getLerp(height1, height4, mnt_var);
|
|
|
|
// 'hilliness' determines whether hills/mountains are
|
|
// small or large
|
|
float hilliness =
|
|
std::fmax(std::fmin(hill1, hill2), std::fmin(hill3, hill4));
|
|
float hills = hill_mnt * hilliness;
|
|
float ridged_mountains = ridge_mnt * hilliness;
|
|
float step_mountains = step_mnt * hilliness;
|
|
|
|
// Gradient & shallow seabed
|
|
s32 grad = (y < water_level) ? grad_wl + (water_level - y) * 3 :
|
|
1 - y;
|
|
|
|
// Final terrain level
|
|
float mountains = hills + ridged_mountains + step_mountains;
|
|
float surface_level = base_level + mountains + grad;
|
|
|
|
// Rivers
|
|
if ((spflags & MGCARPATHIAN_RIVERS) && node_max.Y >= water_level - 16 &&
|
|
river <= valley_width) {
|
|
if (valley < 0.0f) {
|
|
// River channel
|
|
surface_level = std::fmin(surface_level,
|
|
water_level - std::sqrt(-valley) * river_depth);
|
|
} else if (surface_level > water_level) {
|
|
// Valley slopes
|
|
surface_level = water_level + (surface_level - water_level) * valley;
|
|
}
|
|
}
|
|
|
|
if (y < surface_level) { //TODO '<='
|
|
vm->m_data[vi] = mn_stone; // Stone
|
|
if (y > stone_surface_max_y)
|
|
stone_surface_max_y = y;
|
|
} else if (y <= water_level) {
|
|
vm->m_data[vi] = mn_water; // Sea water
|
|
} else {
|
|
vm->m_data[vi] = mn_air; // Air
|
|
}
|
|
}
|
|
}
|
|
|
|
return stone_surface_max_y;
|
|
}
|