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);
78 this->biomemap = new u8[csize.X * csize.Z];
79 this->heightmap = new s16[csize.X * csize.Z];
81 this->humidmap = NULL;
83 this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
84 g_settings->getU16("map_generation_limit"));
86 MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
87 this->spflags = sp->spflags;
89 this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
90 this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
92 this->altitude_chill = sp->altitude_chill;
93 this->humidity_adjust = params->np_biome_humidity.offset - 50.f;
94 this->large_cave_depth = sp->large_cave_depth;
95 this->lava_features_lim = rangelim(sp->lava_features, 0, 10);
96 this->massive_cave_depth = sp->massive_cave_depth;
97 this->river_depth_bed = sp->river_depth + 1.f;
98 this->river_size_factor = sp->river_size / 100.f;
99 this->water_features_lim = rangelim(sp->water_features, 0, 10);
101 // a small chance of overflows if the settings are very high
102 this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
103 this->lava_max_height = water_level + MYMAX(0, lava_features_lim - 4) * 50;
105 tcave_cache = new float[csize.Y + 2];
107 //// 2D Terrain noise
108 noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
109 noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
110 noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z);
111 noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z);
112 noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z);
113 noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z);
115 //// 3D Terrain noise
116 noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z);
117 noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z);
118 noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
119 noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 2, csize.Z);
122 noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
123 noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
124 noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
125 noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
127 //// Resolve nodes to be used
128 INodeDefManager *ndef = emerge->ndef;
130 c_cobble = ndef->getId("mapgen_cobble");
131 c_desert_stone = ndef->getId("mapgen_desert_stone");
132 c_dirt = ndef->getId("mapgen_dirt");
133 c_lava_source = ndef->getId("mapgen_lava_source");
134 c_mossycobble = ndef->getId("mapgen_mossycobble");
135 c_river_water_source = ndef->getId("mapgen_river_water_source");
136 c_sand = ndef->getId("mapgen_sand");
137 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
138 c_sandstone = ndef->getId("mapgen_sandstone");
139 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
140 c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
141 c_stone = ndef->getId("mapgen_stone");
142 c_water_source = ndef->getId("mapgen_water_source");
144 if (c_mossycobble == CONTENT_IGNORE)
145 c_mossycobble = c_cobble;
146 if (c_river_water_source == CONTENT_IGNORE)
147 c_river_water_source = c_water_source;
148 if (c_sand == CONTENT_IGNORE)
150 if (c_sandstonebrick == CONTENT_IGNORE)
151 c_sandstonebrick = c_sandstone;
152 if (c_stair_cobble == CONTENT_IGNORE)
153 c_stair_cobble = c_cobble;
154 if (c_stair_sandstonebrick == CONTENT_IGNORE)
155 c_stair_sandstonebrick = c_sandstone;
159 MapgenValleys::~MapgenValleys()
163 delete noise_filler_depth;
165 delete noise_heat_blend;
166 delete noise_humidity;
167 delete noise_humidity_blend;
168 delete noise_inter_valley_fill;
169 delete noise_inter_valley_slope;
171 delete noise_massive_caves;
172 delete noise_terrain_height;
173 delete noise_valley_depth;
174 delete noise_valley_profile;
178 delete[] tcave_cache;
182 MapgenValleysParams::MapgenValleysParams()
184 spflags = MGVALLEYS_HUMID_RIVERS | MGVALLEYS_ALT_CHILL;
186 altitude_chill = 90; // The altitude at which temperature drops by 20C.
187 large_cave_depth = -33;
188 lava_features = 0; // How often water will occur in caves.
189 massive_cave_depth = -256; // highest altitude of massive caves
190 river_depth = 4; // How deep to carve river channels.
191 river_size = 5; // How wide to make rivers.
192 water_features = 0; // How often water will occur in caves.
194 np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
195 np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 2.0);
196 np_filler_depth = NoiseParams(0.f, 1.2f, v3f(256, 256, 256), 1605, 3, 0.5f, 2.f);
197 np_inter_valley_fill = NoiseParams(0.f, 1.f, v3f(256, 512, 256), 1993, 6, 0.8f, 2.f);
198 np_inter_valley_slope = NoiseParams(0.5f, 0.5f, v3f(128, 128, 128), 746, 1, 1.f, 2.f);
199 np_rivers = NoiseParams(0.f, 1.f, v3f(256, 256, 256), -6050, 5, 0.6f, 2.f);
200 np_massive_caves = NoiseParams(0.f, 1.f, v3f(768, 256, 768), 59033, 6, 0.63f, 2.f);
201 np_terrain_height = NoiseParams(-10.f, 50.f, v3f(1024, 1024, 1024), 5202, 6, 0.4f, 2.f);
202 np_valley_depth = NoiseParams(5.f, 4.f, v3f(512, 512, 512), -1914, 1, 1.f, 2.f);
203 np_valley_profile = NoiseParams(0.6f, 0.5f, v3f(512, 512, 512), 777, 1, 1.f, 2.f);
207 void MapgenValleysParams::readParams(const Settings *settings)
209 settings->getFlagStrNoEx("mg_valleys_spflags", spflags, flagdesc_mapgen_valleys);
211 settings->getU16NoEx("mg_valleys_altitude_chill", altitude_chill);
212 settings->getS16NoEx("mg_valleys_large_cave_depth", large_cave_depth);
213 settings->getU16NoEx("mg_valleys_lava_features", lava_features);
214 settings->getS16NoEx("mg_valleys_massive_cave_depth", massive_cave_depth);
215 settings->getU16NoEx("mg_valleys_river_depth", river_depth);
216 settings->getU16NoEx("mg_valleys_river_size", river_size);
217 settings->getU16NoEx("mg_valleys_water_features", water_features);
219 settings->getNoiseParams("mg_valleys_np_cave1", np_cave1);
220 settings->getNoiseParams("mg_valleys_np_cave2", np_cave2);
221 settings->getNoiseParams("mg_valleys_np_filler_depth", np_filler_depth);
222 settings->getNoiseParams("mg_valleys_np_inter_valley_fill", np_inter_valley_fill);
223 settings->getNoiseParams("mg_valleys_np_inter_valley_slope", np_inter_valley_slope);
224 settings->getNoiseParams("mg_valleys_np_rivers", np_rivers);
225 settings->getNoiseParams("mg_valleys_np_massive_caves", np_massive_caves);
226 settings->getNoiseParams("mg_valleys_np_terrain_height", np_terrain_height);
227 settings->getNoiseParams("mg_valleys_np_valley_depth", np_valley_depth);
228 settings->getNoiseParams("mg_valleys_np_valley_profile", np_valley_profile);
232 void MapgenValleysParams::writeParams(Settings *settings) const
234 settings->setFlagStr("mg_valleys_spflags", spflags, flagdesc_mapgen_valleys, U32_MAX);
236 settings->setU16("mg_valleys_altitude_chill", altitude_chill);
237 settings->setS16("mg_valleys_large_cave_depth", large_cave_depth);
238 settings->setU16("mg_valleys_lava_features", lava_features);
239 settings->setS16("mg_valleys_massive_cave_depth", massive_cave_depth);
240 settings->setU16("mg_valleys_river_depth", river_depth);
241 settings->setU16("mg_valleys_river_size", river_size);
242 settings->setU16("mg_valleys_water_features", water_features);
244 settings->setNoiseParams("mg_valleys_np_cave1", np_cave1);
245 settings->setNoiseParams("mg_valleys_np_cave2", np_cave2);
246 settings->setNoiseParams("mg_valleys_np_filler_depth", np_filler_depth);
247 settings->setNoiseParams("mg_valleys_np_inter_valley_fill", np_inter_valley_fill);
248 settings->setNoiseParams("mg_valleys_np_inter_valley_slope", np_inter_valley_slope);
249 settings->setNoiseParams("mg_valleys_np_rivers", np_rivers);
250 settings->setNoiseParams("mg_valleys_np_massive_caves", np_massive_caves);
251 settings->setNoiseParams("mg_valleys_np_terrain_height", np_terrain_height);
252 settings->setNoiseParams("mg_valleys_np_valley_depth", np_valley_depth);
253 settings->setNoiseParams("mg_valleys_np_valley_profile", np_valley_profile);
257 ///////////////////////////////////////
260 void MapgenValleys::makeChunk(BlockMakeData *data)
263 assert(data->vmanip);
264 assert(data->nodedef);
265 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
266 data->blockpos_requested.Y >= data->blockpos_min.Y &&
267 data->blockpos_requested.Z >= data->blockpos_min.Z);
268 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
269 data->blockpos_requested.Y <= data->blockpos_max.Y &&
270 data->blockpos_requested.Z <= data->blockpos_max.Z);
272 this->generating = true;
273 this->vm = data->vmanip;
274 this->ndef = data->nodedef;
276 //TimeTaker t("makeChunk");
278 v3s16 blockpos_min = data->blockpos_min;
279 v3s16 blockpos_max = data->blockpos_max;
280 node_min = blockpos_min * MAP_BLOCKSIZE;
281 node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
282 full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
283 full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
285 blockseed = getBlockSeed2(full_node_min, seed);
287 // Generate noise maps and base terrain height.
290 // Generate base terrain with initial heightmaps
291 s16 stone_surface_max_y = generateTerrain();
293 // Create biomemap at heightmap surface
294 bmgr->calcBiomes(csize.X, csize.Z, heatmap, humidmap, heightmap, biomemap);
296 // Actually place the biome-specific nodes
297 MgStoneType stone_type = generateBiomes(heatmap, humidmap);
300 if (flags & MG_CAVES)
301 generateCaves(stone_surface_max_y);
304 if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
307 dp.np_rarity = nparams_dungeon_rarity;
308 dp.np_density = nparams_dungeon_density;
309 dp.np_wetness = nparams_dungeon_wetness;
310 dp.c_water = c_water_source;
311 if (stone_type == STONE) {
312 dp.c_cobble = c_cobble;
313 dp.c_moss = c_mossycobble;
314 dp.c_stair = c_stair_cobble;
316 dp.diagonal_dirs = false;
318 dp.holesize = v3s16(1, 2, 1);
319 dp.roomsize = v3s16(0, 0, 0);
320 dp.notifytype = GENNOTIFY_DUNGEON;
321 } else if (stone_type == DESERT_STONE) {
322 dp.c_cobble = c_desert_stone;
323 dp.c_moss = c_desert_stone;
324 dp.c_stair = c_desert_stone;
326 dp.diagonal_dirs = true;
328 dp.holesize = v3s16(2, 3, 2);
329 dp.roomsize = v3s16(2, 5, 2);
330 dp.notifytype = GENNOTIFY_TEMPLE;
331 } else if (stone_type == SANDSTONE) {
332 dp.c_cobble = c_sandstonebrick;
333 dp.c_moss = c_sandstonebrick;
334 dp.c_stair = c_sandstonebrick;
336 dp.diagonal_dirs = false;
338 dp.holesize = v3s16(2, 2, 2);
339 dp.roomsize = v3s16(2, 0, 2);
340 dp.notifytype = GENNOTIFY_DUNGEON;
343 DungeonGen dgen(this, &dp);
344 dgen.generate(blockseed, full_node_min, full_node_max);
347 // Generate the registered decorations
348 if (flags & MG_DECORATIONS)
349 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
351 // Generate the registered ores
352 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
354 // Sprinkle some dust on top after everything else was generated
357 //TimeTaker tll("liquid_lighting");
359 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
361 if (flags & MG_LIGHT)
363 node_min - v3s16(0, 1, 0),
364 node_max + v3s16(0, 1, 0),
368 //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
369 //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
371 this->generating = false;
375 // Populate the noise tables and do most of the
376 // calculation necessary to determine terrain height.
377 void MapgenValleys::calculateNoise()
379 //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
382 int y = node_min.Y - 1;
385 //TimeTaker tcn("actualNoise");
387 noise_filler_depth->perlinMap2D(x, z);
388 noise_heat_blend->perlinMap2D(x, z);
389 noise_heat->perlinMap2D(x, z);
390 noise_humidity_blend->perlinMap2D(x, z);
391 noise_humidity->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 noise_heat->result[index] += noise_heat_blend->result[index] + heat_offset;
416 noise_humidity->result[index] *= humidity_scale;
417 noise_humidity->result[index] += noise_humidity_blend->result[index];
423 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
424 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
425 // The parameters that we actually need to generate terrain
426 // are passed by address (and the return value).
427 tn.terrain_height = noise_terrain_height->result[index];
428 // River noise is replaced with base terrain, which
429 // is basically the height of the water table.
430 tn.rivers = &noise_rivers->result[index];
431 // Valley depth noise is replaced with the valley
432 // number that represents the height of terrain
433 // over rivers and is used to determine about
434 // how close a river is for humidity calculation.
435 tn.valley = &noise_valley_depth->result[index];
436 tn.valley_profile = noise_valley_profile->result[index];
437 // Slope noise is replaced by the calculated slope
438 // which is used to get terrain height in the slow
439 // method, to create sharper mountains.
440 tn.slope = &noise_inter_valley_slope->result[index];
441 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
443 // This is the actual terrain height.
444 float mount = terrainLevelFromNoise(&tn);
445 noise_terrain_height->result[index] = mount;
448 heatmap = noise_heat->result;
449 humidmap = noise_humidity->result;
453 // This keeps us from having to maintain two similar sets of
454 // complicated code to determine ground level.
455 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
457 // The square function changes the behaviour of this noise:
458 // very often small, and sometimes very high.
459 float valley_d = MYSQUARE(*tn->valley);
461 // valley_d is here because terrain is generally higher where valleys
462 // are deep (mountains). base represents the height of the
463 // rivers, most of the surface is above.
464 float base = tn->terrain_height + valley_d;
466 // "river" represents the distance from the river, in arbitrary units.
467 float river = fabs(*tn->rivers) - river_size_factor;
469 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
470 // Making "a" vary (0 < a <= 1) changes the shape of the valleys.
471 // Try it with a geometry software !
472 // (here x = "river" and a = valley_profile).
473 // "valley" represents the height of the terrain, from the rivers.
475 float t = river / tn->valley_profile;
476 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
479 // approximate height of the terrain at this point
480 float mount = base + *tn->valley;
482 *tn->slope *= *tn->valley;
484 // Rivers are placed where "river" is negative, so where the original
485 // noise value is close to zero.
486 // Base ground is returned as rivers since it's basically the water table.
489 // Use the the function -sqrt(1-x^2) which models a circle.
492 float t = river / river_size_factor + 1;
493 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
496 // base - depth : height of the bottom of the river
497 // water_level - 3 : don't make rivers below 3 nodes under the surface
498 // We use three because that's as low as the swamp biomes go.
499 // There is no logical equivalent to this using rangelim.
500 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
502 // Slope has no influence on rivers.
510 // This avoids duplicating the code in terrainLevelFromNoise, adding
511 // only the final step of terrain generation without a noise map.
512 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
514 float mount = terrainLevelFromNoise(tn);
515 s16 y_start = myround(mount);
517 for (s16 y = y_start; y <= y_start + 1000; y++) {
518 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
520 if (fill * *tn->slope < y - mount) {
521 mount = MYMAX(y - 1, mount);
530 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
532 // Check to make sure this isn't a request for a location in a river.
533 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
534 if (fabs(rivers) < river_size_factor)
535 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
537 s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
538 if (level_at_point <= water_level ||
539 level_at_point > water_level + 16)
540 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
542 return level_at_point;
546 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
550 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
551 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
552 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
556 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
559 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
560 tn.slope = &inter_valley_slope;
561 tn.inter_valley_fill = 0.f;
563 return adjustedTerrainLevelFromNoise(&tn);
567 int MapgenValleys::generateTerrain()
569 // Raising this reduces the rate of evaporation.
570 static const float evaporation = 300.f;
572 static const float humidity_dropoff = 4.f;
573 // constant to convert altitude chill (compatible with lua) to heat
574 static const float alt_to_heat = 20.f;
575 // humidity reduction by altitude
576 static const float alt_to_humid = 10.f;
578 MapNode n_air(CONTENT_AIR);
579 MapNode n_river_water(c_river_water_source);
580 MapNode n_sand(c_sand);
581 MapNode n_stone(c_stone);
582 MapNode n_water(c_water_source);
584 v3s16 em = vm->m_area.getExtent();
585 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
588 for (s16 z = node_min.Z; z <= node_max.Z; z++)
589 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
590 float river_y = noise_rivers->result[index_2d];
591 float surface_y = noise_terrain_height->result[index_2d];
592 float slope = noise_inter_valley_slope->result[index_2d];
593 float t_heat = noise_heat->result[index_2d];
595 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
597 if (surface_y > surface_max_y)
598 surface_max_y = ceil(surface_y);
601 // Derive heat from (base) altitude. This will be most correct
602 // at rivers, since other surface heights may vary below.
603 if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
604 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
606 // If humidity is low or heat is high, lower the water table.
607 float delta = noise_humidity->result[index_2d] - 50.f;
609 float t_evap = (t_heat - 32.f) / evaporation;
610 river_y += delta * MYMAX(t_evap, 0.08f);
614 u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
615 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
617 // Mapgens concern themselves with stone and water.
618 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
619 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
620 float fill = noise_inter_valley_fill->result[index_3d];
621 float surface_delta = (float)y - surface_y;
622 bool river = y + 1 < river_y;
624 if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
626 vm->m_data[index_data] = n_sand;
627 } else if (slope * fill > surface_delta) {
629 vm->m_data[index_data] = n_stone;
630 if (y > heightmap[index_2d])
631 heightmap[index_2d] = y;
632 if (y > surface_max_y)
634 } else if (y <= water_level) {
636 vm->m_data[index_data] = n_water;
639 vm->m_data[index_data] = n_river_water;
641 vm->m_data[index_data] = n_air;
645 vm->m_area.add_y(em, index_data, 1);
649 // This happens if we're generating a chunk that doesn't
650 // contain the terrain surface, in which case, we need
651 // to set heightmap to a value outside of the chunk,
652 // to avoid confusing lua mods that use heightmap.
653 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
654 s16 surface_y_int = myround(surface_y);
655 if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
656 // If surface_y is outside the chunk, it's good enough.
657 heightmap[index_2d] = surface_y_int;
659 // If the ground is outside of this chunk, but surface_y
660 // is within the chunk, give a value outside.
661 heightmap[index_2d] = node_min.Y - 2;
666 // Use base ground (water table) in a riverbed, to
667 // avoid an unnatural rise in humidity.
668 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
669 float humid = noise_humidity->result[index_2d];
670 float water_depth = (t_alt - river_y) / humidity_dropoff;
671 humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
673 // Reduce humidity with altitude (ignoring riverbeds).
674 // This is similar to the lua version's seawater adjustment,
675 // but doesn't increase the base humidity, which causes
676 // problems with the default biomes.
678 humid -= alt_to_humid * t_alt / altitude_chill;
680 noise_humidity->result[index_2d] = humid;
683 // Assign the heat adjusted by any changed altitudes.
684 // The altitude will change about half the time.
685 if (use_altitude_chill) {
686 // ground height ignoring riverbeds
687 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
688 if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
689 // The altitude hasn't changed. Use the first result.
690 noise_heat->result[index_2d] = t_heat;
691 else if (t_alt > 0.f)
692 noise_heat->result[index_2d] -= alt_to_heat * t_alt / altitude_chill;
696 return surface_max_y;
700 MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
702 v3s16 em = vm->m_area.getExtent();
704 MgStoneType stone_type = STONE;
706 for (s16 z = node_min.Z; z <= node_max.Z; z++)
707 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
711 u16 depth_water_top = 0;
712 u32 vi = vm->m_area.index(x, node_max.Y, z);
714 // Check node at base of mapchunk above, either a node of a previously
715 // generated mapchunk or if not, a node of overgenerated base terrain.
716 content_t c_above = vm->m_data[vi + em.X].getContent();
717 bool air_above = c_above == CONTENT_AIR;
718 bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
720 // If there is air or water above enable top/filler placement, otherwise force
721 // nplaced to stone level by setting a number exceeding any possible filler depth.
722 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
724 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
725 content_t c = vm->m_data[vi].getContent();
727 // Biome is recalculated each time an upper surface is detected while
728 // working down a column. The selected biome then remains in effect for
729 // all nodes below until the next surface and biome recalculation.
730 // Biome is recalculated:
731 // 1. At the surface of stone below air or water.
732 // 2. At the surface of water below air.
733 // 3. When stone or water is detected but biome has not yet been calculated.
734 if ((c == c_stone && (air_above || water_above || !biome))
735 || ((c == c_water_source || c == c_river_water_source)
736 && (air_above || !biome))) {
737 // Both heat and humidity have already been adjusted for altitude.
738 biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
740 depth_top = biome->depth_top;
741 base_filler = MYMAX(depth_top
742 + biome->depth_filler
743 + noise_filler_depth->result[index], 0.f);
744 depth_water_top = biome->depth_water_top;
746 // Detect stone type for dungeons during every biome calculation.
747 // This is more efficient than detecting per-node and will not
748 // miss any desert stone or sandstone biomes.
749 if (biome->c_stone == c_desert_stone)
750 stone_type = DESERT_STONE;
751 else if (biome->c_stone == c_sandstone)
752 stone_type = SANDSTONE;
756 content_t c_below = vm->m_data[vi - em.X].getContent();
758 // If the node below isn't solid, make this node stone, so that
759 // any top/filler nodes above are structurally supported.
760 // This is done by aborting the cycle of top/filler placement
761 // immediately by forcing nplaced to stone level.
762 if (c_below == CONTENT_AIR
763 || c_below == c_water_source
764 || c_below == c_river_water_source)
767 if (nplaced < depth_top) {
768 vm->m_data[vi] = MapNode(biome->c_top);
770 } else if (nplaced < base_filler) {
771 vm->m_data[vi] = MapNode(biome->c_filler);
774 vm->m_data[vi] = MapNode(biome->c_stone);
779 } else if (c == c_water_source) {
780 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
781 ? biome->c_water_top : biome->c_water);
782 nplaced = 0; // Enable top/filler placement for next surface
785 } else if (c == c_river_water_source) {
786 vm->m_data[vi] = MapNode(biome->c_river_water);
787 nplaced = depth_top; // Enable filler placement for next surface
790 } else if (c == CONTENT_AIR) {
791 nplaced = 0; // Enable top/filler placement for next surface
794 } else { // Possible various nodes overgenerated from neighbouring mapchunks
795 nplaced = U16_MAX; // Disable top/filler placement
800 vm->m_area.add_y(em, vi, -1);
808 void MapgenValleys::dustTopNodes()
810 if (node_max.Y < water_level)
813 v3s16 em = vm->m_area.getExtent();
816 for (s16 z = node_min.Z; z <= node_max.Z; z++)
817 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
818 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
820 if (biome->c_dust == CONTENT_IGNORE)
823 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
824 content_t c_full_max = vm->m_data[vi].getContent();
827 if (c_full_max == CONTENT_AIR) {
828 y_start = full_node_max.Y - 1;
829 } else if (c_full_max == CONTENT_IGNORE) {
830 vi = vm->m_area.index(x, node_max.Y + 1, z);
831 content_t c_max = vm->m_data[vi].getContent();
833 if (c_max == CONTENT_AIR)
834 y_start = node_max.Y;
841 vi = vm->m_area.index(x, y_start, z);
842 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
843 if (vm->m_data[vi].getContent() != CONTENT_AIR)
846 vm->m_area.add_y(em, vi, -1);
849 content_t c = vm->m_data[vi].getContent();
850 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
851 vm->m_area.add_y(em, vi, 1);
852 vm->m_data[vi] = MapNode(biome->c_dust);
858 void MapgenValleys::generateCaves(s16 max_stone_y)
860 if (max_stone_y < node_min.Y)
863 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
864 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
866 PseudoRandom ps(blockseed + 72202);
868 MapNode n_air(CONTENT_AIR);
869 MapNode n_lava(c_lava_source);
870 MapNode n_water(c_river_water_source);
872 v3s16 em = vm->m_area.getExtent();
874 // Cave blend distance near YMIN, YMAX
875 const float massive_cave_blend = 128.f;
876 // noise threshold for massive caves
877 const float massive_cave_threshold = 0.6f;
878 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
880 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
881 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
882 bool made_a_big_one = false;
884 // Cache the tcave values as they only vary by altitude.
885 if (node_max.Y <= massive_cave_depth) {
886 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
888 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
889 float tcave = massive_cave_threshold;
892 float t = (yblmin - y) / massive_cave_blend;
893 tcave += MYSQUARE(t);
894 } else if (y > yblmax) {
895 float t = (y - yblmax) / massive_cave_blend;
896 tcave += MYSQUARE(t);
899 tcave_cache[y - node_min.Y + 1] = tcave;
903 // lava_depth varies between one and ten as you approach
904 // the bottom of the world.
905 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
906 // This allows random lava spawns to be less common at the surface.
907 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
908 // water_depth varies between ten and one on the way down.
909 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
910 // This allows random water spawns to be more common at the surface.
911 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
913 // Reduce the odds of overflows even further.
914 if (node_max.Y > water_level) {
921 for (s16 z = node_min.Z; z <= node_max.Z; z++)
922 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
923 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
924 bool air_above = false;
925 bool underground = false;
926 u32 index_data = vm->m_area.index(x, node_max.Y + 1, z);
928 index_3d = (z - node_min.Z) * zstride + (csize.Y + 1) * ystride + (x - node_min.X);
930 // Dig caves on down loop to check for air above.
931 for (s16 y = node_max.Y + 1;
933 y--, index_3d -= ystride, vm->m_area.add_y(em, index_data, -1)) {
934 float terrain = noise_terrain_height->result[index_2d];
937 if (y > terrain + 10) {
940 } else if (y < terrain - 40) {
944 // Dig massive caves.
945 if (node_max.Y <= massive_cave_depth
946 && noise_massive_caves->result[index_3d]
947 > tcave_cache[y - node_min.Y + 1]) {
948 vm->m_data[index_data] = n_air;
949 made_a_big_one = true;
952 content_t c = vm->m_data[index_data].getContent();
953 float d1 = contour(noise_cave1->result[index_3d]);
954 float d2 = contour(noise_cave2->result[index_3d]);
956 // River water is not set as ground content
957 // in the default game. This can produce strange results
958 // when a cave undercuts a river. However, that's not for
959 // the mapgen to correct. Fix it in lua.
961 if (c == CONTENT_AIR) {
963 } else if (d1 * d2 > 0.3f && ndef->get(c).is_ground_content) {
965 vm->m_data[index_data] = n_air;
967 } else if (air_above && (c == biome->c_filler || c == biome->c_stone)) {
969 s16 sr = ps.range(0,39);
971 vm->m_area.add_y(em, j, 1);
973 if (sr > terrain - y) {
974 // Put dirt in caves near the surface.
976 vm->m_data[index_data] = MapNode(biome->c_filler);
978 vm->m_data[index_data] = MapNode(biome->c_top);
979 } else if (sr < 3 && underground) {
981 if (lava_features_lim > 0 && y <= lava_max_height
982 && c == biome->c_stone && sr < lava_chance)
983 vm->m_data[j] = n_lava;
987 // If sr < 0 then we should have already placed lava --
988 // don't immediately dump water on it.
989 if (water_features_lim > 0 && y <= cave_water_max_height
990 && sr >= 0 && sr < water_chance)
991 vm->m_data[j] = n_water;
996 } else if (c == biome->c_filler || c == biome->c_stone) {
1005 if (node_max.Y <= large_cave_depth && (!made_a_big_one)) {
1006 u32 bruises_count = ps.range(0, 2);
1007 for (u32 i = 0; i < bruises_count; i++) {
1008 CaveV5 cave(this, &ps);
1009 cave.makeCave(node_min, node_max, max_stone_y);