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 this->m_emerge = emerge;
71 this->bmgr = emerge->biomemgr;
73 //// amount of elements to skip for the next index
74 //// for noise/height/biome maps (not vmanip)
75 this->ystride = csize.X;
76 this->zstride = csize.X * (csize.Y + 2);
77 // 1-down overgeneration
78 this->zstride_1d = csize.X * (csize.Y + 1);
80 this->heightmap = new s16[csize.X * csize.Z];
82 this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
83 g_settings->getU16("map_generation_limit"));
85 MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
86 BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
88 this->spflags = sp->spflags;
89 this->altitude_chill = sp->altitude_chill;
90 this->large_cave_depth = sp->large_cave_depth;
91 this->lava_features_lim = rangelim(sp->lava_features, 0, 10);
92 this->massive_cave_depth = sp->massive_cave_depth;
93 this->river_depth_bed = sp->river_depth + 1.f;
94 this->river_size_factor = sp->river_size / 100.f;
95 this->water_features_lim = rangelim(sp->water_features, 0, 10);
96 this->cave_width = sp->cave_width;
99 noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
100 noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
101 noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z);
102 noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z);
103 noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z);
104 noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z);
106 //// 3D Terrain noise
107 // 1-up 1-down overgeneration
108 noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
109 // 1-down overgeneraion
110 noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
111 noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
112 noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
114 //// Initialize biome generator
115 // NOTE: valleys mapgen can only use BiomeGenOriginal
116 biomegen = emerge->biomemgr->createBiomeGen(
117 BIOMEGEN_ORIGINAL, params->bparams, csize);
118 biomemap = biomegen->biomemap;
119 m_bgen = (BiomeGenOriginal *)biomegen;
121 this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
122 this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
123 this->humidity_adjust = bp->np_humidity.offset - 50.f;
125 // a small chance of overflows if the settings are very high
126 this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
127 this->lava_max_height = water_level + MYMAX(0, lava_features_lim - 4) * 50;
129 tcave_cache = new float[csize.Y + 2];
131 //// Resolve nodes to be used
132 c_cobble = ndef->getId("mapgen_cobble");
133 c_desert_stone = ndef->getId("mapgen_desert_stone");
134 c_dirt = ndef->getId("mapgen_dirt");
135 c_lava_source = ndef->getId("mapgen_lava_source");
136 c_mossycobble = ndef->getId("mapgen_mossycobble");
137 c_river_water_source = ndef->getId("mapgen_river_water_source");
138 c_sand = ndef->getId("mapgen_sand");
139 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
140 c_sandstone = ndef->getId("mapgen_sandstone");
141 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
142 c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
143 c_stone = ndef->getId("mapgen_stone");
144 c_water_source = ndef->getId("mapgen_water_source");
146 if (c_mossycobble == CONTENT_IGNORE)
147 c_mossycobble = c_cobble;
148 if (c_river_water_source == CONTENT_IGNORE)
149 c_river_water_source = c_water_source;
150 if (c_sand == CONTENT_IGNORE)
152 if (c_sandstonebrick == CONTENT_IGNORE)
153 c_sandstonebrick = c_sandstone;
154 if (c_stair_cobble == CONTENT_IGNORE)
155 c_stair_cobble = c_cobble;
156 if (c_stair_sandstonebrick == CONTENT_IGNORE)
157 c_stair_sandstonebrick = c_sandstone;
161 MapgenValleys::~MapgenValleys()
165 delete noise_filler_depth;
166 delete noise_inter_valley_fill;
167 delete noise_inter_valley_slope;
169 delete noise_massive_caves;
170 delete noise_terrain_height;
171 delete noise_valley_depth;
172 delete noise_valley_profile;
177 delete[] tcave_cache;
181 MapgenValleysParams::MapgenValleysParams()
183 spflags = MGVALLEYS_HUMID_RIVERS | MGVALLEYS_ALT_CHILL;
184 altitude_chill = 90; // The altitude at which temperature drops by 20C.
185 large_cave_depth = -33;
186 lava_features = 0; // How often water will occur in caves.
187 massive_cave_depth = -256; // highest altitude of massive caves
188 river_depth = 4; // How deep to carve river channels.
189 river_size = 5; // How wide to make rivers.
190 water_features = 0; // How often water will occur in caves.
193 np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
194 np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 2.0);
195 np_filler_depth = NoiseParams(0.f, 1.2f, v3f(256, 256, 256), 1605, 3, 0.5f, 2.f);
196 np_inter_valley_fill = NoiseParams(0.f, 1.f, v3f(256, 512, 256), 1993, 6, 0.8f, 2.f);
197 np_inter_valley_slope = NoiseParams(0.5f, 0.5f, v3f(128, 128, 128), 746, 1, 1.f, 2.f);
198 np_rivers = NoiseParams(0.f, 1.f, v3f(256, 256, 256), -6050, 5, 0.6f, 2.f);
199 np_massive_caves = NoiseParams(0.f, 1.f, v3f(768, 256, 768), 59033, 6, 0.63f, 2.f);
200 np_terrain_height = NoiseParams(-10.f, 50.f, v3f(1024, 1024, 1024), 5202, 6, 0.4f, 2.f);
201 np_valley_depth = NoiseParams(5.f, 4.f, v3f(512, 512, 512), -1914, 1, 1.f, 2.f);
202 np_valley_profile = NoiseParams(0.6f, 0.5f, v3f(512, 512, 512), 777, 1, 1.f, 2.f);
206 void MapgenValleysParams::readParams(const Settings *settings)
208 settings->getFlagStrNoEx("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
209 settings->getU16NoEx("mgvalleys_altitude_chill", altitude_chill);
210 settings->getS16NoEx("mgvalleys_large_cave_depth", large_cave_depth);
211 settings->getU16NoEx("mgvalleys_lava_features", lava_features);
212 settings->getS16NoEx("mgvalleys_massive_cave_depth", massive_cave_depth);
213 settings->getU16NoEx("mgvalleys_river_depth", river_depth);
214 settings->getU16NoEx("mgvalleys_river_size", river_size);
215 settings->getU16NoEx("mgvalleys_water_features", water_features);
216 settings->getFloatNoEx("mgvalleys_cave_width", cave_width);
218 settings->getNoiseParams("mgvalleys_np_cave1", np_cave1);
219 settings->getNoiseParams("mgvalleys_np_cave2", np_cave2);
220 settings->getNoiseParams("mgvalleys_np_filler_depth", np_filler_depth);
221 settings->getNoiseParams("mgvalleys_np_inter_valley_fill", np_inter_valley_fill);
222 settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
223 settings->getNoiseParams("mgvalleys_np_rivers", np_rivers);
224 settings->getNoiseParams("mgvalleys_np_massive_caves", np_massive_caves);
225 settings->getNoiseParams("mgvalleys_np_terrain_height", np_terrain_height);
226 settings->getNoiseParams("mgvalleys_np_valley_depth", np_valley_depth);
227 settings->getNoiseParams("mgvalleys_np_valley_profile", np_valley_profile);
231 void MapgenValleysParams::writeParams(Settings *settings) const
233 settings->setFlagStr("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys, U32_MAX);
234 settings->setU16("mgvalleys_altitude_chill", altitude_chill);
235 settings->setS16("mgvalleys_large_cave_depth", large_cave_depth);
236 settings->setU16("mgvalleys_lava_features", lava_features);
237 settings->setS16("mgvalleys_massive_cave_depth", massive_cave_depth);
238 settings->setU16("mgvalleys_river_depth", river_depth);
239 settings->setU16("mgvalleys_river_size", river_size);
240 settings->setU16("mgvalleys_water_features", water_features);
241 settings->setFloat("mgvalleys_cave_width", cave_width);
243 settings->setNoiseParams("mgvalleys_np_cave1", np_cave1);
244 settings->setNoiseParams("mgvalleys_np_cave2", np_cave2);
245 settings->setNoiseParams("mgvalleys_np_filler_depth", np_filler_depth);
246 settings->setNoiseParams("mgvalleys_np_inter_valley_fill", np_inter_valley_fill);
247 settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
248 settings->setNoiseParams("mgvalleys_np_rivers", np_rivers);
249 settings->setNoiseParams("mgvalleys_np_massive_caves", np_massive_caves);
250 settings->setNoiseParams("mgvalleys_np_terrain_height", np_terrain_height);
251 settings->setNoiseParams("mgvalleys_np_valley_depth", np_valley_depth);
252 settings->setNoiseParams("mgvalleys_np_valley_profile", np_valley_profile);
256 ///////////////////////////////////////
259 void MapgenValleys::makeChunk(BlockMakeData *data)
262 assert(data->vmanip);
263 assert(data->nodedef);
264 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
265 data->blockpos_requested.Y >= data->blockpos_min.Y &&
266 data->blockpos_requested.Z >= data->blockpos_min.Z);
267 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
268 data->blockpos_requested.Y <= data->blockpos_max.Y &&
269 data->blockpos_requested.Z <= data->blockpos_max.Z);
271 this->generating = true;
272 this->vm = data->vmanip;
273 this->ndef = data->nodedef;
275 //TimeTaker t("makeChunk");
277 v3s16 blockpos_min = data->blockpos_min;
278 v3s16 blockpos_max = data->blockpos_max;
279 node_min = blockpos_min * MAP_BLOCKSIZE;
280 node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
281 full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
282 full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
284 blockseed = getBlockSeed2(full_node_min, seed);
286 // Generate noise maps and base terrain height.
289 // Generate biome noises. Note this must be executed strictly before
290 // generateTerrain, because generateTerrain depends on intermediate
291 // biome-related noises.
292 biomegen->calcBiomeNoise(node_min);
294 // Generate base terrain with initial heightmaps
295 s16 stone_surface_max_y = generateTerrain();
298 biomegen->getBiomes(heightmap);
300 // Place biome-specific nodes
301 MgStoneType stone_type = generateBiomes();
304 if (flags & MG_CAVES)
305 generateCaves(stone_surface_max_y, large_cave_depth);
308 if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
311 dp.np_rarity = nparams_dungeon_rarity;
312 dp.np_density = nparams_dungeon_density;
313 dp.np_wetness = nparams_dungeon_wetness;
314 dp.c_water = c_water_source;
315 if (stone_type == MGSTONE_STONE) {
316 dp.c_cobble = c_cobble;
317 dp.c_moss = c_mossycobble;
318 dp.c_stair = c_stair_cobble;
320 dp.diagonal_dirs = false;
322 dp.holesize = v3s16(1, 2, 1);
323 dp.roomsize = v3s16(0, 0, 0);
324 dp.notifytype = GENNOTIFY_DUNGEON;
325 } else if (stone_type == MGSTONE_DESERT_STONE) {
326 dp.c_cobble = c_desert_stone;
327 dp.c_moss = c_desert_stone;
328 dp.c_stair = c_desert_stone;
330 dp.diagonal_dirs = true;
332 dp.holesize = v3s16(2, 3, 2);
333 dp.roomsize = v3s16(2, 5, 2);
334 dp.notifytype = GENNOTIFY_TEMPLE;
335 } else if (stone_type == MGSTONE_SANDSTONE) {
336 dp.c_cobble = c_sandstonebrick;
337 dp.c_moss = c_sandstonebrick;
338 dp.c_stair = c_sandstonebrick;
340 dp.diagonal_dirs = false;
342 dp.holesize = v3s16(2, 2, 2);
343 dp.roomsize = v3s16(2, 0, 2);
344 dp.notifytype = GENNOTIFY_DUNGEON;
347 DungeonGen dgen(this, &dp);
348 dgen.generate(blockseed, full_node_min, full_node_max);
351 // Generate the registered decorations
352 if (flags & MG_DECORATIONS)
353 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
355 // Generate the registered ores
356 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
358 // Sprinkle some dust on top after everything else was generated
361 //TimeTaker tll("liquid_lighting");
363 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
365 if (flags & MG_LIGHT)
367 node_min - v3s16(0, 1, 0),
368 node_max + v3s16(0, 1, 0),
372 //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
373 //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
375 this->generating = false;
379 // Populate the noise tables and do most of the
380 // calculation necessary to determine terrain height.
381 void MapgenValleys::calculateNoise()
383 //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
386 int y = node_min.Y - 1;
389 //TimeTaker tcn("actualNoise");
391 noise_filler_depth->perlinMap2D(x, z);
392 noise_inter_valley_slope->perlinMap2D(x, z);
393 noise_rivers->perlinMap2D(x, z);
394 noise_terrain_height->perlinMap2D(x, z);
395 noise_valley_depth->perlinMap2D(x, z);
396 noise_valley_profile->perlinMap2D(x, z);
398 noise_inter_valley_fill->perlinMap3D(x, y, z);
400 //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
402 float heat_offset = 0.f;
403 float humidity_scale = 1.f;
405 // Altitude chill tends to reduce the average heat.
406 if (use_altitude_chill)
409 // River humidity tends to increase the humidity range.
411 humidity_scale = 0.8f;
414 for (s32 index = 0; index < csize.X * csize.Z; index++) {
415 m_bgen->heatmap[index] += heat_offset;
416 m_bgen->humidmap[index] *= humidity_scale;
422 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
423 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
424 // The parameters that we actually need to generate terrain
425 // are passed by address (and the return value).
426 tn.terrain_height = noise_terrain_height->result[index];
427 // River noise is replaced with base terrain, which
428 // is basically the height of the water table.
429 tn.rivers = &noise_rivers->result[index];
430 // Valley depth noise is replaced with the valley
431 // number that represents the height of terrain
432 // over rivers and is used to determine about
433 // how close a river is for humidity calculation.
434 tn.valley = &noise_valley_depth->result[index];
435 tn.valley_profile = noise_valley_profile->result[index];
436 // Slope noise is replaced by the calculated slope
437 // which is used to get terrain height in the slow
438 // method, to create sharper mountains.
439 tn.slope = &noise_inter_valley_slope->result[index];
440 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
442 // This is the actual terrain height.
443 float mount = terrainLevelFromNoise(&tn);
444 noise_terrain_height->result[index] = mount;
449 // This keeps us from having to maintain two similar sets of
450 // complicated code to determine ground level.
451 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
453 // The square function changes the behaviour of this noise:
454 // very often small, and sometimes very high.
455 float valley_d = MYSQUARE(*tn->valley);
457 // valley_d is here because terrain is generally higher where valleys
458 // are deep (mountains). base represents the height of the
459 // rivers, most of the surface is above.
460 float base = tn->terrain_height + valley_d;
462 // "river" represents the distance from the river, in arbitrary units.
463 float river = fabs(*tn->rivers) - river_size_factor;
465 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
466 // Making "a" vary (0 < a <= 1) changes the shape of the valleys.
467 // Try it with a geometry software !
468 // (here x = "river" and a = valley_profile).
469 // "valley" represents the height of the terrain, from the rivers.
471 float t = river / tn->valley_profile;
472 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
475 // approximate height of the terrain at this point
476 float mount = base + *tn->valley;
478 *tn->slope *= *tn->valley;
480 // Rivers are placed where "river" is negative, so where the original
481 // noise value is close to zero.
482 // Base ground is returned as rivers since it's basically the water table.
485 // Use the the function -sqrt(1-x^2) which models a circle.
488 float t = river / river_size_factor + 1;
489 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
492 // base - depth : height of the bottom of the river
493 // water_level - 3 : don't make rivers below 3 nodes under the surface
494 // We use three because that's as low as the swamp biomes go.
495 // There is no logical equivalent to this using rangelim.
496 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
498 // Slope has no influence on rivers.
506 // This avoids duplicating the code in terrainLevelFromNoise, adding
507 // only the final step of terrain generation without a noise map.
508 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
510 float mount = terrainLevelFromNoise(tn);
511 s16 y_start = myround(mount);
513 for (s16 y = y_start; y <= y_start + 1000; y++) {
514 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
516 if (fill * *tn->slope < y - mount) {
517 mount = MYMAX(y - 1, mount);
526 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
528 // Check to make sure this isn't a request for a location in a river.
529 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
530 if (fabs(rivers) < river_size_factor)
531 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
533 s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
534 if (level_at_point <= water_level ||
535 level_at_point > water_level + 32)
536 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
538 return level_at_point;
542 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
546 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
547 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
548 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
552 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
555 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
556 tn.slope = &inter_valley_slope;
557 tn.inter_valley_fill = 0.f;
559 return adjustedTerrainLevelFromNoise(&tn);
563 int MapgenValleys::generateTerrain()
565 // Raising this reduces the rate of evaporation.
566 static const float evaporation = 300.f;
568 static const float humidity_dropoff = 4.f;
569 // constant to convert altitude chill (compatible with lua) to heat
570 static const float alt_to_heat = 20.f;
571 // humidity reduction by altitude
572 static const float alt_to_humid = 10.f;
574 MapNode n_air(CONTENT_AIR);
575 MapNode n_river_water(c_river_water_source);
576 MapNode n_sand(c_sand);
577 MapNode n_stone(c_stone);
578 MapNode n_water(c_water_source);
580 v3s16 em = vm->m_area.getExtent();
581 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
584 for (s16 z = node_min.Z; z <= node_max.Z; z++)
585 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
586 float river_y = noise_rivers->result[index_2d];
587 float surface_y = noise_terrain_height->result[index_2d];
588 float slope = noise_inter_valley_slope->result[index_2d];
589 float t_heat = m_bgen->heatmap[index_2d];
591 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
593 if (surface_y > surface_max_y)
594 surface_max_y = ceil(surface_y);
597 // Derive heat from (base) altitude. This will be most correct
598 // at rivers, since other surface heights may vary below.
599 if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
600 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
602 // If humidity is low or heat is high, lower the water table.
603 float delta = m_bgen->humidmap[index_2d] - 50.f;
605 float t_evap = (t_heat - 32.f) / evaporation;
606 river_y += delta * MYMAX(t_evap, 0.08f);
610 u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
611 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
613 // Mapgens concern themselves with stone and water.
614 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
615 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
616 float fill = noise_inter_valley_fill->result[index_3d];
617 float surface_delta = (float)y - surface_y;
618 bool river = y + 1 < river_y;
620 if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
622 vm->m_data[index_data] = n_sand;
623 } else if (slope * fill > surface_delta) {
625 vm->m_data[index_data] = n_stone;
626 if (y > heightmap[index_2d])
627 heightmap[index_2d] = y;
628 if (y > surface_max_y)
630 } else if (y <= water_level) {
632 vm->m_data[index_data] = n_water;
635 vm->m_data[index_data] = n_river_water;
637 vm->m_data[index_data] = n_air;
641 vm->m_area.add_y(em, index_data, 1);
645 // This happens if we're generating a chunk that doesn't
646 // contain the terrain surface, in which case, we need
647 // to set heightmap to a value outside of the chunk,
648 // to avoid confusing lua mods that use heightmap.
649 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
650 s16 surface_y_int = myround(surface_y);
651 if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
652 // If surface_y is outside the chunk, it's good enough.
653 heightmap[index_2d] = surface_y_int;
655 // If the ground is outside of this chunk, but surface_y
656 // is within the chunk, give a value outside.
657 heightmap[index_2d] = node_min.Y - 2;
662 // Use base ground (water table) in a riverbed, to
663 // avoid an unnatural rise in humidity.
664 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
665 float humid = m_bgen->humidmap[index_2d];
666 float water_depth = (t_alt - river_y) / humidity_dropoff;
667 humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
669 // Reduce humidity with altitude (ignoring riverbeds).
670 // This is similar to the lua version's seawater adjustment,
671 // but doesn't increase the base humidity, which causes
672 // problems with the default biomes.
674 humid -= alt_to_humid * t_alt / altitude_chill;
676 m_bgen->humidmap[index_2d] = humid;
679 // Assign the heat adjusted by any changed altitudes.
680 // The altitude will change about half the time.
681 if (use_altitude_chill) {
682 // ground height ignoring riverbeds
683 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
684 if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
685 // The altitude hasn't changed. Use the first result.
686 m_bgen->heatmap[index_2d] = t_heat;
687 else if (t_alt > 0.f)
688 m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
692 return surface_max_y;
695 void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
697 if (max_stone_y < node_min.Y)
700 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
701 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
703 PseudoRandom ps(blockseed + 72202);
705 MapNode n_air(CONTENT_AIR);
706 MapNode n_lava(c_lava_source);
707 MapNode n_water(c_river_water_source);
709 v3s16 em = vm->m_area.getExtent();
711 // Cave blend distance near YMIN, YMAX
712 const float massive_cave_blend = 128.f;
713 // noise threshold for massive caves
714 const float massive_cave_threshold = 0.6f;
715 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
717 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
718 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
719 bool made_a_big_one = false;
721 // Cache the tcave values as they only vary by altitude.
722 if (node_max.Y <= massive_cave_depth) {
723 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
725 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
726 float tcave = massive_cave_threshold;
729 float t = (yblmin - y) / massive_cave_blend;
730 tcave += MYSQUARE(t);
731 } else if (y > yblmax) {
732 float t = (y - yblmax) / massive_cave_blend;
733 tcave += MYSQUARE(t);
736 tcave_cache[y - node_min.Y + 1] = tcave;
740 // lava_depth varies between one and ten as you approach
741 // the bottom of the world.
742 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
743 // This allows random lava spawns to be less common at the surface.
744 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
745 // water_depth varies between ten and one on the way down.
746 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
747 // This allows random water spawns to be more common at the surface.
748 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
750 // Reduce the odds of overflows even further.
751 if (node_max.Y > water_level) {
757 for (s16 z = node_min.Z; z <= node_max.Z; z++)
758 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
759 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
760 bool tunnel_air_above = false;
761 bool underground = false;
762 u32 index_data = vm->m_area.index(x, node_max.Y, z);
763 u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X);
765 // Dig caves on down loop to check for air above.
766 // Don't excavate the overgenerated stone at node_max.Y + 1,
767 // this creates a 'roof' over the tunnel, preventing light in
768 // tunnels at mapchunk borders when generating mapchunks upwards.
769 // This 'roof' is removed when the mapchunk above is generated.
770 for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
772 vm->m_area.add_y(em, index_data, -1)) {
774 float terrain = noise_terrain_height->result[index_2d];
777 if (y > terrain + 10)
779 else if (y < terrain - 40)
782 // Dig massive caves.
783 if (node_max.Y <= massive_cave_depth
784 && noise_massive_caves->result[index_3d]
785 > tcave_cache[y - node_min.Y + 1]) {
786 vm->m_data[index_data] = n_air;
787 made_a_big_one = true;
791 content_t c = vm->m_data[index_data].getContent();
792 float d1 = contour(noise_cave1->result[index_3d]);
793 float d2 = contour(noise_cave2->result[index_3d]);
795 // River water is not set as ground content
796 // in the default game. This can produce strange results
797 // when a tunnel undercuts a river. However, that's not for
798 // the mapgen to correct. Fix it in lua.
800 if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
802 vm->m_data[index_data] = n_air;
803 tunnel_air_above = true;
804 } else if (c == biome->c_filler || c == biome->c_stone) {
805 if (tunnel_air_above) {
806 // at the tunnel floor
807 s16 sr = ps.range(0, 39);
809 vm->m_area.add_y(em, j, 1);
811 if (sr > terrain - y) {
812 // Put dirt in tunnels near the surface.
814 vm->m_data[index_data] = MapNode(biome->c_filler);
816 vm->m_data[index_data] = MapNode(biome->c_top);
817 } else if (sr < 3 && underground) {
819 if (lava_features_lim > 0 && y <= lava_max_height
820 && c == biome->c_stone && sr < lava_chance)
821 vm->m_data[j] = n_lava;
825 // If sr < 0 then we should have already placed lava --
826 // don't immediately dump water on it.
827 if (water_features_lim > 0 && y <= cave_water_max_height
828 && sr >= 0 && sr < water_chance)
829 vm->m_data[j] = n_water;
833 tunnel_air_above = false;
836 tunnel_air_above = false;
841 if (node_max.Y <= large_cave_depth && !made_a_big_one) {
842 u32 bruises_count = ps.range(0, 2);
843 for (u32 i = 0; i < bruises_count; i++) {
844 CavesRandomWalk cave(this, &ps);
845 cave.makeCave(node_min, node_max, max_stone_y);