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_inter_valley_slope->perlinMap2D(x, z);
392 noise_rivers->perlinMap2D(x, z);
393 noise_terrain_height->perlinMap2D(x, z);
394 noise_valley_depth->perlinMap2D(x, z);
395 noise_valley_profile->perlinMap2D(x, z);
397 noise_inter_valley_fill->perlinMap3D(x, y, z);
399 //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
401 float heat_offset = 0.f;
402 float humidity_scale = 1.f;
404 // Altitude chill tends to reduce the average heat.
405 if (use_altitude_chill)
408 // River humidity tends to increase the humidity range.
410 humidity_scale = 0.8f;
413 for (s32 index = 0; index < csize.X * csize.Z; index++) {
414 m_bgen->heatmap[index] += heat_offset;
415 m_bgen->humidmap[index] *= humidity_scale;
421 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
422 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
423 // The parameters that we actually need to generate terrain
424 // are passed by address (and the return value).
425 tn.terrain_height = noise_terrain_height->result[index];
426 // River noise is replaced with base terrain, which
427 // is basically the height of the water table.
428 tn.rivers = &noise_rivers->result[index];
429 // Valley depth noise is replaced with the valley
430 // number that represents the height of terrain
431 // over rivers and is used to determine about
432 // how close a river is for humidity calculation.
433 tn.valley = &noise_valley_depth->result[index];
434 tn.valley_profile = noise_valley_profile->result[index];
435 // Slope noise is replaced by the calculated slope
436 // which is used to get terrain height in the slow
437 // method, to create sharper mountains.
438 tn.slope = &noise_inter_valley_slope->result[index];
439 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
441 // This is the actual terrain height.
442 float mount = terrainLevelFromNoise(&tn);
443 noise_terrain_height->result[index] = mount;
448 // This keeps us from having to maintain two similar sets of
449 // complicated code to determine ground level.
450 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
452 // The square function changes the behaviour of this noise:
453 // very often small, and sometimes very high.
454 float valley_d = MYSQUARE(*tn->valley);
456 // valley_d is here because terrain is generally higher where valleys
457 // are deep (mountains). base represents the height of the
458 // rivers, most of the surface is above.
459 float base = tn->terrain_height + valley_d;
461 // "river" represents the distance from the river, in arbitrary units.
462 float river = fabs(*tn->rivers) - river_size_factor;
464 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
465 // Making "a" vary (0 < a <= 1) changes the shape of the valleys.
466 // Try it with a geometry software !
467 // (here x = "river" and a = valley_profile).
468 // "valley" represents the height of the terrain, from the rivers.
470 float t = river / tn->valley_profile;
471 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
474 // approximate height of the terrain at this point
475 float mount = base + *tn->valley;
477 *tn->slope *= *tn->valley;
479 // Rivers are placed where "river" is negative, so where the original
480 // noise value is close to zero.
481 // Base ground is returned as rivers since it's basically the water table.
484 // Use the the function -sqrt(1-x^2) which models a circle.
487 float t = river / river_size_factor + 1;
488 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
491 // base - depth : height of the bottom of the river
492 // water_level - 3 : don't make rivers below 3 nodes under the surface
493 // We use three because that's as low as the swamp biomes go.
494 // There is no logical equivalent to this using rangelim.
495 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
497 // Slope has no influence on rivers.
505 // This avoids duplicating the code in terrainLevelFromNoise, adding
506 // only the final step of terrain generation without a noise map.
507 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
509 float mount = terrainLevelFromNoise(tn);
510 s16 y_start = myround(mount);
512 for (s16 y = y_start; y <= y_start + 1000; y++) {
513 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
515 if (fill * *tn->slope < y - mount) {
516 mount = MYMAX(y - 1, mount);
525 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
527 // Check to make sure this isn't a request for a location in a river.
528 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
529 if (fabs(rivers) < river_size_factor)
530 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
532 s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
533 if (level_at_point <= water_level ||
534 level_at_point > water_level + 32)
535 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
537 return level_at_point;
541 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
545 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
546 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
547 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
551 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
554 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
555 tn.slope = &inter_valley_slope;
556 tn.inter_valley_fill = 0.f;
558 return adjustedTerrainLevelFromNoise(&tn);
562 int MapgenValleys::generateTerrain()
564 // Raising this reduces the rate of evaporation.
565 static const float evaporation = 300.f;
567 static const float humidity_dropoff = 4.f;
568 // constant to convert altitude chill (compatible with lua) to heat
569 static const float alt_to_heat = 20.f;
570 // humidity reduction by altitude
571 static const float alt_to_humid = 10.f;
573 MapNode n_air(CONTENT_AIR);
574 MapNode n_river_water(c_river_water_source);
575 MapNode n_sand(c_sand);
576 MapNode n_stone(c_stone);
577 MapNode n_water(c_water_source);
579 v3s16 em = vm->m_area.getExtent();
580 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
583 for (s16 z = node_min.Z; z <= node_max.Z; z++)
584 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
585 float river_y = noise_rivers->result[index_2d];
586 float surface_y = noise_terrain_height->result[index_2d];
587 float slope = noise_inter_valley_slope->result[index_2d];
588 float t_heat = m_bgen->heatmap[index_2d];
590 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
592 if (surface_y > surface_max_y)
593 surface_max_y = ceil(surface_y);
596 // Derive heat from (base) altitude. This will be most correct
597 // at rivers, since other surface heights may vary below.
598 if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
599 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
601 // If humidity is low or heat is high, lower the water table.
602 float delta = m_bgen->humidmap[index_2d] - 50.f;
604 float t_evap = (t_heat - 32.f) / evaporation;
605 river_y += delta * MYMAX(t_evap, 0.08f);
609 u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
610 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
612 // Mapgens concern themselves with stone and water.
613 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
614 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
615 float fill = noise_inter_valley_fill->result[index_3d];
616 float surface_delta = (float)y - surface_y;
617 bool river = y + 1 < river_y;
619 if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
621 vm->m_data[index_data] = n_sand;
622 } else if (slope * fill > surface_delta) {
624 vm->m_data[index_data] = n_stone;
625 if (y > heightmap[index_2d])
626 heightmap[index_2d] = y;
627 if (y > surface_max_y)
629 } else if (y <= water_level) {
631 vm->m_data[index_data] = n_water;
634 vm->m_data[index_data] = n_river_water;
636 vm->m_data[index_data] = n_air;
640 vm->m_area.add_y(em, index_data, 1);
644 // This happens if we're generating a chunk that doesn't
645 // contain the terrain surface, in which case, we need
646 // to set heightmap to a value outside of the chunk,
647 // to avoid confusing lua mods that use heightmap.
648 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
649 s16 surface_y_int = myround(surface_y);
650 if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
651 // If surface_y is outside the chunk, it's good enough.
652 heightmap[index_2d] = surface_y_int;
654 // If the ground is outside of this chunk, but surface_y
655 // is within the chunk, give a value outside.
656 heightmap[index_2d] = node_min.Y - 2;
661 // Use base ground (water table) in a riverbed, to
662 // avoid an unnatural rise in humidity.
663 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
664 float humid = m_bgen->humidmap[index_2d];
665 float water_depth = (t_alt - river_y) / humidity_dropoff;
666 humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
668 // Reduce humidity with altitude (ignoring riverbeds).
669 // This is similar to the lua version's seawater adjustment,
670 // but doesn't increase the base humidity, which causes
671 // problems with the default biomes.
673 humid -= alt_to_humid * t_alt / altitude_chill;
675 m_bgen->humidmap[index_2d] = humid;
678 // Assign the heat adjusted by any changed altitudes.
679 // The altitude will change about half the time.
680 if (use_altitude_chill) {
681 // ground height ignoring riverbeds
682 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
683 if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
684 // The altitude hasn't changed. Use the first result.
685 m_bgen->heatmap[index_2d] = t_heat;
686 else if (t_alt > 0.f)
687 m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
691 return surface_max_y;
694 void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
696 if (max_stone_y < node_min.Y)
699 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
700 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
702 PseudoRandom ps(blockseed + 72202);
704 MapNode n_air(CONTENT_AIR);
705 MapNode n_lava(c_lava_source);
706 MapNode n_water(c_river_water_source);
708 v3s16 em = vm->m_area.getExtent();
710 // Cave blend distance near YMIN, YMAX
711 const float massive_cave_blend = 128.f;
712 // noise threshold for massive caves
713 const float massive_cave_threshold = 0.6f;
714 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
716 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
717 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
718 bool made_a_big_one = false;
720 // Cache the tcave values as they only vary by altitude.
721 if (node_max.Y <= massive_cave_depth) {
722 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
724 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
725 float tcave = massive_cave_threshold;
728 float t = (yblmin - y) / massive_cave_blend;
729 tcave += MYSQUARE(t);
730 } else if (y > yblmax) {
731 float t = (y - yblmax) / massive_cave_blend;
732 tcave += MYSQUARE(t);
735 tcave_cache[y - node_min.Y + 1] = tcave;
739 // lava_depth varies between one and ten as you approach
740 // the bottom of the world.
741 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
742 // This allows random lava spawns to be less common at the surface.
743 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
744 // water_depth varies between ten and one on the way down.
745 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
746 // This allows random water spawns to be more common at the surface.
747 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
749 // Reduce the odds of overflows even further.
750 if (node_max.Y > water_level) {
756 for (s16 z = node_min.Z; z <= node_max.Z; z++)
757 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
758 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
759 bool tunnel_air_above = false;
760 bool underground = false;
761 u32 index_data = vm->m_area.index(x, node_max.Y, z);
762 u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X);
764 // Dig caves on down loop to check for air above.
765 // Don't excavate the overgenerated stone at node_max.Y + 1,
766 // this creates a 'roof' over the tunnel, preventing light in
767 // tunnels at mapchunk borders when generating mapchunks upwards.
768 // This 'roof' is removed when the mapchunk above is generated.
769 for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
771 vm->m_area.add_y(em, index_data, -1)) {
773 float terrain = noise_terrain_height->result[index_2d];
776 if (y > terrain + 10)
778 else if (y < terrain - 40)
781 // Dig massive caves.
782 if (node_max.Y <= massive_cave_depth
783 && noise_massive_caves->result[index_3d]
784 > tcave_cache[y - node_min.Y + 1]) {
785 vm->m_data[index_data] = n_air;
786 made_a_big_one = true;
790 content_t c = vm->m_data[index_data].getContent();
791 float d1 = contour(noise_cave1->result[index_3d]);
792 float d2 = contour(noise_cave2->result[index_3d]);
794 // River water is not set as ground content
795 // in the default game. This can produce strange results
796 // when a tunnel undercuts a river. However, that's not for
797 // the mapgen to correct. Fix it in lua.
799 if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
801 vm->m_data[index_data] = n_air;
802 tunnel_air_above = true;
803 } else if (c == biome->c_filler || c == biome->c_stone) {
804 if (tunnel_air_above) {
805 // at the tunnel floor
806 s16 sr = ps.range(0, 39);
808 vm->m_area.add_y(em, j, 1);
810 if (sr > terrain - y) {
811 // Put dirt in tunnels near the surface.
813 vm->m_data[index_data] = MapNode(biome->c_filler);
815 vm->m_data[index_data] = MapNode(biome->c_top);
816 } else if (sr < 3 && underground) {
818 if (lava_features_lim > 0 && y <= lava_max_height
819 && c == biome->c_stone && sr < lava_chance)
820 vm->m_data[j] = n_lava;
824 // If sr < 0 then we should have already placed lava --
825 // don't immediately dump water on it.
826 if (water_features_lim > 0 && y <= cave_water_max_height
827 && sr >= 0 && sr < water_chance)
828 vm->m_data[j] = n_water;
832 tunnel_air_above = false;
835 tunnel_air_above = false;
840 if (node_max.Y <= large_cave_depth && !made_a_big_one) {
841 u32 bruises_count = ps.range(0, 2);
842 for (u32 i = 0; i < bruises_count; i++) {
843 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
844 c_water_source, c_lava_source);
846 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);