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 for (s32 index = 0; index < csize.X * csize.Z; index++) {
403 noise_heat->result[index] += noise_heat_blend->result[index];
404 noise_humidity->result[index] += noise_humidity_blend->result[index];
410 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
411 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
412 // The parameters that we actually need to generate terrain
413 // are passed by address (and the return value).
414 tn.terrain_height = noise_terrain_height->result[index];
415 // River noise is replaced with base terrain, which
416 // is basically the height of the water table.
417 tn.rivers = &noise_rivers->result[index];
418 // Valley depth noise is replaced with the valley
419 // number that represents the height of terrain
420 // over rivers and is used to determine about
421 // how close a river is for humidity calculation.
422 tn.valley = &noise_valley_depth->result[index];
423 tn.valley_profile = noise_valley_profile->result[index];
424 // Slope noise is replaced by the calculated slope
425 // which is used to get terrain height in the slow
426 // method, to create sharper mountains.
427 tn.slope = &noise_inter_valley_slope->result[index];
428 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
430 // This is the actual terrain height.
431 float mount = terrainLevelFromNoise(&tn);
432 noise_terrain_height->result[index] = mount;
435 heatmap = noise_heat->result;
436 humidmap = noise_humidity->result;
440 // This keeps us from having to maintain two similar sets of
441 // complicated code to determine ground level.
442 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
444 // The square function changes the behaviour of this noise:
445 // very often small, and sometimes very high.
446 float valley_d = MYSQUARE(*tn->valley);
448 // valley_d is here because terrain is generally higher where valleys
449 // are deep (mountains). base represents the height of the
450 // rivers, most of the surface is above.
451 float base = tn->terrain_height + valley_d;
453 // "river" represents the distance from the river, in arbitrary units.
454 float river = fabs(*tn->rivers) - river_size_factor;
456 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
457 // Making "a" vary (0 < a <= 1) changes the shape of the valleys.
458 // Try it with a geometry software !
459 // (here x = "river" and a = valley_profile).
460 // "valley" represents the height of the terrain, from the rivers.
462 float t = river / tn->valley_profile;
463 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
466 // approximate height of the terrain at this point
467 float mount = base + *tn->valley;
469 *tn->slope *= *tn->valley;
471 // Rivers are placed where "river" is negative, so where the original
472 // noise value is close to zero.
473 // Base ground is returned as rivers since it's basically the water table.
476 // Use the the function -sqrt(1-x^2) which models a circle.
479 float t = river / river_size_factor + 1;
480 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
483 // base - depth : height of the bottom of the river
484 // water_level - 6 : don't make rivers below 6 nodes under the surface
485 // There is no logical equivalent to this using rangelim.
486 mount = MYMIN(MYMAX(base - depth, (float) (water_level - 6)), mount);
488 // Slope has no influence on rivers.
496 // This avoids duplicating the code in terrainLevelFromNoise, adding
497 // only the final step of terrain generation without a noise map.
498 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
500 float mount = terrainLevelFromNoise(tn);
501 s16 y_start = myround(mount);
503 for (s16 y = y_start; y <= y_start + 1000; y++) {
504 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
506 if (fill * *tn->slope <= y - mount) {
507 mount = MYMAX(y - 1, mount);
516 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
518 // Check to make sure this isn't a request for a location in a river.
519 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
520 if (fabs(rivers) < river_size_factor)
521 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
523 s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
524 if (level_at_point <= water_level ||
525 level_at_point > water_level + 16)
526 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
528 return level_at_point;
532 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
536 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
537 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
538 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
542 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
545 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
546 tn.slope = &inter_valley_slope;
547 tn.inter_valley_fill = 0.f;
549 return adjustedTerrainLevelFromNoise(&tn);
553 int MapgenValleys::generateTerrain()
555 MapNode n_air(CONTENT_AIR);
556 MapNode n_river_water(c_river_water_source);
557 MapNode n_sand(c_sand);
558 MapNode n_stone(c_stone);
559 MapNode n_water(c_water_source);
561 v3s16 em = vm->m_area.getExtent();
562 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
565 for (s16 z = node_min.Z; z <= node_max.Z; z++)
566 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
567 s16 river_y = floor(noise_rivers->result[index_2d]);
568 s16 surface_y = floor(noise_terrain_height->result[index_2d]);
569 float slope = noise_inter_valley_slope->result[index_2d];
571 heightmap[index_2d] = surface_y;
573 if (surface_y > surface_max_y)
574 surface_max_y = surface_y;
576 u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
577 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
579 // Mapgens concern themselves with stone and water.
580 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
582 fill = noise_inter_valley_fill->result[index_3d];
584 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
585 bool river = (river_y > surface_y);
587 if (river && y == surface_y) {
589 vm->m_data[index_data] = n_sand;
590 } else if (river && y <= surface_y) {
592 vm->m_data[index_data] = n_stone;
593 } else if (river && y < river_y) {
595 vm->m_data[index_data] = n_river_water;
596 } else if ((!river) && myround(fill * slope) >= y - surface_y) {
598 vm->m_data[index_data] = n_stone;
599 heightmap[index_2d] = surface_max_y = y;
600 } else if (y <= water_level) {
602 vm->m_data[index_data] = n_water;
604 vm->m_data[index_data] = n_air;
608 vm->m_area.add_y(em, index_data, 1);
612 // Although the original valleys adjusts humidity by distance
613 // from seawater, this causes problems with the default biomes.
614 // Adjust only by freshwater proximity.
615 const float humidity_offset = 0.8f; // derived by testing
617 noise_humidity->result[index_2d] *= (1 + pow(0.5f, MYMAX((surface_max_y
618 - noise_rivers->result[index_2d]) / 3.f, 0.f))) * humidity_offset;
620 // Assign the heat adjusted by altitude.
621 if (use_altitude_chill && surface_max_y > 0)
622 noise_heat->result[index_2d] *=
623 pow(0.5f, (surface_max_y - altitude_chill / 3.f) / altitude_chill);
626 return surface_max_y;
630 MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
632 v3s16 em = vm->m_area.getExtent();
634 MgStoneType stone_type = STONE;
636 for (s16 z = node_min.Z; z <= node_max.Z; z++)
637 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
641 u16 depth_water_top = 0;
642 u32 vi = vm->m_area.index(x, node_max.Y, z);
644 // Check node at base of mapchunk above, either a node of a previously
645 // generated mapchunk or if not, a node of overgenerated base terrain.
646 content_t c_above = vm->m_data[vi + em.X].getContent();
647 bool air_above = c_above == CONTENT_AIR;
648 bool water_above = (c_above == c_water_source);
650 // If there is air or water above enable top/filler placement, otherwise force
651 // nplaced to stone level by setting a number exceeding any possible filler depth.
652 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
654 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
655 content_t c = vm->m_data[vi].getContent();
657 // Biome is recalculated each time an upper surface is detected while
658 // working down a column. The selected biome then remains in effect for
659 // all nodes below until the next surface and biome recalculation.
660 // Biome is recalculated:
661 // 1. At the surface of stone below air or water.
662 // 2. At the surface of water below air.
663 // 3. When stone or water is detected but biome has not yet been calculated.
664 if ((c == c_stone && (air_above || water_above || !biome))
665 || ((c == c_water_source || c == c_river_water_source)
666 && (air_above || !biome))) {
667 // Both heat and humidity have already been adjusted for altitude.
668 biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
670 depth_top = biome->depth_top;
671 base_filler = MYMAX(depth_top
672 + biome->depth_filler
673 + noise_filler_depth->result[index], 0.f);
674 depth_water_top = biome->depth_water_top;
676 // Detect stone type for dungeons during every biome calculation.
677 // This is more efficient than detecting per-node and will not
678 // miss any desert stone or sandstone biomes.
679 if (biome->c_stone == c_desert_stone)
680 stone_type = DESERT_STONE;
681 else if (biome->c_stone == c_sandstone)
682 stone_type = SANDSTONE;
686 content_t c_below = vm->m_data[vi - em.X].getContent();
688 // If the node below isn't solid, make this node stone, so that
689 // any top/filler nodes above are structurally supported.
690 // This is done by aborting the cycle of top/filler placement
691 // immediately by forcing nplaced to stone level.
692 if (c_below == CONTENT_AIR
693 || c_below == c_water_source
694 || c_below == c_river_water_source)
697 if (nplaced < depth_top) {
698 vm->m_data[vi] = MapNode(biome->c_top);
700 } else if (nplaced < base_filler) {
701 vm->m_data[vi] = MapNode(biome->c_filler);
704 vm->m_data[vi] = MapNode(biome->c_stone);
709 } else if (c == c_water_source) {
710 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
711 ? biome->c_water_top : biome->c_water);
712 nplaced = 0; // Enable top/filler placement for next surface
715 } else if (c == c_river_water_source) {
716 vm->m_data[vi] = MapNode(biome->c_river_water);
717 nplaced = U16_MAX; // Sand was already placed under rivers.
720 } else if (c == CONTENT_AIR) {
721 nplaced = 0; // Enable top/filler placement for next surface
724 } else { // Possible various nodes overgenerated from neighbouring mapchunks
725 nplaced = U16_MAX; // Disable top/filler placement
730 vm->m_area.add_y(em, vi, -1);
738 void MapgenValleys::dustTopNodes()
740 if (node_max.Y < water_level)
743 v3s16 em = vm->m_area.getExtent();
746 for (s16 z = node_min.Z; z <= node_max.Z; z++)
747 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
748 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
750 if (biome->c_dust == CONTENT_IGNORE)
753 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
754 content_t c_full_max = vm->m_data[vi].getContent();
757 if (c_full_max == CONTENT_AIR) {
758 y_start = full_node_max.Y - 1;
759 } else if (c_full_max == CONTENT_IGNORE) {
760 vi = vm->m_area.index(x, node_max.Y + 1, z);
761 content_t c_max = vm->m_data[vi].getContent();
763 if (c_max == CONTENT_AIR)
764 y_start = node_max.Y;
771 vi = vm->m_area.index(x, y_start, z);
772 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
773 if (vm->m_data[vi].getContent() != CONTENT_AIR)
776 vm->m_area.add_y(em, vi, -1);
779 content_t c = vm->m_data[vi].getContent();
780 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
781 vm->m_area.add_y(em, vi, 1);
782 vm->m_data[vi] = MapNode(biome->c_dust);
788 void MapgenValleys::generateCaves(s16 max_stone_y)
790 if (max_stone_y < node_min.Y)
793 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
794 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
796 PseudoRandom ps(blockseed + 72202);
798 MapNode n_air(CONTENT_AIR);
799 MapNode n_lava(c_lava_source);
800 MapNode n_water(c_river_water_source);
802 v3s16 em = vm->m_area.getExtent();
804 // Cave blend distance near YMIN, YMAX
805 const float massive_cave_blend = 128.f;
806 // noise threshold for massive caves
807 const float massive_cave_threshold = 0.6f;
808 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
810 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
811 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
812 bool made_a_big_one = false;
814 // Cache the tcave values as they only vary by altitude.
815 if (node_max.Y <= massive_cave_depth) {
816 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
818 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
819 float tcave = massive_cave_threshold;
822 float t = (yblmin - y) / massive_cave_blend;
823 tcave += MYSQUARE(t);
824 } else if (y > yblmax) {
825 float t = (y - yblmax) / massive_cave_blend;
826 tcave += MYSQUARE(t);
829 tcave_cache[y - node_min.Y + 1] = tcave;
833 // lava_depth varies between one and ten as you approach
834 // the bottom of the world.
835 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
836 // This allows random lava spawns to be less common at the surface.
837 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
838 // water_depth varies between ten and one on the way down.
839 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
840 // This allows random water spawns to be more common at the surface.
841 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
843 // Reduce the odds of overflows even further.
844 if (node_max.Y > water_level) {
851 for (s16 z = node_min.Z; z <= node_max.Z; z++)
852 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
853 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
854 bool air_above = false;
855 bool underground = false;
856 u32 index_data = vm->m_area.index(x, node_max.Y + 1, z);
858 index_3d = (z - node_min.Z) * zstride + (csize.Y + 1) * ystride + (x - node_min.X);
860 // Dig caves on down loop to check for air above.
861 for (s16 y = node_max.Y + 1;
863 y--, index_3d -= ystride, vm->m_area.add_y(em, index_data, -1)) {
864 float terrain = noise_terrain_height->result[index_2d];
867 if (y > terrain + 10) {
870 } else if (y < terrain - 40) {
874 // Dig massive caves.
875 if (node_max.Y <= massive_cave_depth
876 && noise_massive_caves->result[index_3d]
877 > tcave_cache[y - node_min.Y + 1]) {
878 vm->m_data[index_data] = n_air;
879 made_a_big_one = true;
882 content_t c = vm->m_data[index_data].getContent();
883 float d1 = contour(noise_cave1->result[index_3d]);
884 float d2 = contour(noise_cave2->result[index_3d]);
886 // River water is not set as ground content
887 // in the default game. This can produce strange results
888 // when a cave undercuts a river. However, that's not for
889 // the mapgen to correct. Fix it in lua.
891 if (c == CONTENT_AIR) {
893 } else if (d1 * d2 > 0.3f && ndef->get(c).is_ground_content) {
895 vm->m_data[index_data] = n_air;
897 } else if (air_above && (c == biome->c_filler || c == biome->c_stone)) {
899 s16 sr = ps.range(0,39);
901 vm->m_area.add_y(em, j, 1);
903 if (sr > terrain - y) {
904 // Put dirt in caves near the surface.
906 vm->m_data[index_data] = MapNode(biome->c_filler);
908 vm->m_data[index_data] = MapNode(biome->c_top);
909 } else if (sr < 3 && underground) {
911 if (lava_features_lim > 0 && y <= lava_max_height
912 && c == biome->c_stone && sr < lava_chance)
913 vm->m_data[j] = n_lava;
917 // If sr < 0 then we should have already placed lava --
918 // don't immediately dump water on it.
919 if (water_features_lim > 0 && y <= cave_water_max_height
920 && sr >= 0 && sr < water_chance)
921 vm->m_data[j] = n_water;
926 } else if (c == biome->c_filler || c == biome->c_stone) {
935 if (node_max.Y <= large_cave_depth && (!made_a_big_one)) {
936 u32 bruises_count = ps.range(0, 2);
937 for (u32 i = 0; i < bruises_count; i++) {
938 CaveV5 cave(this, &ps);
939 cave.makeCave(node_min, node_max, max_stone_y);