]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_valleys.cpp
Fix many issues reported by clang-tidy (#7189)
[dragonfireclient.git] / src / mapgen / mapgen_valleys.cpp
1 /*
2 Minetest
3 Copyright (C) 2016-2018 Duane Robertson <duane@duanerobertson.com>
4 Copyright (C) 2016-2018 paramat
5
6 Based on Valleys Mapgen by Gael de Sailly
7 (https://forum.minetest.net/viewtopic.php?f=9&t=11430)
8 and mapgen_v7, mapgen_flat by kwolekr and paramat.
9
10 Licensing changed by permission of Gael de Sailly.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as published by
14 the Free Software Foundation; either version 2.1 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public License along
23 with this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #include "mapgen.h"
28 #include "voxel.h"
29 #include "noise.h"
30 #include "mapblock.h"
31 #include "mapnode.h"
32 #include "map.h"
33 #include "nodedef.h"
34 #include "voxelalgorithms.h"
35 #include "settings.h" // For g_settings
36 #include "emerge.h"
37 #include "dungeongen.h"
38 #include "mg_biome.h"
39 #include "mg_ore.h"
40 #include "mg_decoration.h"
41 #include "mapgen_valleys.h"
42 #include "cavegen.h"
43 #include <cmath>
44
45
46 //#undef NDEBUG
47 //#include "assert.h"
48
49 //#include "util/timetaker.h"
50 //#include "profiler.h"
51
52
53 //static Profiler mapgen_prof;
54 //Profiler *mapgen_profiler = &mapgen_prof;
55
56 static FlagDesc flagdesc_mapgen_valleys[] = {
57         {"altitude_chill", MGVALLEYS_ALT_CHILL},
58         {"humid_rivers",   MGVALLEYS_HUMID_RIVERS},
59         {NULL,             0}
60 };
61
62 ///////////////////////////////////////////////////////////////////////////////
63
64
65 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge)
66         : MapgenBasic(mapgenid, params, emerge)
67 {
68         // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
69         m_bgen = (BiomeGenOriginal *)biomegen;
70
71         BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
72
73         spflags            = params->spflags;
74         altitude_chill     = params->altitude_chill;
75         large_cave_depth   = params->large_cave_depth;
76         lava_features_lim  = rangelim(params->lava_features, 0, 10);
77         massive_cave_depth = params->massive_cave_depth;
78         river_depth_bed    = params->river_depth + 1.f;
79         river_size_factor  = params->river_size / 100.f;
80         water_features_lim = rangelim(params->water_features, 0, 10);
81         cave_width         = params->cave_width;
82         dungeon_ymin       = params->dungeon_ymin;
83         dungeon_ymax       = params->dungeon_ymax;
84
85         //// 2D Terrain noise
86         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
87         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
88         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
89         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
90         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
91         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
92
93         //// 3D Terrain noise
94         // 1-up 1-down overgeneration
95         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
96         // 1-down overgeneraion
97         noise_cave1             = new Noise(&params->np_cave1,             seed, csize.X, csize.Y + 1, csize.Z);
98         noise_cave2             = new Noise(&params->np_cave2,             seed, csize.X, csize.Y + 1, csize.Z);
99         noise_massive_caves     = new Noise(&params->np_massive_caves,     seed, csize.X, csize.Y + 1, csize.Z);
100
101         humid_rivers       = (spflags & MGVALLEYS_HUMID_RIVERS);
102         use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
103         humidity_adjust    = bp->np_humidity.offset - 50.f;
104
105         // a small chance of overflows if the settings are very high
106         cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
107         lava_max_height       = water_level + MYMAX(0, lava_features_lim - 4) * 50;
108
109         tcave_cache = new float[csize.Y + 2];
110 }
111
112
113 MapgenValleys::~MapgenValleys()
114 {
115         delete noise_cave1;
116         delete noise_cave2;
117         delete noise_filler_depth;
118         delete noise_inter_valley_fill;
119         delete noise_inter_valley_slope;
120         delete noise_rivers;
121         delete noise_massive_caves;
122         delete noise_terrain_height;
123         delete noise_valley_depth;
124         delete noise_valley_profile;
125
126         delete[] tcave_cache;
127 }
128
129
130 MapgenValleysParams::MapgenValleysParams():
131         np_cave1              (0,     12,   v3f(61,   61,   61),   52534, 3, 0.5,   2.0),
132         np_cave2              (0,     12,   v3f(67,   67,   67),   10325, 3, 0.5,   2.0),
133         np_filler_depth       (0.f,   1.2f, v3f(256,  256,  256),  1605,  3, 0.5f,  2.f),
134         np_inter_valley_fill  (0.f,   1.f,  v3f(256,  512,  256),  1993,  6, 0.8f,  2.f),
135         np_inter_valley_slope (0.5f,  0.5f, v3f(128,  128,  128),  746,   1, 1.f,   2.f),
136         np_rivers             (0.f,   1.f,  v3f(256,  256,  256),  -6050, 5, 0.6f,  2.f),
137         np_massive_caves      (0.f,   1.f,  v3f(768,  256,  768),  59033, 6, 0.63f, 2.f),
138         np_terrain_height     (-10.f, 50.f, v3f(1024, 1024, 1024), 5202,  6, 0.4f,  2.f),
139         np_valley_depth       (5.f,   4.f,  v3f(512,  512,  512),  -1914, 1, 1.f,   2.f),
140         np_valley_profile     (0.6f,  0.5f, v3f(512,  512,  512),  777,   1, 1.f,   2.f)
141 {
142 }
143
144
145 void MapgenValleysParams::readParams(const Settings *settings)
146 {
147         settings->getFlagStrNoEx("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys);
148         settings->getU16NoEx("mgvalleys_altitude_chill",     altitude_chill);
149         settings->getS16NoEx("mgvalleys_large_cave_depth",   large_cave_depth);
150         settings->getU16NoEx("mgvalleys_lava_features",      lava_features);
151         settings->getS16NoEx("mgvalleys_massive_cave_depth", massive_cave_depth);
152         settings->getU16NoEx("mgvalleys_river_depth",        river_depth);
153         settings->getU16NoEx("mgvalleys_river_size",         river_size);
154         settings->getU16NoEx("mgvalleys_water_features",     water_features);
155         settings->getFloatNoEx("mgvalleys_cave_width",       cave_width);
156         settings->getS16NoEx("mgvalleys_dungeon_ymin",       dungeon_ymin);
157         settings->getS16NoEx("mgvalleys_dungeon_ymax",       dungeon_ymax);
158
159         settings->getNoiseParams("mgvalleys_np_cave1",              np_cave1);
160         settings->getNoiseParams("mgvalleys_np_cave2",              np_cave2);
161         settings->getNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
162         settings->getNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
163         settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
164         settings->getNoiseParams("mgvalleys_np_rivers",             np_rivers);
165         settings->getNoiseParams("mgvalleys_np_massive_caves",      np_massive_caves);
166         settings->getNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
167         settings->getNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
168         settings->getNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
169 }
170
171
172 void MapgenValleysParams::writeParams(Settings *settings) const
173 {
174         settings->setFlagStr("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys, U32_MAX);
175         settings->setU16("mgvalleys_altitude_chill",     altitude_chill);
176         settings->setS16("mgvalleys_large_cave_depth",   large_cave_depth);
177         settings->setU16("mgvalleys_lava_features",      lava_features);
178         settings->setS16("mgvalleys_massive_cave_depth", massive_cave_depth);
179         settings->setU16("mgvalleys_river_depth",        river_depth);
180         settings->setU16("mgvalleys_river_size",         river_size);
181         settings->setU16("mgvalleys_water_features",     water_features);
182         settings->setFloat("mgvalleys_cave_width",       cave_width);
183         settings->setS16("mgvalleys_dungeon_ymin",       dungeon_ymin);
184         settings->setS16("mgvalleys_dungeon_ymax",       dungeon_ymax);
185
186         settings->setNoiseParams("mgvalleys_np_cave1",              np_cave1);
187         settings->setNoiseParams("mgvalleys_np_cave2",              np_cave2);
188         settings->setNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
189         settings->setNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
190         settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
191         settings->setNoiseParams("mgvalleys_np_rivers",             np_rivers);
192         settings->setNoiseParams("mgvalleys_np_massive_caves",      np_massive_caves);
193         settings->setNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
194         settings->setNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
195         settings->setNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
196 }
197
198
199 ///////////////////////////////////////
200
201
202 void MapgenValleys::makeChunk(BlockMakeData *data)
203 {
204         // Pre-conditions
205         assert(data->vmanip);
206         assert(data->nodedef);
207         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
208                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
209                 data->blockpos_requested.Z >= data->blockpos_min.Z);
210         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
211                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
212                 data->blockpos_requested.Z <= data->blockpos_max.Z);
213
214         this->generating = true;
215         this->vm = data->vmanip;
216         this->ndef = data->nodedef;
217
218         //TimeTaker t("makeChunk");
219
220         v3s16 blockpos_min = data->blockpos_min;
221         v3s16 blockpos_max = data->blockpos_max;
222         node_min = blockpos_min * MAP_BLOCKSIZE;
223         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
224         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
225         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
226
227         blockseed = getBlockSeed2(full_node_min, seed);
228
229         // Generate biome noises.  Note this must be executed strictly before
230         // generateTerrain, because generateTerrain depends on intermediate
231         // biome-related noises.
232         m_bgen->calcBiomeNoise(node_min);
233
234         // Generate noise maps and base terrain height.
235         // Modify heat and humidity maps.
236         calculateNoise();
237
238         // Generate base terrain with initial heightmaps
239         s16 stone_surface_max_y = generateTerrain();
240
241         // Recalculate heightmap
242         updateHeightmap(node_min, node_max);
243
244         // Place biome-specific nodes and build biomemap
245         MgStoneType mgstone_type;
246         content_t biome_stone;
247         generateBiomes(&mgstone_type, &biome_stone);
248
249         // Cave creation.
250         if (flags & MG_CAVES)
251                 generateCaves(stone_surface_max_y, large_cave_depth);
252
253         // Dungeon creation
254         if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
255                         full_node_max.Y <= dungeon_ymax)
256                 generateDungeons(stone_surface_max_y, mgstone_type, biome_stone);
257
258         // Generate the registered decorations
259         if (flags & MG_DECORATIONS)
260                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
261
262         // Generate the registered ores
263         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
264
265         // Sprinkle some dust on top after everything else was generated
266         dustTopNodes();
267
268         //TimeTaker tll("liquid_lighting");
269
270         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
271
272         if (flags & MG_LIGHT)
273                 calcLighting(
274                                 node_min - v3s16(0, 1, 0),
275                                 node_max + v3s16(0, 1, 0),
276                                 full_node_min,
277                                 full_node_max);
278
279         //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
280         //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
281
282         this->generating = false;
283 }
284
285
286 // Populate the noise tables and do most of the
287 // calculation necessary to determine terrain height.
288 void MapgenValleys::calculateNoise()
289 {
290         //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
291
292         int x = node_min.X;
293         int y = node_min.Y - 1;
294         int z = node_min.Z;
295
296         //TimeTaker tcn("actualNoise");
297
298         noise_inter_valley_slope->perlinMap2D(x, z);
299         noise_rivers->perlinMap2D(x, z);
300         noise_terrain_height->perlinMap2D(x, z);
301         noise_valley_depth->perlinMap2D(x, z);
302         noise_valley_profile->perlinMap2D(x, z);
303
304         noise_inter_valley_fill->perlinMap3D(x, y, z);
305
306         //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
307
308         float heat_offset = 0.f;
309         float humidity_scale = 1.f;
310
311         // Altitude chill tends to reduce the average heat.
312         if (use_altitude_chill)
313                 heat_offset = 5.f;
314
315         // River humidity tends to increase the humidity range.
316         if (humid_rivers) {
317                 humidity_scale = 0.8f;
318         }
319
320         for (s32 index = 0; index < csize.X * csize.Z; index++) {
321                 m_bgen->heatmap[index] += heat_offset;
322                 m_bgen->humidmap[index] *= humidity_scale;
323         }
324
325         TerrainNoise tn;
326
327         u32 index = 0;
328         for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
329         for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
330                 // The parameters that we actually need to generate terrain
331                 //  are passed by address (and the return value).
332                 tn.terrain_height    = noise_terrain_height->result[index];
333                 // River noise is replaced with base terrain, which
334                 // is basically the height of the water table.
335                 tn.rivers            = &noise_rivers->result[index];
336                 // Valley depth noise is replaced with the valley
337                 // number that represents the height of terrain
338                 // over rivers and is used to determine about
339                 // how close a river is for humidity calculation.
340                 tn.valley            = &noise_valley_depth->result[index];
341                 tn.valley_profile    = noise_valley_profile->result[index];
342                 // Slope noise is replaced by the calculated slope
343                 // which is used to get terrain height in the slow
344                 // method, to create sharper mountains.
345                 tn.slope             = &noise_inter_valley_slope->result[index];
346                 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
347
348                 // This is the actual terrain height.
349                 float mount = terrainLevelFromNoise(&tn);
350                 noise_terrain_height->result[index] = mount;
351         }
352 }
353
354
355 // This keeps us from having to maintain two similar sets of
356 //  complicated code to determine ground level.
357 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
358 {
359         // The square function changes the behaviour of this noise:
360         //  very often small, and sometimes very high.
361         float valley_d = MYSQUARE(*tn->valley);
362
363         // valley_d is here because terrain is generally higher where valleys
364         //  are deep (mountains). base represents the height of the
365         //  rivers, most of the surface is above.
366         float base = tn->terrain_height + valley_d;
367
368         // "river" represents the distance from the river, in arbitrary units.
369         float river = std::fabs(*tn->rivers) - river_size_factor;
370
371         // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
372         //  Making "a" vary (0 < a <= 1) changes the shape of the valleys.
373         //  Try it with a geometry software !
374         //   (here x = "river" and a = valley_profile).
375         //  "valley" represents the height of the terrain, from the rivers.
376         {
377                 float t = std::fmax(river / tn->valley_profile, 0.0f);
378                 *tn->valley = valley_d * (1.f - std::exp(- MYSQUARE(t)));
379         }
380
381         // approximate height of the terrain at this point
382         float mount = base + *tn->valley;
383
384         *tn->slope *= *tn->valley;
385
386         // Rivers are placed where "river" is negative, so where the original
387         //  noise value is close to zero.
388         // Base ground is returned as rivers since it's basically the water table.
389         *tn->rivers = base;
390         if (river < 0.f) {
391                 // Use the the function -sqrt(1-x^2) which models a circle.
392                 float depth;
393                 {
394                         float t = river / river_size_factor + 1;
395                         depth = (river_depth_bed * std::sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
396                 }
397
398                 // base - depth : height of the bottom of the river
399                 // water_level - 3 : don't make rivers below 3 nodes under the surface
400                 // We use three because that's as low as the swamp biomes go.
401                 // There is no logical equivalent to this using rangelim.
402                 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
403
404                 // Slope has no influence on rivers.
405                 *tn->slope = 0.f;
406         }
407
408         return mount;
409 }
410
411
412 // This avoids duplicating the code in terrainLevelFromNoise, adding
413 // only the final step of terrain generation without a noise map.
414 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
415 {
416         float mount = terrainLevelFromNoise(tn);
417         s16 y_start = myround(mount);
418
419         for (s16 y = y_start; y <= y_start + 1000; y++) {
420                 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
421
422                 if (fill * *tn->slope < y - mount) {
423                         mount = MYMAX(y - 1, mount);
424                         break;
425                 }
426         }
427
428         return mount;
429 }
430
431
432 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
433 {
434         // Check to make sure this isn't a request for a location in a river.
435         float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
436         if (fabs(rivers) < river_size_factor)
437                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
438
439         s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
440         if (level_at_point <= water_level ||
441                         level_at_point > water_level + 32)
442                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
443
444         return level_at_point;
445 }
446
447
448 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
449 {
450         TerrainNoise tn;
451
452         float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
453         float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
454         float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
455
456         tn.x                 = x;
457         tn.z                 = z;
458         tn.terrain_height    = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
459         tn.rivers            = &rivers;
460         tn.valley            = &valley;
461         tn.valley_profile    = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
462         tn.slope             = &inter_valley_slope;
463         tn.inter_valley_fill = 0.f;
464
465         return adjustedTerrainLevelFromNoise(&tn);
466 }
467
468
469 int MapgenValleys::generateTerrain()
470 {
471         // Raising this reduces the rate of evaporation.
472         static const float evaporation = 300.f;
473         // from the lua
474         static const float humidity_dropoff = 4.f;
475         // constant to convert altitude chill (compatible with lua) to heat
476         static const float alt_to_heat = 20.f;
477         // humidity reduction by altitude
478         static const float alt_to_humid = 10.f;
479
480         MapNode n_air(CONTENT_AIR);
481         MapNode n_river_water(c_river_water_source);
482         MapNode n_stone(c_stone);
483         MapNode n_water(c_water_source);
484
485         const v3s16 &em = vm->m_area.getExtent();
486         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
487         u32 index_2d = 0;
488
489         for (s16 z = node_min.Z; z <= node_max.Z; z++)
490         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
491                 float river_y = noise_rivers->result[index_2d];
492                 float surface_y = noise_terrain_height->result[index_2d];
493                 float slope = noise_inter_valley_slope->result[index_2d];
494                 float t_heat = m_bgen->heatmap[index_2d];
495
496                 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
497
498                 if (surface_y > surface_max_y)
499                         surface_max_y = std::ceil(surface_y);
500
501                 if (humid_rivers) {
502                         // Derive heat from (base) altitude. This will be most correct
503                         // at rivers, since other surface heights may vary below.
504                         if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
505                                 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
506
507                         // If humidity is low or heat is high, lower the water table.
508                         float delta = m_bgen->humidmap[index_2d] - 50.f;
509                         if (delta < 0.f) {
510                                 float t_evap = (t_heat - 32.f) / evaporation;
511                                 river_y += delta * MYMAX(t_evap, 0.08f);
512                         }
513                 }
514
515                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
516                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
517
518                 // Mapgens concern themselves with stone and water.
519                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
520                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
521                                 float fill = noise_inter_valley_fill->result[index_3d];
522                                 float surface_delta = (float)y - surface_y;
523                                 bool river = y + 1 < river_y;
524
525                                 if (slope * fill > surface_delta) {
526                                         // ground
527                                         vm->m_data[index_data] = n_stone;
528                                         if (y > heightmap[index_2d])
529                                                 heightmap[index_2d] = y;
530                                         if (y > surface_max_y)
531                                                 surface_max_y = y;
532                                 } else if (y <= water_level) {
533                                         // sea
534                                         vm->m_data[index_data] = n_water;
535                                 } else if (river) {
536                                         // river
537                                         vm->m_data[index_data] = n_river_water;
538                                 } else {  // air
539                                         vm->m_data[index_data] = n_air;
540                                 }
541                         }
542
543                         VoxelArea::add_y(em, index_data, 1);
544                         index_3d += ystride;
545                 }
546
547                 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
548                         s16 surface_y_int = myround(surface_y);
549                         if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
550                                 // If surface_y is outside the chunk, it's good enough.
551                                 heightmap[index_2d] = surface_y_int;
552                         } else {
553                                 // If the ground is outside of this chunk, but surface_y
554                                 // is within the chunk, give a value outside.
555                                 heightmap[index_2d] = node_min.Y - 2;
556                         }
557                 }
558
559                 if (humid_rivers) {
560                         // Use base ground (water table) in a riverbed, to
561                         // avoid an unnatural rise in humidity.
562                         float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
563                         float humid = m_bgen->humidmap[index_2d];
564                         float water_depth = (t_alt - river_y) / humidity_dropoff;
565                         humid *= 1.f + std::pow(0.5f, MYMAX(water_depth, 1.f));
566
567                         // Reduce humidity with altitude (ignoring riverbeds).
568                         // This is similar to the lua version's seawater adjustment,
569                         // but doesn't increase the base humidity, which causes
570                         // problems with the default biomes.
571                         if (t_alt > 0.f)
572                                 humid -= alt_to_humid * t_alt / altitude_chill;
573
574                         m_bgen->humidmap[index_2d] = humid;
575                 }
576
577                 // Assign the heat adjusted by any changed altitudes.
578                 // The altitude will change about half the time.
579                 if (use_altitude_chill) {
580                         // ground height ignoring riverbeds
581                         float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
582                         if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
583                                 // The altitude hasn't changed. Use the first result.
584                                 m_bgen->heatmap[index_2d] = t_heat;
585                         else if (t_alt > 0.f)
586                                 m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
587                 }
588         }
589
590         return surface_max_y;
591 }
592
593 void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
594 {
595         if (max_stone_y < node_min.Y)
596                 return;
597
598         noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
599         noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
600
601         PseudoRandom ps(blockseed + 72202);
602
603         MapNode n_air(CONTENT_AIR);
604         MapNode n_lava(c_lava_source);
605         MapNode n_water(c_river_water_source);
606
607         const v3s16 &em = vm->m_area.getExtent();
608
609         // Cave blend distance near YMIN, YMAX
610         const float massive_cave_blend = 128.f;
611         // noise threshold for massive caves
612         const float massive_cave_threshold = 0.6f;
613         // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
614
615         float yblmin = -mapgen_limit + massive_cave_blend * 1.5f;
616         float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
617         bool made_a_big_one = false;
618
619         // Cache the tcave values as they only vary by altitude.
620         if (node_max.Y <= massive_cave_depth) {
621                 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
622
623                 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
624                         float tcave = massive_cave_threshold;
625
626                         if (y < yblmin) {
627                                 float t = (yblmin - y) / massive_cave_blend;
628                                 tcave += MYSQUARE(t);
629                         } else if (y > yblmax) {
630                                 float t = (y - yblmax) / massive_cave_blend;
631                                 tcave += MYSQUARE(t);
632                         }
633
634                         tcave_cache[y - node_min.Y + 1] = tcave;
635                 }
636         }
637
638         // lava_depth varies between one and ten as you approach
639         //  the bottom of the world.
640         s16 lava_depth = std::ceil((lava_max_height - node_min.Y + 1) * 10.f / mapgen_limit);
641         // This allows random lava spawns to be less common at the surface.
642         s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
643         // water_depth varies between ten and one on the way down.
644         s16 water_depth = std::ceil((mapgen_limit - std::abs(node_min.Y) + 1) * 10.f /
645                 mapgen_limit);
646         // This allows random water spawns to be more common at the surface.
647         s16 water_chance = MYCUBE(water_features_lim) * water_depth;
648
649         // Reduce the odds of overflows even further.
650         if (node_max.Y > water_level) {
651                 lava_chance /= 3;
652                 water_chance /= 3;
653         }
654
655         u32 index_2d = 0;
656         for (s16 z = node_min.Z; z <= node_max.Z; z++)
657         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
658                 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index_2d]);
659                 bool tunnel_air_above = false;
660                 bool is_under_river = false;
661                 bool underground = false;
662                 u32 index_data = vm->m_area.index(x, node_max.Y, z);
663                 u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X);
664
665                 // Dig caves on down loop to check for air above.
666                 // Don't excavate the overgenerated stone at node_max.Y + 1,
667                 // this creates a 'roof' over the tunnel, preventing light in
668                 // tunnels at mapchunk borders when generating mapchunks upwards.
669                 // This 'roof' is removed when the mapchunk above is generated.
670                 for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
671                                 index_3d -= ystride,
672                                 VoxelArea::add_y(em, index_data, -1)) {
673
674                         float terrain = noise_terrain_height->result[index_2d];
675
676                         // Saves some time.
677                         if (y > terrain + 10)
678                                 continue;
679
680                         if (y < terrain - 40)
681                                 underground = true;
682
683                         // Dig massive caves.
684                         if (node_max.Y <= massive_cave_depth
685                                         && noise_massive_caves->result[index_3d]
686                                         > tcave_cache[y - node_min.Y + 1]) {
687                                 vm->m_data[index_data] = n_air;
688                                 made_a_big_one = true;
689                                 continue;
690                         }
691
692                         content_t c = vm->m_data[index_data].getContent();
693                         // Detect river water to place riverbed nodes in tunnels
694                         if (c == biome->c_river_water)
695                                 is_under_river = true;
696
697                         float d1 = contour(noise_cave1->result[index_3d]);
698                         float d2 = contour(noise_cave2->result[index_3d]);
699
700                         if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
701                                 // in a tunnel
702                                 vm->m_data[index_data] = n_air;
703                                 tunnel_air_above = true;
704                         } else if (c == biome->c_filler || c == biome->c_stone) {
705                                 if (tunnel_air_above) {
706                                         // at the tunnel floor
707                                         s16 sr = ps.range(0, 39);
708                                         u32 j = index_data;
709                                         VoxelArea::add_y(em, j, 1);
710
711                                         if (sr > terrain - y) {
712                                                 // Put biome nodes in tunnels near the surface
713                                                 if (is_under_river)
714                                                         vm->m_data[index_data] = MapNode(biome->c_riverbed);
715                                                 else if (underground)
716                                                         vm->m_data[index_data] = MapNode(biome->c_filler);
717                                                 else
718                                                         vm->m_data[index_data] = MapNode(biome->c_top);
719                                         } else if (sr < 3 && underground) {
720                                                 sr = abs(ps.next());
721                                                 if (lava_features_lim > 0 && y <= lava_max_height
722                                                                 && c == biome->c_stone && sr < lava_chance)
723                                                         vm->m_data[j] = n_lava;
724
725                                                 sr -= lava_chance;
726
727                                                 // If sr < 0 then we should have already placed lava --
728                                                 // don't immediately dump water on it.
729                                                 if (water_features_lim > 0 && y <= cave_water_max_height
730                                                                 && sr >= 0 && sr < water_chance)
731                                                         vm->m_data[j] = n_water;
732                                         }
733                                 }
734
735                                 tunnel_air_above = false;
736                                 underground = true;
737                         } else {
738                                 tunnel_air_above = false;
739                         }
740                 }
741         }
742
743         if (node_max.Y <= large_cave_depth && !made_a_big_one) {
744                 u32 bruises_count = ps.range(0, 2);
745                 for (u32 i = 0; i < bruises_count; i++) {
746                         CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
747                                 c_water_source, c_lava_source, lava_max_height);
748
749                         cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
750                 }
751         }
752 }