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->biomemap = new u8[csize.X * csize.Z];
81 this->heightmap = new s16[csize.X * csize.Z];
83 this->humidmap = NULL;
85 this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
86 g_settings->getU16("map_generation_limit"));
88 MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
90 this->spflags = sp->spflags;
91 this->altitude_chill = sp->altitude_chill;
92 this->large_cave_depth = sp->large_cave_depth;
93 this->lava_features_lim = rangelim(sp->lava_features, 0, 10);
94 this->massive_cave_depth = sp->massive_cave_depth;
95 this->river_depth_bed = sp->river_depth + 1.f;
96 this->river_size_factor = sp->river_size / 100.f;
97 this->water_features_lim = rangelim(sp->water_features, 0, 10);
98 this->cave_width = sp->cave_width;
100 //// 2D Terrain noise
101 noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
102 noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
103 noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z);
104 noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z);
105 noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z);
106 noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z);
108 //// 3D Terrain noise
109 // 1-up 1-down overgeneration
110 noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
111 // 1-down overgeneraion
112 noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
113 noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
114 noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
117 noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
118 noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
119 noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
120 noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
122 this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
123 this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
124 this->humidity_adjust = params->np_biome_humidity.offset - 50.f;
126 // a small chance of overflows if the settings are very high
127 this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
128 this->lava_max_height = water_level + MYMAX(0, lava_features_lim - 4) * 50;
130 tcave_cache = new float[csize.Y + 2];
132 //// Resolve nodes to be used
133 INodeDefManager *ndef = emerge->ndef;
135 c_cobble = ndef->getId("mapgen_cobble");
136 c_desert_stone = ndef->getId("mapgen_desert_stone");
137 c_dirt = ndef->getId("mapgen_dirt");
138 c_lava_source = ndef->getId("mapgen_lava_source");
139 c_mossycobble = ndef->getId("mapgen_mossycobble");
140 c_river_water_source = ndef->getId("mapgen_river_water_source");
141 c_sand = ndef->getId("mapgen_sand");
142 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
143 c_sandstone = ndef->getId("mapgen_sandstone");
144 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
145 c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
146 c_stone = ndef->getId("mapgen_stone");
147 c_water_source = ndef->getId("mapgen_water_source");
149 if (c_mossycobble == CONTENT_IGNORE)
150 c_mossycobble = c_cobble;
151 if (c_river_water_source == CONTENT_IGNORE)
152 c_river_water_source = c_water_source;
153 if (c_sand == CONTENT_IGNORE)
155 if (c_sandstonebrick == CONTENT_IGNORE)
156 c_sandstonebrick = c_sandstone;
157 if (c_stair_cobble == CONTENT_IGNORE)
158 c_stair_cobble = c_cobble;
159 if (c_stair_sandstonebrick == CONTENT_IGNORE)
160 c_stair_sandstonebrick = c_sandstone;
164 MapgenValleys::~MapgenValleys()
168 delete noise_filler_depth;
169 delete noise_inter_valley_fill;
170 delete noise_inter_valley_slope;
172 delete noise_massive_caves;
173 delete noise_terrain_height;
174 delete noise_valley_depth;
175 delete noise_valley_profile;
178 delete noise_heat_blend;
179 delete noise_humidity;
180 delete noise_humidity_blend;
184 delete[] tcave_cache;
188 MapgenValleysParams::MapgenValleysParams()
190 spflags = MGVALLEYS_HUMID_RIVERS | MGVALLEYS_ALT_CHILL;
191 altitude_chill = 90; // The altitude at which temperature drops by 20C.
192 large_cave_depth = -33;
193 lava_features = 0; // How often water will occur in caves.
194 massive_cave_depth = -256; // highest altitude of massive caves
195 river_depth = 4; // How deep to carve river channels.
196 river_size = 5; // How wide to make rivers.
197 water_features = 0; // How often water will occur in caves.
200 np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
201 np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 2.0);
202 np_filler_depth = NoiseParams(0.f, 1.2f, v3f(256, 256, 256), 1605, 3, 0.5f, 2.f);
203 np_inter_valley_fill = NoiseParams(0.f, 1.f, v3f(256, 512, 256), 1993, 6, 0.8f, 2.f);
204 np_inter_valley_slope = NoiseParams(0.5f, 0.5f, v3f(128, 128, 128), 746, 1, 1.f, 2.f);
205 np_rivers = NoiseParams(0.f, 1.f, v3f(256, 256, 256), -6050, 5, 0.6f, 2.f);
206 np_massive_caves = NoiseParams(0.f, 1.f, v3f(768, 256, 768), 59033, 6, 0.63f, 2.f);
207 np_terrain_height = NoiseParams(-10.f, 50.f, v3f(1024, 1024, 1024), 5202, 6, 0.4f, 2.f);
208 np_valley_depth = NoiseParams(5.f, 4.f, v3f(512, 512, 512), -1914, 1, 1.f, 2.f);
209 np_valley_profile = NoiseParams(0.6f, 0.5f, v3f(512, 512, 512), 777, 1, 1.f, 2.f);
213 void MapgenValleysParams::readParams(const Settings *settings)
215 settings->getFlagStrNoEx("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
216 settings->getU16NoEx("mgvalleys_altitude_chill", altitude_chill);
217 settings->getS16NoEx("mgvalleys_large_cave_depth", large_cave_depth);
218 settings->getU16NoEx("mgvalleys_lava_features", lava_features);
219 settings->getS16NoEx("mgvalleys_massive_cave_depth", massive_cave_depth);
220 settings->getU16NoEx("mgvalleys_river_depth", river_depth);
221 settings->getU16NoEx("mgvalleys_river_size", river_size);
222 settings->getU16NoEx("mgvalleys_water_features", water_features);
223 settings->getFloatNoEx("mgvalleys_cave_width", cave_width);
225 settings->getNoiseParams("mgvalleys_np_cave1", np_cave1);
226 settings->getNoiseParams("mgvalleys_np_cave2", np_cave2);
227 settings->getNoiseParams("mgvalleys_np_filler_depth", np_filler_depth);
228 settings->getNoiseParams("mgvalleys_np_inter_valley_fill", np_inter_valley_fill);
229 settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
230 settings->getNoiseParams("mgvalleys_np_rivers", np_rivers);
231 settings->getNoiseParams("mgvalleys_np_massive_caves", np_massive_caves);
232 settings->getNoiseParams("mgvalleys_np_terrain_height", np_terrain_height);
233 settings->getNoiseParams("mgvalleys_np_valley_depth", np_valley_depth);
234 settings->getNoiseParams("mgvalleys_np_valley_profile", np_valley_profile);
238 void MapgenValleysParams::writeParams(Settings *settings) const
240 settings->setFlagStr("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys, U32_MAX);
241 settings->setU16("mgvalleys_altitude_chill", altitude_chill);
242 settings->setS16("mgvalleys_large_cave_depth", large_cave_depth);
243 settings->setU16("mgvalleys_lava_features", lava_features);
244 settings->setS16("mgvalleys_massive_cave_depth", massive_cave_depth);
245 settings->setU16("mgvalleys_river_depth", river_depth);
246 settings->setU16("mgvalleys_river_size", river_size);
247 settings->setU16("mgvalleys_water_features", water_features);
248 settings->setFloat("mgvalleys_cave_width", cave_width);
250 settings->setNoiseParams("mgvalleys_np_cave1", np_cave1);
251 settings->setNoiseParams("mgvalleys_np_cave2", np_cave2);
252 settings->setNoiseParams("mgvalleys_np_filler_depth", np_filler_depth);
253 settings->setNoiseParams("mgvalleys_np_inter_valley_fill", np_inter_valley_fill);
254 settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
255 settings->setNoiseParams("mgvalleys_np_rivers", np_rivers);
256 settings->setNoiseParams("mgvalleys_np_massive_caves", np_massive_caves);
257 settings->setNoiseParams("mgvalleys_np_terrain_height", np_terrain_height);
258 settings->setNoiseParams("mgvalleys_np_valley_depth", np_valley_depth);
259 settings->setNoiseParams("mgvalleys_np_valley_profile", np_valley_profile);
263 ///////////////////////////////////////
266 void MapgenValleys::makeChunk(BlockMakeData *data)
269 assert(data->vmanip);
270 assert(data->nodedef);
271 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
272 data->blockpos_requested.Y >= data->blockpos_min.Y &&
273 data->blockpos_requested.Z >= data->blockpos_min.Z);
274 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
275 data->blockpos_requested.Y <= data->blockpos_max.Y &&
276 data->blockpos_requested.Z <= data->blockpos_max.Z);
278 this->generating = true;
279 this->vm = data->vmanip;
280 this->ndef = data->nodedef;
282 //TimeTaker t("makeChunk");
284 v3s16 blockpos_min = data->blockpos_min;
285 v3s16 blockpos_max = data->blockpos_max;
286 node_min = blockpos_min * MAP_BLOCKSIZE;
287 node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
288 full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
289 full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
291 blockseed = getBlockSeed2(full_node_min, seed);
293 // Generate noise maps and base terrain height.
296 // Generate base terrain with initial heightmaps
297 s16 stone_surface_max_y = generateTerrain();
299 // Create biomemap at heightmap surface
300 bmgr->calcBiomes(csize.X, csize.Z, heatmap, humidmap, heightmap, biomemap);
302 // Actually place the biome-specific nodes
303 MgStoneType stone_type = generateBiomes(heatmap, humidmap);
306 if (flags & MG_CAVES)
307 generateCaves(stone_surface_max_y);
310 if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
313 dp.np_rarity = nparams_dungeon_rarity;
314 dp.np_density = nparams_dungeon_density;
315 dp.np_wetness = nparams_dungeon_wetness;
316 dp.c_water = c_water_source;
317 if (stone_type == STONE) {
318 dp.c_cobble = c_cobble;
319 dp.c_moss = c_mossycobble;
320 dp.c_stair = c_stair_cobble;
322 dp.diagonal_dirs = false;
324 dp.holesize = v3s16(1, 2, 1);
325 dp.roomsize = v3s16(0, 0, 0);
326 dp.notifytype = GENNOTIFY_DUNGEON;
327 } else if (stone_type == DESERT_STONE) {
328 dp.c_cobble = c_desert_stone;
329 dp.c_moss = c_desert_stone;
330 dp.c_stair = c_desert_stone;
332 dp.diagonal_dirs = true;
334 dp.holesize = v3s16(2, 3, 2);
335 dp.roomsize = v3s16(2, 5, 2);
336 dp.notifytype = GENNOTIFY_TEMPLE;
337 } else if (stone_type == SANDSTONE) {
338 dp.c_cobble = c_sandstonebrick;
339 dp.c_moss = c_sandstonebrick;
340 dp.c_stair = c_sandstonebrick;
342 dp.diagonal_dirs = false;
344 dp.holesize = v3s16(2, 2, 2);
345 dp.roomsize = v3s16(2, 0, 2);
346 dp.notifytype = GENNOTIFY_DUNGEON;
349 DungeonGen dgen(this, &dp);
350 dgen.generate(blockseed, full_node_min, full_node_max);
353 // Generate the registered decorations
354 if (flags & MG_DECORATIONS)
355 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
357 // Generate the registered ores
358 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
360 // Sprinkle some dust on top after everything else was generated
363 //TimeTaker tll("liquid_lighting");
365 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
367 if (flags & MG_LIGHT)
369 node_min - v3s16(0, 1, 0),
370 node_max + v3s16(0, 1, 0),
374 //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
375 //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
377 this->generating = false;
381 // Populate the noise tables and do most of the
382 // calculation necessary to determine terrain height.
383 void MapgenValleys::calculateNoise()
385 //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
388 int y = node_min.Y - 1;
391 //TimeTaker tcn("actualNoise");
393 noise_filler_depth->perlinMap2D(x, z);
394 noise_heat_blend->perlinMap2D(x, z);
395 noise_heat->perlinMap2D(x, z);
396 noise_humidity_blend->perlinMap2D(x, z);
397 noise_humidity->perlinMap2D(x, z);
398 noise_inter_valley_slope->perlinMap2D(x, z);
399 noise_rivers->perlinMap2D(x, z);
400 noise_terrain_height->perlinMap2D(x, z);
401 noise_valley_depth->perlinMap2D(x, z);
402 noise_valley_profile->perlinMap2D(x, z);
404 noise_inter_valley_fill->perlinMap3D(x, y, z);
406 //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
408 float heat_offset = 0.f;
409 float humidity_scale = 1.f;
411 // Altitude chill tends to reduce the average heat.
412 if (use_altitude_chill)
415 // River humidity tends to increase the humidity range.
417 humidity_scale = 0.8f;
420 for (s32 index = 0; index < csize.X * csize.Z; index++) {
421 noise_heat->result[index] += noise_heat_blend->result[index] + heat_offset;
422 noise_humidity->result[index] *= humidity_scale;
423 noise_humidity->result[index] += noise_humidity_blend->result[index];
429 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
430 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
431 // The parameters that we actually need to generate terrain
432 // are passed by address (and the return value).
433 tn.terrain_height = noise_terrain_height->result[index];
434 // River noise is replaced with base terrain, which
435 // is basically the height of the water table.
436 tn.rivers = &noise_rivers->result[index];
437 // Valley depth noise is replaced with the valley
438 // number that represents the height of terrain
439 // over rivers and is used to determine about
440 // how close a river is for humidity calculation.
441 tn.valley = &noise_valley_depth->result[index];
442 tn.valley_profile = noise_valley_profile->result[index];
443 // Slope noise is replaced by the calculated slope
444 // which is used to get terrain height in the slow
445 // method, to create sharper mountains.
446 tn.slope = &noise_inter_valley_slope->result[index];
447 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
449 // This is the actual terrain height.
450 float mount = terrainLevelFromNoise(&tn);
451 noise_terrain_height->result[index] = mount;
454 heatmap = noise_heat->result;
455 humidmap = noise_humidity->result;
459 // This keeps us from having to maintain two similar sets of
460 // complicated code to determine ground level.
461 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
463 // The square function changes the behaviour of this noise:
464 // very often small, and sometimes very high.
465 float valley_d = MYSQUARE(*tn->valley);
467 // valley_d is here because terrain is generally higher where valleys
468 // are deep (mountains). base represents the height of the
469 // rivers, most of the surface is above.
470 float base = tn->terrain_height + valley_d;
472 // "river" represents the distance from the river, in arbitrary units.
473 float river = fabs(*tn->rivers) - river_size_factor;
475 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
476 // Making "a" vary (0 < a <= 1) changes the shape of the valleys.
477 // Try it with a geometry software !
478 // (here x = "river" and a = valley_profile).
479 // "valley" represents the height of the terrain, from the rivers.
481 float t = river / tn->valley_profile;
482 *tn->valley = valley_d * (1.f - exp(- MYSQUARE(t)));
485 // approximate height of the terrain at this point
486 float mount = base + *tn->valley;
488 *tn->slope *= *tn->valley;
490 // Rivers are placed where "river" is negative, so where the original
491 // noise value is close to zero.
492 // Base ground is returned as rivers since it's basically the water table.
495 // Use the the function -sqrt(1-x^2) which models a circle.
498 float t = river / river_size_factor + 1;
499 depth = (river_depth_bed * sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
502 // base - depth : height of the bottom of the river
503 // water_level - 3 : don't make rivers below 3 nodes under the surface
504 // We use three because that's as low as the swamp biomes go.
505 // There is no logical equivalent to this using rangelim.
506 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
508 // Slope has no influence on rivers.
516 // This avoids duplicating the code in terrainLevelFromNoise, adding
517 // only the final step of terrain generation without a noise map.
518 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
520 float mount = terrainLevelFromNoise(tn);
521 s16 y_start = myround(mount);
523 for (s16 y = y_start; y <= y_start + 1000; y++) {
524 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
526 if (fill * *tn->slope < y - mount) {
527 mount = MYMAX(y - 1, mount);
536 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
538 // Check to make sure this isn't a request for a location in a river.
539 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
540 if (fabs(rivers) < river_size_factor)
541 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
543 s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
544 if (level_at_point <= water_level ||
545 level_at_point > water_level + 32)
546 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
548 return level_at_point;
552 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
556 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
557 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
558 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
562 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
565 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
566 tn.slope = &inter_valley_slope;
567 tn.inter_valley_fill = 0.f;
569 return adjustedTerrainLevelFromNoise(&tn);
573 int MapgenValleys::generateTerrain()
575 // Raising this reduces the rate of evaporation.
576 static const float evaporation = 300.f;
578 static const float humidity_dropoff = 4.f;
579 // constant to convert altitude chill (compatible with lua) to heat
580 static const float alt_to_heat = 20.f;
581 // humidity reduction by altitude
582 static const float alt_to_humid = 10.f;
584 MapNode n_air(CONTENT_AIR);
585 MapNode n_river_water(c_river_water_source);
586 MapNode n_sand(c_sand);
587 MapNode n_stone(c_stone);
588 MapNode n_water(c_water_source);
590 v3s16 em = vm->m_area.getExtent();
591 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
594 for (s16 z = node_min.Z; z <= node_max.Z; z++)
595 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
596 float river_y = noise_rivers->result[index_2d];
597 float surface_y = noise_terrain_height->result[index_2d];
598 float slope = noise_inter_valley_slope->result[index_2d];
599 float t_heat = noise_heat->result[index_2d];
601 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
603 if (surface_y > surface_max_y)
604 surface_max_y = ceil(surface_y);
607 // Derive heat from (base) altitude. This will be most correct
608 // at rivers, since other surface heights may vary below.
609 if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
610 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
612 // If humidity is low or heat is high, lower the water table.
613 float delta = noise_humidity->result[index_2d] - 50.f;
615 float t_evap = (t_heat - 32.f) / evaporation;
616 river_y += delta * MYMAX(t_evap, 0.08f);
620 u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
621 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
623 // Mapgens concern themselves with stone and water.
624 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
625 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
626 float fill = noise_inter_valley_fill->result[index_3d];
627 float surface_delta = (float)y - surface_y;
628 bool river = y + 1 < river_y;
630 if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
632 vm->m_data[index_data] = n_sand;
633 } else if (slope * fill > surface_delta) {
635 vm->m_data[index_data] = n_stone;
636 if (y > heightmap[index_2d])
637 heightmap[index_2d] = y;
638 if (y > surface_max_y)
640 } else if (y <= water_level) {
642 vm->m_data[index_data] = n_water;
645 vm->m_data[index_data] = n_river_water;
647 vm->m_data[index_data] = n_air;
651 vm->m_area.add_y(em, index_data, 1);
655 // This happens if we're generating a chunk that doesn't
656 // contain the terrain surface, in which case, we need
657 // to set heightmap to a value outside of the chunk,
658 // to avoid confusing lua mods that use heightmap.
659 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
660 s16 surface_y_int = myround(surface_y);
661 if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
662 // If surface_y is outside the chunk, it's good enough.
663 heightmap[index_2d] = surface_y_int;
665 // If the ground is outside of this chunk, but surface_y
666 // is within the chunk, give a value outside.
667 heightmap[index_2d] = node_min.Y - 2;
672 // Use base ground (water table) in a riverbed, to
673 // avoid an unnatural rise in humidity.
674 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
675 float humid = noise_humidity->result[index_2d];
676 float water_depth = (t_alt - river_y) / humidity_dropoff;
677 humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
679 // Reduce humidity with altitude (ignoring riverbeds).
680 // This is similar to the lua version's seawater adjustment,
681 // but doesn't increase the base humidity, which causes
682 // problems with the default biomes.
684 humid -= alt_to_humid * t_alt / altitude_chill;
686 noise_humidity->result[index_2d] = humid;
689 // Assign the heat adjusted by any changed altitudes.
690 // The altitude will change about half the time.
691 if (use_altitude_chill) {
692 // ground height ignoring riverbeds
693 float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
694 if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
695 // The altitude hasn't changed. Use the first result.
696 noise_heat->result[index_2d] = t_heat;
697 else if (t_alt > 0.f)
698 noise_heat->result[index_2d] -= alt_to_heat * t_alt / altitude_chill;
702 return surface_max_y;
706 MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
708 v3s16 em = vm->m_area.getExtent();
710 MgStoneType stone_type = STONE;
712 for (s16 z = node_min.Z; z <= node_max.Z; z++)
713 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
717 u16 depth_water_top = 0;
718 u32 vi = vm->m_area.index(x, node_max.Y, z);
720 // Check node at base of mapchunk above, either a node of a previously
721 // generated mapchunk or if not, a node of overgenerated base terrain.
722 content_t c_above = vm->m_data[vi + em.X].getContent();
723 bool air_above = c_above == CONTENT_AIR;
724 bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
726 // If there is air or water above enable top/filler placement, otherwise force
727 // nplaced to stone level by setting a number exceeding any possible filler depth.
728 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
730 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
731 content_t c = vm->m_data[vi].getContent();
733 // Biome is recalculated each time an upper surface is detected while
734 // working down a column. The selected biome then remains in effect for
735 // all nodes below until the next surface and biome recalculation.
736 // Biome is recalculated:
737 // 1. At the surface of stone below air or water.
738 // 2. At the surface of water below air.
739 // 3. When stone or water is detected but biome has not yet been calculated.
740 if ((c == c_stone && (air_above || water_above || !biome))
741 || ((c == c_water_source || c == c_river_water_source)
742 && (air_above || !biome))) {
743 // Both heat and humidity have already been adjusted for altitude.
744 biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
746 depth_top = biome->depth_top;
747 base_filler = MYMAX(depth_top
748 + biome->depth_filler
749 + noise_filler_depth->result[index], 0.f);
750 depth_water_top = biome->depth_water_top;
752 // Detect stone type for dungeons during every biome calculation.
753 // This is more efficient than detecting per-node and will not
754 // miss any desert stone or sandstone biomes.
755 if (biome->c_stone == c_desert_stone)
756 stone_type = DESERT_STONE;
757 else if (biome->c_stone == c_sandstone)
758 stone_type = SANDSTONE;
762 content_t c_below = vm->m_data[vi - em.X].getContent();
764 // If the node below isn't solid, make this node stone, so that
765 // any top/filler nodes above are structurally supported.
766 // This is done by aborting the cycle of top/filler placement
767 // immediately by forcing nplaced to stone level.
768 if (c_below == CONTENT_AIR
769 || c_below == c_water_source
770 || c_below == c_river_water_source)
773 if (nplaced < depth_top) {
774 vm->m_data[vi] = MapNode(biome->c_top);
776 } else if (nplaced < base_filler) {
777 vm->m_data[vi] = MapNode(biome->c_filler);
780 vm->m_data[vi] = MapNode(biome->c_stone);
785 } else if (c == c_water_source) {
786 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
787 ? biome->c_water_top : biome->c_water);
788 nplaced = 0; // Enable top/filler placement for next surface
791 } else if (c == c_river_water_source) {
792 vm->m_data[vi] = MapNode(biome->c_river_water);
793 nplaced = depth_top; // Enable filler placement for next surface
796 } else if (c == CONTENT_AIR) {
797 nplaced = 0; // Enable top/filler placement for next surface
800 } else { // Possible various nodes overgenerated from neighbouring mapchunks
801 nplaced = U16_MAX; // Disable top/filler placement
806 vm->m_area.add_y(em, vi, -1);
814 void MapgenValleys::dustTopNodes()
816 if (node_max.Y < water_level)
819 v3s16 em = vm->m_area.getExtent();
822 for (s16 z = node_min.Z; z <= node_max.Z; z++)
823 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
824 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
826 if (biome->c_dust == CONTENT_IGNORE)
829 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
830 content_t c_full_max = vm->m_data[vi].getContent();
833 if (c_full_max == CONTENT_AIR) {
834 y_start = full_node_max.Y - 1;
835 } else if (c_full_max == CONTENT_IGNORE) {
836 vi = vm->m_area.index(x, node_max.Y + 1, z);
837 content_t c_max = vm->m_data[vi].getContent();
839 if (c_max == CONTENT_AIR)
840 y_start = node_max.Y;
847 vi = vm->m_area.index(x, y_start, z);
848 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
849 if (vm->m_data[vi].getContent() != CONTENT_AIR)
852 vm->m_area.add_y(em, vi, -1);
855 content_t c = vm->m_data[vi].getContent();
856 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
857 vm->m_area.add_y(em, vi, 1);
858 vm->m_data[vi] = MapNode(biome->c_dust);
864 void MapgenValleys::generateCaves(s16 max_stone_y)
866 if (max_stone_y < node_min.Y)
869 noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
870 noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
872 PseudoRandom ps(blockseed + 72202);
874 MapNode n_air(CONTENT_AIR);
875 MapNode n_lava(c_lava_source);
876 MapNode n_water(c_river_water_source);
878 v3s16 em = vm->m_area.getExtent();
880 // Cave blend distance near YMIN, YMAX
881 const float massive_cave_blend = 128.f;
882 // noise threshold for massive caves
883 const float massive_cave_threshold = 0.6f;
884 // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
886 float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
887 float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
888 bool made_a_big_one = false;
890 // Cache the tcave values as they only vary by altitude.
891 if (node_max.Y <= massive_cave_depth) {
892 noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
894 for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) {
895 float tcave = massive_cave_threshold;
898 float t = (yblmin - y) / massive_cave_blend;
899 tcave += MYSQUARE(t);
900 } else if (y > yblmax) {
901 float t = (y - yblmax) / massive_cave_blend;
902 tcave += MYSQUARE(t);
905 tcave_cache[y - node_min.Y + 1] = tcave;
909 // lava_depth varies between one and ten as you approach
910 // the bottom of the world.
911 s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
912 // This allows random lava spawns to be less common at the surface.
913 s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
914 // water_depth varies between ten and one on the way down.
915 s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
916 // This allows random water spawns to be more common at the surface.
917 s16 water_chance = MYCUBE(water_features_lim) * water_depth;
919 // Reduce the odds of overflows even further.
920 if (node_max.Y > water_level) {
926 for (s16 z = node_min.Z; z <= node_max.Z; z++)
927 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
928 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
929 bool tunnel_air_above = false;
930 bool underground = false;
931 u32 index_data = vm->m_area.index(x, node_max.Y, z);
932 u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X);
934 // Dig caves on down loop to check for air above.
935 // Don't excavate the overgenerated stone at node_max.Y + 1,
936 // this creates a 'roof' over the tunnel, preventing light in
937 // tunnels at mapchunk borders when generating mapchunks upwards.
938 // This 'roof' is removed when the mapchunk above is generated.
939 for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
941 vm->m_area.add_y(em, index_data, -1)) {
943 float terrain = noise_terrain_height->result[index_2d];
946 if (y > terrain + 10)
948 else if (y < terrain - 40)
951 // Dig massive caves.
952 if (node_max.Y <= massive_cave_depth
953 && noise_massive_caves->result[index_3d]
954 > tcave_cache[y - node_min.Y + 1]) {
955 vm->m_data[index_data] = n_air;
956 made_a_big_one = true;
960 content_t c = vm->m_data[index_data].getContent();
961 float d1 = contour(noise_cave1->result[index_3d]);
962 float d2 = contour(noise_cave2->result[index_3d]);
964 // River water is not set as ground content
965 // in the default game. This can produce strange results
966 // when a tunnel undercuts a river. However, that's not for
967 // the mapgen to correct. Fix it in lua.
969 if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
971 vm->m_data[index_data] = n_air;
972 tunnel_air_above = true;
973 } else if (c == biome->c_filler || c == biome->c_stone) {
974 if (tunnel_air_above) {
975 // at the tunnel floor
976 s16 sr = ps.range(0, 39);
978 vm->m_area.add_y(em, j, 1);
980 if (sr > terrain - y) {
981 // Put dirt in tunnels near the surface.
983 vm->m_data[index_data] = MapNode(biome->c_filler);
985 vm->m_data[index_data] = MapNode(biome->c_top);
986 } else if (sr < 3 && underground) {
988 if (lava_features_lim > 0 && y <= lava_max_height
989 && c == biome->c_stone && sr < lava_chance)
990 vm->m_data[j] = n_lava;
994 // If sr < 0 then we should have already placed lava --
995 // don't immediately dump water on it.
996 if (water_features_lim > 0 && y <= cave_water_max_height
997 && sr >= 0 && sr < water_chance)
998 vm->m_data[j] = n_water;
1002 tunnel_air_above = false;
1005 tunnel_air_above = false;
1010 if (node_max.Y <= large_cave_depth && !made_a_big_one) {
1011 u32 bruises_count = ps.range(0, 2);
1012 for (u32 i = 0; i < bruises_count; i++) {
1013 CaveV5 cave(this, &ps);
1014 cave.makeCave(node_min, node_max, max_stone_y);