aboutsummaryrefslogtreecommitdiff
path: root/src/mapgen
diff options
context:
space:
mode:
Diffstat (limited to 'src/mapgen')
-rw-r--r--src/mapgen/cavegen.cpp56
-rw-r--r--src/mapgen/cavegen.h4
-rw-r--r--src/mapgen/dungeongen.cpp89
-rw-r--r--src/mapgen/dungeongen.h43
-rw-r--r--src/mapgen/mapgen.cpp232
-rw-r--r--src/mapgen/mapgen.h31
-rw-r--r--src/mapgen/mapgen_carpathian.cpp228
-rw-r--r--src/mapgen/mapgen_carpathian.h28
-rw-r--r--src/mapgen/mapgen_flat.cpp51
-rw-r--r--src/mapgen/mapgen_flat.h3
-rw-r--r--src/mapgen/mapgen_fractal.cpp115
-rw-r--r--src/mapgen/mapgen_fractal.h16
-rw-r--r--src/mapgen/mapgen_singlenode.cpp5
-rw-r--r--src/mapgen/mapgen_singlenode.h2
-rw-r--r--src/mapgen/mapgen_v5.cpp28
-rw-r--r--src/mapgen/mapgen_v5.h3
-rw-r--r--src/mapgen/mapgen_v6.cpp278
-rw-r--r--src/mapgen/mapgen_v6.h4
-rw-r--r--src/mapgen/mapgen_v7.cpp16
-rw-r--r--src/mapgen/mapgen_v7.h3
-rw-r--r--src/mapgen/mapgen_valleys.cpp385
-rw-r--r--src/mapgen/mapgen_valleys.h30
-rw-r--r--src/mapgen/mg_biome.cpp3
-rw-r--r--src/mapgen/mg_biome.h2
-rw-r--r--src/mapgen/mg_schematic.cpp2
-rw-r--r--src/mapgen/treegen.cpp2
26 files changed, 822 insertions, 837 deletions
diff --git a/src/mapgen/cavegen.cpp b/src/mapgen/cavegen.cpp
index e54d76e08..fa34b7273 100644
--- a/src/mapgen/cavegen.cpp
+++ b/src/mapgen/cavegen.cpp
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mg_biome.h"
#include "cavegen.h"
+// TODO Remove this. Cave liquids are now defined and located using biome definitions
static NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0);
@@ -321,9 +322,26 @@ void CavesRandomWalk::makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax,
this->ystride = nmax.X - nmin.X + 1;
+ flooded = ps->range(1, 2) == 2;
+
+ // If flooded:
+ // Get biome at mapchunk midpoint. If cave liquid defined for biome, use it.
+ // If defined liquid is "air", disable 'flooded' to avoid placing "air".
+ use_biome_liquid = false;
+ if (flooded && bmgn) {
+ v3s16 midp = node_min + (node_max - node_min) / v3s16(2, 2, 2);
+ Biome *biome = (Biome *)bmgn->getBiomeAtPoint(midp);
+ if (biome->c_cave_liquid[0] != CONTENT_IGNORE) {
+ use_biome_liquid = true;
+ c_biome_liquid =
+ biome->c_cave_liquid[ps->range(0, biome->c_cave_liquid.size() - 1)];
+ if (c_biome_liquid == CONTENT_AIR)
+ flooded = false;
+ }
+ }
+
// Set initial parameters from randomness
int dswitchint = ps->range(1, 14);
- flooded = ps->range(1, 2) == 2;
if (large_cave) {
part_max_length_rs = ps->range(2, 4);
@@ -502,31 +520,21 @@ void CavesRandomWalk::carveRoute(v3f vec, float f, bool randomize_xz)
fp.Z += 0.1f * ps->range(-10, 10);
v3s16 cp(fp.X, fp.Y, fp.Z);
- // Get biome at 'cp + of', the absolute centre point of this route
- v3s16 cpabs = cp + of;
+ // Choose cave liquid
MapNode liquidnode = CONTENT_IGNORE;
- if (bmgn) {
- Biome *biome = nullptr;
- if (cpabs.X < node_min.X || cpabs.X > node_max.X ||
- cpabs.Z < node_min.Z || cpabs.Z > node_max.Z)
- // Point is outside heat and humidity noise maps so use point noise
- // calculations.
- biome = (Biome *)bmgn->calcBiomeAtPoint(cpabs);
- else
- // Point is inside heat and humidity noise maps so use them
- biome = (Biome *)bmgn->getBiomeAtPoint(cpabs);
-
- if (biome->c_cave_liquid != CONTENT_IGNORE)
- liquidnode = biome->c_cave_liquid;
- }
-
- if (liquidnode == CONTENT_IGNORE) {
- // Fallback to classic behaviour using point 'startp'
- float nval = NoisePerlin3D(np_caveliquids, startp.X,
- startp.Y, startp.Z, seed);
- liquidnode = (nval < 0.40f && node_max.Y < lava_depth) ?
- lavanode : waternode;
+ if (flooded) {
+ if (use_biome_liquid) {
+ liquidnode = c_biome_liquid;
+ } else {
+ // TODO remove this. Cave liquids are now defined and located using biome
+ // definitions.
+ // If cave liquid not defined by biome, fallback to old hardcoded behaviour.
+ float nval = NoisePerlin3D(np_caveliquids, startp.X,
+ startp.Y, startp.Z, seed);
+ liquidnode = (nval < 0.40f && node_max.Y < lava_depth) ?
+ lavanode : waternode;
+ }
}
s16 d0 = -rs / 2;
diff --git a/src/mapgen/cavegen.h b/src/mapgen/cavegen.h
index 7b7be6219..3f1730ddb 100644
--- a/src/mapgen/cavegen.h
+++ b/src/mapgen/cavegen.h
@@ -119,6 +119,8 @@ public:
// configurable parameters
s32 seed;
int water_level;
+ // TODO 'lava_depth' and 'np_caveliquids' are deprecated and should be removed.
+ // Cave liquids are now defined and located using biome definitions.
int lava_depth;
NoiseParams *np_caveliquids;
@@ -133,6 +135,7 @@ public:
bool large_cave;
bool large_cave_is_flat;
bool flooded;
+ bool use_biome_liquid;
v3s16 node_min;
v3s16 node_max;
@@ -150,6 +153,7 @@ public:
content_t c_water_source;
content_t c_lava_source;
+ content_t c_biome_liquid;
// ndef is a mandatory parameter.
// If gennotify is NULL, generation events are not logged.
diff --git a/src/mapgen/dungeongen.cpp b/src/mapgen/dungeongen.cpp
index 77ac05770..acdb1a0f0 100644
--- a/src/mapgen/dungeongen.cpp
+++ b/src/mapgen/dungeongen.cpp
@@ -31,9 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
//#define DGEN_USE_TORCHES
-NoiseParams nparams_dungeon_density(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
-NoiseParams nparams_dungeon_alt_wall(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
-
///////////////////////////////////////////////////////////////////////////////
@@ -69,28 +66,26 @@ DungeonGen::DungeonGen(const NodeDefManager *ndef,
dp.room_size_max = v3s16(8, 6, 8);
dp.room_size_large_min = v3s16(8, 8, 8);
dp.room_size_large_max = v3s16(16, 16, 16);
- dp.rooms_min = 2;
- dp.rooms_max = 16;
+ dp.large_room_chance = 1;
+ dp.num_rooms = 8;
+ dp.num_dungeons = 1;
dp.notifytype = GENNOTIFY_DUNGEON;
- dp.np_density = nparams_dungeon_density;
- dp.np_alt_wall = nparams_dungeon_alt_wall;
+ dp.np_alt_wall =
+ NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
}
}
void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
{
+ if (dp.num_dungeons == 0)
+ return;
+
assert(vm);
//TimeTaker t("gen dungeons");
- float nval_density = NoisePerlin3D(&dp.np_density, nmin.X, nmin.Y, nmin.Z, dp.seed);
- if (nval_density < 1.0f)
- return;
-
- static const bool preserve_ignore = !g_settings->getBool("projecting_dungeons");
-
this->vm = vm;
this->blockseed = bseed;
random.seed(bseed + 2);
@@ -99,9 +94,13 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
vm->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE);
if (dp.only_in_ground) {
- // Set all air and liquid drawtypes to be untouchable to make dungeons
- // open to air and liquids. Optionally set ignore to be untouchable to
- // prevent projecting dungeons.
+ // Set all air and liquid drawtypes to be untouchable to make dungeons generate
+ // in ground only.
+ // Set 'ignore' to be untouchable to prevent generation in ungenerated neighbor
+ // mapchunks, to avoid dungeon rooms generating outside ground.
+ // Like randomwalk caves, preserve nodes that have 'is_ground_content = false',
+ // to avoid dungeons that generate out beyond the edge of a mapchunk destroying
+ // nodes added by mods in 'register_on_generated()'.
for (s16 z = nmin.Z; z <= nmax.Z; z++) {
for (s16 y = nmin.Y; y <= nmax.Y; y++) {
u32 i = vm->m_area.index(nmin.X, y, z);
@@ -109,7 +108,7 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
content_t c = vm->m_data[i].getContent();
NodeDrawType dtype = ndef->get(c).drawtype;
if (dtype == NDT_AIRLIKE || dtype == NDT_LIQUID ||
- (preserve_ignore && c == CONTENT_IGNORE))
+ c == CONTENT_IGNORE || !ndef->get(c).is_ground_content)
vm->m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
i++;
}
@@ -118,7 +117,7 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
}
// Add them
- for (u32 i = 0; i < std::floor(nval_density); i++)
+ for (u32 i = 0; i < dp.num_dungeons; i++)
makeDungeon(v3s16(1, 1, 1) * MAP_BLOCKSIZE);
// Optionally convert some structure to alternative structure
@@ -149,19 +148,13 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
/*
Find place for first room.
- There is a 1 in 4 chance of the first room being 'large',
- all other rooms are not 'large'.
*/
bool fits = false;
for (u32 i = 0; i < 100 && !fits; i++) {
- bool is_large_room = ((random.next() & 3) == 1);
- if (is_large_room) {
- roomsize.Z = random.range(
- dp.room_size_large_min.Z, dp.room_size_large_max.Z);
- roomsize.Y = random.range(
- dp.room_size_large_min.Y, dp.room_size_large_max.Y);
- roomsize.X = random.range(
- dp.room_size_large_min.X, dp.room_size_large_max.X);
+ if (dp.large_room_chance >= 1) {
+ roomsize.Z = random.range(dp.room_size_large_min.Z, dp.room_size_large_max.Z);
+ roomsize.Y = random.range(dp.room_size_large_min.Y, dp.room_size_large_max.Y);
+ roomsize.X = random.range(dp.room_size_large_min.X, dp.room_size_large_max.X);
} else {
roomsize.Z = random.range(dp.room_size_min.Z, dp.room_size_max.Z);
roomsize.Y = random.range(dp.room_size_min.Y, dp.room_size_max.Y);
@@ -203,8 +196,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
*/
v3s16 last_room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
- u32 room_count = random.range(dp.rooms_min, dp.rooms_max);
- for (u32 i = 0; i < room_count; i++) {
+ for (u32 i = 0; i < dp.num_rooms; i++) {
// Make a room to the determined place
makeRoom(roomsize, roomplace);
@@ -218,7 +210,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
#endif
// Quit if last room
- if (i == room_count - 1)
+ if (i + 1 == dp.num_rooms)
break;
// Determine walker start position
@@ -256,9 +248,16 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
makeCorridor(doorplace, doordir, corridor_end, corridor_end_dir);
// Find a place for a random sized room
- roomsize.Z = random.range(dp.room_size_min.Z, dp.room_size_max.Z);
- roomsize.Y = random.range(dp.room_size_min.Y, dp.room_size_max.Y);
- roomsize.X = random.range(dp.room_size_min.X, dp.room_size_max.X);
+ if (dp.large_room_chance > 1 && random.range(1, dp.large_room_chance) == 1) {
+ // Large room
+ roomsize.Z = random.range(dp.room_size_large_min.Z, dp.room_size_large_max.Z);
+ roomsize.Y = random.range(dp.room_size_large_min.Y, dp.room_size_large_max.Y);
+ roomsize.X = random.range(dp.room_size_large_min.X, dp.room_size_large_max.X);
+ } else {
+ roomsize.Z = random.range(dp.room_size_min.Z, dp.room_size_max.Z);
+ roomsize.Y = random.range(dp.room_size_min.Y, dp.room_size_max.Y);
+ roomsize.X = random.range(dp.room_size_min.X, dp.room_size_max.X);
+ }
m_pos = corridor_end;
m_dir = corridor_end_dir;
@@ -271,7 +270,6 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
else
// Don't actually make a door
roomplace -= doordir;
-
}
}
@@ -490,7 +488,7 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
if (partcount >= partlength) {
partcount = 0;
- dir = random_turn(random, dir);
+ random_turn(random, dir);
partlength = random.range(1, length);
@@ -651,20 +649,19 @@ v3s16 turn_xz(v3s16 olddir, int t)
}
-v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
+void random_turn(PseudoRandom &random, v3s16 &dir)
{
int turn = random.range(0, 2);
- v3s16 dir;
- if (turn == 0)
- // Go straight
- dir = olddir;
- else if (turn == 1)
+ if (turn == 0) {
+ // Go straight: nothing to do
+ return;
+ } else if (turn == 1) {
// Turn right
- dir = turn_xz(olddir, 0);
- else
+ dir = turn_xz(dir, 0);
+ } else {
// Turn left
- dir = turn_xz(olddir, 1);
- return dir;
+ dir = turn_xz(dir, 1);
+ }
}
diff --git a/src/mapgen/dungeongen.h b/src/mapgen/dungeongen.h
index 2748524c5..35e6beef5 100644
--- a/src/mapgen/dungeongen.h
+++ b/src/mapgen/dungeongen.h
@@ -34,7 +34,7 @@ class NodeDefManager;
v3s16 rand_ortho_dir(PseudoRandom &random, bool diagonal_dirs);
v3s16 turn_xz(v3s16 olddir, int t);
-v3s16 random_turn(PseudoRandom &random, v3s16 olddir);
+void random_turn(PseudoRandom &random, v3s16 &dir);
int dir_to_facedir(v3s16 d);
@@ -42,24 +42,44 @@ struct DungeonParams {
s32 seed;
content_t c_wall;
+ // Randomly scattered alternative wall nodes
content_t c_alt_wall;
content_t c_stair;
- bool diagonal_dirs;
+ // 3D noise that determines which c_wall nodes are converted to c_alt_wall
+ NoiseParams np_alt_wall;
+
+ // Number of dungeons generated in mapchunk. All will use the same set of
+ // dungeonparams.
+ u16 num_dungeons;
+ // Dungeons only generate in ground
bool only_in_ground;
- v3s16 holesize;
- u16 corridor_len_min;
- u16 corridor_len_max;
+ // Number of rooms
+ u16 num_rooms;
+ // Room size random range. Includes walls / floor / ceilng
v3s16 room_size_min;
v3s16 room_size_max;
+ // Large room size random range. Includes walls / floor / ceilng
v3s16 room_size_large_min;
v3s16 room_size_large_max;
- u16 rooms_min;
- u16 rooms_max;
+ // Value 0 disables large rooms.
+ // Value 1 results in 1 large room, the first generated room.
+ // Value > 1 makes the first generated room large, all other rooms have a
+ // '1 in value' chance of being large.
+ u16 large_room_chance;
+ // Dimensions of 3D 'brush' that creates corridors.
+ // Dimensions are of the empty space, not including walls / floor / ceilng.
+ // Diagonal corridors must have hole width >=2 to be passable.
+ // Currently, hole width >= 3 causes stair corridor bugs.
+ v3s16 holesize;
+ // Corridor length random range
+ u16 corridor_len_min;
+ u16 corridor_len_max;
+ // Diagonal corridors are possible, 1 in 4 corridors will be diagonal
+ bool diagonal_dirs;
+ // Usually 'GENNOTIFY_DUNGEON', but mapgen v6 uses 'GENNOTIFY_TEMPLE' for
+ // desert dungeons.
GenNotifyType notifytype;
-
- NoiseParams np_density;
- NoiseParams np_alt_wall;
};
class DungeonGen {
@@ -82,8 +102,7 @@ public:
DungeonGen(const NodeDefManager *ndef,
GenerateNotifier *gennotify, DungeonParams *dparams);
- void generate(MMVManip *vm, u32 bseed,
- v3s16 full_node_min, v3s16 full_node_max);
+ void generate(MMVManip *vm, u32 bseed, v3s16 full_node_min, v3s16 full_node_max);
void makeDungeon(v3s16 start_padding);
void makeRoom(v3s16 roomsize, v3s16 roomplace);
diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp
index 7de367a27..6d5e721ce 100644
--- a/src/mapgen/mapgen.cpp
+++ b/src/mapgen/mapgen.cpp
@@ -19,6 +19,7 @@ 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"
@@ -38,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serialization.h"
#include "util/serialize.h"
#include "util/numeric.h"
+#include "util/directiontables.h"
#include "filesys.h"
#include "log.h"
#include "mapgen_carpathian.h"
@@ -80,15 +82,21 @@ struct MapgenDesc {
//// Built-in mapgens
////
+// Order used here defines the order of appearence in mainmenu.
+// v6 always last to discourage selection.
+// Special mapgens flat, fractal, singlenode, next to last. Of these, singlenode
+// last to discourage selection.
+// Of the remaining, v5 last due to age, v7 first due to being the default.
+// The order of 'enum MapgenType' in mapgen.h must match this order.
static MapgenDesc g_reg_mapgens[] = {
- {"v5", true},
- {"v6", true},
{"v7", true},
+ {"valleys", true},
+ {"carpathian", true},
+ {"v5", true},
{"flat", true},
{"fractal", true},
- {"valleys", true},
{"singlenode", true},
- {"carpathian", true},
+ {"v6", true},
};
STATIC_ASSERT(
@@ -148,28 +156,28 @@ const char *Mapgen::getMapgenName(MapgenType mgtype)
}
-Mapgen *Mapgen::createMapgen(MapgenType mgtype, int mgid,
- MapgenParams *params, EmergeManager *emerge)
+Mapgen *Mapgen::createMapgen(MapgenType mgtype, MapgenParams *params,
+ EmergeManager *emerge)
{
switch (mgtype) {
case MAPGEN_CARPATHIAN:
- return new MapgenCarpathian(mgid, (MapgenCarpathianParams *)params, emerge);
+ return new MapgenCarpathian((MapgenCarpathianParams *)params, emerge);
case MAPGEN_FLAT:
- return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
+ return new MapgenFlat((MapgenFlatParams *)params, emerge);
case MAPGEN_FRACTAL:
- return new MapgenFractal(mgid, (MapgenFractalParams *)params, emerge);
+ return new MapgenFractal((MapgenFractalParams *)params, emerge);
case MAPGEN_SINGLENODE:
- return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params, emerge);
+ return new MapgenSinglenode((MapgenSinglenodeParams *)params, emerge);
case MAPGEN_V5:
- return new MapgenV5(mgid, (MapgenV5Params *)params, emerge);
+ return new MapgenV5((MapgenV5Params *)params, emerge);
case MAPGEN_V6:
- return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
+ return new MapgenV6((MapgenV6Params *)params, emerge);
case MAPGEN_V7:
- return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
+ return new MapgenV7((MapgenV7Params *)params, emerge);
case MAPGEN_VALLEYS:
- return new MapgenValleys(mgid, (MapgenValleysParams *)params, emerge);
+ return new MapgenValleys((MapgenValleysParams *)params, emerge);
default:
- return NULL;
+ return nullptr;
}
}
@@ -194,7 +202,7 @@ MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
case MAPGEN_VALLEYS:
return new MapgenValleysParams;
default:
- return NULL;
+ return nullptr;
}
}
@@ -415,7 +423,7 @@ void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nm
void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
{
- ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+ ScopeProfiler sp(g_profiler, "EmergeThread: update lighting", SPT_AVG);
VoxelArea a(nmin, nmax);
for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
@@ -428,7 +436,8 @@ void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
}
-void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
+void Mapgen::lightSpread(VoxelArea &a, std::queue<std::pair<v3s16, u8>> &queue,
+ const v3s16 &p, u8 light)
{
if (light <= 1 || !a.contains(p))
return;
@@ -448,8 +457,8 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
// Bail out only if we have no more light from either bank to propogate, or
// we hit a solid block that light cannot pass through.
if ((light_day <= (n.param1 & 0x0F) &&
- light_night <= (n.param1 & 0xF0)) ||
- !ndef->get(n).light_propagates)
+ light_night <= (n.param1 & 0xF0)) ||
+ !ndef->get(n).light_propagates)
return;
// Since this recursive function only terminates when there is no light from
@@ -460,19 +469,15 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
n.param1 = light;
- lightSpread(a, p + v3s16(0, 0, 1), light);
- lightSpread(a, p + v3s16(0, 1, 0), light);
- lightSpread(a, p + v3s16(1, 0, 0), light);
- lightSpread(a, p - v3s16(0, 0, 1), light);
- lightSpread(a, p - v3s16(0, 1, 0), light);
- lightSpread(a, p - v3s16(1, 0, 0), light);
+ // add to queue
+ queue.emplace(p, light);
}
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
bool propagate_shadow)
{
- ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+ ScopeProfiler sp(g_profiler, "EmergeThread: update lighting", SPT_AVG);
//TimeTaker t("updateLighting");
propagateSunlight(nmin, nmax, propagate_shadow);
@@ -518,9 +523,10 @@ void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
}
-void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
+void Mapgen::spreadLight(const v3s16 &nmin, const v3s16 &nmax)
{
//TimeTaker t("spreadLight");
+ std::queue<std::pair<v3s16, u8>> queue;
VoxelArea a(nmin, nmax);
for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
@@ -544,18 +550,24 @@ void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
u8 light = n.param1;
if (light) {
- lightSpread(a, v3s16(x, y, z + 1), light);
- lightSpread(a, v3s16(x, y + 1, z ), light);
- lightSpread(a, v3s16(x + 1, y, z ), light);
- lightSpread(a, v3s16(x, y, z - 1), light);
- lightSpread(a, v3s16(x, y - 1, z ), light);
- lightSpread(a, v3s16(x - 1, y, z ), light);
+ const v3s16 p(x, y, z);
+ // spread to all 6 neighbor nodes
+ for (const auto &dir : g_6dirs)
+ lightSpread(a, queue, p + dir, light);
}
}
}
}
- //printf("spreadLight: %dms\n", t.stop());
+ while (!queue.empty()) {
+ const auto &i = queue.front();
+ // spread to all 6 neighbor nodes
+ for (const auto &dir : g_6dirs)
+ lightSpread(a, queue, i.first + dir, i.second);
+ queue.pop();
+ }
+
+ //printf("spreadLight: %lums\n", t.stop());
}
@@ -592,45 +604,20 @@ MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emer
this->heightmap = new s16[csize.X * csize.Z];
//// Initialize biome generator
- // TODO(hmmmm): should we have a way to disable biomemanager biomes?
biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
biomemap = biomegen->biomemap;
//// Look up some commonly used content
c_stone = ndef->getId("mapgen_stone");
- c_desert_stone = ndef->getId("mapgen_desert_stone");
- c_sandstone = ndef->getId("mapgen_sandstone");
c_water_source = ndef->getId("mapgen_water_source");
c_river_water_source = ndef->getId("mapgen_river_water_source");
c_lava_source = ndef->getId("mapgen_lava_source");
+ c_cobble = ndef->getId("mapgen_cobble");
- // Fall back to more basic content if not defined
- // river_water_source cannot fallback to water_source because river water
- // needs to be non-renewable and have a short flow range.
- if (c_desert_stone == CONTENT_IGNORE)
- c_desert_stone = c_stone;
- if (c_sandstone == CONTENT_IGNORE)
- c_sandstone = c_stone;
-
- //// Content used for dungeon generation
- c_cobble = ndef->getId("mapgen_cobble");
- c_mossycobble = ndef->getId("mapgen_mossycobble");
- c_stair_cobble = ndef->getId("mapgen_stair_cobble");
- c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
- c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
- c_stair_sandstone_block = ndef->getId("mapgen_stair_sandstone_block");
-
- // Fall back to more basic content if not defined
- if (c_mossycobble == CONTENT_IGNORE)
- c_mossycobble = c_cobble;
- if (c_stair_cobble == CONTENT_IGNORE)
- c_stair_cobble = c_cobble;
- if (c_stair_desert_stone == CONTENT_IGNORE)
- c_stair_desert_stone = c_desert_stone;
- if (c_sandstonebrick == CONTENT_IGNORE)
- c_sandstonebrick = c_sandstone;
- if (c_stair_sandstone_block == CONTENT_IGNORE)
- c_stair_sandstone_block = c_sandstonebrick;
+ // Fall back to more basic content if not defined.
+ // Lava falls back to water as both are suitable as cave liquids.
+ if (c_lava_source == CONTENT_IGNORE)
+ c_lava_source = c_water_source;
}
@@ -889,94 +876,59 @@ void MapgenBasic::generateDungeons(s16 max_stone_y)
if (max_stone_y < node_min.Y)
return;
- // Get biome at mapchunk midpoint
- v3s16 chunk_mid = node_min + (node_max - node_min) / v3s16(2, 2, 2);
- Biome *biome = (Biome *)biomegen->getBiomeAtPoint(chunk_mid);
+ u16 num_dungeons = std::fmax(std::floor(
+ NoisePerlin3D(&np_dungeons, node_min.X, node_min.Y, node_min.Z, seed)), 0.0f);
+ if (num_dungeons == 0)
+ return;
+
+ PseudoRandom ps(blockseed + 70033);
DungeonParams dp;
- dp.seed = seed;
- dp.only_in_ground = true;
- dp.corridor_len_min = 1;
- dp.corridor_len_max = 13;
- dp.rooms_min = 2;
- dp.rooms_max = 16;
+ dp.np_alt_wall =
+ NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
+
+ dp.seed = seed;
+ dp.only_in_ground = true;
+ dp.num_dungeons = num_dungeons;
+ dp.notifytype = GENNOTIFY_DUNGEON;
+ dp.num_rooms = ps.range(2, 16);
+ dp.room_size_min = v3s16(5, 5, 5);
+ dp.room_size_max = v3s16(12, 6, 12);
+ dp.room_size_large_min = v3s16(12, 6, 12);
+ dp.room_size_large_max = v3s16(16, 16, 16);
+ dp.large_room_chance = (ps.range(1, 4) == 1) ? 8 : 0;
+ dp.diagonal_dirs = ps.range(1, 8) == 1;
+ // Diagonal corridors must have 'hole' width >=2 to be passable
+ u8 holewidth = (dp.diagonal_dirs) ? 2 : ps.range(1, 2);
+ dp.holesize = v3s16(holewidth, 3, holewidth);
+ dp.corridor_len_min = 1;
+ dp.corridor_len_max = 13;
- dp.np_density = nparams_dungeon_density;
- dp.np_alt_wall = nparams_dungeon_alt_wall;
+ // Get biome at mapchunk midpoint
+ v3s16 chunk_mid = node_min + (node_max - node_min) / v3s16(2, 2, 2);
+ Biome *biome = (Biome *)biomegen->getBiomeAtPoint(chunk_mid);
- // Biome-defined dungeon nodes
+ // Use biome-defined dungeon nodes if defined
if (biome->c_dungeon != CONTENT_IGNORE) {
- dp.c_wall = biome->c_dungeon;
+ dp.c_wall = biome->c_dungeon;
// If 'node_dungeon_alt' is not defined by biome, it and dp.c_alt_wall
// become CONTENT_IGNORE which skips the alt wall node placement loop in
// dungeongen.cpp.
- dp.c_alt_wall = biome->c_dungeon_alt;
+ dp.c_alt_wall = biome->c_dungeon_alt;
// Stairs fall back to 'c_dungeon' if not defined by biome
dp.c_stair = (biome->c_dungeon_stair != CONTENT_IGNORE) ?
biome->c_dungeon_stair : biome->c_dungeon;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(2, 2, 2);
- dp.room_size_min = v3s16(6, 4, 6);
- dp.room_size_max = v3s16(10, 6, 10);
- dp.room_size_large_min = v3s16(10, 8, 10);
- dp.room_size_large_max = v3s16(18, 16, 18);
- dp.notifytype = GENNOTIFY_DUNGEON;
-
- // Otherwise classic behaviour
- } else if (biome->c_stone == c_stone) {
- dp.c_wall = c_cobble;
- dp.c_alt_wall = c_mossycobble;
- dp.c_stair = c_stair_cobble;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(1, 2, 1);
- dp.room_size_min = v3s16(4, 4, 4);
- dp.room_size_max = v3s16(8, 6, 8);
- dp.room_size_large_min = v3s16(8, 8, 8);
- dp.room_size_large_max = v3s16(16, 16, 16);
- dp.notifytype = GENNOTIFY_DUNGEON;
-
- } else if (biome->c_stone == c_desert_stone) {
- dp.c_wall = c_desert_stone;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = c_stair_desert_stone;
-
- dp.diagonal_dirs = true;
- dp.holesize = v3s16(2, 3, 2);
- dp.room_size_min = v3s16(6, 9, 6);
- dp.room_size_max = v3s16(10, 11, 10);
- dp.room_size_large_min = v3s16(10, 13, 10);
- dp.room_size_large_max = v3s16(18, 21, 18);
- dp.notifytype = GENNOTIFY_TEMPLE;
-
- } else if (biome->c_stone == c_sandstone) {
- dp.c_wall = c_sandstonebrick;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = c_stair_sandstone_block;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(2, 2, 2);
- dp.room_size_min = v3s16(6, 4, 6);
- dp.room_size_max = v3s16(10, 6, 10);
- dp.room_size_large_min = v3s16(10, 8, 10);
- dp.room_size_large_max = v3s16(18, 16, 18);
- dp.notifytype = GENNOTIFY_DUNGEON;
-
- // Fallback to using biome 'node_stone'
+ // Fallback to using cobble mapgen alias if defined
+ } else if (c_cobble != CONTENT_IGNORE) {
+ dp.c_wall = c_cobble;
+ dp.c_alt_wall = CONTENT_IGNORE;
+ dp.c_stair = c_cobble;
+ // Fallback to using biome-defined stone
} else {
- dp.c_wall = biome->c_stone;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = biome->c_stone;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(2, 2, 2);
- dp.room_size_min = v3s16(6, 4, 6);
- dp.room_size_max = v3s16(10, 6, 10);
- dp.room_size_large_min = v3s16(10, 8, 10);
- dp.room_size_large_max = v3s16(18, 16, 18);
- dp.notifytype = GENNOTIFY_DUNGEON;
+ dp.c_wall = biome->c_stone;
+ dp.c_alt_wall = CONTENT_IGNORE;
+ dp.c_stair = biome->c_stone;
}
DungeonGen dgen(ndef, &gennotify, &dp);
diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h
index b60aea57e..0ac26d538 100644
--- a/src/mapgen/mapgen.h
+++ b/src/mapgen/mapgen.h
@@ -102,15 +102,16 @@ private:
std::list<GenNotifyEvent> m_notify_events;
};
+// Order must match the order of 'static MapgenDesc g_reg_mapgens[]' in mapgen.cpp
enum MapgenType {
- MAPGEN_V5,
- MAPGEN_V6,
MAPGEN_V7,
+ MAPGEN_VALLEYS,
+ MAPGEN_CARPATHIAN,
+ MAPGEN_V5,
MAPGEN_FLAT,
MAPGEN_FRACTAL,
- MAPGEN_VALLEYS,
MAPGEN_SINGLENODE,
- MAPGEN_CARPATHIAN,
+ MAPGEN_V6,
MAPGEN_INVALID,
};
@@ -189,11 +190,12 @@ public:
void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax);
void setLighting(u8 light, v3s16 nmin, v3s16 nmax);
- void lightSpread(VoxelArea &a, v3s16 p, u8 light);
+ void lightSpread(VoxelArea &a, std::queue<std::pair<v3s16, u8>> &queue,
+ const v3s16 &p, u8 light);
void calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
bool propagate_shadow = true);
void propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow);
- void spreadLight(v3s16 nmin, v3s16 nmax);
+ void spreadLight(const v3s16 &nmin, const v3s16 &nmax);
virtual void makeChunk(BlockMakeData *data) {}
virtual int getGroundLevelAtPoint(v2s16 p) { return 0; }
@@ -208,8 +210,8 @@ public:
// Mapgen management functions
static MapgenType getMapgenType(const std::string &mgname);
static const char *getMapgenName(MapgenType mgtype);
- static Mapgen *createMapgen(MapgenType mgtype, int mgid,
- MapgenParams *params, EmergeManager *emerge);
+ static Mapgen *createMapgen(MapgenType mgtype, MapgenParams *params,
+ EmergeManager *emerge);
static MapgenParams *createMapgenParams(MapgenType mgtype);
static void getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden);
@@ -257,21 +259,11 @@ protected:
v3s16 full_node_min;
v3s16 full_node_max;
- // Content required for generateBiomes
content_t c_stone;
- content_t c_desert_stone;
- content_t c_sandstone;
content_t c_water_source;
content_t c_river_water_source;
content_t c_lava_source;
-
- // Content required for generateDungeons
content_t c_cobble;
- content_t c_stair_cobble;
- content_t c_mossycobble;
- content_t c_stair_desert_stone;
- content_t c_sandstonebrick;
- content_t c_stair_sandstone_block;
int ystride;
int zstride;
@@ -283,9 +275,12 @@ protected:
NoiseParams np_cave1;
NoiseParams np_cave2;
NoiseParams np_cavern;
+ NoiseParams np_dungeons;
float cave_width;
float cavern_limit;
float cavern_taper;
float cavern_threshold;
+ // TODO 'lava_depth' is deprecated and should be removed. Cave liquids are
+ // now defined and located using biome definitions.
int lava_depth;
};
diff --git a/src/mapgen/mapgen_carpathian.cpp b/src/mapgen/mapgen_carpathian.cpp
index f7daef708..12ce07da4 100644
--- a/src/mapgen/mapgen_carpathian.cpp
+++ b/src/mapgen/mapgen_carpathian.cpp
@@ -1,8 +1,7 @@
/*
Minetest
-Copyright (C) 2017-2018 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
-Copyright (C) 2010-2018 paramat
-Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+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
@@ -43,6 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
FlagDesc flagdesc_mapgen_carpathian[] = {
{"caverns", MGCARPATHIAN_CAVERNS},
+ {"rivers", MGCARPATHIAN_RIVERS},
{NULL, 0}
};
@@ -50,11 +50,13 @@ FlagDesc flagdesc_mapgen_carpathian[] = {
///////////////////////////////////////////////////////////////////////////////
-MapgenCarpathian::MapgenCarpathian(
- int mapgenid, MapgenCarpathianParams *params, EmergeManager *emerge)
- : MapgenBasic(mapgenid, params, emerge)
+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;
@@ -80,6 +82,8 @@ MapgenCarpathian::MapgenCarpathian(
noise_hills = new Noise(&params->np_hills, seed, csize.X, csize.Z);
noise_ridge_mnt = new Noise(&params->np_ridge_mnt, seed, csize.X, csize.Z);
noise_step_mnt = new Noise(&params->np_step_mnt, seed, csize.X, csize.Z);
+ if (spflags & MGCARPATHIAN_RIVERS)
+ noise_rivers = new Noise(&params->np_rivers, seed, csize.X, csize.Z);
//// 3D terrain noise
// 1 up 1 down overgeneration
@@ -89,6 +93,7 @@ MapgenCarpathian::MapgenCarpathian(
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
MapgenBasic::np_cavern = params->np_cavern;
+ MapgenBasic::np_dungeons = params->np_dungeons;
}
@@ -105,26 +110,31 @@ MapgenCarpathian::~MapgenCarpathian()
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_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_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)
{
}
@@ -132,7 +142,12 @@ MapgenCarpathianParams::MapgenCarpathianParams():
void MapgenCarpathianParams::readParams(const Settings *settings)
{
settings->getFlagStrNoEx("mgcarpathian_spflags", spflags, flagdesc_mapgen_carpathian);
- settings->getFloatNoEx("mgcarpathian_base_level", base_level);
+
+ 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);
@@ -153,17 +168,24 @@ void MapgenCarpathianParams::readParams(const Settings *settings)
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_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);
@@ -184,10 +206,12 @@ void MapgenCarpathianParams::writeParams(Settings *settings) const
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);
}
@@ -307,64 +331,95 @@ void MapgenCarpathian::makeChunk(BlockMakeData *data)
int MapgenCarpathian::getSpawnLevelAtPoint(v2s16 p)
{
- s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
- if (level_at_point <= water_level || level_at_point > water_level + 32)
- return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
-
- return level_at_point;
-}
-
-
-float MapgenCarpathian::terrainLevelAtPoint(s16 x, s16 z)
-{
- float height1 = NoisePerlin2D(&noise_height1->np, x, z, seed);
- float height2 = NoisePerlin2D(&noise_height2->np, x, z, seed);
- float height3 = NoisePerlin2D(&noise_height3->np, x, z, seed);
- float height4 = NoisePerlin2D(&noise_height4->np, x, z, seed);
- float hter = NoisePerlin2D(&noise_hills_terrain->np, x, z, seed);
- float rter = NoisePerlin2D(&noise_ridge_terrain->np, x, z, seed);
- float ster = NoisePerlin2D(&noise_step_terrain->np, x, z, seed);
- float n_hills = NoisePerlin2D(&noise_hills->np, x, z, seed);
- float n_ridge_mnt = NoisePerlin2D(&noise_ridge_mnt->np, x, z, seed);
- float n_step_mnt = NoisePerlin2D(&noise_step_mnt->np, x, z, seed);
-
- int height = -MAX_MAP_GENERATION_LIMIT;
+ // 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
+ }
- for (s16 y = 1; y <= 30; y++) {
- float mnt_var = NoisePerlin3D(&noise_mnt_var->np, x, y, z, seed);
+ 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);
+ }
+ }
+ }
- // Gradient & shallow seabed
- s32 grad = (y < water_level) ? grad_wl + (water_level - y) * 3 : 1 - y;
+ bool solid_below = false;
+ u8 cons_non_solid = 0; // consecutive non-solid nodes
- // Hill/Mountain height (hilliness)
+ 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));
-
- // Rolling hills
- float hill_mnt = hilliness * std::pow(n_hills, 2.f);
- float hills = std::pow(std::fabs(hter), 3.f) * hill_mnt;
- // Ridged mountains
- float ridge_mnt = hilliness * (1.f - std::fabs(n_ridge_mnt));
- float ridged_mountains = std::pow(std::fabs(rter), 3.f) * ridge_mnt;
+ 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;
- // Step (terraced) mountains
- float step_mnt = hilliness * getSteps(n_step_mnt);
- float step_mountains = std::pow(std::fabs(ster), 3.f) * step_mnt;
+ s32 grad = 1 - y;
- // Final terrain level
float mountains = hills + ridged_mountains + step_mountains;
float surface_level = base_level + mountains + grad;
- if (y > surface_level && height < 0)
- height = y;
+ 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 height;
+ return MAX_MAP_GENERATION_LIMIT; // No suitable spawn point found
}
@@ -390,6 +445,9 @@ int MapgenCarpathian::generateTerrain()
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;
@@ -412,13 +470,34 @@ int MapgenCarpathian::generateTerrain()
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.f - std::fabs(n_ridge_mnt));
+ (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);
@@ -453,7 +532,20 @@ int MapgenCarpathian::generateTerrain()
float mountains = hills + ridged_mountains + step_mountains;
float surface_level = base_level + mountains + grad;
- if (y < surface_level) {
+ // 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;
diff --git a/src/mapgen/mapgen_carpathian.h b/src/mapgen/mapgen_carpathian.h
index c32212c9a..1fbac4bfd 100644
--- a/src/mapgen/mapgen_carpathian.h
+++ b/src/mapgen/mapgen_carpathian.h
@@ -1,8 +1,7 @@
/*
Minetest
-Copyright (C) 2017-2018 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
-Copyright (C) 2010-2018 paramat
-Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+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
@@ -23,8 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
-///////// Mapgen Carpathian flags
#define MGCARPATHIAN_CAVERNS 0x01
+#define MGCARPATHIAN_RIVERS 0x02
class BiomeManager;
@@ -34,6 +33,9 @@ extern FlagDesc flagdesc_mapgen_carpathian[];
struct MapgenCarpathianParams : public MapgenParams
{
float base_level = 12.0f;
+ float river_width = 0.05f;
+ float river_depth = 24.0f;
+ float valley_width = 0.25f;
u32 spflags = MGCARPATHIAN_CAVERNS;
float cave_width = 0.09f;
@@ -56,10 +58,12 @@ struct MapgenCarpathianParams : public MapgenParams
NoiseParams np_hills;
NoiseParams np_ridge_mnt;
NoiseParams np_step_mnt;
+ NoiseParams np_rivers;
NoiseParams np_mnt_var;
NoiseParams np_cave1;
NoiseParams np_cave2;
NoiseParams np_cavern;
+ NoiseParams np_dungeons;
MapgenCarpathianParams();
~MapgenCarpathianParams() = default;
@@ -71,21 +75,19 @@ struct MapgenCarpathianParams : public MapgenParams
class MapgenCarpathian : public MapgenBasic
{
public:
- MapgenCarpathian(int mapgenid, MapgenCarpathianParams *params,
- EmergeManager *emerge);
+ MapgenCarpathian(MapgenCarpathianParams *params, EmergeManager *emerge);
~MapgenCarpathian();
virtual MapgenType getType() const { return MAPGEN_CARPATHIAN; }
- float getSteps(float noise);
- inline float getLerp(float noise1, float noise2, float mod);
-
virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
private:
float base_level;
- s32 grad_wl;
+ float river_width;
+ float river_depth;
+ float valley_width;
s16 large_cave_depth;
s16 dungeon_ymin;
@@ -101,8 +103,12 @@ private:
Noise *noise_hills;
Noise *noise_ridge_mnt;
Noise *noise_step_mnt;
+ Noise *noise_rivers = nullptr;
Noise *noise_mnt_var;
- float terrainLevelAtPoint(s16 x, s16 z);
+ s32 grad_wl;
+
+ float getSteps(float noise);
+ inline float getLerp(float noise1, float noise2, float mod);
int generateTerrain();
};
diff --git a/src/mapgen/mapgen_flat.cpp b/src/mapgen/mapgen_flat.cpp
index 11b27f85c..773b7b10f 100644
--- a/src/mapgen/mapgen_flat.cpp
+++ b/src/mapgen/mapgen_flat.cpp
@@ -48,8 +48,8 @@ FlagDesc flagdesc_mapgen_flat[] = {
///////////////////////////////////////////////////////////////////////////////////////
-MapgenFlat::MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge)
- : MapgenBasic(mapgenid, params, emerge)
+MapgenFlat::MapgenFlat(MapgenFlatParams *params, EmergeManager *emerge)
+ : MapgenBasic(MAPGEN_FLAT, params, emerge)
{
spflags = params->spflags;
ground_level = params->ground_level;
@@ -69,8 +69,9 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *em
if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
noise_terrain = new Noise(&params->np_terrain, seed, csize.X, csize.Z);
// 3D noise
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_dungeons = params->np_dungeons;
}
@@ -84,10 +85,11 @@ MapgenFlat::~MapgenFlat()
MapgenFlatParams::MapgenFlatParams():
- np_terrain (0, 1, v3f(600, 600, 600), 7244, 5, 0.6, 2.0),
- np_filler_depth (0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 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_terrain (0, 1, v3f(600, 600, 600), 7244, 5, 0.6, 2.0),
+ np_filler_depth (0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 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_dungeons (0.9, 0.5, v3f(500, 500, 500), 0, 2, 0.8, 2.0)
{
}
@@ -110,6 +112,7 @@ void MapgenFlatParams::readParams(const Settings *settings)
settings->getNoiseParams("mgflat_np_filler_depth", np_filler_depth);
settings->getNoiseParams("mgflat_np_cave1", np_cave1);
settings->getNoiseParams("mgflat_np_cave2", np_cave2);
+ settings->getNoiseParams("mgflat_np_dungeons", np_dungeons);
}
@@ -131,6 +134,7 @@ void MapgenFlatParams::writeParams(Settings *settings) const
settings->setNoiseParams("mgflat_np_filler_depth", np_filler_depth);
settings->setNoiseParams("mgflat_np_cave1", np_cave1);
settings->setNoiseParams("mgflat_np_cave2", np_cave2);
+ settings->setNoiseParams("mgflat_np_dungeons", np_dungeons);
}
@@ -139,26 +143,31 @@ void MapgenFlatParams::writeParams(Settings *settings) const
int MapgenFlat::getSpawnLevelAtPoint(v2s16 p)
{
- s16 level_at_point = ground_level;
- float n_terrain = 0.0f;
- if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
- n_terrain = NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed);
+ s16 stone_level = ground_level;
+ float n_terrain =
+ ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS)) ?
+ NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed) :
+ 0.0f;
if ((spflags & MGFLAT_LAKES) && n_terrain < lake_threshold) {
- level_at_point = ground_level -
- (lake_threshold - n_terrain) * lake_steepness;
+ s16 depress = (lake_threshold - n_terrain) * lake_steepness;
+ stone_level = ground_level - depress;
} else if ((spflags & MGFLAT_HILLS) && n_terrain > hill_threshold) {
- level_at_point = ground_level +
- (n_terrain - hill_threshold) * hill_steepness;
+ s16 rise = (n_terrain - hill_threshold) * hill_steepness;
+ stone_level = ground_level + rise;
}
- if (ground_level < water_level) // Ocean world, allow spawn in water
- return MYMAX(level_at_point, water_level);
+ if (ground_level < water_level)
+ // Ocean world, may not have islands so allow spawn in water
+ return MYMAX(stone_level + 2, water_level);
- if (level_at_point > water_level)
- return level_at_point; // Spawn on land
+ if (stone_level >= water_level)
+ // Spawn on land
+ // + 2 not + 1, to spawn above biome 'dust' nodes
+ return stone_level + 2;
- return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+ // Unsuitable spawn point
+ return MAX_MAP_GENERATION_LIMIT;
}
diff --git a/src/mapgen/mapgen_flat.h b/src/mapgen/mapgen_flat.h
index d8ec9f126..d2598695f 100644
--- a/src/mapgen/mapgen_flat.h
+++ b/src/mapgen/mapgen_flat.h
@@ -48,6 +48,7 @@ struct MapgenFlatParams : public MapgenParams
NoiseParams np_filler_depth;
NoiseParams np_cave1;
NoiseParams np_cave2;
+ NoiseParams np_dungeons;
MapgenFlatParams();
~MapgenFlatParams() = default;
@@ -59,7 +60,7 @@ struct MapgenFlatParams : public MapgenParams
class MapgenFlat : public MapgenBasic
{
public:
- MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge);
+ MapgenFlat(MapgenFlatParams *params, EmergeManager *emerge);
~MapgenFlat();
virtual MapgenType getType() const { return MAPGEN_FLAT; }
diff --git a/src/mapgen/mapgen_fractal.cpp b/src/mapgen/mapgen_fractal.cpp
index 68a66bba9..091dbacfa 100644
--- a/src/mapgen/mapgen_fractal.cpp
+++ b/src/mapgen/mapgen_fractal.cpp
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2015-2018 paramat
-Copyright (C) 2015-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2019 paramat
+Copyright (C) 2015-2016 kwolekr, Ryan Kwolek
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
@@ -41,14 +41,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
FlagDesc flagdesc_mapgen_fractal[] = {
- {NULL, 0}
+ {"terrain", MGFRACTAL_TERRAIN},
+ {NULL, 0}
};
///////////////////////////////////////////////////////////////////////////////////////
-MapgenFractal::MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge)
- : MapgenBasic(mapgenid, params, emerge)
+MapgenFractal::MapgenFractal(MapgenFractalParams *params, EmergeManager *emerge)
+ : MapgenBasic(MAPGEN_FRACTAL, params, emerge)
{
spflags = params->spflags;
cave_width = params->cave_width;
@@ -66,12 +67,17 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeMa
julia_z = params->julia_z;
julia_w = params->julia_w;
- //// 2D terrain noise
- noise_seabed = new Noise(&params->np_seabed, seed, csize.X, csize.Z);
+ //// 2D noise
+ if (spflags & MGFRACTAL_TERRAIN)
+ noise_seabed = new Noise(&params->np_seabed, seed, csize.X, csize.Z);
+
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
+ //// 3D noise
+ MapgenBasic::np_dungeons = params->np_dungeons;
+ // Overgeneration to node_min.Y - 1
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
formula = fractal / 2 + fractal % 2;
julia = fractal % 2 == 0;
@@ -80,7 +86,9 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeMa
MapgenFractal::~MapgenFractal()
{
- delete noise_seabed;
+ if (noise_seabed)
+ delete noise_seabed;
+
delete noise_filler_depth;
}
@@ -89,7 +97,8 @@ MapgenFractalParams::MapgenFractalParams():
np_seabed (-14, 9, v3f(600, 600, 600), 41900, 5, 0.6, 2.0),
np_filler_depth (0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 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_cave2 (0, 12, v3f(67, 67, 67), 10325, 3, 0.5, 2.0),
+ np_dungeons (0.9, 0.5, v3f(500, 500, 500), 0, 2, 0.8, 2.0)
{
}
@@ -116,6 +125,7 @@ void MapgenFractalParams::readParams(const Settings *settings)
settings->getNoiseParams("mgfractal_np_filler_depth", np_filler_depth);
settings->getNoiseParams("mgfractal_np_cave1", np_cave1);
settings->getNoiseParams("mgfractal_np_cave2", np_cave2);
+ settings->getNoiseParams("mgfractal_np_dungeons", np_dungeons);
}
@@ -141,6 +151,7 @@ void MapgenFractalParams::writeParams(Settings *settings) const
settings->setNoiseParams("mgfractal_np_filler_depth", np_filler_depth);
settings->setNoiseParams("mgfractal_np_cave1", np_cave1);
settings->setNoiseParams("mgfractal_np_cave2", np_cave2);
+ settings->setNoiseParams("mgfractal_np_dungeons", np_dungeons);
}
@@ -149,21 +160,25 @@ void MapgenFractalParams::writeParams(Settings *settings) const
int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
{
- bool solid_below = false; // Dry solid node is present below to spawn on
- u8 air_count = 0; // Consecutive air nodes above the dry solid node
- s16 seabed_level = NoisePerlin2D(&noise_seabed->np, p.X, p.Y, seed);
- // Seabed can rise above water_level or might be raised to create dry land
- s16 search_start = MYMAX(seabed_level, water_level + 1);
- if (seabed_level > water_level)
- solid_below = true;
-
- for (s16 y = search_start; y <= search_start + 128; y++) {
- if (getFractalAtPoint(p.X, y, p.Y)) { // Fractal node
+ bool solid_below = false; // Fractal node is present below to spawn on
+ u8 air_count = 0; // Consecutive air nodes above a fractal node
+ s16 search_start = 0; // No terrain search start
+
+ // If terrain present, don't start search below terrain or water level
+ if (noise_seabed) {
+ s16 seabed_level = NoisePerlin2D(&noise_seabed->np, p.X, p.Y, seed);
+ search_start = MYMAX(search_start, MYMAX(seabed_level, water_level));
+ }
+
+ for (s16 y = search_start; y <= search_start + 4096; y++) {
+ if (getFractalAtPoint(p.X, y, p.Y)) {
+ // Fractal node
solid_below = true;
air_count = 0;
- } else if (solid_below) { // Air above solid node
+ } else if (solid_below) {
+ // Air above fractal node
air_count++;
- // 3 to account for snowblock dust
+ // 3 and -2 to account for biome dust nodes
if (air_count == 3)
return y - 2;
}
@@ -185,10 +200,11 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
+ //TimeTaker t("makeChunk");
+
this->generating = true;
- this->vm = data->vmanip;
+ this->vm = data->vmanip;
this->ndef = data->nodedef;
- //TimeTaker t("makeChunk");
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
@@ -199,7 +215,7 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
blockseed = getBlockSeed2(full_node_min, seed);
- // Generate base terrain, mountains, and ridges with initial heightmaps
+ // Generate fractal and optional terrain
s16 stone_surface_max_y = generateTerrain();
// Create heightmap
@@ -211,16 +227,16 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
generateBiomes();
}
+ // Generate tunnels and randomwalk caves
if (flags & MG_CAVES) {
- // Generate tunnels
generateCavesNoiseIntersection(stone_surface_max_y);
- // Generate large randomwalk caves
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);
@@ -233,18 +249,18 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
if (flags & MG_BIOMES)
dustTopNodes();
- //printf("makeChunk: %dms\n", t.stop());
-
- updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
+ // Update liquids
+ if (spflags & MGFRACTAL_TERRAIN)
+ 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);
- //setLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
- // node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE, 0xFF);
-
this->generating = false;
+
+ //printf("makeChunk: %lums\n", t.stop());
}
@@ -387,24 +403,29 @@ s16 MapgenFractal::generateTerrain()
s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
u32 index2d = 0;
- noise_seabed->perlinMap2D(node_min.X, node_min.Z);
+ if (noise_seabed)
+ noise_seabed->perlinMap2D(node_min.X, node_min.Z);
for (s16 z = node_min.Z; z <= node_max.Z; z++) {
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
u32 vi = vm->m_area.index(node_min.X, y, z);
for (s16 x = node_min.X; x <= node_max.X; x++, vi++, index2d++) {
- if (vm->m_data[vi].getContent() == CONTENT_IGNORE) {
- s16 seabed_height = noise_seabed->result[index2d];
-
- if (y <= seabed_height || getFractalAtPoint(x, y, z)) {
- vm->m_data[vi] = n_stone;
- if (y > stone_surface_max_y)
- stone_surface_max_y = y;
- } else if (y <= water_level) {
- vm->m_data[vi] = n_water;
- } else {
- vm->m_data[vi] = n_air;
- }
+ if (vm->m_data[vi].getContent() != CONTENT_IGNORE)
+ continue;
+
+ s16 seabed_height = -MAX_MAP_GENERATION_LIMIT;
+ if (noise_seabed)
+ seabed_height = noise_seabed->result[index2d];
+
+ if (((spflags & MGFRACTAL_TERRAIN) && y <= seabed_height) ||
+ getFractalAtPoint(x, y, z)) {
+ vm->m_data[vi] = n_stone;
+ if (y > stone_surface_max_y)
+ stone_surface_max_y = y;
+ } else if ((spflags & MGFRACTAL_TERRAIN) && y <= water_level) {
+ vm->m_data[vi] = n_water;
+ } else {
+ vm->m_data[vi] = n_air;
}
}
index2d -= ystride;
diff --git a/src/mapgen/mapgen_fractal.h b/src/mapgen/mapgen_fractal.h
index 5a1948b9a..82622d4d9 100644
--- a/src/mapgen/mapgen_fractal.h
+++ b/src/mapgen/mapgen_fractal.h
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2015-2018 paramat
-Copyright (C) 2015-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2019 paramat
+Copyright (C) 2015-2016 kwolekr, Ryan Kwolek
Fractal formulas from http://www.bugman123.com/Hypercomplex/index.html
by Paul Nylander, and from http://www.fractalforums.com, thank you.
@@ -25,13 +25,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
+///////////// Mapgen Fractal flags
+#define MGFRACTAL_TERRAIN 0x01
+
class BiomeManager;
extern FlagDesc flagdesc_mapgen_fractal[];
+
struct MapgenFractalParams : public MapgenParams
{
- u32 spflags = 0;
+ u32 spflags = MGFRACTAL_TERRAIN;
float cave_width = 0.09f;
s16 large_cave_depth = -33;
s16 lava_depth = -256;
@@ -51,6 +55,7 @@ struct MapgenFractalParams : public MapgenParams
NoiseParams np_filler_depth;
NoiseParams np_cave1;
NoiseParams np_cave2;
+ NoiseParams np_dungeons;
MapgenFractalParams();
~MapgenFractalParams() = default;
@@ -59,10 +64,11 @@ struct MapgenFractalParams : public MapgenParams
void writeParams(Settings *settings) const;
};
+
class MapgenFractal : public MapgenBasic
{
public:
- MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge);
+ MapgenFractal(MapgenFractalParams *params, EmergeManager *emerge);
~MapgenFractal();
virtual MapgenType getType() const { return MAPGEN_FRACTAL; }
@@ -88,5 +94,5 @@ private:
float julia_y;
float julia_z;
float julia_w;
- Noise *noise_seabed;
+ Noise *noise_seabed = nullptr;
};
diff --git a/src/mapgen/mapgen_singlenode.cpp b/src/mapgen/mapgen_singlenode.cpp
index 76f7e6e8e..b64524e1c 100644
--- a/src/mapgen/mapgen_singlenode.cpp
+++ b/src/mapgen/mapgen_singlenode.cpp
@@ -29,9 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
-MapgenSinglenode::MapgenSinglenode(int mapgenid,
- MapgenParams *params, EmergeManager *emerge)
- : Mapgen(mapgenid, params, emerge)
+MapgenSinglenode::MapgenSinglenode(MapgenParams *params, EmergeManager *emerge)
+ : Mapgen(MAPGEN_SINGLENODE, params, emerge)
{
const NodeDefManager *ndef = emerge->ndef;
diff --git a/src/mapgen/mapgen_singlenode.h b/src/mapgen/mapgen_singlenode.h
index ebfb3c729..c21089eda 100644
--- a/src/mapgen/mapgen_singlenode.h
+++ b/src/mapgen/mapgen_singlenode.h
@@ -38,7 +38,7 @@ public:
content_t c_node;
u8 set_light;
- MapgenSinglenode(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+ MapgenSinglenode(MapgenParams *params, EmergeManager *emerge);
~MapgenSinglenode() = default;
virtual MapgenType getType() const { return MAPGEN_SINGLENODE; }
diff --git a/src/mapgen/mapgen_v5.cpp b/src/mapgen/mapgen_v5.cpp
index c5be727b9..bf99fd335 100644
--- a/src/mapgen/mapgen_v5.cpp
+++ b/src/mapgen/mapgen_v5.cpp
@@ -45,8 +45,8 @@ FlagDesc flagdesc_mapgen_v5[] = {
};
-MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
- : MapgenBasic(mapgenid, params, emerge)
+MapgenV5::MapgenV5(MapgenV5Params *params, EmergeManager *emerge)
+ : MapgenBasic(MAPGEN_V5, params, emerge)
{
spflags = params->spflags;
cave_width = params->cave_width;
@@ -67,9 +67,10 @@ MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
// 1-up 1-down overgeneration
noise_ground = new Noise(&params->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
// 1 down overgeneration
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
- MapgenBasic::np_cavern = params->np_cavern;
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_cavern = params->np_cavern;
+ MapgenBasic::np_dungeons = params->np_dungeons;
}
@@ -83,13 +84,14 @@ MapgenV5::~MapgenV5()
MapgenV5Params::MapgenV5Params():
- np_filler_depth (0, 1, v3f(150, 150, 150), 261, 4, 0.7, 2.0),
- np_factor (0, 1, v3f(250, 250, 250), 920381, 3, 0.45, 2.0),
- np_height (0, 10, v3f(250, 250, 250), 84174, 4, 0.5, 2.0),
- np_ground (0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED),
- 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_filler_depth (0, 1, v3f(150, 150, 150), 261, 4, 0.7, 2.0),
+ np_factor (0, 1, v3f(250, 250, 250), 920381, 3, 0.45, 2.0),
+ np_height (0, 10, v3f(250, 250, 250), 84174, 4, 0.5, 2.0),
+ np_ground (0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED),
+ 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)
{
}
@@ -113,6 +115,7 @@ void MapgenV5Params::readParams(const Settings *settings)
settings->getNoiseParams("mgv5_np_cave1", np_cave1);
settings->getNoiseParams("mgv5_np_cave2", np_cave2);
settings->getNoiseParams("mgv5_np_cavern", np_cavern);
+ settings->getNoiseParams("mgv5_np_dungeons", np_dungeons);
}
@@ -135,6 +138,7 @@ void MapgenV5Params::writeParams(Settings *settings) const
settings->setNoiseParams("mgv5_np_cave1", np_cave1);
settings->setNoiseParams("mgv5_np_cave2", np_cave2);
settings->setNoiseParams("mgv5_np_cavern", np_cavern);
+ settings->setNoiseParams("mgv5_np_dungeons", np_dungeons);
}
diff --git a/src/mapgen/mapgen_v5.h b/src/mapgen/mapgen_v5.h
index a1b56a070..1a3b6d3c3 100644
--- a/src/mapgen/mapgen_v5.h
+++ b/src/mapgen/mapgen_v5.h
@@ -48,6 +48,7 @@ struct MapgenV5Params : public MapgenParams
NoiseParams np_cave1;
NoiseParams np_cave2;
NoiseParams np_cavern;
+ NoiseParams np_dungeons;
MapgenV5Params();
~MapgenV5Params() = default;
@@ -59,7 +60,7 @@ struct MapgenV5Params : public MapgenParams
class MapgenV5 : public MapgenBasic
{
public:
- MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge);
+ MapgenV5(MapgenV5Params *params, EmergeManager *emerge);
~MapgenV5();
virtual MapgenType getType() const { return MAPGEN_V5; }
diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp
index fdfebe575..4e876fc53 100644
--- a/src/mapgen/mapgen_v6.cpp
+++ b/src/mapgen/mapgen_v6.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
+#include <cmath>
#include "mapgen.h"
#include "voxel.h"
#include "noise.h"
@@ -55,11 +56,11 @@ FlagDesc flagdesc_mapgen_v6[] = {
/////////////////////////////////////////////////////////////////////////////
-MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
- : Mapgen(mapgenid, params, emerge)
+MapgenV6::MapgenV6(MapgenV6Params *params, EmergeManager *emerge)
+ : Mapgen(MAPGEN_V6, params, emerge)
{
m_emerge = emerge;
- ystride = csize.X; //////fix this
+ ystride = csize.X;
heightmap = new s16[csize.X * csize.Z];
@@ -74,6 +75,8 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
np_trees = &params->np_trees;
np_apple_trees = &params->np_apple_trees;
+ np_dungeons = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
+
//// Create noise objects
noise_terrain_base = new Noise(&params->np_terrain_base, seed, csize.X, csize.Y);
noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
@@ -535,7 +538,7 @@ void MapgenV6::makeChunk(BlockMakeData *data)
updateHeightmap(node_min, node_max);
const s16 max_spread_amount = MAP_BLOCKSIZE;
- // Limit dirt flow area by 1 because mud is flown into neighbors.
+ // Limit dirt flow area by 1 because mud is flowed into neighbors
s16 mudflow_minpos = -max_spread_amount + 1;
s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2;
@@ -561,48 +564,54 @@ void MapgenV6::makeChunk(BlockMakeData *data)
// Add dungeons
if ((flags & MG_DUNGEONS) && stone_surface_max_y >= node_min.Y &&
full_node_min.Y >= dungeon_ymin && full_node_max.Y <= dungeon_ymax) {
- DungeonParams dp;
-
- dp.seed = seed;
- dp.only_in_ground = true;
- dp.corridor_len_min = 1;
- dp.corridor_len_max = 13;
- dp.rooms_min = 2;
- dp.rooms_max = 16;
-
- dp.np_density
- = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
- dp.np_alt_wall
- = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
-
- if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
- dp.c_wall = c_desert_stone;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = c_stair_desert_stone;
-
- dp.diagonal_dirs = true;
- dp.holesize = v3s16(2, 3, 2);
- dp.room_size_min = v3s16(6, 9, 6);
- dp.room_size_max = v3s16(10, 11, 10);
- dp.room_size_large_min = v3s16(10, 13, 10);
- dp.room_size_large_max = v3s16(18, 21, 18);
- dp.notifytype = GENNOTIFY_TEMPLE;
- } else {
- dp.c_wall = c_cobble;
- dp.c_alt_wall = c_mossycobble;
- dp.c_stair = c_stair_cobble;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(1, 2, 1);
- dp.room_size_min = v3s16(4, 4, 4);
- dp.room_size_max = v3s16(8, 6, 8);
- dp.room_size_large_min = v3s16(8, 8, 8);
- dp.room_size_large_max = v3s16(16, 16, 16);
- dp.notifytype = GENNOTIFY_DUNGEON;
- }
+ u16 num_dungeons = std::fmax(std::floor(
+ NoisePerlin3D(&np_dungeons, node_min.X, node_min.Y, node_min.Z, seed)), 0.0f);
+
+ if (num_dungeons >= 1) {
+ PseudoRandom ps(blockseed + 4713);
+
+ DungeonParams dp;
+
+ dp.seed = seed;
+ dp.num_dungeons = num_dungeons;
+ dp.only_in_ground = true;
+ dp.corridor_len_min = 1;
+ dp.corridor_len_max = 13;
+ dp.num_rooms = ps.range(2, 16);
+ dp.large_room_chance = (ps.range(1, 4) == 1) ? 1 : 0;
+
+ dp.np_alt_wall
+ = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
+
+ if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
+ dp.c_wall = c_desert_stone;
+ dp.c_alt_wall = CONTENT_IGNORE;
+ dp.c_stair = c_stair_desert_stone;
+
+ dp.diagonal_dirs = true;
+ dp.holesize = v3s16(2, 3, 2);
+ dp.room_size_min = v3s16(6, 9, 6);
+ dp.room_size_max = v3s16(10, 11, 10);
+ dp.room_size_large_min = v3s16(10, 13, 10);
+ dp.room_size_large_max = v3s16(18, 21, 18);
+ dp.notifytype = GENNOTIFY_TEMPLE;
+ } else {
+ dp.c_wall = c_cobble;
+ dp.c_alt_wall = c_mossycobble;
+ dp.c_stair = c_stair_cobble;
+
+ dp.diagonal_dirs = false;
+ dp.holesize = v3s16(1, 2, 1);
+ dp.room_size_min = v3s16(4, 4, 4);
+ dp.room_size_max = v3s16(8, 6, 8);
+ dp.room_size_large_min = v3s16(8, 8, 8);
+ dp.room_size_large_max = v3s16(16, 16, 16);
+ dp.notifytype = GENNOTIFY_DUNGEON;
+ }
- DungeonGen dgen(ndef, &gennotify, &dp);
- dgen.generate(vm, blockseed, full_node_min, full_node_max);
+ DungeonGen dgen(ndef, &gennotify, &dp);
+ dgen.generate(vm, blockseed, full_node_min, full_node_max);
+ }
}
// Add top and bottom side of water to transforming_liquid queue
@@ -764,128 +773,113 @@ void MapgenV6::addMud()
void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
{
- // 340ms @cs=8
- //TimeTaker timer1("flow mud");
-
- // Iterate a few times
- for (s16 k = 0; k < 3; k++) {
+ const v3s16 &em = vm->m_area.getExtent();
+ static const v3s16 dirs4[4] = {
+ v3s16(0, 0, 1), // Back
+ v3s16(1, 0, 0), // Right
+ v3s16(0, 0, -1), // Front
+ v3s16(-1, 0, 0), // Left
+ };
+
+ // Iterate twice
+ for (s16 k = 0; k < 2; k++) {
for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
- // Invert coordinates every 2nd iteration
- if (k % 2 == 0) {
- x = mudflow_maxpos - (x - mudflow_minpos);
- z = mudflow_maxpos - (z - mudflow_minpos);
- }
+ // Node column position
+ v2s16 p2d;
+ // Invert coordinates on second iteration to process columns in
+ // opposite order, to avoid a directional bias.
+ if (k == 1)
+ p2d = v2s16(node_max.X, node_max.Z) - v2s16(x, z);
+ else
+ p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
- // Node position in 2d
- v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
-
- const v3s16 &em = vm->m_area.getExtent();
- u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
s16 y = node_max.Y;
while (y >= node_min.Y) {
+ for (;; y--) {
+ u32 i = vm->m_area.index(p2d.X, y, p2d.Y);
+ MapNode *n = nullptr;
+
+ // Find next mud node in mapchunk column
+ for (; y >= node_min.Y; y--) {
+ n = &vm->m_data[i];
+ if (n->getContent() == c_dirt ||
+ n->getContent() == c_dirt_with_grass ||
+ n->getContent() == c_gravel)
+ break;
- for (;; y--) {
- MapNode *n = NULL;
- // Find mud
- for (; y >= node_min.Y; y--) {
- n = &vm->m_data[i];
- if (n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass ||
- n->getContent() == c_gravel)
+ VoxelArea::add_y(em, i, -1);
+ }
+ if (y < node_min.Y)
+ // No mud found in mapchunk column, process the next column
break;
- VoxelArea::add_y(em, i, -1);
- }
-
- // Stop if out of area
- //if(vmanip.m_area.contains(i) == false)
- if (y < node_min.Y)
- break;
-
- if (n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass) {
- // Make it exactly mud
- n->setContent(c_dirt);
-
- // Don't flow it if the stuff under it is not mud
- {
+ if (n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) {
+ // Convert dirt_with_grass to dirt
+ n->setContent(c_dirt);
+ // Don't flow mud if the stuff under it is not mud,
+ // to leave at least 1 node of mud.
u32 i2 = i;
VoxelArea::add_y(em, i2, -1);
- // Cancel if out of area
- if (!vm->m_area.contains(i2))
- continue;
MapNode *n2 = &vm->m_data[i2];
if (n2->getContent() != c_dirt &&
n2->getContent() != c_dirt_with_grass)
+ // Find next mud node in column
continue;
}
- }
- static const v3s16 dirs4[4] = {
- v3s16(0, 0, 1), // back
- v3s16(1, 0, 0), // right
- v3s16(0, 0, -1), // front
- v3s16(-1, 0, 0), // left
- };
-
- // Check that upper is walkable. Cancel
- // dropping if upper keeps it in place.
- u32 i3 = i;
- VoxelArea::add_y(em, i3, 1);
- MapNode *n3 = NULL;
-
- if (vm->m_area.contains(i3)) {
- n3 = &vm->m_data[i3];
+ // Check if node above is walkable. If so, cancel
+ // flowing as if node above keeps it in place.
+ u32 i3 = i;
+ VoxelArea::add_y(em, i3, 1);
+ MapNode *n3 = &vm->m_data[i3];
if (ndef->get(*n3).walkable)
+ // Find next mud node in column
continue;
- }
- // Drop mud on side
- for (const v3s16 &dirp : dirs4) {
- u32 i2 = i;
- // Move to side
- VoxelArea::add_p(em, i2, dirp);
- // Fail if out of area
- if (!vm->m_area.contains(i2))
- continue;
- // Check that side is air
- MapNode *n2 = &vm->m_data[i2];
- if (ndef->get(*n2).walkable)
- continue;
- // Check that under side is air
- VoxelArea::add_y(em, i2, -1);
- if (!vm->m_area.contains(i2))
- continue;
- n2 = &vm->m_data[i2];
- if (ndef->get(*n2).walkable)
- continue;
- // Loop further down until not air
- bool dropped_to_unknown = false;
- do {
+ // Drop mud on one side
+ for (const v3s16 &dirp : dirs4) {
+ u32 i2 = i;
+ // Move to side
+ VoxelArea::add_p(em, i2, dirp);
+ // Check that side is air
+ MapNode *n2 = &vm->m_data[i2];
+ if (ndef->get(*n2).walkable)
+ continue;
+
+ // Check that under side is air
VoxelArea::add_y(em, i2, -1);
n2 = &vm->m_data[i2];
- // if out of known area
- if (!vm->m_area.contains(i2) ||
- n2->getContent() == CONTENT_IGNORE) {
- dropped_to_unknown = true;
- break;
- }
- } while (!ndef->get(*n2).walkable);
- // Loop one up so that we're in air
- VoxelArea::add_y(em, i2, 1);
-
- // Move mud to new place. Outside mapchunk remove
- // any decorations above removed or placed mud.
- if (!dropped_to_unknown)
- moveMud(i, i2, i3, p2d, em);
+ if (ndef->get(*n2).walkable)
+ continue;
- // Done
- break;
+ // Loop further down until not air
+ s16 y2 = y - 1; // y of i2
+ bool dropped_to_unknown = false;
+ do {
+ y2--;
+ VoxelArea::add_y(em, i2, -1);
+ n2 = &vm->m_data[i2];
+ // If out of area or in ungenerated world
+ if (y2 < full_node_min.Y || n2->getContent() == CONTENT_IGNORE) {
+ dropped_to_unknown = true;
+ break;
+ }
+ } while (!ndef->get(*n2).walkable);
+
+ if (!dropped_to_unknown) {
+ // Move up one so that we're in air
+ VoxelArea::add_y(em, i2, 1);
+ // Move mud to new place, and if outside mapchunk remove
+ // any decorations above removed or placed mud.
+ moveMud(i, i2, i3, p2d, em);
+ }
+ // Done, find next mud node in column
+ break;
+ }
}
}
- }
}
}
}
diff --git a/src/mapgen/mapgen_v6.h b/src/mapgen/mapgen_v6.h
index 056281f2f..7d5229559 100644
--- a/src/mapgen/mapgen_v6.h
+++ b/src/mapgen/mapgen_v6.h
@@ -108,6 +108,8 @@ public:
NoiseParams *np_trees;
NoiseParams *np_apple_trees;
+ NoiseParams np_dungeons;
+
float freq_desert;
float freq_beach;
s16 dungeon_ymin;
@@ -132,7 +134,7 @@ public:
content_t c_stair_cobble;
content_t c_stair_desert_stone;
- MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge);
+ MapgenV6(MapgenV6Params *params, EmergeManager *emerge);
~MapgenV6();
virtual MapgenType getType() const { return MAPGEN_V6; }
diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp
index 1354bf256..c9568760f 100644
--- a/src/mapgen/mapgen_v7.cpp
+++ b/src/mapgen/mapgen_v7.cpp
@@ -52,8 +52,8 @@ FlagDesc flagdesc_mapgen_v7[] = {
////////////////////////////////////////////////////////////////////////////////
-MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
- : MapgenBasic(mapgenid, params, emerge)
+MapgenV7::MapgenV7(MapgenV7Params *params, EmergeManager *emerge)
+ : MapgenBasic(MAPGEN_V7, params, emerge)
{
spflags = params->spflags;
mount_zero_level = params->mount_zero_level;
@@ -113,9 +113,10 @@ MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
new Noise(&params->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
// 3D noise, 1 down overgeneration
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
- MapgenBasic::np_cavern = params->np_cavern;
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_cavern = params->np_cavern;
+ MapgenBasic::np_dungeons = params->np_dungeons;
}
@@ -159,7 +160,8 @@ MapgenV7Params::MapgenV7Params():
np_ridge (0.0, 1.0, v3f(100, 100, 100), 6467, 4, 0.75, 2.0),
np_cavern (0.0, 1.0, v3f(384, 128, 384), 723, 5, 0.63, 2.0),
np_cave1 (0.0, 12.0, v3f(61, 61, 61), 52534, 3, 0.5, 2.0),
- np_cave2 (0.0, 12.0, v3f(67, 67, 67), 10325, 3, 0.5, 2.0)
+ np_cave2 (0.0, 12.0, v3f(67, 67, 67), 10325, 3, 0.5, 2.0),
+ np_dungeons (0.9, 0.5, v3f(500, 500, 500), 0, 2, 0.8, 2.0)
{
}
@@ -196,6 +198,7 @@ void MapgenV7Params::readParams(const Settings *settings)
settings->getNoiseParams("mgv7_np_cavern", np_cavern);
settings->getNoiseParams("mgv7_np_cave1", np_cave1);
settings->getNoiseParams("mgv7_np_cave2", np_cave2);
+ settings->getNoiseParams("mgv7_np_dungeons", np_dungeons);
}
@@ -231,6 +234,7 @@ void MapgenV7Params::writeParams(Settings *settings) const
settings->setNoiseParams("mgv7_np_cavern", np_cavern);
settings->setNoiseParams("mgv7_np_cave1", np_cave1);
settings->setNoiseParams("mgv7_np_cave2", np_cave2);
+ settings->setNoiseParams("mgv7_np_dungeons", np_dungeons);
}
diff --git a/src/mapgen/mapgen_v7.h b/src/mapgen/mapgen_v7.h
index b55c80d3a..50039b16a 100644
--- a/src/mapgen/mapgen_v7.h
+++ b/src/mapgen/mapgen_v7.h
@@ -66,6 +66,7 @@ struct MapgenV7Params : public MapgenParams {
NoiseParams np_cavern;
NoiseParams np_cave1;
NoiseParams np_cave2;
+ NoiseParams np_dungeons;
MapgenV7Params();
~MapgenV7Params() = default;
@@ -77,7 +78,7 @@ struct MapgenV7Params : public MapgenParams {
class MapgenV7 : public MapgenBasic {
public:
- MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge);
+ MapgenV7(MapgenV7Params *params, EmergeManager *emerge);
~MapgenV7();
virtual MapgenType getType() const { return MAPGEN_V7; }
diff --git a/src/mapgen/mapgen_valleys.cpp b/src/mapgen/mapgen_valleys.cpp
index 5f9267875..d0b36f29b 100644
--- a/src/mapgen/mapgen_valleys.cpp
+++ b/src/mapgen/mapgen_valleys.cpp
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2016-2018 Duane Robertson <duane@duanerobertson.com>
-Copyright (C) 2016-2018 paramat
+Copyright (C) 2016-2019 Duane Robertson <duane@duanerobertson.com>
+Copyright (C) 2016-2019 paramat
Based on Valleys Mapgen by Gael de Sailly
(https://forum.minetest.net/viewtopic.php?f=9&t=11430)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
#include "mapgen.h"
#include "voxel.h"
#include "noise.h"
@@ -53,18 +54,12 @@ FlagDesc flagdesc_mapgen_valleys[] = {
};
-////////////////////////////////////////////////////////////////////////////////
-
-
-MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params,
- EmergeManager *emerge)
- : MapgenBasic(mapgenid, params, emerge)
+MapgenValleys::MapgenValleys(MapgenValleysParams *params, EmergeManager *emerge)
+ : MapgenBasic(MAPGEN_VALLEYS, params, emerge)
{
// NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
m_bgen = (BiomeGenOriginal *)biomegen;
- BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
-
spflags = params->spflags;
altitude_chill = params->altitude_chill;
river_depth_bed = params->river_depth + 1.0f;
@@ -92,11 +87,10 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params,
noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill,
seed, csize.X, csize.Y + 2, csize.Z);
// 1-down overgeneraion
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
- MapgenBasic::np_cavern = params->np_cavern;
-
- humidity_adjust = bp->np_humidity.offset - 50.0f;
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_cavern = params->np_cavern;
+ MapgenBasic::np_dungeons = params->np_dungeons;
}
@@ -122,7 +116,8 @@ MapgenValleysParams::MapgenValleysParams():
np_valley_profile (0.6, 0.50, v3f(512, 512, 512), 777, 1, 1.0, 2.0),
np_cave1 (0.0, 12.0, v3f(61, 61, 61), 52534, 3, 0.5, 2.0),
np_cave2 (0.0, 12.0, v3f(67, 67, 67), 10325, 3, 0.5, 2.0),
- np_cavern (0.0, 1.0, v3f(768, 256, 768), 59033, 6, 0.63, 2.0)
+ np_cavern (0.0, 1.0, v3f(768, 256, 768), 59033, 6, 0.63, 2.0),
+ np_dungeons (0.9, 0.5, v3f(500, 500, 500), 0, 2, 0.8, 2.0)
{
}
@@ -153,6 +148,7 @@ void MapgenValleysParams::readParams(const Settings *settings)
settings->getNoiseParams("mgvalleys_np_cave1", np_cave1);
settings->getNoiseParams("mgvalleys_np_cave2", np_cave2);
settings->getNoiseParams("mgvalleys_np_cavern", np_cavern);
+ settings->getNoiseParams("mgvalleys_np_dungeons", np_dungeons);
}
@@ -182,12 +178,10 @@ void MapgenValleysParams::writeParams(Settings *settings) const
settings->setNoiseParams("mgvalleys_np_cave1", np_cave1);
settings->setNoiseParams("mgvalleys_np_cave2", np_cave2);
settings->setNoiseParams("mgvalleys_np_cavern", np_cavern);
+ settings->setNoiseParams("mgvalleys_np_dungeons", np_dungeons);
}
-////////////////////////////////////////////////////////////////////////////////
-
-
void MapgenValleys::makeChunk(BlockMakeData *data)
{
// Pre-conditions
@@ -220,19 +214,16 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
// biome-related noises.
m_bgen->calcBiomeNoise(node_min);
- // Generate noise maps and base terrain height.
- // Modify heat and humidity maps.
- calculateNoise();
-
- // Generate base terrain with initial heightmaps
+ // Generate terrain
s16 stone_surface_max_y = generateTerrain();
- // Recalculate heightmap
+ // Create heightmap
updateHeightmap(node_min, node_max);
// Place biome-specific nodes and build biomemap
- if (flags & MG_BIOMES)
+ if (flags & MG_BIOMES) {
generateBiomes();
+ }
// Generate tunnels, caverns and large randomwalk caves
if (flags & MG_CAVES) {
@@ -281,244 +272,151 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
}
-void MapgenValleys::calculateNoise()
-{
- int x = node_min.X;
- int y = node_min.Y - 1;
- int z = node_min.Z;
-
- noise_inter_valley_slope->perlinMap2D(x, z);
- noise_rivers->perlinMap2D(x, z);
- noise_terrain_height->perlinMap2D(x, z);
- noise_valley_depth->perlinMap2D(x, z);
- noise_valley_profile->perlinMap2D(x, z);
-
- noise_inter_valley_fill->perlinMap3D(x, y, z);
-
- float heat_offset = 0.0f;
- float humidity_scale = 1.0f;
- // Altitude chill tends to reduce the average heat.
- if (spflags & MGVALLEYS_ALT_CHILL)
- heat_offset = 5.0f;
- // River humidity tends to increase the humidity range.
- if (spflags & MGVALLEYS_HUMID_RIVERS)
- humidity_scale = 0.8f;
-
- for (s32 index = 0; index < csize.X * csize.Z; index++) {
- m_bgen->heatmap[index] += heat_offset;
- m_bgen->humidmap[index] *= humidity_scale;
- }
-
- TerrainNoise tn;
-
- u32 index = 0;
- for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
- for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
- // The parameters that we actually need to generate terrain are passed
- // by address (and the return value).
- tn.terrain_height = noise_terrain_height->result[index];
- // River noise is replaced with base terrain, which is basically the
- // height of the water table.
- tn.rivers = &noise_rivers->result[index];
- // Valley depth noise is replaced with the valley number that represents
- // the height of terrain over rivers and is used to determine how close
- // a river is for humidity calculation.
- tn.valley = &noise_valley_depth->result[index];
- tn.valley_profile = noise_valley_profile->result[index];
- // Slope noise is replaced by the calculated slope which is used to get
- // terrain height in the slow method, to create sharper mountains.
- tn.slope = &noise_inter_valley_slope->result[index];
- tn.inter_valley_fill = noise_inter_valley_fill->result[index];
-
- // This is the actual terrain height.
- float mount = terrainLevelFromNoise(&tn);
- noise_terrain_height->result[index] = mount;
- }
-}
-
-
-float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
-{
- // The square function changes the behaviour of this noise: very often
- // small, and sometimes very high.
- float valley_d = MYSQUARE(*tn->valley);
-
- // valley_d is here because terrain is generally higher where valleys are
- // deep (mountains). base represents the height of the rivers, most of the
- // surface is above.
- float base = tn->terrain_height + valley_d;
-
- // "river" represents the distance from the river
- float river = std::fabs(*tn->rivers) - river_size_factor;
-
- // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
- // "valley" represents the height of the terrain, from the rivers.
- float tv = std::fmax(river / tn->valley_profile, 0.0f);
- *tn->valley = valley_d * (1.0f - std::exp(-MYSQUARE(tv)));
-
- // Approximate height of the terrain at this point
- float mount = base + *tn->valley;
-
- *tn->slope *= *tn->valley;
-
- // Base ground is returned as rivers since it's basically the water table.
- *tn->rivers = base;
-
- // Rivers are placed where "river" is negative, so where the original noise
- // value is close to zero.
- if (river < 0.0f) {
- // Use the the function -sqrt(1-x^2) which models a circle
- float tr = river / river_size_factor + 1.0f;
- float depth = (river_depth_bed *
- std::sqrt(std::fmax(0.0f, 1.0f - MYSQUARE(tr))));
-
- // base - depth : height of the bottom of the river
- // water_level - 3 : don't make rivers below 3 nodes under the surface.
- // We use three because that's as low as the swamp biomes go.
- // There is no logical equivalent to this using rangelim.
- mount =
- std::fmin(std::fmax(base - depth, (float)(water_level - 3)), mount);
-
- // Slope has no influence on rivers
- *tn->slope = 0.0f;
- }
-
- return mount;
-}
-
-
-// This avoids duplicating the code in terrainLevelFromNoise, adding only the
-// final step of terrain generation without a noise map.
-
-float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
-{
- float mount = terrainLevelFromNoise(tn);
- float result = mount;
- s16 y_start = myround(mount);
- float fill =
- NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y_start, tn->z, seed);
- bool is_ground = fill * *tn->slope >= y_start - mount;
- s16 search_direction = is_ground ? 1 : -1;
-
- for (s16 i = 1; i <= 1000; i++) {
- s16 y = y_start + i * search_direction;
- fill =
- NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
-
- bool was_ground = is_ground;
- is_ground = fill * *tn->slope >= y - mount;
- if (is_ground)
- result = y;
- if (is_ground != was_ground)
- break;
- }
-
- return result;
-}
-
-
int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
{
- // Check if in a river
- float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
- if (std::fabs(rivers) < river_size_factor)
- return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
-
- s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
- if (level_at_point <= water_level ||
- level_at_point > water_level + 16)
- return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
-
- // +1 to account for biome dust that can be 1 node deep
- return level_at_point + 1;
-}
-
-
-float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
-{
- TerrainNoise tn;
-
- float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
- float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
- float inter_valley_slope =
- NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
-
- tn.x = x;
- tn.z = z;
- tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
- tn.rivers = &rivers;
- tn.valley = &valley;
- tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
- tn.slope = &inter_valley_slope;
- tn.inter_valley_fill = 0.0f;
-
- return adjustedTerrainLevelFromNoise(&tn);
+ // Check if in a river channel
+ float n_rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
+ if (std::fabs(n_rivers) <= river_size_factor)
+ // Unsuitable spawn point
+ return MAX_MAP_GENERATION_LIMIT;
+
+ float n_slope = NoisePerlin2D(&noise_inter_valley_slope->np, p.X, p.Y, seed);
+ float n_terrain_height = NoisePerlin2D(&noise_terrain_height->np, p.X, p.Y, seed);
+ float n_valley = NoisePerlin2D(&noise_valley_depth->np, p.X, p.Y, seed);
+ float n_valley_profile = NoisePerlin2D(&noise_valley_profile->np, p.X, p.Y, seed);
+
+ float valley_d = n_valley * n_valley;
+ float base = n_terrain_height + valley_d;
+ float river = std::fabs(n_rivers) - river_size_factor;
+ float tv = std::fmax(river / n_valley_profile, 0.0f);
+ float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
+ float surface_y = base + valley_h;
+ float slope = n_slope * valley_h;
+ float river_y = base - 1.0f;
+
+ // Raising the maximum spawn level above 'water_level + 16' is necessary for custom
+ // parameters that set average terrain level much higher than water_level.
+ s16 max_spawn_y = std::fmax(
+ noise_terrain_height->np.offset +
+ noise_valley_depth->np.offset * noise_valley_depth->np.offset,
+ water_level + 16);
+
+ // Starting spawn search at max_spawn_y + 128 ensures 128 nodes of open
+ // space above spawn position. Avoids spawning in possibly sealed voids.
+ for (s16 y = max_spawn_y + 128; y >= water_level; y--) {
+ float n_fill = NoisePerlin3D(&noise_inter_valley_fill->np, p.X, y, p.Y, seed);
+ float surface_delta = (float)y - surface_y;
+ float density = slope * n_fill - surface_delta;
+
+ if (density > 0.0f) { // If solid
+ // Sometimes surface level is below river water level in places that are not
+ // river channels.
+ if (y < water_level || y > max_spawn_y || y < (s16)river_y)
+ // Unsuitable spawn point
+ return MAX_MAP_GENERATION_LIMIT;
+
+ // y + 2 because y is surface and due to biome 'dust' nodes.
+ return y + 2;
+ }
+ }
+ // Unsuitable spawn position, no ground found
+ return MAX_MAP_GENERATION_LIMIT;
}
int MapgenValleys::generateTerrain()
{
- // Raising this reduces the rate of evaporation
- static const float evaporation = 300.0f;
- static const float humidity_dropoff = 4.0f;
- // Constant to convert altitude chill to heat
- static const float alt_to_heat = 20.0f;
- // Humidity reduction by altitude
- static const float alt_to_humid = 10.0f;
-
MapNode n_air(CONTENT_AIR);
MapNode n_river_water(c_river_water_source);
MapNode n_stone(c_stone);
MapNode n_water(c_water_source);
+ noise_inter_valley_slope->perlinMap2D(node_min.X, node_min.Z);
+ noise_rivers->perlinMap2D(node_min.X, node_min.Z);
+ noise_terrain_height->perlinMap2D(node_min.X, node_min.Z);
+ noise_valley_depth->perlinMap2D(node_min.X, node_min.Z);
+ noise_valley_profile->perlinMap2D(node_min.X, node_min.Z);
+
+ noise_inter_valley_fill->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
+
const v3s16 &em = vm->m_area.getExtent();
s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
u32 index_2d = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
- float river_y = noise_rivers->result[index_2d];
- float surface_y = noise_terrain_height->result[index_2d];
- float slope = noise_inter_valley_slope->result[index_2d];
- float t_heat = m_bgen->heatmap[index_2d];
-
- heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
-
- if (surface_y > surface_max_y)
- surface_max_y = std::ceil(surface_y);
+ float n_slope = noise_inter_valley_slope->result[index_2d];
+ float n_rivers = noise_rivers->result[index_2d];
+ float n_terrain_height = noise_terrain_height->result[index_2d];
+ float n_valley = noise_valley_depth->result[index_2d];
+ float n_valley_profile = noise_valley_profile->result[index_2d];
+
+ float valley_d = n_valley * n_valley;
+ // 'base' represents the level of the river banks
+ float base = n_terrain_height + valley_d;
+ // 'river' represents the distance from the river edge
+ float river = std::fabs(n_rivers) - river_size_factor;
+ // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
+ // 'valley_h' represents the height of the terrain, from the rivers.
+ float tv = std::fmax(river / n_valley_profile, 0.0f);
+ float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
+ // Approximate height of the terrain
+ float surface_y = base + valley_h;
+ float slope = n_slope * valley_h;
+ // River water surface is 1 node below river banks
+ float river_y = base - 1.0f;
+
+ // Rivers are placed where 'river' is negative
+ if (river < 0.0f) {
+ // Use the the function -sqrt(1-x^2) which models a circle
+ float tr = river / river_size_factor + 1.0f;
+ float depth = (river_depth_bed *
+ std::sqrt(std::fmax(0.0f, 1.0f - tr * tr)));
+ // There is no logical equivalent to this using rangelim
+ surface_y = std::fmin(
+ std::fmax(base - depth, (float)(water_level - 3)),
+ surface_y);
+ slope = 0.0f;
+ }
// Optionally vary river depth according to heat and humidity
if (spflags & MGVALLEYS_VARY_RIVER_DEPTH) {
- float heat = ((spflags & MGVALLEYS_ALT_CHILL) &&
- (surface_y > 0.0f || river_y > 0.0f)) ?
- t_heat - alt_to_heat *
- std::fmax(surface_y, river_y) / altitude_chill :
+ float t_heat = m_bgen->heatmap[index_2d];
+ float heat = (spflags & MGVALLEYS_ALT_CHILL) ?
+ // Match heat value calculated below in
+ // 'Optionally decrease heat with altitude'.
+ // In rivers, 'ground height ignoring riverbeds' is 'base'.
+ // As this only affects river water we can assume y > water_level.
+ t_heat + 5.0f - (base - water_level) * 20.0f / altitude_chill :
t_heat;
float delta = m_bgen->humidmap[index_2d] - 50.0f;
if (delta < 0.0f) {
- float t_evap = (heat - 32.0f) / evaporation;
+ float t_evap = (heat - 32.0f) / 300.0f;
river_y += delta * std::fmax(t_evap, 0.08f);
}
}
+ // Highest solid node in column
+ s16 column_max_y = surface_y;
u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
- float fill = noise_inter_valley_fill->result[index_3d];
+ float n_fill = noise_inter_valley_fill->result[index_3d];
float surface_delta = (float)y - surface_y;
- bool river = y < river_y - 1;
+ // Density = density noise + density gradient
+ float density = slope * n_fill - surface_delta;
- if (slope * fill > surface_delta) {
+ if (density > 0.0f) {
vm->m_data[index_data] = n_stone; // Stone
- if (y > heightmap[index_2d])
- heightmap[index_2d] = y;
if (y > surface_max_y)
surface_max_y = y;
+ if (y > column_max_y)
+ column_max_y = y;
} else if (y <= water_level) {
vm->m_data[index_data] = n_water; // Water
- } else if (river) {
+ } else if (y <= (s16)river_y) {
vm->m_data[index_data] = n_river_water; // River water
} else {
vm->m_data[index_data] = n_air; // Air
@@ -529,26 +427,13 @@ int MapgenValleys::generateTerrain()
index_3d += ystride;
}
- if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
- s16 surface_y_int = myround(surface_y);
-
- if (surface_y_int > node_max.Y + 1 ||
- surface_y_int < node_min.Y - 1) {
- // If surface_y is outside the chunk, it's good enough
- heightmap[index_2d] = surface_y_int;
- } else {
- // If the ground is outside of this chunk, but surface_y is
- // within the chunk, give a value outside.
- heightmap[index_2d] = node_min.Y - 2;
- }
- }
-
// Optionally increase humidity around rivers
if (spflags & MGVALLEYS_HUMID_RIVERS) {
+ // Compensate to avoid increasing average humidity
+ m_bgen->humidmap[index_2d] *= 0.8f;
// Ground height ignoring riverbeds
- float t_alt = std::fmax(noise_rivers->result[index_2d],
- (float)heightmap[index_2d]);
- float water_depth = (t_alt - river_y) / humidity_dropoff;
+ float t_alt = std::fmax(base, (float)column_max_y);
+ float water_depth = (t_alt - base) / 4.0f;
m_bgen->humidmap[index_2d] *=
1.0f + std::pow(0.5f, std::fmax(water_depth, 1.0f));
}
@@ -556,21 +441,23 @@ int MapgenValleys::generateTerrain()
// Optionally decrease humidity with altitude
if (spflags & MGVALLEYS_ALT_DRY) {
// Ground height ignoring riverbeds
- float t_alt = std::fmax(noise_rivers->result[index_2d],
- (float)heightmap[index_2d]);
- if (t_alt > 0.0f)
+ float t_alt = std::fmax(base, (float)column_max_y);
+ // Only decrease above water_level
+ if (t_alt > water_level)
m_bgen->humidmap[index_2d] -=
- alt_to_humid * t_alt / altitude_chill;
+ (t_alt - water_level) * 10.0f / altitude_chill;
}
// Optionally decrease heat with altitude
if (spflags & MGVALLEYS_ALT_CHILL) {
+ // Compensate to avoid reducing the average heat
+ m_bgen->heatmap[index_2d] += 5.0f;
// Ground height ignoring riverbeds
- float t_alt = std::fmax(noise_rivers->result[index_2d],
- (float)heightmap[index_2d]);
- if (t_alt > 0.0f)
+ float t_alt = std::fmax(base, (float)column_max_y);
+ // Only decrease above water_level
+ if (t_alt > water_level)
m_bgen->heatmap[index_2d] -=
- alt_to_heat * t_alt / altitude_chill;
+ (t_alt - water_level) * 20.0f / altitude_chill;
}
}
diff --git a/src/mapgen/mapgen_valleys.h b/src/mapgen/mapgen_valleys.h
index 8bde7a622..ab80dc5c9 100644
--- a/src/mapgen/mapgen_valleys.h
+++ b/src/mapgen/mapgen_valleys.h
@@ -1,11 +1,11 @@
/*
Minetest
-Copyright (C) 2016-2018 Duane Robertson <duane@duanerobertson.com>
-Copyright (C) 2016-2018 paramat
+Copyright (C) 2016-2019 Duane Robertson <duane@duanerobertson.com>
+Copyright (C) 2016-2019 paramat
Based on Valleys Mapgen by Gael de Sailly
(https://forum.minetest.net/viewtopic.php?f=9&t=11430)
-and mapgen_v7 by kwolekr and paramat.
+and mapgen_v7, mapgen_flat by kwolekr and paramat.
Licensing changed by permission of Gael de Sailly.
@@ -24,20 +24,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
#pragma once
#include "mapgen.h"
-/////////////////// Mapgen Valleys flags
#define MGVALLEYS_ALT_CHILL 0x01
#define MGVALLEYS_HUMID_RIVERS 0x02
#define MGVALLEYS_VARY_RIVER_DEPTH 0x04
#define MGVALLEYS_ALT_DRY 0x08
-// Feed only one variable into these
-#define MYSQUARE(x) (x) * (x)
-#define MYCUBE(x) (x) * (x) * (x)
-
class BiomeManager;
class BiomeGenOriginal;
@@ -71,6 +67,7 @@ struct MapgenValleysParams : public MapgenParams {
NoiseParams np_cave1;
NoiseParams np_cave2;
NoiseParams np_cavern;
+ NoiseParams np_dungeons;
MapgenValleysParams();
~MapgenValleysParams() = default;
@@ -79,21 +76,11 @@ struct MapgenValleysParams : public MapgenParams {
void writeParams(Settings *settings) const;
};
-struct TerrainNoise {
- s16 x;
- s16 z;
- float terrain_height;
- float *rivers;
- float *valley;
- float valley_profile;
- float *slope;
- float inter_valley_fill;
-};
class MapgenValleys : public MapgenBasic {
public:
- MapgenValleys(int mapgenid, MapgenValleysParams *params,
+ MapgenValleys(MapgenValleysParams *params,
EmergeManager *emerge);
~MapgenValleys();
@@ -106,7 +93,6 @@ private:
BiomeGenOriginal *m_bgen;
float altitude_chill;
- float humidity_adjust;
float river_depth_bed;
float river_size_factor;
@@ -121,9 +107,5 @@ private:
Noise *noise_valley_depth;
Noise *noise_valley_profile;
- float terrainLevelAtPoint(s16 x, s16 z);
- void calculateNoise();
virtual int generateTerrain();
- float terrainLevelFromNoise(TerrainNoise *tn);
- float adjustedTerrainLevelFromNoise(TerrainNoise *tn);
};
diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp
index 7f717011c..345bc8c6a 100644
--- a/src/mapgen/mg_biome.cpp
+++ b/src/mapgen/mg_biome.cpp
@@ -63,6 +63,7 @@ BiomeManager::BiomeManager(Server *server) :
b->m_nodenames.emplace_back("mapgen_stone");
b->m_nodenames.emplace_back("ignore");
b->m_nodenames.emplace_back("ignore");
+ b->m_nnlistsizes.push_back(1);
b->m_nodenames.emplace_back("ignore");
b->m_nodenames.emplace_back("ignore");
b->m_nodenames.emplace_back("ignore");
@@ -330,7 +331,7 @@ void Biome::resolveNodeNames()
getIdFromNrBacklog(&c_river_water, "mapgen_river_water_source", CONTENT_AIR, false);
getIdFromNrBacklog(&c_riverbed, "mapgen_stone", CONTENT_AIR, false);
getIdFromNrBacklog(&c_dust, "ignore", CONTENT_IGNORE, false);
- getIdFromNrBacklog(&c_cave_liquid, "ignore", CONTENT_IGNORE, false);
+ getIdsFromNrBacklog(&c_cave_liquid);
getIdFromNrBacklog(&c_dungeon, "ignore", CONTENT_IGNORE, false);
getIdFromNrBacklog(&c_dungeon_alt, "ignore", CONTENT_IGNORE, false);
getIdFromNrBacklog(&c_dungeon_stair, "ignore", CONTENT_IGNORE, false);
diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h
index 1f60f7bac..ee148adbc 100644
--- a/src/mapgen/mg_biome.h
+++ b/src/mapgen/mg_biome.h
@@ -52,7 +52,7 @@ public:
content_t c_river_water;
content_t c_riverbed;
content_t c_dust;
- content_t c_cave_liquid;
+ std::vector<content_t> c_cave_liquid;
content_t c_dungeon;
content_t c_dungeon_alt;
content_t c_dungeon_stair;
diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp
index 36f1dd76b..c1acbfd9d 100644
--- a/src/mapgen/mg_schematic.cpp
+++ b/src/mapgen/mg_schematic.cpp
@@ -246,7 +246,7 @@ void Schematic::placeOnMap(ServerMap *map, v3s16 p, u32 flags,
for (it = modified_blocks.begin(); it != modified_blocks.end(); ++it)
event.modified_blocks.insert(it->first);
- map->dispatchEvent(&event);
+ map->dispatchEvent(event);
}
diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp
index 4c351fcef..0d8af2851 100644
--- a/src/mapgen/treegen.cpp
+++ b/src/mapgen/treegen.cpp
@@ -135,7 +135,7 @@ treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
event.type = MEET_OTHER;
for (auto &modified_block : modified_blocks)
event.modified_blocks.insert(modified_block.first);
- map->dispatchEvent(&event);
+ map->dispatchEvent(event);
return SUCCESS;
}