Mgvalleys: Use shared tunnel / cavern code instead of internal
[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 "settings.h" // For g_settings
36 #include "emerge.h"
37 #include "dungeongen.h"
38 #include "mg_biome.h"
39 #include "mg_ore.h"
40 #include "mg_decoration.h"
41 #include "mapgen_valleys.h"
42 #include "cavegen.h"
43 #include <cmath>
44
45
46 //#undef NDEBUG
47 //#include "assert.h"
48
49 //#include "util/timetaker.h"
50 //#include "profiler.h"
51
52
53 //static Profiler mapgen_prof;
54 //Profiler *mapgen_profiler = &mapgen_prof;
55
56 static FlagDesc flagdesc_mapgen_valleys[] = {
57         {"altitude_chill", MGVALLEYS_ALT_CHILL},
58         {"humid_rivers",   MGVALLEYS_HUMID_RIVERS},
59         {NULL,             0}
60 };
61
62 ///////////////////////////////////////////////////////////////////////////////
63
64
65 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge)
66         : MapgenBasic(mapgenid, params, emerge)
67 {
68         // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
69         m_bgen = (BiomeGenOriginal *)biomegen;
70
71         BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
72
73         spflags            = params->spflags;
74         altitude_chill     = params->altitude_chill;
75         river_depth_bed    = params->river_depth + 1.f;
76         river_size_factor  = params->river_size / 100.f;
77
78         cave_width         = params->cave_width;
79         large_cave_depth   = params->large_cave_depth;
80         lava_depth         = params->lava_depth;
81         cavern_limit       = params->cavern_limit;
82         cavern_taper       = params->cavern_taper;
83         cavern_threshold   = params->cavern_threshold;
84         dungeon_ymin       = params->dungeon_ymin;
85         dungeon_ymax       = params->dungeon_ymax;
86
87         //// 2D Terrain noise
88         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
89         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
90         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
91         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
92         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
93         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
94
95         //// 3D Terrain noise
96         // 1-up 1-down overgeneration
97         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
98         // 1-down overgeneraion
99         MapgenBasic::np_cave1   = params->np_cave1;
100         MapgenBasic::np_cave2   = params->np_cave2;
101         MapgenBasic::np_cavern  = params->np_cavern;
102
103         humid_rivers       = (spflags & MGVALLEYS_HUMID_RIVERS);
104         use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
105         humidity_adjust    = bp->np_humidity.offset - 50.f;
106 }
107
108
109 MapgenValleys::~MapgenValleys()
110 {
111         delete noise_filler_depth;
112         delete noise_inter_valley_fill;
113         delete noise_inter_valley_slope;
114         delete noise_rivers;
115         delete noise_terrain_height;
116         delete noise_valley_depth;
117         delete noise_valley_profile;
118 }
119
120
121 MapgenValleysParams::MapgenValleysParams():
122         np_filler_depth       (0.f,   1.2f, v3f(256,  256,  256),  1605,  3, 0.5f,  2.f),
123         np_inter_valley_fill  (0.f,   1.f,  v3f(256,  512,  256),  1993,  6, 0.8f,  2.f),
124         np_inter_valley_slope (0.5f,  0.5f, v3f(128,  128,  128),  746,   1, 1.f,   2.f),
125         np_rivers             (0.f,   1.f,  v3f(256,  256,  256),  -6050, 5, 0.6f,  2.f),
126         np_terrain_height     (-10.f, 50.f, v3f(1024, 1024, 1024), 5202,  6, 0.4f,  2.f),
127         np_valley_depth       (5.f,   4.f,  v3f(512,  512,  512),  -1914, 1, 1.f,   2.f),
128         np_valley_profile     (0.6f,  0.5f, v3f(512,  512,  512),  777,   1, 1.f,   2.f),
129         np_cave1              (0,     12,   v3f(61,   61,   61),   52534, 3, 0.5,   2.0),
130         np_cave2              (0,     12,   v3f(67,   67,   67),   10325, 3, 0.5,   2.0),
131         np_cavern             (0.f,   1.f,  v3f(768,  256,  768),  59033, 6, 0.63f, 2.f)
132 {
133 }
134
135
136 void MapgenValleysParams::readParams(const Settings *settings)
137 {
138         settings->getFlagStrNoEx("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys);
139         settings->getU16NoEx("mgvalleys_altitude_chill",     altitude_chill);
140         settings->getS16NoEx("mgvalleys_large_cave_depth",   large_cave_depth);
141         settings->getS16NoEx("mgvalleys_lava_depth",         lava_depth);
142         settings->getU16NoEx("mgvalleys_river_depth",        river_depth);
143         settings->getU16NoEx("mgvalleys_river_size",         river_size);
144         settings->getFloatNoEx("mgvalleys_cave_width",       cave_width);
145         settings->getS16NoEx("mgvalleys_cavern_limit",       cavern_limit);
146         settings->getS16NoEx("mgvalleys_cavern_taper",       cavern_taper);
147         settings->getFloatNoEx("mgvalleys_cavern_threshold", cavern_threshold);
148         settings->getS16NoEx("mgvalleys_dungeon_ymin",       dungeon_ymin);
149         settings->getS16NoEx("mgvalleys_dungeon_ymax",       dungeon_ymax);
150
151         settings->getNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
152         settings->getNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
153         settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
154         settings->getNoiseParams("mgvalleys_np_rivers",             np_rivers);
155         settings->getNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
156         settings->getNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
157         settings->getNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
158
159         settings->getNoiseParams("mgvalleys_np_cave1",              np_cave1);
160         settings->getNoiseParams("mgvalleys_np_cave2",              np_cave2);
161         settings->getNoiseParams("mgvalleys_np_cavern",             np_cavern);
162 }
163
164
165 void MapgenValleysParams::writeParams(Settings *settings) const
166 {
167         settings->setFlagStr("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys, U32_MAX);
168         settings->setU16("mgvalleys_altitude_chill",     altitude_chill);
169         settings->setS16("mgvalleys_large_cave_depth",   large_cave_depth);
170         settings->setS16("mgvalleys_lava_depth",         lava_depth);
171         settings->setU16("mgvalleys_river_depth",        river_depth);
172         settings->setU16("mgvalleys_river_size",         river_size);
173         settings->setFloat("mgvalleys_cave_width",       cave_width);
174         settings->setS16("mgvalleys_cavern_limit",       cavern_limit);
175         settings->setS16("mgvalleys_cavern_taper",       cavern_taper);
176         settings->setFloat("mgvalleys_cavern_threshold", cavern_threshold);
177         settings->setS16("mgvalleys_dungeon_ymin",       dungeon_ymin);
178         settings->setS16("mgvalleys_dungeon_ymax",       dungeon_ymax);
179
180         settings->setNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
181         settings->setNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
182         settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
183         settings->setNoiseParams("mgvalleys_np_rivers",             np_rivers);
184         settings->setNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
185         settings->setNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
186         settings->setNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
187
188         settings->setNoiseParams("mgvalleys_np_cave1",              np_cave1);
189         settings->setNoiseParams("mgvalleys_np_cave2",              np_cave2);
190         settings->setNoiseParams("mgvalleys_np_cavern",             np_cavern);
191 }
192
193
194 ///////////////////////////////////////
195
196
197 void MapgenValleys::makeChunk(BlockMakeData *data)
198 {
199         // Pre-conditions
200         assert(data->vmanip);
201         assert(data->nodedef);
202         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
203                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
204                 data->blockpos_requested.Z >= data->blockpos_min.Z);
205         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
206                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
207                 data->blockpos_requested.Z <= data->blockpos_max.Z);
208
209         this->generating = true;
210         this->vm = data->vmanip;
211         this->ndef = data->nodedef;
212
213         //TimeTaker t("makeChunk");
214
215         v3s16 blockpos_min = data->blockpos_min;
216         v3s16 blockpos_max = data->blockpos_max;
217         node_min = blockpos_min * MAP_BLOCKSIZE;
218         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
219         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
220         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
221
222         blockseed = getBlockSeed2(full_node_min, seed);
223
224         // Generate biome noises.  Note this must be executed strictly before
225         // generateTerrain, because generateTerrain depends on intermediate
226         // biome-related noises.
227         m_bgen->calcBiomeNoise(node_min);
228
229         // Generate noise maps and base terrain height.
230         // Modify heat and humidity maps.
231         calculateNoise();
232
233         // Generate base terrain with initial heightmaps
234         s16 stone_surface_max_y = generateTerrain();
235
236         // Recalculate heightmap
237         updateHeightmap(node_min, node_max);
238
239         // Place biome-specific nodes and build biomemap
240         generateBiomes();
241
242         // Generate caverns, tunnels and classic caves
243         if (flags & MG_CAVES) {
244                 bool near_cavern = false;
245                 // Generate caverns
246                 near_cavern = generateCaverns(stone_surface_max_y);
247                 // Generate tunnels and classic caves
248                 if (near_cavern)
249                         // Disable classic caves in this mapchunk by setting
250                         // 'large cave depth' to world base. Avoids excessive liquid in
251                         // large caverns and floating blobs of overgenerated liquid.
252                         generateCaves(stone_surface_max_y, -MAX_MAP_GENERATION_LIMIT);
253                 else
254                         generateCaves(stone_surface_max_y, large_cave_depth);
255         }
256
257         // Dungeon creation
258         if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
259                         full_node_max.Y <= dungeon_ymax)
260                 generateDungeons(stone_surface_max_y);
261
262         // Generate the registered decorations
263         if (flags & MG_DECORATIONS)
264                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
265
266         // Generate the registered ores
267         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
268
269         // Sprinkle some dust on top after everything else was generated
270         dustTopNodes();
271
272         //TimeTaker tll("liquid_lighting");
273
274         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
275
276         if (flags & MG_LIGHT)
277                 calcLighting(
278                                 node_min - v3s16(0, 1, 0),
279                                 node_max + v3s16(0, 1, 0),
280                                 full_node_min,
281                                 full_node_max);
282
283         //mapgen_profiler->avg("liquid_lighting", tll.stop() / 1000.f);
284         //mapgen_profiler->avg("makeChunk", t.stop() / 1000.f);
285
286         this->generating = false;
287 }
288
289
290 // Populate the noise tables and do most of the
291 // calculation necessary to determine terrain height.
292 void MapgenValleys::calculateNoise()
293 {
294         //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
295
296         int x = node_min.X;
297         int y = node_min.Y - 1;
298         int z = node_min.Z;
299
300         //TimeTaker tcn("actualNoise");
301
302         noise_inter_valley_slope->perlinMap2D(x, z);
303         noise_rivers->perlinMap2D(x, z);
304         noise_terrain_height->perlinMap2D(x, z);
305         noise_valley_depth->perlinMap2D(x, z);
306         noise_valley_profile->perlinMap2D(x, z);
307
308         noise_inter_valley_fill->perlinMap3D(x, y, z);
309
310         //mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
311
312         float heat_offset = 0.f;
313         float humidity_scale = 1.f;
314
315         // Altitude chill tends to reduce the average heat.
316         if (use_altitude_chill)
317                 heat_offset = 5.f;
318
319         // River humidity tends to increase the humidity range.
320         if (humid_rivers) {
321                 humidity_scale = 0.8f;
322         }
323
324         for (s32 index = 0; index < csize.X * csize.Z; index++) {
325                 m_bgen->heatmap[index] += heat_offset;
326                 m_bgen->humidmap[index] *= humidity_scale;
327         }
328
329         TerrainNoise tn;
330
331         u32 index = 0;
332         for (tn.z = node_min.Z; tn.z <= node_max.Z; tn.z++)
333         for (tn.x = node_min.X; tn.x <= node_max.X; tn.x++, index++) {
334                 // The parameters that we actually need to generate terrain
335                 //  are passed by address (and the return value).
336                 tn.terrain_height    = noise_terrain_height->result[index];
337                 // River noise is replaced with base terrain, which
338                 // is basically the height of the water table.
339                 tn.rivers            = &noise_rivers->result[index];
340                 // Valley depth noise is replaced with the valley
341                 // number that represents the height of terrain
342                 // over rivers and is used to determine about
343                 // how close a river is for humidity calculation.
344                 tn.valley            = &noise_valley_depth->result[index];
345                 tn.valley_profile    = noise_valley_profile->result[index];
346                 // Slope noise is replaced by the calculated slope
347                 // which is used to get terrain height in the slow
348                 // method, to create sharper mountains.
349                 tn.slope             = &noise_inter_valley_slope->result[index];
350                 tn.inter_valley_fill = noise_inter_valley_fill->result[index];
351
352                 // This is the actual terrain height.
353                 float mount = terrainLevelFromNoise(&tn);
354                 noise_terrain_height->result[index] = mount;
355         }
356 }
357
358
359 // This keeps us from having to maintain two similar sets of
360 //  complicated code to determine ground level.
361 float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
362 {
363         // The square function changes the behaviour of this noise:
364         //  very often small, and sometimes very high.
365         float valley_d = MYSQUARE(*tn->valley);
366
367         // valley_d is here because terrain is generally higher where valleys
368         //  are deep (mountains). base represents the height of the
369         //  rivers, most of the surface is above.
370         float base = tn->terrain_height + valley_d;
371
372         // "river" represents the distance from the river, in arbitrary units.
373         float river = std::fabs(*tn->rivers) - river_size_factor;
374
375         // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
376         //  Making "a" vary (0 < a <= 1) changes the shape of the valleys.
377         //  Try it with a geometry software !
378         //   (here x = "river" and a = valley_profile).
379         //  "valley" represents the height of the terrain, from the rivers.
380         {
381                 float t = std::fmax(river / tn->valley_profile, 0.0f);
382                 *tn->valley = valley_d * (1.f - std::exp(- MYSQUARE(t)));
383         }
384
385         // approximate height of the terrain at this point
386         float mount = base + *tn->valley;
387
388         *tn->slope *= *tn->valley;
389
390         // Rivers are placed where "river" is negative, so where the original
391         //  noise value is close to zero.
392         // Base ground is returned as rivers since it's basically the water table.
393         *tn->rivers = base;
394         if (river < 0.f) {
395                 // Use the the function -sqrt(1-x^2) which models a circle.
396                 float depth;
397                 {
398                         float t = river / river_size_factor + 1;
399                         depth = (river_depth_bed * std::sqrt(MYMAX(0, 1.f - MYSQUARE(t))));
400                 }
401
402                 // base - depth : height of the bottom of the river
403                 // water_level - 3 : don't make rivers below 3 nodes under the surface
404                 // We use three because that's as low as the swamp biomes go.
405                 // There is no logical equivalent to this using rangelim.
406                 mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
407
408                 // Slope has no influence on rivers.
409                 *tn->slope = 0.f;
410         }
411
412         return mount;
413 }
414
415
416 // This avoids duplicating the code in terrainLevelFromNoise, adding
417 // only the final step of terrain generation without a noise map.
418 float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
419 {
420         float mount = terrainLevelFromNoise(tn);
421         s16 y_start = myround(mount);
422
423         for (s16 y = y_start; y <= y_start + 1000; y++) {
424                 float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
425
426                 if (fill * *tn->slope < y - mount) {
427                         mount = MYMAX(y - 1, mount);
428                         break;
429                 }
430         }
431
432         return mount;
433 }
434
435
436 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
437 {
438         // Check to make sure this isn't a request for a location in a river.
439         float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
440         if (std::fabs(rivers) < river_size_factor)
441                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
442
443         s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
444         if (level_at_point <= water_level ||
445                         level_at_point > water_level + 32)
446                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
447
448         return level_at_point;
449 }
450
451
452 float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
453 {
454         TerrainNoise tn;
455
456         float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
457         float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
458         float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
459
460         tn.x                 = x;
461         tn.z                 = z;
462         tn.terrain_height    = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
463         tn.rivers            = &rivers;
464         tn.valley            = &valley;
465         tn.valley_profile    = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
466         tn.slope             = &inter_valley_slope;
467         tn.inter_valley_fill = 0.f;
468
469         return adjustedTerrainLevelFromNoise(&tn);
470 }
471
472
473 int MapgenValleys::generateTerrain()
474 {
475         // Raising this reduces the rate of evaporation.
476         static const float evaporation = 300.f;
477         // from the lua
478         static const float humidity_dropoff = 4.f;
479         // constant to convert altitude chill (compatible with lua) to heat
480         static const float alt_to_heat = 20.f;
481         // humidity reduction by altitude
482         static const float alt_to_humid = 10.f;
483
484         MapNode n_air(CONTENT_AIR);
485         MapNode n_river_water(c_river_water_source);
486         MapNode n_stone(c_stone);
487         MapNode n_water(c_water_source);
488
489         const v3s16 &em = vm->m_area.getExtent();
490         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
491         u32 index_2d = 0;
492
493         for (s16 z = node_min.Z; z <= node_max.Z; z++)
494         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
495                 float river_y = noise_rivers->result[index_2d];
496                 float surface_y = noise_terrain_height->result[index_2d];
497                 float slope = noise_inter_valley_slope->result[index_2d];
498                 float t_heat = m_bgen->heatmap[index_2d];
499
500                 heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
501
502                 if (surface_y > surface_max_y)
503                         surface_max_y = std::ceil(surface_y);
504
505                 if (humid_rivers) {
506                         // Derive heat from (base) altitude. This will be most correct
507                         // at rivers, since other surface heights may vary below.
508                         if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
509                                 t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
510
511                         // If humidity is low or heat is high, lower the water table.
512                         float delta = m_bgen->humidmap[index_2d] - 50.f;
513                         if (delta < 0.f) {
514                                 float t_evap = (t_heat - 32.f) / evaporation;
515                                 river_y += delta * MYMAX(t_evap, 0.08f);
516                         }
517                 }
518
519                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
520                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
521
522                 // Mapgens concern themselves with stone and water.
523                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
524                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
525                                 float fill = noise_inter_valley_fill->result[index_3d];
526                                 float surface_delta = (float)y - surface_y;
527                                 bool river = y + 1 < river_y;
528
529                                 if (slope * fill > surface_delta) {
530                                         // ground
531                                         vm->m_data[index_data] = n_stone;
532                                         if (y > heightmap[index_2d])
533                                                 heightmap[index_2d] = y;
534                                         if (y > surface_max_y)
535                                                 surface_max_y = y;
536                                 } else if (y <= water_level) {
537                                         // sea
538                                         vm->m_data[index_data] = n_water;
539                                 } else if (river) {
540                                         // river
541                                         vm->m_data[index_data] = n_river_water;
542                                 } else {  // air
543                                         vm->m_data[index_data] = n_air;
544                                 }
545                         }
546
547                         VoxelArea::add_y(em, index_data, 1);
548                         index_3d += ystride;
549                 }
550
551                 if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
552                         s16 surface_y_int = myround(surface_y);
553                         if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
554                                 // If surface_y is outside the chunk, it's good enough.
555                                 heightmap[index_2d] = surface_y_int;
556                         } else {
557                                 // If the ground is outside of this chunk, but surface_y
558                                 // is within the chunk, give a value outside.
559                                 heightmap[index_2d] = node_min.Y - 2;
560                         }
561                 }
562
563                 if (humid_rivers) {
564                         // Use base ground (water table) in a riverbed, to
565                         // avoid an unnatural rise in humidity.
566                         float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
567                         float humid = m_bgen->humidmap[index_2d];
568                         float water_depth = (t_alt - river_y) / humidity_dropoff;
569                         humid *= 1.f + std::pow(0.5f, MYMAX(water_depth, 1.f));
570
571                         // Reduce humidity with altitude (ignoring riverbeds).
572                         // This is similar to the lua version's seawater adjustment,
573                         // but doesn't increase the base humidity, which causes
574                         // problems with the default biomes.
575                         if (t_alt > 0.f)
576                                 humid -= alt_to_humid * t_alt / altitude_chill;
577
578                         m_bgen->humidmap[index_2d] = humid;
579                 }
580
581                 // Assign the heat adjusted by any changed altitudes.
582                 // The altitude will change about half the time.
583                 if (use_altitude_chill) {
584                         // ground height ignoring riverbeds
585                         float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
586                         if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
587                                 // The altitude hasn't changed. Use the first result.
588                                 m_bgen->heatmap[index_2d] = t_heat;
589                         else if (t_alt > 0.f)
590                                 m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
591                 }
592         }
593
594         return surface_max_y;
595 }