Mapgen caves: Re-order generation to fix cavern bug
[oweals/minetest.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 static FlagDesc flagdesc_mapgen_valleys[] = {
48         {"altitude_chill", MGVALLEYS_ALT_CHILL},
49         {"humid_rivers",   MGVALLEYS_HUMID_RIVERS},
50         {NULL,             0}
51 };
52
53
54 ////////////////////////////////////////////////////////////////////////////////
55
56
57 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params,
58         EmergeManager *emerge)
59         : MapgenBasic(mapgenid, params, emerge)
60 {
61         // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
62         m_bgen = (BiomeGenOriginal *)biomegen;
63
64         BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
65
66         spflags            = params->spflags;
67         altitude_chill     = params->altitude_chill;
68         river_depth_bed    = params->river_depth + 1.0f;
69         river_size_factor  = params->river_size / 100.0f;
70
71         cave_width         = params->cave_width;
72         large_cave_depth   = params->large_cave_depth;
73         lava_depth         = params->lava_depth;
74         cavern_limit       = params->cavern_limit;
75         cavern_taper       = params->cavern_taper;
76         cavern_threshold   = params->cavern_threshold;
77         dungeon_ymin       = params->dungeon_ymin;
78         dungeon_ymax       = params->dungeon_ymax;
79
80         //// 2D Terrain noise
81         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
82         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
83         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
84         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
85         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
86         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
87
88         //// 3D Terrain noise
89         // 1-up 1-down overgeneration
90         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill,
91                 seed, csize.X, csize.Y + 2, csize.Z);
92         // 1-down overgeneraion
93         MapgenBasic::np_cave1   = params->np_cave1;
94         MapgenBasic::np_cave2   = params->np_cave2;
95         MapgenBasic::np_cavern  = params->np_cavern;
96
97         humid_rivers       = (spflags & MGVALLEYS_HUMID_RIVERS);
98         use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
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         generateBiomes();
235
236         // Generate tunnels, caverns and large randomwalk caves
237         if (flags & MG_CAVES) {
238                 // Generate tunnels first as caverns confuse them
239                 generateCavesNoiseIntersection(stone_surface_max_y);
240
241                 // Generate caverns
242                 bool near_cavern = generateCavernsNoise(stone_surface_max_y);
243
244                 // Generate large randomwalk caves
245                 if (near_cavern)
246                         // Disable large randomwalk caves in this mapchunk by setting
247                         // 'large cave depth' to world base. Avoids excessive liquid in
248                         // large caverns and floating blobs of overgenerated liquid.
249                         generateCavesRandomWalk(stone_surface_max_y,
250                                 -MAX_MAP_GENERATION_LIMIT);
251                 else
252                         generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
253         }
254
255         // Dungeon creation
256         if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
257                         full_node_max.Y <= dungeon_ymax)
258                 generateDungeons(stone_surface_max_y);
259
260         // Generate the registered decorations
261         if (flags & MG_DECORATIONS)
262                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
263
264         // Generate the registered ores
265         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
266
267         // Sprinkle some dust on top after everything else was generated
268         dustTopNodes();
269
270         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
271
272         if (flags & MG_LIGHT)
273                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
274                         full_node_min, full_node_max);
275
276         this->generating = false;
277
278         //printf("makeChunk: %lums\n", t.stop());
279 }
280
281
282 void MapgenValleys::calculateNoise()
283 {
284         int x = node_min.X;
285         int y = node_min.Y - 1;
286         int z = node_min.Z;
287
288         noise_inter_valley_slope->perlinMap2D(x, z);
289         noise_rivers->perlinMap2D(x, z);
290         noise_terrain_height->perlinMap2D(x, z);
291         noise_valley_depth->perlinMap2D(x, z);
292         noise_valley_profile->perlinMap2D(x, z);
293
294         noise_inter_valley_fill->perlinMap3D(x, y, z);
295
296         float heat_offset = 0.0f;
297         float humidity_scale = 1.0f;
298         // Altitude chill tends to reduce the average heat.
299         if (use_altitude_chill)
300                 heat_offset = 5.0f;
301         // River humidity tends to increase the humidity range.
302         if (humid_rivers)
303                 humidity_scale = 0.8f;
304
305         for (s32 index = 0; index < csize.X * csize.Z; index++) {
306                 m_bgen->heatmap[index] += heat_offset;
307                 m_bgen->humidmap[index] *= humidity_scale;
308         }
309
310         TerrainNoise tn;
311
312         u32 index = 0;
313         for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
314         for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
315                 // The parameters that we actually need to generate terrain are passed
316                 // by address (and the return value).
317                 tn.terrain_height    = noise_terrain_height->result[index];
318                 // River noise is replaced with base terrain, which is basically the
319                 // height of the water table.
320                 tn.rivers            = &noise_rivers->result[index];
321                 // Valley depth noise is replaced with the valley number that represents
322                 // the height of terrain over rivers and is used to determine how close
323                 // a river is for humidity calculation.
324                 tn.valley            = &noise_valley_depth->result[index];
325                 tn.valley_profile    = noise_valley_profile->result[index];
326                 // Slope noise is replaced by the calculated slope which is used to get
327                 // terrain height in the slow method, to create sharper mountains.
328                 tn.slope             = &noise_inter_valley_slope->result[index];
329                 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
330
331                 // This is the actual terrain height.
332                 float mount = terrainLevelFromNoise(&tn);
333                 noise_terrain_height->result[index] = mount;
334         }
335 }
336
337
338 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
339 {
340         // The square function changes the behaviour of this noise: very often
341         // small, and sometimes very high.
342         float valley_d = MYSQUARE(*tn->valley);
343
344         // valley_d is here because terrain is generally higher where valleys are
345         // deep (mountains). base represents the height of the rivers, most of the
346         // surface is above.
347         float base = tn->terrain_height + valley_d;
348
349         // "river" represents the distance from the river
350         float river = std::fabs(*tn->rivers) - river_size_factor;
351
352         // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
353         // "valley" represents the height of the terrain, from the rivers.
354         float tv = std::fmax(river / tn->valley_profile, 0.0f);
355         *tn->valley = valley_d * (1.0f - std::exp(-MYSQUARE(tv)));
356
357         // Approximate height of the terrain at this point
358         float mount = base + *tn->valley;
359
360         *tn->slope *= *tn->valley;
361
362         // Base ground is returned as rivers since it's basically the water table.
363         *tn->rivers = base;
364
365         // Rivers are placed where "river" is negative, so where the original noise
366         // value is close to zero.
367         if (river < 0.0f) {
368                 // Use the the function -sqrt(1-x^2) which models a circle
369                 float tr = river / river_size_factor + 1.0f;
370                 float depth = (river_depth_bed *
371                         std::sqrt(std::fmax(0.0f, 1.0f - MYSQUARE(tr))));
372
373                 // base - depth : height of the bottom of the river
374                 // water_level - 3 : don't make rivers below 3 nodes under the surface.
375                 // We use three because that's as low as the swamp biomes go.
376                 // There is no logical equivalent to this using rangelim.
377                 mount =
378                         std::fmin(std::fmax(base - depth, (float)(water_level - 3)), mount);
379
380                 // Slope has no influence on rivers
381                 *tn->slope = 0.0f;
382         }
383
384         return mount;
385 }
386
387
388 // This avoids duplicating the code in terrainLevelFromNoise, adding only the
389 // final step of terrain generation without a noise map.
390
391 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
392 {
393         float mount = terrainLevelFromNoise(tn);
394         s16 y_start = myround(mount);
395
396         for (s16 y = y_start; y <= y_start + 1000; y++) {
397                 float fill =
398                         NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
399                 if (fill * *tn->slope < y - mount) {
400                         mount = std::fmax((float)(y - 1), mount);
401                         break;
402                 }
403         }
404
405         return mount;
406 }
407
408
409 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
410 {
411         // Check if in a river
412         float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
413         if (std::fabs(rivers) < river_size_factor)
414                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
415
416         s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
417         if (level_at_point <= water_level ||
418                         level_at_point > water_level + 16)
419                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
420
421         return level_at_point;
422 }
423
424
425 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
426 {
427         TerrainNoise tn;
428
429         float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
430         float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
431         float inter_valley_slope =
432                 NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
433
434         tn.x                 = x;
435         tn.z                 = z;
436         tn.terrain_height    = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
437         tn.rivers            = &rivers;
438         tn.valley            = &valley;
439         tn.valley_profile    = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
440         tn.slope             = &inter_valley_slope;
441         tn.inter_valley_fill = 0.0f;
442
443         return adjustedTerrainLevelFromNoise(&tn);
444 }
445
446
447 int MapgenValleys::generateTerrain()
448 {
449         // Raising this reduces the rate of evaporation
450         static const float evaporation = 300.0f;
451         static const float humidity_dropoff = 4.0f;
452         // Constant to convert altitude chill to heat
453         static const float alt_to_heat = 20.0f;
454         // Humidity reduction by altitude
455         static const float alt_to_humid = 10.0f;
456
457         MapNode n_air(CONTENT_AIR);
458         MapNode n_river_water(c_river_water_source);
459         MapNode n_stone(c_stone);
460         MapNode n_water(c_water_source);
461
462         const v3s16 &em = vm->m_area.getExtent();
463         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
464         u32 index_2d = 0;
465
466         for (s16 z = node_min.Z; z <= node_max.Z; z++)
467         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
468                 float river_y = noise_rivers->result[index_2d];
469                 float surface_y = noise_terrain_height->result[index_2d];
470                 float slope = noise_inter_valley_slope->result[index_2d];
471                 float t_heat = m_bgen->heatmap[index_2d];
472
473                 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
474
475                 if (surface_y > surface_max_y)
476                         surface_max_y = std::ceil(surface_y);
477
478                 if (humid_rivers) {
479                         // Derive heat from (base) altitude. This will be most correct
480                         // at rivers, since other surface heights may vary below.
481                         if (use_altitude_chill && (surface_y > 0.0f || river_y > 0.0f))
482                                 t_heat -= alt_to_heat *
483                                         std::fmax(surface_y, river_y) / altitude_chill;
484
485                         // If humidity is low or heat is high, lower the water table
486                         float delta = m_bgen->humidmap[index_2d] - 50.0f;
487                         if (delta < 0.0f) {
488                                 float t_evap = (t_heat - 32.0f) / evaporation;
489                                 river_y += delta * std::fmax(t_evap, 0.08f);
490                         }
491                 }
492
493                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
494                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
495
496                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
497                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
498                                 float fill = noise_inter_valley_fill->result[index_3d];
499                                 float surface_delta = (float)y - surface_y;
500                                 bool river = y < river_y - 1;
501
502                                 if (slope * fill > surface_delta) {
503                                         vm->m_data[index_data] = n_stone; // Stone
504                                         if (y > heightmap[index_2d])
505                                                 heightmap[index_2d] = y;
506                                         if (y > surface_max_y)
507                                                 surface_max_y = y;
508                                 } else if (y <= water_level) {
509                                         vm->m_data[index_data] = n_water; // Water
510                                 } else if (river) {
511                                         vm->m_data[index_data] = n_river_water; // River water
512                                 } else {
513                                         vm->m_data[index_data] = n_air; // Air
514                                 }
515                         }
516
517                         VoxelArea::add_y(em, index_data, 1);
518                         index_3d += ystride;
519                 }
520
521                 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
522                         s16 surface_y_int = myround(surface_y);
523
524                         if (surface_y_int > node_max.Y + 1 ||
525                                         surface_y_int < node_min.Y - 1) {
526                                 // If surface_y is outside the chunk, it's good enough
527                                 heightmap[index_2d] = surface_y_int;
528                         } else {
529                                 // If the ground is outside of this chunk, but surface_y is
530                                 // within the chunk, give a value outside.
531                                 heightmap[index_2d] = node_min.Y - 2;
532                         }
533                 }
534
535                 if (humid_rivers) {
536                         // Use base ground (water table) in a riverbed, to avoid an
537                         // unnatural rise in humidity.
538                         float t_alt = std::fmax(noise_rivers->result[index_2d],
539                                 (float)heightmap[index_2d]);
540                         float humid = m_bgen->humidmap[index_2d];
541                         float water_depth = (t_alt - river_y) / humidity_dropoff;
542                         humid *= 1.0f + std::pow(0.5f, std::fmax(water_depth, 1.0f));
543
544                         // Reduce humidity with altitude (ignoring riverbeds)
545                         if (t_alt > 0.0f)
546                                 humid -= alt_to_humid * t_alt / altitude_chill;
547
548                         m_bgen->humidmap[index_2d] = humid;
549                 }
550
551                 // Assign the heat adjusted by any changed altitudes.
552                 // The altitude will change about half the time.
553                 if (use_altitude_chill) {
554                         // Ground height ignoring riverbeds
555                         float t_alt = std::fmax(noise_rivers->result[index_2d],
556                                 (float)heightmap[index_2d]);
557
558                         if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
559                                 // The altitude hasn't changed. Use the first result
560                                 m_bgen->heatmap[index_2d] = t_heat;
561                         else 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 }