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 : Mapgen(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);
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 == 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 == 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 == 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;
696 MgStoneType MapgenValleys::generateBiomes()
698 v3s16 em = vm->m_area.getExtent();
700 MgStoneType stone_type = STONE;
702 for (s16 z = node_min.Z; z <= node_max.Z; z++)
703 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
707 u16 depth_water_top = 0;
708 u32 vi = vm->m_area.index(x, node_max.Y, z);
710 // Check node at base of mapchunk above, either a node of a previously
711 // generated mapchunk or if not, a node of overgenerated base terrain.
712 content_t c_above = vm->m_data[vi + em.X].getContent();
713 bool air_above = c_above == CONTENT_AIR;
714 bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
716 // If there is air or water above enable top/filler placement, otherwise force
717 // nplaced to stone level by setting a number exceeding any possible filler depth.
718 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
720 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
721 content_t c = vm->m_data[vi].getContent();
723 // Biome is recalculated each time an upper surface is detected while
724 // working down a column. The selected biome then remains in effect for
725 // all nodes below until the next surface and biome recalculation.
726 // Biome is recalculated:
727 // 1. At the surface of stone below air or water.
728 // 2. At the surface of water below air.
729 // 3. When stone or water is detected but biome has not yet been calculated.
730 if ((c == c_stone && (air_above || water_above || !biome))
731 || ((c == c_water_source || c == c_river_water_source)
732 && (air_above || !biome))) {
733 // Both heat and humidity have already been adjusted for altitude.
734 biome = biomegen->getBiomeAtIndex(index, y);
736 depth_top = biome->depth_top;
737 base_filler = MYMAX(depth_top
738 + biome->depth_filler
739 + noise_filler_depth->result[index], 0.f);
740 depth_water_top = biome->depth_water_top;
742 // Detect stone type for dungeons during every biome calculation.
743 // This is more efficient than detecting per-node and will not
744 // miss any desert stone or sandstone biomes.
745 if (biome->c_stone == c_desert_stone)
746 stone_type = DESERT_STONE;
747 else if (biome->c_stone == c_sandstone)
748 stone_type = SANDSTONE;
752 content_t c_below = vm->m_data[vi - em.X].getContent();
754 // If the node below isn't solid, make this node stone, so that
755 // any top/filler nodes above are structurally supported.
756 // This is done by aborting the cycle of top/filler placement
757 // immediately by forcing nplaced to stone level.
758 if (c_below == CONTENT_AIR
759 || c_below == c_water_source
760 || c_below == c_river_water_source)
763 if (nplaced < depth_top) {
764 vm->m_data[vi] = MapNode(biome->c_top);
766 } else if (nplaced < base_filler) {
767 vm->m_data[vi] = MapNode(biome->c_filler);
770 vm->m_data[vi] = MapNode(biome->c_stone);
775 } else if (c == c_water_source) {
776 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
777 ? biome->c_water_top : biome->c_water);
778 nplaced = 0; // Enable top/filler placement for next surface
781 } else if (c == c_river_water_source) {
782 vm->m_data[vi] = MapNode(biome->c_river_water);
783 nplaced = depth_top; // Enable filler placement for next surface
786 } else if (c == CONTENT_AIR) {
787 nplaced = 0; // Enable top/filler placement for next surface
790 } else { // Possible various nodes overgenerated from neighbouring mapchunks
791 nplaced = U16_MAX; // Disable top/filler placement
796 vm->m_area.add_y(em, vi, -1);
804 void MapgenValleys::dustTopNodes()
806 if (node_max.Y < water_level)
809 v3s16 em = vm->m_area.getExtent();
812 for (s16 z = node_min.Z; z <= node_max.Z; z++)
813 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
814 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
816 if (biome->c_dust == CONTENT_IGNORE)
819 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
820 content_t c_full_max = vm->m_data[vi].getContent();
823 if (c_full_max == CONTENT_AIR) {
824 y_start = full_node_max.Y - 1;
825 } else if (c_full_max == CONTENT_IGNORE) {
826 vi = vm->m_area.index(x, node_max.Y + 1, z);
827 content_t c_max = vm->m_data[vi].getContent();
829 if (c_max == CONTENT_AIR)
830 y_start = node_max.Y;
837 vi = vm->m_area.index(x, y_start, z);
838 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
839 if (vm->m_data[vi].getContent() != CONTENT_AIR)
842 vm->m_area.add_y(em, vi, -1);
845 content_t c = vm->m_data[vi].getContent();
846 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
847 vm->m_area.add_y(em, vi, 1);
848 vm->m_data[vi] = MapNode(biome->c_dust);
854 void MapgenValleys::generateCaves(s16 max_stone_y)
856 if (max_stone_y < node_min.Y)
859 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
860 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
862 PseudoRandom ps(blockseed + 72202);
864 MapNode n_air(CONTENT_AIR);
865 MapNode n_lava(c_lava_source);
866 MapNode n_water(c_river_water_source);
868 v3s16 em = vm->m_area.getExtent();
870 // Cave blend distance near YMIN, YMAX
871 const float massive_cave_blend = 128.f;
872 // noise threshold for massive caves
873 const float massive_cave_threshold = 0.6f;
874 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
876 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
877 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
878 bool made_a_big_one = false;
880 // Cache the tcave values as they only vary by altitude.
881 if (node_max.Y <= massive_cave_depth) {
882 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
884 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
885 float tcave = massive_cave_threshold;
888 float t = (yblmin - y) / massive_cave_blend;
889 tcave += MYSQUARE(t);
890 } else if (y > yblmax) {
891 float t = (y - yblmax) / massive_cave_blend;
892 tcave += MYSQUARE(t);
895 tcave_cache[y - node_min.Y + 1] = tcave;
899 // lava_depth varies between one and ten as you approach
900 // the bottom of the world.
901 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
902 // This allows random lava spawns to be less common at the surface.
903 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
904 // water_depth varies between ten and one on the way down.
905 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
906 // This allows random water spawns to be more common at the surface.
907 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
909 // Reduce the odds of overflows even further.
910 if (node_max.Y > water_level) {
916 for (s16 z = node_min.Z; z <= node_max.Z; z++)
917 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
918 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
919 bool tunnel_air_above = false;
920 bool underground = false;
921 u32 index_data = vm->m_area.index(x, node_max.Y, z);
922 u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X);
924 // Dig caves on down loop to check for air above.
925 // Don't excavate the overgenerated stone at node_max.Y + 1,
926 // this creates a 'roof' over the tunnel, preventing light in
927 // tunnels at mapchunk borders when generating mapchunks upwards.
928 // This 'roof' is removed when the mapchunk above is generated.
929 for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
931 vm->m_area.add_y(em, index_data, -1)) {
933 float terrain = noise_terrain_height->result[index_2d];
936 if (y > terrain + 10)
938 else if (y < terrain - 40)
941 // Dig massive caves.
942 if (node_max.Y <= massive_cave_depth
943 && noise_massive_caves->result[index_3d]
944 > tcave_cache[y - node_min.Y + 1]) {
945 vm->m_data[index_data] = n_air;
946 made_a_big_one = true;
950 content_t c = vm->m_data[index_data].getContent();
951 float d1 = contour(noise_cave1->result[index_3d]);
952 float d2 = contour(noise_cave2->result[index_3d]);
954 // River water is not set as ground content
955 // in the default game. This can produce strange results
956 // when a tunnel undercuts a river. However, that's not for
957 // the mapgen to correct. Fix it in lua.
959 if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
961 vm->m_data[index_data] = n_air;
962 tunnel_air_above = true;
963 } else if (c == biome->c_filler || c == biome->c_stone) {
964 if (tunnel_air_above) {
965 // at the tunnel floor
966 s16 sr = ps.range(0, 39);
968 vm->m_area.add_y(em, j, 1);
970 if (sr > terrain - y) {
971 // Put dirt in tunnels near the surface.
973 vm->m_data[index_data] = MapNode(biome->c_filler);
975 vm->m_data[index_data] = MapNode(biome->c_top);
976 } else if (sr < 3 && underground) {
978 if (lava_features_lim > 0 && y <= lava_max_height
979 && c == biome->c_stone && sr < lava_chance)
980 vm->m_data[j] = n_lava;
984 // If sr < 0 then we should have already placed lava --
985 // don't immediately dump water on it.
986 if (water_features_lim > 0 && y <= cave_water_max_height
987 && sr >= 0 && sr < water_chance)
988 vm->m_data[j] = n_water;
992 tunnel_air_above = false;
995 tunnel_air_above = false;
1000 if (node_max.Y <= large_cave_depth && !made_a_big_one) {
1001 u32 bruises_count = ps.range(0, 2);
1002 for (u32 i = 0; i < bruises_count; i++) {
1003 CaveV5 cave(this, &ps);
1004 cave.makeCave(node_min, node_max, max_stone_y);