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 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.
35 #include "content_sao.h"
37 #include "voxelalgorithms.h"
38 #include "settings.h" // For g_settings
40 #include "dungeongen.h"
44 #include "mg_decoration.h"
45 #include "mapgen_valleys.h"
50 //#include "util/timetaker.h"
51 //#include "profiler.h"
54 //static Profiler mapgen_prof;
55 //Profiler *mapgen_profiler = &mapgen_prof;
57 static FlagDesc flagdesc_mapgen_valleys[] = {
58 {"altitude_chill", MG_VALLEYS_ALT_CHILL},
59 {"cliffs", MG_VALLEYS_CLIFFS},
60 {"fast", MG_VALLEYS_FAST},
61 {"humid_rivers", MG_VALLEYS_HUMID_RIVERS},
62 {"rugged", MG_VALLEYS_RUGGED},
66 ///////////////////////////////////////////////////////////////////////////////
69 MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
70 : Mapgen(mapgenid, params, emerge)
72 this->m_emerge = emerge;
73 this->bmgr = emerge->biomemgr;
75 //// amount of elements to skip for the next index
76 //// for noise/height/biome maps (not vmanip)
77 this->ystride = csize.X;
78 this->zstride = csize.X * (csize.Y + 2);
80 this->biomemap = new u8[csize.X * csize.Z];
81 this->heightmap = new s16[csize.X * csize.Z];
83 this->humidmap = NULL;
85 MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
86 this->spflags = sp->spflags;
88 this->cliff_terrain = (spflags & MG_VALLEYS_CLIFFS);
89 this->fast_terrain = (spflags & MG_VALLEYS_FAST);
90 this->humid_rivers = (spflags & MG_VALLEYS_HUMID_RIVERS);
91 this->rugged_terrain = (spflags & MG_VALLEYS_RUGGED);
92 this->use_altitude_chill = (spflags & MG_VALLEYS_ALT_CHILL);
94 this->altitude_chill = sp->altitude_chill;
95 this->cave_water_max_height = sp->cave_water_max_height;
96 this->humidity_adjust = sp->humidity - 50.f;
97 this->humidity_break_point = sp->humidity_break_point;
98 this->lava_max_height = sp->lava_max_height;
99 this->river_depth = sp->river_depth + 1.f;
100 this->river_size = sp->river_size / 100.f;
101 this->temperature_adjust = sp->temperature - 50.f;
102 this->water_features = MYMAX(1, MYMIN(11, 11 - sp->water_features));
104 //// 2D Terrain noise
105 noise_cliffs = new Noise(&sp->np_cliffs, seed, csize.X, csize.Z);
106 noise_corr = new Noise(&sp->np_corr, seed, csize.X, csize.Z);
107 noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
108 noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
109 noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z);
110 noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z);
111 noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z);
112 noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z);
114 if (this->fast_terrain)
115 noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Z);
117 //// 3D Terrain noise
118 noise_simple_caves_1 = new Noise(&sp->np_simple_caves_1, seed, csize.X, csize.Y + 2, csize.Z);
119 noise_simple_caves_2 = new Noise(&sp->np_simple_caves_2, seed, csize.X, csize.Y + 2, csize.Z);
121 if (!this->fast_terrain)
122 noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
125 noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
126 noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
127 noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
128 noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
130 //// Resolve nodes to be used
131 INodeDefManager *ndef = emerge->ndef;
133 c_cobble = ndef->getId("mapgen_cobble");
134 c_desert_stone = ndef->getId("mapgen_desert_stone");
135 c_dirt = ndef->getId("mapgen_dirt");
136 c_lava_source = ndef->getId("mapgen_lava_source");
137 c_mossycobble = ndef->getId("mapgen_mossycobble");
138 c_river_water_source = ndef->getId("mapgen_river_water_source");
139 c_sand = ndef->getId("mapgen_sand");
140 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
141 c_sandstone = ndef->getId("mapgen_sandstone");
142 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
143 c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
144 c_stone = ndef->getId("mapgen_stone");
145 c_water_source = ndef->getId("mapgen_water_source");
147 if (c_mossycobble == CONTENT_IGNORE)
148 c_mossycobble = c_cobble;
149 if (c_river_water_source == CONTENT_IGNORE)
150 c_river_water_source = c_water_source;
151 if (c_sand == CONTENT_IGNORE)
153 if (c_sandstonebrick == CONTENT_IGNORE)
154 c_sandstonebrick = c_sandstone;
155 if (c_stair_cobble == CONTENT_IGNORE)
156 c_stair_cobble = c_cobble;
157 if (c_stair_sandstonebrick == CONTENT_IGNORE)
158 c_stair_sandstonebrick = c_sandstone;
162 MapgenValleys::~MapgenValleys()
166 delete noise_filler_depth;
168 delete noise_heat_blend;
169 delete noise_humidity;
170 delete noise_humidity_blend;
171 delete noise_inter_valley_fill;
172 delete noise_inter_valley_slope;
174 delete noise_simple_caves_1;
175 delete noise_simple_caves_2;
176 delete noise_terrain_height;
177 delete noise_valley_depth;
178 delete noise_valley_profile;
185 MapgenValleysParams::MapgenValleysParams()
187 spflags = MG_VALLEYS_CLIFFS | MG_VALLEYS_RUGGED
188 | MG_VALLEYS_HUMID_RIVERS | MG_VALLEYS_ALT_CHILL;
190 altitude_chill = 90; // The altitude at which temperature drops by 20C.
191 // Water in caves will never be higher than this.
192 cave_water_max_height = MAX_MAP_GENERATION_LIMIT;
194 // the maximum humidity around rivers in otherwise dry areas
195 humidity_break_point = 65;
196 lava_max_height = 0; // Lava will never be higher than this.
197 river_depth = 4; // How deep to carve river channels.
198 river_size = 5; // How wide to make rivers.
200 water_features = 3; // How often water will occur in caves.
202 np_cliffs = NoiseParams(0.f, 1.f, v3f(750, 750, 750), 8445, 5, 1.f, 2.f);
203 np_corr = NoiseParams(0.f, 1.f, v3f(40, 40, 40), -3536, 4, 1.f, 2.f);
204 np_filler_depth = NoiseParams(0.f, 1.2f, v3f(256, 256, 256), 1605, 3, 0.5f, 2.f);
205 np_inter_valley_fill = NoiseParams(0.f, 1.f, v3f(256, 512, 256), 1993, 6, 0.8f, 2.f);
206 np_inter_valley_slope = NoiseParams(0.5f, 0.5f, v3f(128, 128, 128), 746, 1, 1.f, 2.f);
207 np_rivers = NoiseParams(0.f, 1.f, v3f(256, 256, 256), -6050, 5, 0.6f, 2.f);
208 np_simple_caves_1 = NoiseParams(0.f, 1.f, v3f(64, 64, 64), -8402, 3, 0.5f, 2.f);
209 np_simple_caves_2 = NoiseParams(0.f, 1.f, v3f(64, 64, 64), 3944, 3, 0.5f, 2.f);
210 np_terrain_height = NoiseParams(-10.f, 50.f, v3f(1024, 1024, 1024), 5202, 6, 0.4f, 2.f);
211 np_valley_depth = NoiseParams(5.f, 4.f, v3f(512, 512, 512), -1914, 1, 1.f, 2.f);
212 np_valley_profile = NoiseParams(0.6f, 0.5f, v3f(512, 512, 512), 777, 1, 1.f, 2.f);
216 void MapgenValleysParams::readParams(const Settings *settings)
218 settings->getFlagStrNoEx("mg_valleys_spflags", spflags, flagdesc_mapgen_valleys);
220 settings->getU16NoEx("mg_valleys_altitude_chill", altitude_chill);
221 settings->getS16NoEx("mg_valleys_cave_water_max_height", cave_water_max_height);
222 settings->getS16NoEx("mg_valleys_humidity", humidity);
223 settings->getS16NoEx("mg_valleys_humidity_break_point", humidity_break_point);
224 settings->getS16NoEx("mg_valleys_lava_max_height", lava_max_height);
225 settings->getU16NoEx("mg_valleys_river_depth", river_depth);
226 settings->getU16NoEx("mg_valleys_river_size", river_size);
227 settings->getS16NoEx("mg_valleys_temperature", temperature);
228 settings->getU16NoEx("mg_valleys_water_features", water_features);
230 settings->getNoiseParams("mg_valleys_np_cliffs", np_cliffs);
231 settings->getNoiseParams("mg_valleys_np_corr", np_corr);
232 settings->getNoiseParams("mg_valleys_np_filler_depth", np_filler_depth);
233 settings->getNoiseParams("mg_valleys_np_inter_valley_fill", np_inter_valley_fill);
234 settings->getNoiseParams("mg_valleys_np_inter_valley_slope", np_inter_valley_slope);
235 settings->getNoiseParams("mg_valleys_np_rivers", np_rivers);
236 settings->getNoiseParams("mg_valleys_np_simple_caves_1", np_simple_caves_1);
237 settings->getNoiseParams("mg_valleys_np_simple_caves_2", np_simple_caves_2);
238 settings->getNoiseParams("mg_valleys_np_terrain_height", np_terrain_height);
239 settings->getNoiseParams("mg_valleys_np_valley_depth", np_valley_depth);
240 settings->getNoiseParams("mg_valleys_np_valley_profile", np_valley_profile);
244 void MapgenValleysParams::writeParams(Settings *settings) const
246 settings->setFlagStr("mg_valleys_spflags", spflags, flagdesc_mapgen_valleys, U32_MAX);
248 settings->setU16("mg_valleys_altitude_chill", altitude_chill);
249 settings->setS16("mg_valleys_cave_water_max_height", cave_water_max_height);
250 settings->setS16("mg_valleys_humidity", humidity);
251 settings->setS16("mg_valleys_humidity_break_point", humidity_break_point);
252 settings->setS16("mg_valleys_lava_max_height", lava_max_height);
253 settings->setU16("mg_valleys_river_depth", river_depth);
254 settings->setU16("mg_valleys_river_size", river_size);
255 settings->setS16("mg_valleys_temperature", temperature);
256 settings->setU16("mg_valleys_water_features", water_features);
258 settings->setNoiseParams("mg_valleys_np_cliffs", np_cliffs);
259 settings->setNoiseParams("mg_valleys_np_corr", np_corr);
260 settings->setNoiseParams("mg_valleys_np_filler_depth", np_filler_depth);
261 settings->setNoiseParams("mg_valleys_np_inter_valley_fill", np_inter_valley_fill);
262 settings->setNoiseParams("mg_valleys_np_inter_valley_slope", np_inter_valley_slope);
263 settings->setNoiseParams("mg_valleys_np_rivers", np_rivers);
264 settings->setNoiseParams("mg_valleys_np_simple_caves_1", np_simple_caves_1);
265 settings->setNoiseParams("mg_valleys_np_simple_caves_2", np_simple_caves_2);
266 settings->setNoiseParams("mg_valleys_np_terrain_height", np_terrain_height);
267 settings->setNoiseParams("mg_valleys_np_valley_depth", np_valley_depth);
268 settings->setNoiseParams("mg_valleys_np_valley_profile", np_valley_profile);
272 ///////////////////////////////////////
275 void MapgenValleys::makeChunk(BlockMakeData *data)
278 assert(data->vmanip);
279 assert(data->nodedef);
280 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
281 data->blockpos_requested.Y >= data->blockpos_min.Y &&
282 data->blockpos_requested.Z >= data->blockpos_min.Z);
283 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
284 data->blockpos_requested.Y <= data->blockpos_max.Y &&
285 data->blockpos_requested.Z <= data->blockpos_max.Z);
287 this->generating = true;
288 this->vm = data->vmanip;
289 this->ndef = data->nodedef;
291 //TimeTaker t("makeChunk");
293 v3s16 blockpos_min = data->blockpos_min;
294 v3s16 blockpos_max = data->blockpos_max;
295 node_min = blockpos_min * MAP_BLOCKSIZE;
296 node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
297 full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
298 full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
300 blockseed = getBlockSeed2(full_node_min, seed);
302 // Generate noise maps and base terrain height.
305 // Generate base terrain with initial heightmaps
306 s16 stone_surface_max_y = generateTerrain();
308 // Create biomemap at heightmap surface
309 bmgr->calcBiomes(csize.X, csize.Z, heatmap, humidmap, heightmap, biomemap);
311 // Actually place the biome-specific nodes
312 MgStoneType stone_type = generateBiomes(heatmap, humidmap);
315 if (flags & MG_CAVES)
316 generateSimpleCaves(stone_surface_max_y);
319 if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
322 dp.np_rarity = nparams_dungeon_rarity;
323 dp.np_density = nparams_dungeon_density;
324 dp.np_wetness = nparams_dungeon_wetness;
325 dp.c_water = c_water_source;
326 if (stone_type == STONE) {
327 dp.c_cobble = c_cobble;
328 dp.c_moss = c_mossycobble;
329 dp.c_stair = c_stair_cobble;
331 dp.diagonal_dirs = false;
333 dp.holesize = v3s16(1, 2, 1);
334 dp.roomsize = v3s16(0, 0, 0);
335 dp.notifytype = GENNOTIFY_DUNGEON;
336 } else if (stone_type == DESERT_STONE) {
337 dp.c_cobble = c_desert_stone;
338 dp.c_moss = c_desert_stone;
339 dp.c_stair = c_desert_stone;
341 dp.diagonal_dirs = true;
343 dp.holesize = v3s16(2, 3, 2);
344 dp.roomsize = v3s16(2, 5, 2);
345 dp.notifytype = GENNOTIFY_TEMPLE;
346 } else if (stone_type == SANDSTONE) {
347 dp.c_cobble = c_sandstonebrick;
348 dp.c_moss = c_sandstonebrick;
349 dp.c_stair = c_sandstonebrick;
351 dp.diagonal_dirs = false;
353 dp.holesize = v3s16(2, 2, 2);
354 dp.roomsize = v3s16(2, 0, 2);
355 dp.notifytype = GENNOTIFY_DUNGEON;
358 DungeonGen dgen(this, &dp);
359 dgen.generate(blockseed, full_node_min, full_node_max);
362 // Generate the registered decorations
363 if (flags & MG_DECORATIONS)
364 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
366 // Generate the registered ores
367 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
369 // Sprinkle some dust on top after everything else was generated
372 //TimeTaker tll("liquid_lighting");
374 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
376 if (flags & MG_LIGHT)
378 node_min - v3s16(0, 1, 0),
379 node_max + v3s16(0, 1, 0),
383 //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
384 //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
386 this->generating = false;
390 // Populate the noise tables and do most of the
391 // calculation necessary to determine terrain height.
392 void MapgenValleys::calculateNoise()
394 //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
397 int y = node_min.Y - 1;
400 //TimeTaker tcn("actualNoise");
402 noise_filler_depth->perlinMap2D(x, z);
403 noise_heat_blend->perlinMap2D(x, z);
404 noise_heat->perlinMap2D(x, z);
405 noise_humidity_blend->perlinMap2D(x, z);
406 noise_humidity->perlinMap2D(x, z);
407 noise_inter_valley_slope->perlinMap2D(x, z);
408 noise_rivers->perlinMap2D(x, z);
409 noise_terrain_height->perlinMap2D(x, z);
410 noise_valley_depth->perlinMap2D(x, z);
411 noise_valley_profile->perlinMap2D(x, z);
414 // Make this 2D for speed, if requested.
415 noise_inter_valley_fill->perlinMap2D(x, z);
418 noise_cliffs->perlinMap2D(x, z);
420 noise_corr->perlinMap2D(x, z);
422 noise_inter_valley_fill->perlinMap3D(x, y, z);
425 if (flags & MG_CAVES) {
426 noise_simple_caves_1->perlinMap3D(x, y, z);
427 noise_simple_caves_2->perlinMap3D(x, y, z);
430 //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
432 for (s32 index = 0; index < csize.X * csize.Z; index++) {
433 noise_heat->result[index] += noise_heat_blend->result[index];
434 noise_heat->result[index] += temperature_adjust;
435 noise_humidity->result[index] += noise_humidity_blend->result[index];
441 for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
442 for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
443 // The parameters that we actually need to generate terrain
444 // are passed by address (and the return value).
445 tn.terrain_height = noise_terrain_height->result[index];
446 // River noise is replaced with base terrain, which
447 // is basically the height of the water table.
448 tn.rivers = &noise_rivers->result[index];
449 // Valley depth noise is replaced with the valley
450 // number that represents the height of terrain
451 // over rivers and is used to determine about
452 // how close a river is for humidity calculation.
453 tn.valley = &noise_valley_depth->result[index];
454 tn.valley_profile = noise_valley_profile->result[index];
455 // Slope noise is replaced by the calculated slope
456 // which is used to get terrain height in the slow
457 // method, to create sharper mountains.
458 tn.slope = &noise_inter_valley_slope->result[index];
459 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
460 tn.cliffs = noise_cliffs->result[index];
461 tn.corr = noise_corr->result[index];
463 // This is the actual terrain height.
464 float mount = terrainLevelFromNoise(&tn);
465 noise_terrain_height->result[index] = mount;
468 // Assign humidity adjusted by water proximity.
469 // I can't think of a reason why a mod would expect base humidity
470 // from noise or at any altitude other than ground level.
471 noise_humidity->result[index] = humidityByTerrain(
472 noise_humidity->result[index],
474 noise_rivers->result[index],
475 noise_valley_depth->result[index]);
477 // Assign heat adjusted by altitude. See humidity, above.
478 if (use_altitude_chill && mount > 0.f)
479 noise_heat->result[index] *= pow(0.5f, (mount - altitude_chill / 3.f) / altitude_chill);
483 heatmap = noise_heat->result;
484 humidmap = noise_humidity->result;
488 // This keeps us from having to maintain two similar sets of
489 // complicated code to determine ground level.
490 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
492 float inter_valley_slope = *tn->slope;
494 // The square function changes the behaviour of this noise:
495 // very often small, and sometimes very high.
496 float valley_d = pow(*tn->valley, 2);
498 // valley_d is here because terrain is generally higher where valleys
499 // are deep (mountains). base represents the height of the
500 // rivers, most of the surface is above.
501 float base = tn->terrain_height + valley_d;
503 // "river" represents the distance from the river, in arbitrary units.
504 float river = fabs(*tn->rivers) - river_size;
506 // Use the curve of the function 1−exp(−(x/a)²) to model valleys.
507 // Making "a" vary (0 < a ≤ 1) changes the shape of the valleys.
508 // Try it with a geometry software !
509 // (here x = "river" and a = valley_profile).
510 // "valley" represents the height of the terrain, from the rivers.
511 *tn->valley = valley_d * (1.f - exp(- pow(river / tn->valley_profile, 2)));
513 // approximate height of the terrain at this point
514 float mount = base + *tn->valley;
516 *tn->slope *= *tn->valley;
518 // Rivers are placed where "river" is negative, so where the original
519 // noise value is close to zero.
520 // Base ground is returned as rivers since it's basically the water table.
523 // Use the the function −sqrt(1−x²) which models a circle.
524 float depth = (river_depth * sqrt(1.f - pow((river / river_size + 1), 2)));
526 // base - depth : height of the bottom of the river
527 // water_level - 2 : don't make rivers below 2 nodes under the surface
531 mount = fmin(fmax(base - depth, (float) (water_level - min_bottom)), mount);
533 // Slope has no influence on rivers.
538 // The penultimate step builds up the heights, but we reduce it
539 // occasionally to create cliffs.
540 float delta = sin(tn->inter_valley_fill) * *tn->slope;
541 if (cliff_terrain && tn->cliffs >= 0.2f)
542 mount += delta * 0.66f;
546 // Use yet another noise to make the heights look more rugged.
548 && mount > water_level
549 && fabs(inter_valley_slope * tn->inter_valley_fill) < 0.3f)
550 mount += ((delta < 0.f) ? -1.f : 1.f) * pow(fabs(delta), 0.5f) * fabs(sin(tn->corr));
557 // This avoids duplicating the code in terrainLevelFromNoise, adding
558 // only the final step of terrain generation without a noise map.
559 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
561 float mount = terrainLevelFromNoise(tn);
564 for (s16 y = round(mount); y <= round(mount) + 1000; y++) {
565 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
567 if (fill * *tn->slope <= y - mount) {
568 mount = fmax(y - 1, mount);
578 float MapgenValleys::humidityByTerrain(
584 // Although the original valleys adjusts humidity by distance
585 // from seawater, this causes problems with the default biomes.
586 // Adjust only by freshwater proximity.
587 float humidity = humidity_base + humidity_adjust;
589 if (humid_rivers && mount > water_level) {
590 // Offset to make everything average the same.
591 humidity -= (humidity_break_point - humidity_adjust) / 3.f;
593 // This method is from the original lua.
594 float water_table = pow(0.5f, fmax(rivers / 3.f, 0.f));
595 // This adds humidity next to rivers and lakes.
596 float river_water = pow(0.5f, fmax(valley / 12.f, 0.f));
598 float water = water_table + (1.f - water_table) * river_water;
599 humidity = fmax(humidity, (humidity_break_point * water));
606 int MapgenValleys::getGroundLevelAtPoint(v2s16 p)
608 // ***********************************************
609 // This method (deliberately) does not return correct
610 // terrain values. This may be a problem in the future.
611 // ***********************************************
613 // Since MT doesn't normally deal with rivers, check
614 // to make sure this isn't a request for a location
616 float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
618 // If it's wet, return an unusable number.
619 if (fabs(rivers) < river_size)
620 return MAX_MAP_GENERATION_LIMIT;
622 // Otherwise, return the real result.
623 return terrainLevelAtPoint(p.X, p.Y);
627 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
631 float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
632 float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
633 float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
637 tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
640 tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
641 tn.slope = &inter_valley_slope;
642 tn.inter_valley_fill = 0.f;
647 tn.inter_valley_fill = NoisePerlin2D(&noise_inter_valley_fill->np, x, z, seed);
650 tn.cliffs = NoisePerlin2D(&noise_cliffs->np, x, z, seed);
652 tn.corr = NoisePerlin2D(&noise_corr->np, x, z, seed);
655 return adjustedTerrainLevelFromNoise(&tn);
659 int MapgenValleys::generateTerrain()
661 MapNode n_air(CONTENT_AIR);
662 MapNode n_river_water(c_river_water_source);
663 MapNode n_sand(c_sand);
664 MapNode n_stone(c_stone);
665 MapNode n_water(c_water_source);
667 v3s16 em = vm->m_area.getExtent();
668 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
671 for (s16 z = node_min.Z; z <= node_max.Z; z++)
672 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
673 s16 river_y = round(noise_rivers->result[index_2d]);
674 s16 surface_y = round(noise_terrain_height->result[index_2d]);
675 float slope = noise_inter_valley_slope->result[index_2d];
677 heightmap[index_2d] = surface_y;
679 if (surface_y > surface_max_y)
680 surface_max_y = surface_y;
684 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
686 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
688 // Mapgens concern themselves with stone and water.
689 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
692 fill = noise_inter_valley_fill->result[index_3d];
694 if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
695 bool river = (river_y > surface_y);
697 if (river && y == surface_y) {
699 vm->m_data[index_data] = n_sand;
700 } else if ((fast_terrain || river) && y <= surface_y) {
702 vm->m_data[index_data] = n_stone;
703 } else if (river && y < river_y) {
705 vm->m_data[index_data] = n_river_water;
706 } else if ((!fast_terrain) && (!river) && fill * slope > y - surface_y) {
707 // ground (slow method)
708 vm->m_data[index_data] = n_stone;
709 heightmap[index_2d] = surface_max_y = y;
710 } else if (y <= water_level) {
712 vm->m_data[index_data] = n_water;
714 vm->m_data[index_data] = n_air;
718 vm->m_area.add_y(em, index_data, 1);
724 // Assign the humidity adjusted by water proximity.
725 noise_humidity->result[index_2d] = humidityByTerrain(
726 noise_humidity->result[index_2d],
728 noise_rivers->result[index_2d],
729 noise_valley_depth->result[index_2d]);
731 // Assign the heat adjusted by altitude. See humidity, above.
732 if (use_altitude_chill && surface_max_y > 0)
733 noise_heat->result[index_2d]
734 *= pow(0.5f, (surface_max_y - altitude_chill / 3.f) / altitude_chill);
738 return surface_max_y;
742 MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
744 v3s16 em = vm->m_area.getExtent();
746 MgStoneType stone_type = STONE;
748 for (s16 z = node_min.Z; z <= node_max.Z; z++)
749 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
753 u16 depth_water_top = 0;
754 u32 vi = vm->m_area.index(x, node_max.Y, z);
756 // Check node at base of mapchunk above, either a node of a previously
757 // generated mapchunk or if not, a node of overgenerated base terrain.
758 content_t c_above = vm->m_data[vi + em.X].getContent();
759 bool air_above = c_above == CONTENT_AIR;
760 bool water_above = (c_above == c_water_source);
762 // If there is air or water above enable top/filler placement, otherwise force
763 // nplaced to stone level by setting a number exceeding any possible filler depth.
764 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
766 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
767 content_t c = vm->m_data[vi].getContent();
769 // Biome is recalculated each time an upper surface is detected while
770 // working down a column. The selected biome then remains in effect for
771 // all nodes below until the next surface and biome recalculation.
772 // Biome is recalculated:
773 // 1. At the surface of stone below air or water.
774 // 2. At the surface of water below air.
775 // 3. When stone or water is detected but biome has not yet been calculated.
776 if ((c == c_stone && (air_above || water_above || !biome))
777 || ((c == c_water_source || c == c_river_water_source)
778 && (air_above || !biome))) {
779 // Both heat and humidity have already been adjusted for altitude.
780 biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
782 depth_top = biome->depth_top;
783 base_filler = MYMAX(depth_top
784 + biome->depth_filler
785 + noise_filler_depth->result[index], 0.f);
786 depth_water_top = biome->depth_water_top;
788 // Detect stone type for dungeons during every biome calculation.
789 // This is more efficient than detecting per-node and will not
790 // miss any desert stone or sandstone biomes.
791 if (biome->c_stone == c_desert_stone)
792 stone_type = DESERT_STONE;
793 else if (biome->c_stone == c_sandstone)
794 stone_type = SANDSTONE;
798 content_t c_below = vm->m_data[vi - em.X].getContent();
800 // If the node below isn't solid, make this node stone, so that
801 // any top/filler nodes above are structurally supported.
802 // This is done by aborting the cycle of top/filler placement
803 // immediately by forcing nplaced to stone level.
804 if (c_below == CONTENT_AIR
805 || c_below == c_water_source
806 || c_below == c_river_water_source)
809 if (nplaced < depth_top) {
810 vm->m_data[vi] = MapNode(biome->c_top);
812 } else if (nplaced < base_filler) {
813 vm->m_data[vi] = MapNode(biome->c_filler);
816 vm->m_data[vi] = MapNode(biome->c_stone);
821 } else if (c == c_water_source) {
822 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
823 ? biome->c_water_top : biome->c_water);
824 nplaced = 0; // Enable top/filler placement for next surface
827 } else if (c == c_river_water_source) {
828 vm->m_data[vi] = MapNode(biome->c_river_water);
829 nplaced = U16_MAX; // Sand was already placed under rivers.
832 } else if (c == CONTENT_AIR) {
833 nplaced = 0; // Enable top/filler placement for next surface
836 } else { // Possible various nodes overgenerated from neighbouring mapchunks
837 nplaced = U16_MAX; // Disable top/filler placement
842 vm->m_area.add_y(em, vi, -1);
850 void MapgenValleys::dustTopNodes()
852 if (node_max.Y < water_level)
855 v3s16 em = vm->m_area.getExtent();
858 for (s16 z = node_min.Z; z <= node_max.Z; z++)
859 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
860 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
862 if (biome->c_dust == CONTENT_IGNORE)
865 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
866 content_t c_full_max = vm->m_data[vi].getContent();
869 if (c_full_max == CONTENT_AIR) {
870 y_start = full_node_max.Y - 1;
871 } else if (c_full_max == CONTENT_IGNORE) {
872 vi = vm->m_area.index(x, node_max.Y + 1, z);
873 content_t c_max = vm->m_data[vi].getContent();
875 if (c_max == CONTENT_AIR)
876 y_start = node_max.Y;
883 vi = vm->m_area.index(x, y_start, z);
884 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
885 if (vm->m_data[vi].getContent() != CONTENT_AIR)
888 vm->m_area.add_y(em, vi, -1);
891 content_t c = vm->m_data[vi].getContent();
892 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
893 vm->m_area.add_y(em, vi, 1);
894 vm->m_data[vi] = MapNode(biome->c_dust);
900 void MapgenValleys::generateSimpleCaves(s16 max_stone_y)
902 PseudoRandom ps(blockseed + 72202);
904 MapNode n_air(CONTENT_AIR);
905 MapNode n_dirt(c_dirt);
906 MapNode n_lava(c_lava_source);
907 MapNode n_water(c_river_water_source);
909 v3s16 em = vm->m_area.getExtent();
911 s16 base_water_chance = 0;
912 if (water_features < 11)
913 base_water_chance = ceil(MAX_MAP_GENERATION_LIMIT / (water_features * 1000));
915 if (max_stone_y >= node_min.Y) {
918 for (s16 z = node_min.Z; z <= node_max.Z; z++)
919 for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
920 bool air_above = false;
921 //bool underground = false;
922 u32 index_data = vm->m_area.index(x, node_max.Y + 1, z);
924 index_3d = (z - node_min.Z) * zstride + (csize.Y + 1) * ystride + (x - node_min.X);
926 // Dig caves on down loop to check for air above.
927 for (s16 y = node_max.Y + 1;
929 y--, index_3d -= ystride, vm->m_area.add_y(em, index_data, -1)) {
930 float terrain = noise_terrain_height->result[index_2d];
932 // Saves some time and prevents removing above ground nodes.
933 if (y > terrain + 1) {
938 content_t c = vm->m_data[index_data].getContent();
939 bool n1 = (fabs(noise_simple_caves_1->result[index_3d]) < 0.07f);
940 bool n2 = (fabs(noise_simple_caves_2->result[index_3d]) < 0.07f);
942 // River water is (foolishly) not set as ground content
943 // in the default game. This can produce strange results
944 // when a cave undercuts a river. However, that's not for
945 // the mapgen to correct. Fix it in lua.
947 if (c == CONTENT_AIR) {
949 } else if (n1 && n2 && ndef->get(c).is_ground_content) {
950 // When both n's are true, we're in a cave.
951 vm->m_data[index_data] = n_air;
954 && (c == c_stone || c == c_sandstone || c == c_desert_stone)) {
956 s16 sr = ps.next() & 1023;
958 vm->m_area.add_y(em, j, 1);
960 if (sr > (terrain - y) * 25) {
961 // Put dirt in caves near the surface.
962 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
963 vm->m_data[index_data] = MapNode(biome->c_filler);
967 if (y <= lava_max_height && c == c_stone) {
968 // Lava spawns increase with depth.
969 lava_chance = ceil((lava_max_height - y + 1) / 10000);
971 if (sr < lava_chance)
972 vm->m_data[j] = n_lava;
975 if (base_water_chance > 0 && y <= cave_water_max_height) {
976 s16 water_chance = base_water_chance
977 - (abs(y - water_level) / (water_features * 1000));
979 // Waterfalls may get out of control above ground.
981 // If sr < 0 then we should have already placed lava --
982 // don't immediately dump water on it.
983 if (sr >= 0 && sr < water_chance)
984 vm->m_data[j] = n_water;
991 // If we're not in a cave, there's no open space.