3 Copyright (C) 2016-2017 Duane Robertson <duane@duanerobertson.com>
4 Copyright (C) 2016-2017 paramat
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.
10 Licensing changed by permission of Gael de Sailly.
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.
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.
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.
33 #include "content_sao.h"
35 #include "voxelalgorithms.h"
36 #include "settings.h" // For g_settings
38 #include "dungeongen.h"
41 #include "mg_decoration.h"
42 #include "mapgen_valleys.h"
49 //#include "util/timetaker.h"
50 //#include "profiler.h"
53 //static Profiler mapgen_prof;
54 //Profiler *mapgen_profiler = &mapgen_prof;
56 static FlagDesc flagdesc_mapgen_valleys[] = {
57 {"altitude_chill", MGVALLEYS_ALT_CHILL},
58 {"humid_rivers", MGVALLEYS_HUMID_RIVERS},
62 ///////////////////////////////////////////////////////////////////////////////
65 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge)
66 : MapgenBasic(mapgenid, params, emerge)
68 // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
69 this->m_bgen = (BiomeGenOriginal *)biomegen;
71 BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
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;
84 noise_filler_depth = new Noise(¶ms->np_filler_depth, seed, csize.X, csize.Z);
85 noise_inter_valley_slope = new Noise(¶ms->np_inter_valley_slope, seed, csize.X, csize.Z);
86 noise_rivers = new Noise(¶ms->np_rivers, seed, csize.X, csize.Z);
87 noise_terrain_height = new Noise(¶ms->np_terrain_height, seed, csize.X, csize.Z);
88 noise_valley_depth = new Noise(¶ms->np_valley_depth, seed, csize.X, csize.Z);
89 noise_valley_profile = new Noise(¶ms->np_valley_profile, seed, csize.X, csize.Z);
92 // 1-up 1-down overgeneration
93 noise_inter_valley_fill = new Noise(¶ms->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
94 // 1-down overgeneraion
95 noise_cave1 = new Noise(¶ms->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
96 noise_cave2 = new Noise(¶ms->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
97 noise_massive_caves = new Noise(¶ms->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
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;
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;
107 tcave_cache = new float[csize.Y + 2];
111 MapgenValleys::~MapgenValleys()
115 delete noise_filler_depth;
116 delete noise_inter_valley_fill;
117 delete noise_inter_valley_slope;
119 delete noise_massive_caves;
120 delete noise_terrain_height;
121 delete noise_valley_depth;
122 delete noise_valley_profile;
124 delete[] tcave_cache;
128 MapgenValleysParams::MapgenValleysParams()
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);
143 void MapgenValleysParams::readParams(const Settings *settings)
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);
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);
168 void MapgenValleysParams::writeParams(Settings *settings) const
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);
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);
193 ///////////////////////////////////////
196 void MapgenValleys::makeChunk(BlockMakeData *data)
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);
208 this->generating = true;
209 this->vm = data->vmanip;
210 this->ndef = data->nodedef;
212 //TimeTaker t("makeChunk");
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);
221 blockseed = getBlockSeed2(full_node_min, seed);
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);
228 // Generate noise maps and base terrain height.
229 // Modify heat and humidity maps.
232 // Generate base terrain with initial heightmaps
233 s16 stone_surface_max_y = generateTerrain();
235 // Recalculate heightmap
236 updateHeightmap(node_min, node_max);
238 // Place biome-specific nodes and build biomemap
239 MgStoneType stone_type = generateBiomes();
242 if (flags & MG_CAVES)
243 generateCaves(stone_surface_max_y, large_cave_depth);
246 if ((flags & MG_DUNGEONS) && node_max.Y < 50)
247 generateDungeons(stone_surface_max_y, stone_type);
249 // Generate the registered decorations
250 if (flags & MG_DECORATIONS)
251 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
253 // Generate the registered ores
254 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
256 // Sprinkle some dust on top after everything else was generated
259 //TimeTaker tll("liquid_lighting");
261 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
263 if (flags & MG_LIGHT)
265 node_min - v3s16(0, 1, 0),
266 node_max + v3s16(0, 1, 0),
270 //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
271 //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
273 this->generating = false;
277 // Populate the noise tables and do most of the
278 // calculation necessary to determine terrain height.
279 void MapgenValleys::calculateNoise()
281 //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
284 int y = node_min.Y - 1;
287 //TimeTaker tcn("actualNoise");
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);
295 noise_inter_valley_fill->perlinMap3D(x, y, z);
297 //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
299 float heat_offset = 0.f;
300 float humidity_scale = 1.f;
302 // Altitude chill tends to reduce the average heat.
303 if (use_altitude_chill)
306 // River humidity tends to increase the humidity range.
308 humidity_scale = 0.8f;
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;
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];
339 // This is the actual terrain height.
340 float mount = terrainLevelFromNoise(&tn);
341 noise_terrain_height->result[index] = mount;
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)
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);
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;
359 // "river" represents the distance from the river, in arbitrary units.
360 float river = fabs(*tn->rivers) - river_size_factor;
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.
368 float t = river / tn->valley_profile;
369 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
372 // approximate height of the terrain at this point
373 float mount = base + *tn->valley;
375 *tn->slope *= *tn->valley;
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.
382 // Use the the function -sqrt(1-x^2) which models a circle.
385 float t = river / river_size_factor + 1;
386 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
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);
395 // Slope has no influence on rivers.
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)
407 float mount = terrainLevelFromNoise(tn);
408 s16 y_start = myround(mount);
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);
413 if (fill * *tn->slope < y - mount) {
414 mount = MYMAX(y - 1, mount);
423 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
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
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
435 return level_at_point;
439 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
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);
449 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
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;
456 return adjustedTerrainLevelFromNoise(&tn);
460 int MapgenValleys::generateTerrain()
462 // Raising this reduces the rate of evaporation.
463 static const float evaporation = 300.f;
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;
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);
476 v3s16 em = vm->m_area.getExtent();
477 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
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];
487 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
489 if (surface_y > surface_max_y)
490 surface_max_y = ceil(surface_y);
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;
498 // If humidity is low or heat is high, lower the water table.
499 float delta = m_bgen->humidmap[index_2d] - 50.f;
501 float t_evap = (t_heat - 32.f) / evaporation;
502 river_y += delta * MYMAX(t_evap, 0.08f);
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);
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;
516 if (slope * fill > surface_delta) {
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)
523 } else if (y <= water_level) {
525 vm->m_data[index_data] = n_water;
528 vm->m_data[index_data] = n_river_water;
530 vm->m_data[index_data] = n_air;
534 vm->m_area.add_y(em, index_data, 1);
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;
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;
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));
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.
563 humid -= alt_to_humid * t_alt / altitude_chill;
565 m_bgen->humidmap[index_2d] = humid;
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;
581 return surface_max_y;
584 void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
586 if (max_stone_y < node_min.Y)
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);
592 PseudoRandom ps(blockseed + 72202);
594 MapNode n_air(CONTENT_AIR);
595 MapNode n_lava(c_lava_source);
596 MapNode n_water(c_river_water_source);
598 v3s16 em = vm->m_area.getExtent();
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.
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;
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);
614 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
615 float tcave = massive_cave_threshold;
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);
625 tcave_cache[y - node_min.Y + 1] = tcave;
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;
639 // Reduce the odds of overflows even further.
640 if (node_max.Y > water_level) {
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);
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--,
662 vm->m_area.add_y(em, index_data, -1)) {
664 float terrain = noise_terrain_height->result[index_2d];
667 if (y > terrain + 10)
669 else if (y < terrain - 40)
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;
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;
686 float d1 = contour(noise_cave1->result[index_3d]);
687 float d2 = contour(noise_cave2->result[index_3d]);
689 if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
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);
698 vm->m_area.add_y(em, j, 1);
700 if (sr > terrain - y) {
701 // Put biome nodes in tunnels near the surface
703 vm->m_data[index_data] = MapNode(biome->c_riverbed);
704 else if (underground)
705 vm->m_data[index_data] = MapNode(biome->c_filler);
707 vm->m_data[index_data] = MapNode(biome->c_top);
708 } else if (sr < 3 && underground) {
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;
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;
724 tunnel_air_above = false;
727 tunnel_air_above = false;
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);
738 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);