3 Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
4 Copyright (C) 2010-2015 paramat, Matt Gregory
5 Copyright (C) 2016 Duane Robertson <duane@duanerobertson.com>
7 Based on Valleys Mapgen by Gael de Sailly
8 (https://forum.minetest.net/viewtopic.php?f=9&t=11430)
9 and mapgen_v7, mapgen_flat by kwolekr and paramat.
11 Licensing changed by permission of Gael de Sailly.
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU Lesser General Public License as published by
15 the Free Software Foundation; either version 2.1 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public License along
24 with this program; if not, write to the Free Software Foundation, Inc.,
25 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include "content_sao.h"
36 #include "voxelalgorithms.h"
37 #include "settings.h" // For g_settings
39 #include "dungeongen.h"
43 #include "mg_decoration.h"
44 #include "mapgen_valleys.h"
51 //#include "util/timetaker.h"
52 //#include "profiler.h"
55 //static Profiler mapgen_prof;
56 //Profiler *mapgen_profiler = &mapgen_prof;
58 static FlagDesc flagdesc_mapgen_valleys[] = {
59 {"altitude_chill", MGVALLEYS_ALT_CHILL},
60 {"humid_rivers", MGVALLEYS_HUMID_RIVERS},
64 ///////////////////////////////////////////////////////////////////////////////
67 MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
68 : MapgenBasic(mapgenid, params, emerge)
70 // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
71 this->m_bgen = (BiomeGenOriginal *)biomegen;
73 this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
74 g_settings->getU16("map_generation_limit"));
76 MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
77 BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
79 this->spflags = sp->spflags;
80 this->altitude_chill = sp->altitude_chill;
81 this->large_cave_depth = sp->large_cave_depth;
82 this->lava_features_lim = rangelim(sp->lava_features, 0, 10);
83 this->massive_cave_depth = sp->massive_cave_depth;
84 this->river_depth_bed = sp->river_depth + 1.f;
85 this->river_size_factor = sp->river_size / 100.f;
86 this->water_features_lim = rangelim(sp->water_features, 0, 10);
87 this->cave_width = sp->cave_width;
90 noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
91 noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
92 noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z);
93 noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z);
94 noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z);
95 noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z);
98 // 1-up 1-down overgeneration
99 noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
100 // 1-down overgeneraion
101 noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
102 noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
103 noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
105 this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
106 this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
107 this->humidity_adjust = bp->np_humidity.offset - 50.f;
109 // a small chance of overflows if the settings are very high
110 this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
111 this->lava_max_height = water_level + MYMAX(0, lava_features_lim - 4) * 50;
113 tcave_cache = new float[csize.Y + 2];
115 // Resolve content to be used
116 c_lava_source = ndef->getId("mapgen_lava_source");
117 c_sand = ndef->getId("mapgen_sand");
119 // Fall back to more basic content if not defined
120 if (c_sand == CONTENT_IGNORE)
125 MapgenValleys::~MapgenValleys()
129 delete noise_filler_depth;
130 delete noise_inter_valley_fill;
131 delete noise_inter_valley_slope;
133 delete noise_massive_caves;
134 delete noise_terrain_height;
135 delete noise_valley_depth;
136 delete noise_valley_profile;
138 delete[] tcave_cache;
142 MapgenValleysParams::MapgenValleysParams()
144 spflags = MGVALLEYS_HUMID_RIVERS | MGVALLEYS_ALT_CHILL;
145 altitude_chill = 90; // The altitude at which temperature drops by 20C.
146 large_cave_depth = -33;
147 lava_features = 0; // How often water will occur in caves.
148 massive_cave_depth = -256; // highest altitude of massive caves
149 river_depth = 4; // How deep to carve river channels.
150 river_size = 5; // How wide to make rivers.
151 water_features = 0; // How often water will occur in caves.
154 np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
155 np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 2.0);
156 np_filler_depth = NoiseParams(0.f, 1.2f, v3f(256, 256, 256), 1605, 3, 0.5f, 2.f);
157 np_inter_valley_fill = NoiseParams(0.f, 1.f, v3f(256, 512, 256), 1993, 6, 0.8f, 2.f);
158 np_inter_valley_slope = NoiseParams(0.5f, 0.5f, v3f(128, 128, 128), 746, 1, 1.f, 2.f);
159 np_rivers = NoiseParams(0.f, 1.f, v3f(256, 256, 256), -6050, 5, 0.6f, 2.f);
160 np_massive_caves = NoiseParams(0.f, 1.f, v3f(768, 256, 768), 59033, 6, 0.63f, 2.f);
161 np_terrain_height = NoiseParams(-10.f, 50.f, v3f(1024, 1024, 1024), 5202, 6, 0.4f, 2.f);
162 np_valley_depth = NoiseParams(5.f, 4.f, v3f(512, 512, 512), -1914, 1, 1.f, 2.f);
163 np_valley_profile = NoiseParams(0.6f, 0.5f, v3f(512, 512, 512), 777, 1, 1.f, 2.f);
167 void MapgenValleysParams::readParams(const Settings *settings)
169 settings->getFlagStrNoEx("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
170 settings->getU16NoEx("mgvalleys_altitude_chill", altitude_chill);
171 settings->getS16NoEx("mgvalleys_large_cave_depth", large_cave_depth);
172 settings->getU16NoEx("mgvalleys_lava_features", lava_features);
173 settings->getS16NoEx("mgvalleys_massive_cave_depth", massive_cave_depth);
174 settings->getU16NoEx("mgvalleys_river_depth", river_depth);
175 settings->getU16NoEx("mgvalleys_river_size", river_size);
176 settings->getU16NoEx("mgvalleys_water_features", water_features);
177 settings->getFloatNoEx("mgvalleys_cave_width", cave_width);
179 settings->getNoiseParams("mgvalleys_np_cave1", np_cave1);
180 settings->getNoiseParams("mgvalleys_np_cave2", np_cave2);
181 settings->getNoiseParams("mgvalleys_np_filler_depth", np_filler_depth);
182 settings->getNoiseParams("mgvalleys_np_inter_valley_fill", np_inter_valley_fill);
183 settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
184 settings->getNoiseParams("mgvalleys_np_rivers", np_rivers);
185 settings->getNoiseParams("mgvalleys_np_massive_caves", np_massive_caves);
186 settings->getNoiseParams("mgvalleys_np_terrain_height", np_terrain_height);
187 settings->getNoiseParams("mgvalleys_np_valley_depth", np_valley_depth);
188 settings->getNoiseParams("mgvalleys_np_valley_profile", np_valley_profile);
192 void MapgenValleysParams::writeParams(Settings *settings) const
194 settings->setFlagStr("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys, U32_MAX);
195 settings->setU16("mgvalleys_altitude_chill", altitude_chill);
196 settings->setS16("mgvalleys_large_cave_depth", large_cave_depth);
197 settings->setU16("mgvalleys_lava_features", lava_features);
198 settings->setS16("mgvalleys_massive_cave_depth", massive_cave_depth);
199 settings->setU16("mgvalleys_river_depth", river_depth);
200 settings->setU16("mgvalleys_river_size", river_size);
201 settings->setU16("mgvalleys_water_features", water_features);
202 settings->setFloat("mgvalleys_cave_width", cave_width);
204 settings->setNoiseParams("mgvalleys_np_cave1", np_cave1);
205 settings->setNoiseParams("mgvalleys_np_cave2", np_cave2);
206 settings->setNoiseParams("mgvalleys_np_filler_depth", np_filler_depth);
207 settings->setNoiseParams("mgvalleys_np_inter_valley_fill", np_inter_valley_fill);
208 settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
209 settings->setNoiseParams("mgvalleys_np_rivers", np_rivers);
210 settings->setNoiseParams("mgvalleys_np_massive_caves", np_massive_caves);
211 settings->setNoiseParams("mgvalleys_np_terrain_height", np_terrain_height);
212 settings->setNoiseParams("mgvalleys_np_valley_depth", np_valley_depth);
213 settings->setNoiseParams("mgvalleys_np_valley_profile", np_valley_profile);
217 ///////////////////////////////////////
220 void MapgenValleys::makeChunk(BlockMakeData *data)
223 assert(data->vmanip);
224 assert(data->nodedef);
225 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
226 data->blockpos_requested.Y >= data->blockpos_min.Y &&
227 data->blockpos_requested.Z >= data->blockpos_min.Z);
228 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
229 data->blockpos_requested.Y <= data->blockpos_max.Y &&
230 data->blockpos_requested.Z <= data->blockpos_max.Z);
232 this->generating = true;
233 this->vm = data->vmanip;
234 this->ndef = data->nodedef;
236 //TimeTaker t("makeChunk");
238 v3s16 blockpos_min = data->blockpos_min;
239 v3s16 blockpos_max = data->blockpos_max;
240 node_min = blockpos_min * MAP_BLOCKSIZE;
241 node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
242 full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
243 full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
245 blockseed = getBlockSeed2(full_node_min, seed);
247 // Generate noise maps and base terrain height.
250 // Generate biome noises. Note this must be executed strictly before
251 // generateTerrain, because generateTerrain depends on intermediate
252 // biome-related noises.
253 m_bgen->calcBiomeNoise(node_min);
255 // Generate base terrain with initial heightmaps
256 s16 stone_surface_max_y = generateTerrain();
259 m_bgen->getBiomes(heightmap);
261 // Place biome-specific nodes
262 MgStoneType stone_type = generateBiomes();
265 if (flags & MG_CAVES)
266 generateCaves(stone_surface_max_y, large_cave_depth);
269 if ((flags & MG_DUNGEONS) && node_max.Y < 50)
270 generateDungeons(stone_surface_max_y, stone_type);
272 // Generate the registered decorations
273 if (flags & MG_DECORATIONS)
274 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
276 // Generate the registered ores
277 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
279 // Sprinkle some dust on top after everything else was generated
282 //TimeTaker tll("liquid_lighting");
284 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
286 if (flags & MG_LIGHT)
288 node_min - v3s16(0, 1, 0),
289 node_max + v3s16(0, 1, 0),
293 //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
294 //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
296 this->generating = false;
300 // Populate the noise tables and do most of the
301 // calculation necessary to determine terrain height.
302 void MapgenValleys::calculateNoise()
304 //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
307 int y = node_min.Y - 1;
310 //TimeTaker tcn("actualNoise");
312 noise_inter_valley_slope->perlinMap2D(x, z);
313 noise_rivers->perlinMap2D(x, z);
314 noise_terrain_height->perlinMap2D(x, z);
315 noise_valley_depth->perlinMap2D(x, z);
316 noise_valley_profile->perlinMap2D(x, z);
318 noise_inter_valley_fill->perlinMap3D(x, y, z);
320 //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
322 float heat_offset = 0.f;
323 float humidity_scale = 1.f;
325 // Altitude chill tends to reduce the average heat.
326 if (use_altitude_chill)
329 // River humidity tends to increase the humidity range.
331 humidity_scale = 0.8f;
334 for (s32 index = 0; index < csize.X * csize.Z; index++) {
335 m_bgen->heatmap[index] += heat_offset;
336 m_bgen->humidmap[index] *= humidity_scale;
342 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
343 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
344 // The parameters that we actually need to generate terrain
345 // are passed by address (and the return value).
346 tn.terrain_height = noise_terrain_height->result[index];
347 // River noise is replaced with base terrain, which
348 // is basically the height of the water table.
349 tn.rivers = &noise_rivers->result[index];
350 // Valley depth noise is replaced with the valley
351 // number that represents the height of terrain
352 // over rivers and is used to determine about
353 // how close a river is for humidity calculation.
354 tn.valley = &noise_valley_depth->result[index];
355 tn.valley_profile = noise_valley_profile->result[index];
356 // Slope noise is replaced by the calculated slope
357 // which is used to get terrain height in the slow
358 // method, to create sharper mountains.
359 tn.slope = &noise_inter_valley_slope->result[index];
360 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
362 // This is the actual terrain height.
363 float mount = terrainLevelFromNoise(&tn);
364 noise_terrain_height->result[index] = mount;
369 // This keeps us from having to maintain two similar sets of
370 // complicated code to determine ground level.
371 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
373 // The square function changes the behaviour of this noise:
374 // very often small, and sometimes very high.
375 float valley_d = MYSQUARE(*tn->valley);
377 // valley_d is here because terrain is generally higher where valleys
378 // are deep (mountains). base represents the height of the
379 // rivers, most of the surface is above.
380 float base = tn->terrain_height + valley_d;
382 // "river" represents the distance from the river, in arbitrary units.
383 float river = fabs(*tn->rivers) - river_size_factor;
385 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
386 // Making "a" vary (0 < a <= 1) changes the shape of the valleys.
387 // Try it with a geometry software !
388 // (here x = "river" and a = valley_profile).
389 // "valley" represents the height of the terrain, from the rivers.
391 float t = river / tn->valley_profile;
392 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
395 // approximate height of the terrain at this point
396 float mount = base + *tn->valley;
398 *tn->slope *= *tn->valley;
400 // Rivers are placed where "river" is negative, so where the original
401 // noise value is close to zero.
402 // Base ground is returned as rivers since it's basically the water table.
405 // Use the the function -sqrt(1-x^2) which models a circle.
408 float t = river / river_size_factor + 1;
409 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
412 // base - depth : height of the bottom of the river
413 // water_level - 3 : don't make rivers below 3 nodes under the surface
414 // We use three because that's as low as the swamp biomes go.
415 // There is no logical equivalent to this using rangelim.
416 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
418 // Slope has no influence on rivers.
426 // This avoids duplicating the code in terrainLevelFromNoise, adding
427 // only the final step of terrain generation without a noise map.
428 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
430 float mount = terrainLevelFromNoise(tn);
431 s16 y_start = myround(mount);
433 for (s16 y = y_start; y <= y_start + 1000; y++) {
434 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
436 if (fill * *tn->slope < y - mount) {
437 mount = MYMAX(y - 1, mount);
446 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
448 // Check to make sure this isn't a request for a location in a river.
449 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
450 if (fabs(rivers) < river_size_factor)
451 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
453 s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
454 if (level_at_point <= water_level ||
455 level_at_point > water_level + 32)
456 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
458 return level_at_point;
462 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
466 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
467 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
468 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
472 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
475 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
476 tn.slope = &inter_valley_slope;
477 tn.inter_valley_fill = 0.f;
479 return adjustedTerrainLevelFromNoise(&tn);
483 int MapgenValleys::generateTerrain()
485 // Raising this reduces the rate of evaporation.
486 static const float evaporation = 300.f;
488 static const float humidity_dropoff = 4.f;
489 // constant to convert altitude chill (compatible with lua) to heat
490 static const float alt_to_heat = 20.f;
491 // humidity reduction by altitude
492 static const float alt_to_humid = 10.f;
494 MapNode n_air(CONTENT_AIR);
495 MapNode n_river_water(c_river_water_source);
496 MapNode n_sand(c_sand);
497 MapNode n_stone(c_stone);
498 MapNode n_water(c_water_source);
500 v3s16 em = vm->m_area.getExtent();
501 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
504 for (s16 z = node_min.Z; z <= node_max.Z; z++)
505 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
506 float river_y = noise_rivers->result[index_2d];
507 float surface_y = noise_terrain_height->result[index_2d];
508 float slope = noise_inter_valley_slope->result[index_2d];
509 float t_heat = m_bgen->heatmap[index_2d];
511 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
513 if (surface_y > surface_max_y)
514 surface_max_y = ceil(surface_y);
517 // Derive heat from (base) altitude. This will be most correct
518 // at rivers, since other surface heights may vary below.
519 if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
520 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
522 // If humidity is low or heat is high, lower the water table.
523 float delta = m_bgen->humidmap[index_2d] - 50.f;
525 float t_evap = (t_heat - 32.f) / evaporation;
526 river_y += delta * MYMAX(t_evap, 0.08f);
530 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
531 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
533 // Mapgens concern themselves with stone and water.
534 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
535 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
536 float fill = noise_inter_valley_fill->result[index_3d];
537 float surface_delta = (float)y - surface_y;
538 bool river = y + 1 < river_y;
540 if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
542 vm->m_data[index_data] = n_sand;
543 } else if (slope * fill > surface_delta) {
545 vm->m_data[index_data] = n_stone;
546 if (y > heightmap[index_2d])
547 heightmap[index_2d] = y;
548 if (y > surface_max_y)
550 } else if (y <= water_level) {
552 vm->m_data[index_data] = n_water;
555 vm->m_data[index_data] = n_river_water;
557 vm->m_data[index_data] = n_air;
561 vm->m_area.add_y(em, index_data, 1);
565 // This happens if we're generating a chunk that doesn't
566 // contain the terrain surface, in which case, we need
567 // to set heightmap to a value outside of the chunk,
568 // to avoid confusing lua mods that use heightmap.
569 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
570 s16 surface_y_int = myround(surface_y);
571 if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
572 // If surface_y is outside the chunk, it's good enough.
573 heightmap[index_2d] = surface_y_int;
575 // If the ground is outside of this chunk, but surface_y
576 // is within the chunk, give a value outside.
577 heightmap[index_2d] = node_min.Y - 2;
582 // Use base ground (water table) in a riverbed, to
583 // avoid an unnatural rise in humidity.
584 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
585 float humid = m_bgen->humidmap[index_2d];
586 float water_depth = (t_alt - river_y) / humidity_dropoff;
587 humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
589 // Reduce humidity with altitude (ignoring riverbeds).
590 // This is similar to the lua version's seawater adjustment,
591 // but doesn't increase the base humidity, which causes
592 // problems with the default biomes.
594 humid -= alt_to_humid * t_alt / altitude_chill;
596 m_bgen->humidmap[index_2d] = humid;
599 // Assign the heat adjusted by any changed altitudes.
600 // The altitude will change about half the time.
601 if (use_altitude_chill) {
602 // ground height ignoring riverbeds
603 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
604 if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
605 // The altitude hasn't changed. Use the first result.
606 m_bgen->heatmap[index_2d] = t_heat;
607 else if (t_alt > 0.f)
608 m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
612 return surface_max_y;
615 void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
617 if (max_stone_y < node_min.Y)
620 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
621 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
623 PseudoRandom ps(blockseed + 72202);
625 MapNode n_air(CONTENT_AIR);
626 MapNode n_lava(c_lava_source);
627 MapNode n_water(c_river_water_source);
629 v3s16 em = vm->m_area.getExtent();
631 // Cave blend distance near YMIN, YMAX
632 const float massive_cave_blend = 128.f;
633 // noise threshold for massive caves
634 const float massive_cave_threshold = 0.6f;
635 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
637 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
638 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
639 bool made_a_big_one = false;
641 // Cache the tcave values as they only vary by altitude.
642 if (node_max.Y <= massive_cave_depth) {
643 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
645 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
646 float tcave = massive_cave_threshold;
649 float t = (yblmin - y) / massive_cave_blend;
650 tcave += MYSQUARE(t);
651 } else if (y > yblmax) {
652 float t = (y - yblmax) / massive_cave_blend;
653 tcave += MYSQUARE(t);
656 tcave_cache[y - node_min.Y + 1] = tcave;
660 // lava_depth varies between one and ten as you approach
661 // the bottom of the world.
662 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
663 // This allows random lava spawns to be less common at the surface.
664 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
665 // water_depth varies between ten and one on the way down.
666 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
667 // This allows random water spawns to be more common at the surface.
668 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
670 // Reduce the odds of overflows even further.
671 if (node_max.Y > water_level) {
677 for (s16 z = node_min.Z; z <= node_max.Z; z++)
678 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
679 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index_2d]);
680 bool tunnel_air_above = false;
681 bool underground = false;
682 u32 index_data = vm->m_area.index(x, node_max.Y, z);
683 u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X);
685 // Dig caves on down loop to check for air above.
686 // Don't excavate the overgenerated stone at node_max.Y + 1,
687 // this creates a 'roof' over the tunnel, preventing light in
688 // tunnels at mapchunk borders when generating mapchunks upwards.
689 // This 'roof' is removed when the mapchunk above is generated.
690 for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
692 vm->m_area.add_y(em, index_data, -1)) {
694 float terrain = noise_terrain_height->result[index_2d];
697 if (y > terrain + 10)
699 else if (y < terrain - 40)
702 // Dig massive caves.
703 if (node_max.Y <= massive_cave_depth
704 && noise_massive_caves->result[index_3d]
705 > tcave_cache[y - node_min.Y + 1]) {
706 vm->m_data[index_data] = n_air;
707 made_a_big_one = true;
711 content_t c = vm->m_data[index_data].getContent();
712 float d1 = contour(noise_cave1->result[index_3d]);
713 float d2 = contour(noise_cave2->result[index_3d]);
715 // River water is not set as ground content
716 // in the default game. This can produce strange results
717 // when a tunnel undercuts a river. However, that's not for
718 // the mapgen to correct. Fix it in lua.
720 if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
722 vm->m_data[index_data] = n_air;
723 tunnel_air_above = true;
724 } else if (c == biome->c_filler || c == biome->c_stone) {
725 if (tunnel_air_above) {
726 // at the tunnel floor
727 s16 sr = ps.range(0, 39);
729 vm->m_area.add_y(em, j, 1);
731 if (sr > terrain - y) {
732 // Put dirt in tunnels near the surface.
734 vm->m_data[index_data] = MapNode(biome->c_filler);
736 vm->m_data[index_data] = MapNode(biome->c_top);
737 } else if (sr < 3 && underground) {
739 if (lava_features_lim > 0 && y <= lava_max_height
740 && c == biome->c_stone && sr < lava_chance)
741 vm->m_data[j] = n_lava;
745 // If sr < 0 then we should have already placed lava --
746 // don't immediately dump water on it.
747 if (water_features_lim > 0 && y <= cave_water_max_height
748 && sr >= 0 && sr < water_chance)
749 vm->m_data[j] = n_water;
753 tunnel_air_above = false;
756 tunnel_air_above = false;
761 if (node_max.Y <= large_cave_depth && !made_a_big_one) {
762 u32 bruises_count = ps.range(0, 2);
763 for (u32 i = 0; i < bruises_count; i++) {
764 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
765 c_water_source, c_lava_source);
767 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);