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