]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_valleys.cpp
Change mapgen order to ores > dungeons > decorations (#7656)
[dragonfireclient.git] / src / mapgen / mapgen_valleys.cpp
1 /*
2 Minetest
3 Copyright (C) 2016-2018 Duane Robertson <duane@duanerobertson.com>
4 Copyright (C) 2016-2018 paramat
5
6 Based on Valleys Mapgen by Gael de Sailly
7 (https://forum.minetest.net/viewtopic.php?f=9&t=11430)
8 and mapgen_v7, mapgen_flat by kwolekr and paramat.
9
10 Licensing changed by permission of Gael de Sailly.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as published by
14 the Free Software Foundation; either version 2.1 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public License along
23 with this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #include "mapgen.h"
28 #include "voxel.h"
29 #include "noise.h"
30 #include "mapblock.h"
31 #include "mapnode.h"
32 #include "map.h"
33 #include "nodedef.h"
34 #include "voxelalgorithms.h"
35 //#include "profiler.h" // For TimeTaker
36 #include "settings.h" // For g_settings
37 #include "emerge.h"
38 #include "dungeongen.h"
39 #include "mg_biome.h"
40 #include "mg_ore.h"
41 #include "mg_decoration.h"
42 #include "mapgen_valleys.h"
43 #include "cavegen.h"
44 #include <cmath>
45
46
47 FlagDesc flagdesc_mapgen_valleys[] = {
48         {"altitude_chill",   MGVALLEYS_ALT_CHILL},
49         {"humid_rivers",     MGVALLEYS_HUMID_RIVERS},
50         {"vary_river_depth", MGVALLEYS_VARY_RIVER_DEPTH},
51         {"altitude_dry",     MGVALLEYS_ALT_DRY},
52         {NULL,               0}
53 };
54
55
56 ////////////////////////////////////////////////////////////////////////////////
57
58
59 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params,
60         EmergeManager *emerge)
61         : MapgenBasic(mapgenid, params, emerge)
62 {
63         // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
64         m_bgen = (BiomeGenOriginal *)biomegen;
65
66         BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
67
68         spflags            = params->spflags;
69         altitude_chill     = params->altitude_chill;
70         river_depth_bed    = params->river_depth + 1.0f;
71         river_size_factor  = params->river_size / 100.0f;
72
73         cave_width         = params->cave_width;
74         large_cave_depth   = params->large_cave_depth;
75         lava_depth         = params->lava_depth;
76         cavern_limit       = params->cavern_limit;
77         cavern_taper       = params->cavern_taper;
78         cavern_threshold   = params->cavern_threshold;
79         dungeon_ymin       = params->dungeon_ymin;
80         dungeon_ymax       = params->dungeon_ymax;
81
82         //// 2D Terrain noise
83         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
84         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
85         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
86         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
87         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
88         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
89
90         //// 3D Terrain noise
91         // 1-up 1-down overgeneration
92         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill,
93                 seed, csize.X, csize.Y + 2, csize.Z);
94         // 1-down overgeneraion
95         MapgenBasic::np_cave1   = params->np_cave1;
96         MapgenBasic::np_cave2   = params->np_cave2;
97         MapgenBasic::np_cavern  = params->np_cavern;
98
99         humidity_adjust    = bp->np_humidity.offset - 50.0f;
100 }
101
102
103 MapgenValleys::~MapgenValleys()
104 {
105         delete noise_filler_depth;
106         delete noise_inter_valley_fill;
107         delete noise_inter_valley_slope;
108         delete noise_rivers;
109         delete noise_terrain_height;
110         delete noise_valley_depth;
111         delete noise_valley_profile;
112 }
113
114
115 MapgenValleysParams::MapgenValleysParams():
116         np_filler_depth       (0.0,   1.2,  v3f(256,  256,  256),  1605,  3, 0.5,  2.0),
117         np_inter_valley_fill  (0.0,   1.0,  v3f(256,  512,  256),  1993,  6, 0.8,  2.0),
118         np_inter_valley_slope (0.5,   0.5,  v3f(128,  128,  128),  746,   1, 1.0,  2.0),
119         np_rivers             (0.0,   1.0,  v3f(256,  256,  256),  -6050, 5, 0.6,  2.0),
120         np_terrain_height     (-10.0, 50.0, v3f(1024, 1024, 1024), 5202,  6, 0.4,  2.0),
121         np_valley_depth       (5.0,   4.0,  v3f(512,  512,  512),  -1914, 1, 1.0,  2.0),
122         np_valley_profile     (0.6,   0.50, v3f(512,  512,  512),  777,   1, 1.0,  2.0),
123         np_cave1              (0.0,   12.0, v3f(61,   61,   61),   52534, 3, 0.5,  2.0),
124         np_cave2              (0.0,   12.0, v3f(67,   67,   67),   10325, 3, 0.5,  2.0),
125         np_cavern             (0.0,   1.0,  v3f(768,  256,  768),  59033, 6, 0.63, 2.0)
126 {
127 }
128
129
130 void MapgenValleysParams::readParams(const Settings *settings)
131 {
132         settings->getFlagStrNoEx("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys);
133         settings->getU16NoEx("mgvalleys_altitude_chill",     altitude_chill);
134         settings->getS16NoEx("mgvalleys_large_cave_depth",   large_cave_depth);
135         settings->getS16NoEx("mgvalleys_lava_depth",         lava_depth);
136         settings->getU16NoEx("mgvalleys_river_depth",        river_depth);
137         settings->getU16NoEx("mgvalleys_river_size",         river_size);
138         settings->getFloatNoEx("mgvalleys_cave_width",       cave_width);
139         settings->getS16NoEx("mgvalleys_cavern_limit",       cavern_limit);
140         settings->getS16NoEx("mgvalleys_cavern_taper",       cavern_taper);
141         settings->getFloatNoEx("mgvalleys_cavern_threshold", cavern_threshold);
142         settings->getS16NoEx("mgvalleys_dungeon_ymin",       dungeon_ymin);
143         settings->getS16NoEx("mgvalleys_dungeon_ymax",       dungeon_ymax);
144
145         settings->getNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
146         settings->getNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
147         settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
148         settings->getNoiseParams("mgvalleys_np_rivers",             np_rivers);
149         settings->getNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
150         settings->getNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
151         settings->getNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
152
153         settings->getNoiseParams("mgvalleys_np_cave1",              np_cave1);
154         settings->getNoiseParams("mgvalleys_np_cave2",              np_cave2);
155         settings->getNoiseParams("mgvalleys_np_cavern",             np_cavern);
156 }
157
158
159 void MapgenValleysParams::writeParams(Settings *settings) const
160 {
161         settings->setFlagStr("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys, U32_MAX);
162         settings->setU16("mgvalleys_altitude_chill",     altitude_chill);
163         settings->setS16("mgvalleys_large_cave_depth",   large_cave_depth);
164         settings->setS16("mgvalleys_lava_depth",         lava_depth);
165         settings->setU16("mgvalleys_river_depth",        river_depth);
166         settings->setU16("mgvalleys_river_size",         river_size);
167         settings->setFloat("mgvalleys_cave_width",       cave_width);
168         settings->setS16("mgvalleys_cavern_limit",       cavern_limit);
169         settings->setS16("mgvalleys_cavern_taper",       cavern_taper);
170         settings->setFloat("mgvalleys_cavern_threshold", cavern_threshold);
171         settings->setS16("mgvalleys_dungeon_ymin",       dungeon_ymin);
172         settings->setS16("mgvalleys_dungeon_ymax",       dungeon_ymax);
173
174         settings->setNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
175         settings->setNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
176         settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
177         settings->setNoiseParams("mgvalleys_np_rivers",             np_rivers);
178         settings->setNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
179         settings->setNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
180         settings->setNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
181
182         settings->setNoiseParams("mgvalleys_np_cave1",              np_cave1);
183         settings->setNoiseParams("mgvalleys_np_cave2",              np_cave2);
184         settings->setNoiseParams("mgvalleys_np_cavern",             np_cavern);
185 }
186
187
188 ////////////////////////////////////////////////////////////////////////////////
189
190
191 void MapgenValleys::makeChunk(BlockMakeData *data)
192 {
193         // Pre-conditions
194         assert(data->vmanip);
195         assert(data->nodedef);
196         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
197                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
198                 data->blockpos_requested.Z >= data->blockpos_min.Z);
199         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
200                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
201                 data->blockpos_requested.Z <= data->blockpos_max.Z);
202
203         //TimeTaker t("makeChunk");
204
205         this->generating = true;
206         this->vm = data->vmanip;
207         this->ndef = data->nodedef;
208
209         v3s16 blockpos_min = data->blockpos_min;
210         v3s16 blockpos_max = data->blockpos_max;
211         node_min = blockpos_min * MAP_BLOCKSIZE;
212         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
213         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
214         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
215
216         blockseed = getBlockSeed2(full_node_min, seed);
217
218         // Generate biome noises. Note this must be executed strictly before
219         // generateTerrain, because generateTerrain depends on intermediate
220         // biome-related noises.
221         m_bgen->calcBiomeNoise(node_min);
222
223         // Generate noise maps and base terrain height.
224         // Modify heat and humidity maps.
225         calculateNoise();
226
227         // Generate base terrain with initial heightmaps
228         s16 stone_surface_max_y = generateTerrain();
229
230         // Recalculate heightmap
231         updateHeightmap(node_min, node_max);
232
233         // Place biome-specific nodes and build biomemap
234         if (flags & MG_BIOMES)
235                 generateBiomes();
236
237         // Generate tunnels, caverns and large randomwalk caves
238         if (flags & MG_CAVES) {
239                 // Generate tunnels first as caverns confuse them
240                 generateCavesNoiseIntersection(stone_surface_max_y);
241
242                 // Generate caverns
243                 bool near_cavern = generateCavernsNoise(stone_surface_max_y);
244
245                 // Generate large randomwalk caves
246                 if (near_cavern)
247                         // Disable large randomwalk caves in this mapchunk by setting
248                         // 'large cave depth' to world base. Avoids excessive liquid in
249                         // large caverns and floating blobs of overgenerated liquid.
250                         generateCavesRandomWalk(stone_surface_max_y,
251                                 -MAX_MAP_GENERATION_LIMIT);
252                 else
253                         generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
254         }
255
256         // Generate the registered ores
257         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
258
259         // Dungeon creation
260         if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
261                         full_node_max.Y <= dungeon_ymax)
262                 generateDungeons(stone_surface_max_y);
263
264         // Generate the registered decorations
265         if (flags & MG_DECORATIONS)
266                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
267
268         // Sprinkle some dust on top after everything else was generated
269         if (flags & MG_BIOMES)
270                 dustTopNodes();
271
272         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
273
274         if (flags & MG_LIGHT)
275                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
276                         full_node_min, full_node_max);
277
278         this->generating = false;
279
280         //printf("makeChunk: %lums\n", t.stop());
281 }
282
283
284 void MapgenValleys::calculateNoise()
285 {
286         int x = node_min.X;
287         int y = node_min.Y - 1;
288         int z = node_min.Z;
289
290         noise_inter_valley_slope->perlinMap2D(x, z);
291         noise_rivers->perlinMap2D(x, z);
292         noise_terrain_height->perlinMap2D(x, z);
293         noise_valley_depth->perlinMap2D(x, z);
294         noise_valley_profile->perlinMap2D(x, z);
295
296         noise_inter_valley_fill->perlinMap3D(x, y, z);
297
298         float heat_offset = 0.0f;
299         float humidity_scale = 1.0f;
300         // Altitude chill tends to reduce the average heat.
301         if (spflags & MGVALLEYS_ALT_CHILL)
302                 heat_offset = 5.0f;
303         // River humidity tends to increase the humidity range.
304         if (spflags & MGVALLEYS_HUMID_RIVERS)
305                 humidity_scale = 0.8f;
306
307         for (s32 index = 0; index < csize.X * csize.Z; index++) {
308                 m_bgen->heatmap[index] += heat_offset;
309                 m_bgen->humidmap[index] *= humidity_scale;
310         }
311
312         TerrainNoise tn;
313
314         u32 index = 0;
315         for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
316         for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
317                 // The parameters that we actually need to generate terrain are passed
318                 // by address (and the return value).
319                 tn.terrain_height    = noise_terrain_height->result[index];
320                 // River noise is replaced with base terrain, which is basically the
321                 // height of the water table.
322                 tn.rivers            = &noise_rivers->result[index];
323                 // Valley depth noise is replaced with the valley number that represents
324                 // the height of terrain over rivers and is used to determine how close
325                 // a river is for humidity calculation.
326                 tn.valley            = &noise_valley_depth->result[index];
327                 tn.valley_profile    = noise_valley_profile->result[index];
328                 // Slope noise is replaced by the calculated slope which is used to get
329                 // terrain height in the slow method, to create sharper mountains.
330                 tn.slope             = &noise_inter_valley_slope->result[index];
331                 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
332
333                 // This is the actual terrain height.
334                 float mount = terrainLevelFromNoise(&tn);
335                 noise_terrain_height->result[index] = mount;
336         }
337 }
338
339
340 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
341 {
342         // The square function changes the behaviour of this noise: very often
343         // small, and sometimes very high.
344         float valley_d = MYSQUARE(*tn->valley);
345
346         // valley_d is here because terrain is generally higher where valleys are
347         // deep (mountains). base represents the height of the rivers, most of the
348         // surface is above.
349         float base = tn->terrain_height + valley_d;
350
351         // "river" represents the distance from the river
352         float river = std::fabs(*tn->rivers) - river_size_factor;
353
354         // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
355         // "valley" represents the height of the terrain, from the rivers.
356         float tv = std::fmax(river / tn->valley_profile, 0.0f);
357         *tn->valley = valley_d * (1.0f - std::exp(-MYSQUARE(tv)));
358
359         // Approximate height of the terrain at this point
360         float mount = base + *tn->valley;
361
362         *tn->slope *= *tn->valley;
363
364         // Base ground is returned as rivers since it's basically the water table.
365         *tn->rivers = base;
366
367         // Rivers are placed where "river" is negative, so where the original noise
368         // value is close to zero.
369         if (river < 0.0f) {
370                 // Use the the function -sqrt(1-x^2) which models a circle
371                 float tr = river / river_size_factor + 1.0f;
372                 float depth = (river_depth_bed *
373                         std::sqrt(std::fmax(0.0f, 1.0f - MYSQUARE(tr))));
374
375                 // base - depth : height of the bottom of the river
376                 // water_level - 3 : don't make rivers below 3 nodes under the surface.
377                 // We use three because that's as low as the swamp biomes go.
378                 // There is no logical equivalent to this using rangelim.
379                 mount =
380                         std::fmin(std::fmax(base - depth, (float)(water_level - 3)), mount);
381
382                 // Slope has no influence on rivers
383                 *tn->slope = 0.0f;
384         }
385
386         return mount;
387 }
388
389
390 // This avoids duplicating the code in terrainLevelFromNoise, adding only the
391 // final step of terrain generation without a noise map.
392
393 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
394 {
395         float mount = terrainLevelFromNoise(tn);
396         s16 y_start = myround(mount);
397
398         for (s16 y = y_start; y <= y_start + 1000; y++) {
399                 float fill =
400                         NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
401                 if (fill * *tn->slope < y - mount) {
402                         mount = std::fmax((float)(y - 1), mount);
403                         break;
404                 }
405         }
406
407         return mount;
408 }
409
410
411 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
412 {
413         // Check if in a river
414         float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
415         if (std::fabs(rivers) < river_size_factor)
416                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
417
418         s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
419         if (level_at_point <= water_level ||
420                         level_at_point > water_level + 16)
421                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
422
423         return level_at_point;
424 }
425
426
427 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
428 {
429         TerrainNoise tn;
430
431         float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
432         float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
433         float inter_valley_slope =
434                 NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
435
436         tn.x                 = x;
437         tn.z                 = z;
438         tn.terrain_height    = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
439         tn.rivers            = &rivers;
440         tn.valley            = &valley;
441         tn.valley_profile    = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
442         tn.slope             = &inter_valley_slope;
443         tn.inter_valley_fill = 0.0f;
444
445         return adjustedTerrainLevelFromNoise(&tn);
446 }
447
448
449 int MapgenValleys::generateTerrain()
450 {
451         // Raising this reduces the rate of evaporation
452         static const float evaporation = 300.0f;
453         static const float humidity_dropoff = 4.0f;
454         // Constant to convert altitude chill to heat
455         static const float alt_to_heat = 20.0f;
456         // Humidity reduction by altitude
457         static const float alt_to_humid = 10.0f;
458
459         MapNode n_air(CONTENT_AIR);
460         MapNode n_river_water(c_river_water_source);
461         MapNode n_stone(c_stone);
462         MapNode n_water(c_water_source);
463
464         const v3s16 &em = vm->m_area.getExtent();
465         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
466         u32 index_2d = 0;
467
468         for (s16 z = node_min.Z; z <= node_max.Z; z++)
469         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
470                 float river_y = noise_rivers->result[index_2d];
471                 float surface_y = noise_terrain_height->result[index_2d];
472                 float slope = noise_inter_valley_slope->result[index_2d];
473                 float t_heat = m_bgen->heatmap[index_2d];
474
475                 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
476
477                 if (surface_y > surface_max_y)
478                         surface_max_y = std::ceil(surface_y);
479
480                 // Optionally vary river depth according to heat and humidity
481                 if (spflags & MGVALLEYS_VARY_RIVER_DEPTH) {
482                         float heat = ((spflags & MGVALLEYS_ALT_CHILL) &&
483                                 (surface_y > 0.0f || river_y > 0.0f)) ?
484                                 t_heat - alt_to_heat *
485                                         std::fmax(surface_y, river_y) / altitude_chill :
486                                 t_heat;
487                         float delta = m_bgen->humidmap[index_2d] - 50.0f;
488                         if (delta < 0.0f) {
489                                 float t_evap = (heat - 32.0f) / evaporation;
490                                 river_y += delta * std::fmax(t_evap, 0.08f);
491                         }
492                 }
493
494                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
495                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
496
497                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
498                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
499                                 float fill = noise_inter_valley_fill->result[index_3d];
500                                 float surface_delta = (float)y - surface_y;
501                                 bool river = y < river_y - 1;
502
503                                 if (slope * fill > surface_delta) {
504                                         vm->m_data[index_data] = n_stone; // Stone
505                                         if (y > heightmap[index_2d])
506                                                 heightmap[index_2d] = y;
507                                         if (y > surface_max_y)
508                                                 surface_max_y = y;
509                                 } else if (y <= water_level) {
510                                         vm->m_data[index_data] = n_water; // Water
511                                 } else if (river) {
512                                         vm->m_data[index_data] = n_river_water; // River water
513                                 } else {
514                                         vm->m_data[index_data] = n_air; // Air
515                                 }
516                         }
517
518                         VoxelArea::add_y(em, index_data, 1);
519                         index_3d += ystride;
520                 }
521
522                 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
523                         s16 surface_y_int = myround(surface_y);
524
525                         if (surface_y_int > node_max.Y + 1 ||
526                                         surface_y_int < node_min.Y - 1) {
527                                 // If surface_y is outside the chunk, it's good enough
528                                 heightmap[index_2d] = surface_y_int;
529                         } else {
530                                 // If the ground is outside of this chunk, but surface_y is
531                                 // within the chunk, give a value outside.
532                                 heightmap[index_2d] = node_min.Y - 2;
533                         }
534                 }
535
536                 // Optionally increase humidity around rivers
537                 if (spflags & MGVALLEYS_HUMID_RIVERS) {
538                         // Ground height ignoring riverbeds
539                         float t_alt = std::fmax(noise_rivers->result[index_2d],
540                                 (float)heightmap[index_2d]);
541                         float water_depth = (t_alt - river_y) / humidity_dropoff;
542                         m_bgen->humidmap[index_2d] *=
543                                 1.0f + std::pow(0.5f, std::fmax(water_depth, 1.0f));
544                 }
545
546                 // Optionally decrease humidity with altitude
547                 if (spflags & MGVALLEYS_ALT_DRY) {
548                         // Ground height ignoring riverbeds
549                         float t_alt = std::fmax(noise_rivers->result[index_2d],
550                                 (float)heightmap[index_2d]);
551                         if (t_alt > 0.0f)
552                                 m_bgen->humidmap[index_2d] -=
553                                         alt_to_humid * t_alt / altitude_chill;
554                 }
555
556                 // Optionally decrease heat with altitude
557                 if (spflags & MGVALLEYS_ALT_CHILL) {
558                         // Ground height ignoring riverbeds
559                         float t_alt = std::fmax(noise_rivers->result[index_2d],
560                                 (float)heightmap[index_2d]);
561                         if (t_alt > 0.0f)
562                                 m_bgen->heatmap[index_2d] -=
563                                         alt_to_heat * t_alt / altitude_chill;
564                 }
565         }
566
567         return surface_max_y;
568 }