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