Cavegen/Mgv5/Mgv7: Add optional giant caverns
authorparamat <mat.gregory@virginmedia.com>
Sun, 12 Mar 2017 13:26:09 +0000 (13:26 +0000)
committerparamat <mat.gregory@virginmedia.com>
Mon, 3 Apr 2017 03:49:32 +0000 (04:49 +0100)
Add to MapgenBasic for use by multiple mapgens.
Add to mgv5 and mgv7, enabled by default.

Similar to mgvalleys caverns but half the scale.
Parameters for upper y limit, distance caverns taper to full size, and
noise threshold (full cavern size).
As with mgvalleys caverns are generated first and classic caves are
disabled in any mapchunk containing a cavern, to avoid excessive
spreading volumes of liquids.
This also avoids floating blobs of liquid where a large classic cave
has overgenerated out into a neighbouring previously-generated mapchunk.

builtin/settingtypes.txt
minetest.conf.example
src/cavegen.cpp
src/cavegen.h
src/mapgen.cpp
src/mapgen.h
src/mapgen_v5.cpp
src/mapgen_v5.h
src/mapgen_v7.cpp
src/mapgen_v7.h

index c9e0f7b87f897cf7b459a70c756e6cc0fe19047e..bbee777497903fcdfb19d57635da0de1a1f32257 100644 (file)
@@ -940,12 +940,25 @@ mg_biome_np_humidity_blend (Mapgen biome humidity blend noise parameters) noise_
 #    Controls width of tunnels, a smaller value creates wider tunnels.
 mgv5_cave_width (Mapgen v5 cave width) float 0.125
 
+#    Y-level of cavern upper limit.
+mgv5_cavern_limit (Mapgen v5 cavern limit) int -256
+
+#    Y-distance over which caverns expand to full size.
+mgv5_cavern_taper (Mapgen v5 cavern taper) int 256
+
+#    Defines full size of caverns, smaller values create larger caverns.
+mgv5_cavern_threshold (Mapgen v5 cavern threshold) float 0.7
+
 mgv5_np_filler_depth (Mapgen v5 filler depth noise parameters) noise_params 0, 1, (150, 150, 150), 261, 4, 0.7, 2.0
 mgv5_np_factor (Mapgen v5 factor noise parameters) noise_params 0, 1, (250, 250, 250), 920381, 3, 0.45, 2.0
 mgv5_np_height (Mapgen v5 height noise parameters) noise_params 0, 10, (250, 250, 250), 84174, 4, 0.5, 2.0
 mgv5_np_cave1 (Mapgen v5 cave1 noise parameters) noise_params 0, 12, (50, 50, 50), 52534, 4, 0.5, 2.0
 mgv5_np_cave2 (Mapgen v5 cave2 noise parameters) noise_params 0, 12, (50, 50, 50), 10325, 4, 0.5, 2.0
+mgv5_np_cavern (Mapgen v5 cavern noise parameters) noise_params 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0
 #    TODO
+#    Noise parameters in group format, unsupported by advanced settings
+#    menu but settable in minetest.conf.
+#    See documentation of noise parameter formats in minetest.conf.example.
 #mgv5_np_ground = {
 #    offset      = 0
 #    scale       = 40
@@ -1007,6 +1020,15 @@ mgv7_floatland_level (Mapgen v7 floatland level) int 1280
 #    Y-level to which floatland shadows extend.
 mgv7_shadow_limit (Mapgen v7 shadow limit) int 1024
 
+#    Y-level of cavern upper limit.
+mgv7_cavern_limit (Mapgen v7 cavern limit) int -256
+
+#    Y-distance over which caverns expand to full size.
+mgv7_cavern_taper (Mapgen v7 cavern taper) int 256
+
+#    Defines full size of caverns, smaller values create larger caverns.
+mgv7_cavern_threshold (Mapgen v7 cavern threshold) float 0.7
+
 mgv7_np_terrain_base (Mapgen v7 terrain base noise parameters) noise_params 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0
 mgv7_np_terrain_alt (Mapgen v7 terrain altitude noise parameters) noise_params 4, 25, (600, 600, 600), 5934, 5, 0.6, 2.0
 mgv7_np_terrain_persist (Mapgen v7 terrain persistation noise parameters) noise_params 0.6, 0.1, (2000, 2000, 2000), 539, 3, 0.6, 2.0
@@ -1018,6 +1040,7 @@ mgv7_np_floatland_base (Mapgen v7 floatland base terrain noise parameters) noise
 mgv7_np_float_base_height (Mapgen v7 floatland base terrain height noise parameters) noise_params 48, 24, (300, 300, 300), 907, 4, 0.7, 2.0
 mgv7_np_mountain (Mapgen v7 mountain noise parameters) noise_params -0.6, 1, (250, 350, 250), 5333, 5, 0.63, 2.0
 mgv7_np_ridge (Mapgen v7 river channel wall noise parameters) noise_params 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0
+mgv7_np_cavern (Mapgen v7 cavern noise parameters) noise_params 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0
 mgv7_np_cave1 (Mapgen v7 cave1 noise parameters) noise_params 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
 mgv7_np_cave2 (Mapgen v7 cave2 noise parameters) noise_params 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
 
index a45a9948a3c8f540b7f88ad540089fadfc235922..5927cdb0392042dc11bc85b948246d5961b9493d 100644 (file)
@@ -1174,6 +1174,18 @@ server_side_occlusion_culling = true
 #    type: float
 # mgv5_cave_width = 0.125
 
+#    Y-level of cavern upper limit.
+#    type: int
+# mgv5_cavern_limit = -256
+
+#    Y-distance over which caverns expand to full size.
+#    type: int
+# mgv5_cavern_taper = 256
+
+#    Defines full size of caverns, smaller values create larger caverns.
+#    type: float
+# mgv5_cavern_threshold = 0.7
+
 #    type: noise_params
 # mgv5_np_filler_depth = 0, 1, (150, 150, 150), 261, 4, 0.7, 2.0
 
@@ -1189,6 +1201,9 @@ server_side_occlusion_culling = true
 #    type: noise_params
 # mgv5_np_cave2 = 0, 12, (50, 50, 50), 10325, 4, 0.5, 2.0
 
+#    type: noise_params
+# mgv5_np_cavern = 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0
+
 #    Noise parameters in group format, unsupported by advanced settings
 #    menu but settable in minetest.conf.
 #    See documentation of noise parameter formats above.
@@ -1284,6 +1299,18 @@ server_side_occlusion_culling = true
 #    type: int
 # mgv7_shadow_limit = 1024
 
+#    Y-level of cavern upper limit.
+#    type: int
+# mgv7_cavern_limit = -256
+
+#    Y-distance over which caverns expand to full size.
+#    type: int
+# mgv7_cavern_taper = 256
+
+#    Defines full size of caverns, smaller values create larger caverns.
+#    type: float
+# mgv7_cavern_threshold = 0.7
+
 #    type: noise_params
 # mgv7_np_terrain_base = 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0
 
@@ -1317,6 +1344,9 @@ server_side_occlusion_culling = true
 #    type: noise_params
 # mgv7_np_ridge = 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0
 
+#    type: noise_params
+# mgv7_np_cavern = 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0
+
 #    type: noise_params
 # mgv7_np_cave1 = 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
 
index 1005640c1cbfc9303423a02c30dbafad52711c12..6275c516e1c6a1565544523c687298c7436216b7 100644 (file)
@@ -150,6 +150,101 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm,
 }
 
 
+////
+//// CavernsNoise
+////
+
+CavernsNoise::CavernsNoise(
+       INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
+       s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold)
+{
+       assert(nodedef);
+
+       m_ndef = nodedef;
+
+       m_csize = chunksize;
+       m_cavern_limit     = cavern_limit;
+       m_cavern_taper     = cavern_taper;
+       m_cavern_threshold = cavern_threshold;
+
+       m_ystride = m_csize.X;
+       m_zstride_1d = m_csize.X * (m_csize.Y + 1);
+
+       // Noise is created using 1-down overgeneration
+       // A Nx-by-1-by-Nz-sized plane is at the bottom of the desired for
+       // re-carving the solid overtop placed for blocking sunlight
+       noise_cavern = new Noise(np_cavern, seed, m_csize.X, m_csize.Y + 1, m_csize.Z);
+
+       c_water_source = m_ndef->getId("mapgen_water_source");
+       if (c_water_source == CONTENT_IGNORE)
+               c_water_source = CONTENT_AIR;
+
+       c_lava_source = m_ndef->getId("mapgen_lava_source");
+       if (c_lava_source == CONTENT_IGNORE)
+               c_lava_source = CONTENT_AIR;
+}
+
+
+CavernsNoise::~CavernsNoise()
+{
+       delete noise_cavern;
+}
+
+
+bool CavernsNoise::generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax)
+{
+       assert(vm);
+
+       // Calculate noise
+       noise_cavern->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);
+
+       // Cache cavern_amp values
+       float cavern_amp[m_csize.Y + 1];
+       u8 cavern_amp_index = 0;  // Index zero at column top
+       for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, cavern_amp_index++) {
+               cavern_amp[cavern_amp_index] =
+                       MYMIN((m_cavern_limit - y) / (float)m_cavern_taper, 1.0f);
+       }
+
+       //// Place nodes
+       bool has_cavern = false;
+       v3s16 em = vm->m_area.getExtent();
+       u32 index2d = 0;
+
+       for (s16 z = nmin.Z; z <= nmax.Z; z++)
+       for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) {
+               // Reset cave_amp index to column top
+               cavern_amp_index = 0;
+               // Initial voxelmanip index at column top
+               u32 vi = vm->m_area.index(x, nmax.Y, z);
+               // Initial 3D noise index at column top
+               u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride +
+                       (x - nmin.X);
+               // Don't excavate the overgenerated stone at node_max.Y + 1,
+               // this creates a 'roof' over the cavern, preventing light in
+               // caverns at mapchunk borders when generating mapchunks upwards.
+               // This 'roof' is excavated when the mapchunk above is generated.
+               for (s16 y = nmax.Y; y >= nmin.Y - 1; y--,
+                               index3d -= m_ystride,
+                               vm->m_area.add_y(em, vi, -1),
+                               cavern_amp_index++) {
+                       content_t c = vm->m_data[vi].getContent();
+                       float nabs_cavern = fabs(noise_cavern->result[index3d]);
+                       // Caverns generate first but still remove lava and water in case
+                       // of overgenerated classic caves.
+                       if (nabs_cavern * cavern_amp[cavern_amp_index] > m_cavern_threshold &&
+                                       (m_ndef->get(c).is_ground_content ||
+                                       c == c_lava_source || c == c_water_source)) {
+                               vm->m_data[vi] = MapNode(CONTENT_AIR);
+                               has_cavern = true;
+                       }
+               }
+       }
+
+       return has_cavern;
+}
+
+
 ////
 //// CavesRandomWalk
 ////
index 2bf503d476dd105bf2beca0d5689e6f46ff53856..e322c181c625c1e2e5fd6433a1291fce90297496 100644 (file)
@@ -62,6 +62,36 @@ private:
        Noise *noise_cave2;
 };
 
+/*
+       CavernsNoise is a cave digging algorithm
+*/
+class CavernsNoise {
+public:
+       CavernsNoise(INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
+       s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold);
+       ~CavernsNoise();
+
+       bool generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax);
+
+private:
+       INodeDefManager *m_ndef;
+
+       // configurable parameters
+       v3s16 m_csize;
+       float m_cavern_limit;
+       float m_cavern_taper;
+       float m_cavern_threshold;
+
+       // intermediate state variables
+       u16 m_ystride;
+       u16 m_zstride_1d;
+
+       Noise *noise_cavern;
+
+       content_t c_water_source;
+       content_t c_lava_source;
+};
+
 /*
        CavesRandomWalk is an implementation of a cave-digging algorithm that
        operates on the principle of a "random walk" to approximate the stochiastic
index b6e8c0fd12a3d94b60881ab6dd5dbf6ef9489873..c63c426fa186470499bfe0d231aba47d17cd42bb 100644 (file)
@@ -840,6 +840,18 @@ void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
 }
 
 
+bool MapgenBasic::generateCaverns(s16 max_stone_y)
+{
+       if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
+               return false;
+
+       CavernsNoise caverns_noise(ndef, csize, &np_cavern,
+               seed, cavern_limit, cavern_taper, cavern_threshold);
+
+       return caverns_noise.generateCaverns(vm, node_min, node_max);
+}
+
+
 void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
 {
        if (max_stone_y < node_min.Y)
index c4e1652e89ddc3d18ed25bb13495776717dd3fbf..f738b1bce6b1a0fc345b0583ecd8a99fc6f5e912 100644 (file)
@@ -243,6 +243,7 @@ public:
        virtual ~MapgenBasic();
 
        virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
+       virtual bool generateCaverns(s16 max_stone_y);
        virtual void generateDungeons(s16 max_stone_y, MgStoneType stone_type);
        virtual MgStoneType generateBiomes();
        virtual void dustTopNodes();
@@ -282,7 +283,11 @@ protected:
 
        NoiseParams np_cave1;
        NoiseParams np_cave2;
+       NoiseParams np_cavern;
        float cave_width;
+       float cavern_limit;
+       float cavern_taper;
+       float cavern_threshold;
 };
 
 #endif
index 9f189e25399b58f161992293ee15f9acee0dd8aa..b983026e6d47141f63ce8ce8ed95f9d41d2b2785 100644 (file)
@@ -41,15 +41,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 
 FlagDesc flagdesc_mapgen_v5[] = {
-       {NULL,         0}
+       {"caverns", MGV5_CAVERNS},
+       {NULL,      0}
 };
 
 
 MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
        : MapgenBasic(mapgenid, params, emerge)
 {
-       this->spflags    = params->spflags;
-       this->cave_width = params->cave_width;
+       this->spflags          = params->spflags;
+       this->cave_width       = params->cave_width;
+       this->cavern_limit     = params->cavern_limit;
+       this->cavern_taper     = params->cavern_taper;
+       this->cavern_threshold = params->cavern_threshold;
 
        // Terrain noise
        noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
@@ -59,9 +63,10 @@ MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
        // 3D terrain noise
        // 1-up 1-down overgeneration
        noise_ground = new Noise(&params->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
-
-       MapgenBasic::np_cave1 = params->np_cave1;
-       MapgenBasic::np_cave2 = params->np_cave2;
+       // 1 down overgeneration
+       MapgenBasic::np_cave1  = params->np_cave1;
+       MapgenBasic::np_cave2  = params->np_cave2;
+       MapgenBasic::np_cavern = params->np_cavern;
 }
 
 
@@ -76,47 +81,55 @@ MapgenV5::~MapgenV5()
 
 MapgenV5Params::MapgenV5Params()
 {
-       spflags    = 0;
-       cave_width = 0.125;
+       spflags          = MGV5_CAVERNS;
+       cave_width       = 0.125;
+       cavern_limit     = -256;
+       cavern_taper     = 256;
+       cavern_threshold = 0.7;
 
        np_filler_depth = NoiseParams(0, 1,  v3f(150, 150, 150), 261,    4, 0.7,  2.0);
        np_factor       = NoiseParams(0, 1,  v3f(250, 250, 250), 920381, 3, 0.45, 2.0);
        np_height       = NoiseParams(0, 10, v3f(250, 250, 250), 84174,  4, 0.5,  2.0);
+       np_ground       = NoiseParams(0, 40, v3f(80,  80,  80),  983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
        np_cave1        = NoiseParams(0, 12, v3f(50,  50,  50),  52534,  4, 0.5,  2.0);
        np_cave2        = NoiseParams(0, 12, v3f(50,  50,  50),  10325,  4, 0.5,  2.0);
-       np_ground       = NoiseParams(0, 40, v3f(80,  80,  80),  983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
+       np_cavern       = NoiseParams(0, 1,  v3f(384, 128, 384), 723,    5, 0.63, 2.0);
 }
 
 
-//#define CAVE_NOISE_SCALE 12.0
-//#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE) = 0.125
-
-
 void MapgenV5Params::readParams(const Settings *settings)
 {
-       settings->getFlagStrNoEx("mgv5_spflags",  spflags, flagdesc_mapgen_v5);
-       settings->getFloatNoEx("mgv5_cave_width", cave_width);
+       settings->getFlagStrNoEx("mgv5_spflags",        spflags, flagdesc_mapgen_v5);
+       settings->getFloatNoEx("mgv5_cave_width",       cave_width);
+       settings->getS16NoEx("mgv5_cavern_limit",       cavern_limit);
+       settings->getS16NoEx("mgv5_cavern_taper",       cavern_taper);
+       settings->getFloatNoEx("mgv5_cavern_threshold", cavern_threshold);
 
        settings->getNoiseParams("mgv5_np_filler_depth", np_filler_depth);
        settings->getNoiseParams("mgv5_np_factor",       np_factor);
        settings->getNoiseParams("mgv5_np_height",       np_height);
+       settings->getNoiseParams("mgv5_np_ground",       np_ground);
        settings->getNoiseParams("mgv5_np_cave1",        np_cave1);
        settings->getNoiseParams("mgv5_np_cave2",        np_cave2);
-       settings->getNoiseParams("mgv5_np_ground",       np_ground);
+       settings->getNoiseParams("mgv5_np_cavern",       np_cavern);
 }
 
 
 void MapgenV5Params::writeParams(Settings *settings) const
 {
-       settings->setFlagStr("mgv5_spflags",  spflags, flagdesc_mapgen_v5, U32_MAX);
-       settings->setFloat("mgv5_cave_width", cave_width);
+       settings->setFlagStr("mgv5_spflags",        spflags, flagdesc_mapgen_v5, U32_MAX);
+       settings->setFloat("mgv5_cave_width",       cave_width);
+       settings->setS16("mgv5_cavern_limit",       cavern_limit);
+       settings->setS16("mgv5_cavern_taper",       cavern_taper);
+       settings->setFloat("mgv5_cavern_threshold", cavern_threshold);
 
        settings->setNoiseParams("mgv5_np_filler_depth", np_filler_depth);
        settings->setNoiseParams("mgv5_np_factor",       np_factor);
        settings->setNoiseParams("mgv5_np_height",       np_height);
+       settings->setNoiseParams("mgv5_np_ground",       np_ground);
        settings->setNoiseParams("mgv5_np_cave1",        np_cave1);
        settings->setNoiseParams("mgv5_np_cave2",        np_cave2);
-       settings->setNoiseParams("mgv5_np_ground",       np_ground);
+       settings->setNoiseParams("mgv5_np_cavern",       np_cavern);
 }
 
 
@@ -190,9 +203,21 @@ void MapgenV5::makeChunk(BlockMakeData *data)
        biomegen->calcBiomeNoise(node_min);
        MgStoneType stone_type = generateBiomes();
 
-       // Generate caves
-       if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
-               generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
+       // Generate caverns, tunnels and classic caves
+       if (flags & MG_CAVES) {
+               bool has_cavern = false;
+               // Generate caverns
+               if (spflags & MGV5_CAVERNS)
+                       has_cavern = generateCaverns(stone_surface_max_y);
+               // Generate tunnels and classic caves
+               if (has_cavern)
+                       // Disable classic caves in this mapchunk by setting
+                       // 'large cave depth' to world base. Avoids excessive liquid in
+                       // large caverns and floating blobs of overgenerated liquid.
+                       generateCaves(stone_surface_max_y, -MAX_MAP_GENERATION_LIMIT);
+               else
+                       generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
+       }
 
        // Generate dungeons and desert temples
        if (flags & MG_DUNGEONS)
@@ -223,23 +248,6 @@ void MapgenV5::makeChunk(BlockMakeData *data)
 }
 
 
-//bool is_cave(u32 index) {
-//     double d1 = contour(noise_cave1->result[index]);
-//     double d2 = contour(noise_cave2->result[index]);
-//     return d1*d2 > CAVE_NOISE_THRESHOLD;
-//}
-
-//bool val_is_ground(v3s16 p, u32 index, u32 index2d) {
-//     double f = 0.55 + noise_factor->result[index2d];
-//     if(f < 0.01)
-//             f = 0.01;
-//     else if(f >= 1.0)
-//             f *= 1.6;
-//     double h = WATER_LEVEL + 10 * noise_height->result[index2d];
-//     return (noise_ground->result[index] * f > (double)p.Y - h);
-//}
-
-
 int MapgenV5::generateBaseTerrain()
 {
        u32 index = 0;
index ddb090a9c4a06af16bd3ace7d5e93de82bb9045f..034d53560ccc30f0d8613afd4f5874332328ed17 100644 (file)
@@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define MGV5_LARGE_CAVE_DEPTH -256
 
+///////// Mapgen V5 flags
+#define MGV5_CAVERNS 0x01
+
 class BiomeManager;
 
 extern FlagDesc flagdesc_mapgen_v5[];
@@ -33,12 +36,17 @@ extern FlagDesc flagdesc_mapgen_v5[];
 struct MapgenV5Params : public MapgenParams {
        u32 spflags;
        float cave_width;
+       s16 cavern_limit;
+       s16 cavern_taper;
+       float cavern_threshold;
+
        NoiseParams np_filler_depth;
        NoiseParams np_factor;
        NoiseParams np_height;
+       NoiseParams np_ground;
        NoiseParams np_cave1;
        NoiseParams np_cave2;
-       NoiseParams np_ground;
+       NoiseParams np_cavern;
 
        MapgenV5Params();
        ~MapgenV5Params() {}
index 04a9e3c16e3332b0d747ad3cf7749b24c7038cc2..760299fd6f0e7f7a86cbd41f25886afdfccbb466 100644 (file)
@@ -41,10 +41,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 
 FlagDesc flagdesc_mapgen_v7[] = {
-       {"mountains",    MGV7_MOUNTAINS},
-       {"ridges",       MGV7_RIDGES},
-       {"floatlands",   MGV7_FLOATLANDS},
-       {NULL,           0}
+       {"mountains",  MGV7_MOUNTAINS},
+       {"ridges",     MGV7_RIDGES},
+       {"floatlands", MGV7_FLOATLANDS},
+       {"caverns",    MGV7_CAVERNS},
+       {NULL,         0}
 };
 
 
@@ -60,6 +61,9 @@ MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
        this->float_mount_height  = params->float_mount_height;
        this->floatland_level     = params->floatland_level;
        this->shadow_limit        = params->shadow_limit;
+       this->cavern_limit        = params->cavern_limit;
+       this->cavern_taper        = params->cavern_taper;
+       this->cavern_threshold    = params->cavern_threshold;
 
        //// Terrain noise
        noise_terrain_base      = new Noise(&params->np_terrain_base,      seed, csize.X, csize.Z);
@@ -76,9 +80,10 @@ MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
        // 1-up 1-down overgeneration
        noise_mountain = new Noise(&params->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
        noise_ridge    = new Noise(&params->np_ridge,    seed, csize.X, csize.Y + 2, csize.Z);
-
-       MapgenBasic::np_cave1 = params->np_cave1;
-       MapgenBasic::np_cave2 = params->np_cave2;
+       // 1 down overgeneration
+       MapgenBasic::np_cave1  = params->np_cave1;
+       MapgenBasic::np_cave2  = params->np_cave2;
+       MapgenBasic::np_cavern = params->np_cavern;
 }
 
 
@@ -100,12 +105,15 @@ MapgenV7::~MapgenV7()
 
 MapgenV7Params::MapgenV7Params()
 {
-       spflags             = MGV7_MOUNTAINS | MGV7_RIDGES;
+       spflags             = MGV7_MOUNTAINS | MGV7_RIDGES | MGV7_CAVERNS;
        cave_width          = 0.09;
        float_mount_density = 0.6;
        float_mount_height  = 128.0;
        floatland_level     = 1280;
        shadow_limit        = 1024;
+       cavern_limit        = -256;
+       cavern_taper        = 256;
+       cavern_threshold    = 0.7;
 
        np_terrain_base      = NoiseParams(4,    70,   v3f(600,  600,  600),  82341, 5, 0.6,  2.0);
        np_terrain_alt       = NoiseParams(4,    25,   v3f(600,  600,  600),  5934,  5, 0.6,  2.0);
@@ -118,6 +126,7 @@ MapgenV7Params::MapgenV7Params()
        np_float_base_height = NoiseParams(48,   24,   v3f(300,  300,  300),  907,   4, 0.7,  2.0);
        np_mountain          = NoiseParams(-0.6, 1,    v3f(250,  350,  250),  5333,  5, 0.63, 2.0);
        np_ridge             = NoiseParams(0,    1,    v3f(100,  100,  100),  6467,  4, 0.75, 2.0);
+       np_cavern            = NoiseParams(0,    1,    v3f(384,  128,  384),  723,   5, 0.63, 2.0);
        np_cave1             = NoiseParams(0,    12,   v3f(61,   61,   61),   52534, 3, 0.5,  2.0);
        np_cave2             = NoiseParams(0,    12,   v3f(67,   67,   67),   10325, 3, 0.5,  2.0);
 }
@@ -131,6 +140,9 @@ void MapgenV7Params::readParams(const Settings *settings)
        settings->getFloatNoEx("mgv7_float_mount_height",  float_mount_height);
        settings->getS16NoEx("mgv7_floatland_level",       floatland_level);
        settings->getS16NoEx("mgv7_shadow_limit",          shadow_limit);
+       settings->getS16NoEx("mgv7_cavern_limit",          cavern_limit);
+       settings->getS16NoEx("mgv7_cavern_taper",          cavern_taper);
+       settings->getFloatNoEx("mgv7_cavern_threshold",    cavern_threshold);
 
        settings->getNoiseParams("mgv7_np_terrain_base",      np_terrain_base);
        settings->getNoiseParams("mgv7_np_terrain_alt",       np_terrain_alt);
@@ -143,6 +155,7 @@ void MapgenV7Params::readParams(const Settings *settings)
        settings->getNoiseParams("mgv7_np_float_base_height", np_float_base_height);
        settings->getNoiseParams("mgv7_np_mountain",          np_mountain);
        settings->getNoiseParams("mgv7_np_ridge",             np_ridge);
+       settings->getNoiseParams("mgv7_np_cavern",            np_cavern);
        settings->getNoiseParams("mgv7_np_cave1",             np_cave1);
        settings->getNoiseParams("mgv7_np_cave2",             np_cave2);
 }
@@ -156,6 +169,9 @@ void MapgenV7Params::writeParams(Settings *settings) const
        settings->setFloat("mgv7_float_mount_height",  float_mount_height);
        settings->setS16("mgv7_floatland_level",       floatland_level);
        settings->setS16("mgv7_shadow_limit",          shadow_limit);
+       settings->setS16("mgv7_cavern_limit",          cavern_limit);
+       settings->setS16("mgv7_cavern_taper",          cavern_taper);
+       settings->setFloat("mgv7_cavern_threshold",    cavern_threshold);
 
        settings->setNoiseParams("mgv7_np_terrain_base",      np_terrain_base);
        settings->setNoiseParams("mgv7_np_terrain_alt",       np_terrain_alt);
@@ -168,6 +184,7 @@ void MapgenV7Params::writeParams(Settings *settings) const
        settings->setNoiseParams("mgv7_np_float_base_height", np_float_base_height);
        settings->setNoiseParams("mgv7_np_mountain",          np_mountain);
        settings->setNoiseParams("mgv7_np_ridge",             np_ridge);
+       settings->setNoiseParams("mgv7_np_cavern",            np_cavern);
        settings->setNoiseParams("mgv7_np_cave1",             np_cave1);
        settings->setNoiseParams("mgv7_np_cave2",             np_cave2);
 }
@@ -256,9 +273,23 @@ void MapgenV7::makeChunk(BlockMakeData *data)
        biomegen->calcBiomeNoise(node_min);
        MgStoneType stone_type = generateBiomes();
 
-       if (flags & MG_CAVES)
-               generateCaves(stone_surface_max_y, water_level);
+       // Generate caverns, tunnels and classic caves
+       if (flags & MG_CAVES) {
+               bool has_cavern = false;
+               // Generate caverns
+               if (spflags & MGV7_CAVERNS)
+                       has_cavern = generateCaverns(stone_surface_max_y);
+               // Generate tunnels and classic caves
+               if (has_cavern)
+                       // Disable classic caves in this mapchunk by setting
+                       // 'large cave depth' to world base. Avoids excessive liquid in
+                       // large caverns and floating blobs of overgenerated liquid.
+                       generateCaves(stone_surface_max_y, -MAX_MAP_GENERATION_LIMIT);
+               else
+                       generateCaves(stone_surface_max_y, water_level);
+       }
 
+       // Generate dungeons
        if (flags & MG_DUNGEONS)
                generateDungeons(stone_surface_max_y, stone_type);
 
@@ -274,8 +305,10 @@ void MapgenV7::makeChunk(BlockMakeData *data)
 
        //printf("makeChunk: %dms\n", t.stop());
 
+       // Update liquids
        updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
 
+       // Calculate lighting
        // Limit floatland shadow
        bool propagate_shadow = !((spflags & MGV7_FLOATLANDS) &&
                node_min.Y <= shadow_limit && node_max.Y >= shadow_limit);
index 3972387a79b48726868d1f82ce1f122162fed249..71a341afe78cc6dd3c273f156cdab11ca9b97609 100644 (file)
@@ -23,10 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "mapgen.h"
 
-////////////// Mapgen V7 flags
-#define MGV7_MOUNTAINS    0x01
-#define MGV7_RIDGES       0x02
-#define MGV7_FLOATLANDS   0x04
+//////////// Mapgen V7 flags
+#define MGV7_MOUNTAINS  0x01
+#define MGV7_RIDGES     0x02
+#define MGV7_FLOATLANDS 0x04
+#define MGV7_CAVERNS    0x08
 
 class BiomeManager;
 
@@ -40,6 +41,9 @@ struct MapgenV7Params : public MapgenParams {
        float float_mount_height;
        s16 floatland_level;
        s16 shadow_limit;
+       s16 cavern_limit;
+       s16 cavern_taper;
+       float cavern_threshold;
 
        NoiseParams np_terrain_base;
        NoiseParams np_terrain_alt;
@@ -52,6 +56,7 @@ struct MapgenV7Params : public MapgenParams {
        NoiseParams np_float_base_height;
        NoiseParams np_mountain;
        NoiseParams np_ridge;
+       NoiseParams np_cavern;
        NoiseParams np_cave1;
        NoiseParams np_cave2;