]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_carpathian.cpp
Randomwalk caves: Add parameters for number, proportion flooded. Allow small caves...
[dragonfireclient.git] / src / mapgen / mapgen_carpathian.cpp
1 /*
2 Minetest
3 Copyright (C) 2017-2019 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
4 Copyright (C) 2017-2019 paramat
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22 #include <cmath>
23 #include "mapgen.h"
24 #include "voxel.h"
25 #include "noise.h"
26 #include "mapblock.h"
27 #include "mapnode.h"
28 #include "map.h"
29 #include "content_sao.h"
30 #include "nodedef.h"
31 #include "voxelalgorithms.h"
32 //#include "profiler.h" // For TimeTaker
33 #include "settings.h" // For g_settings
34 #include "emerge.h"
35 #include "dungeongen.h"
36 #include "cavegen.h"
37 #include "mg_biome.h"
38 #include "mg_ore.h"
39 #include "mg_decoration.h"
40 #include "mapgen_carpathian.h"
41
42
43 FlagDesc flagdesc_mapgen_carpathian[] = {
44         {"caverns", MGCARPATHIAN_CAVERNS},
45         {"rivers",  MGCARPATHIAN_RIVERS},
46         {NULL,      0}
47 };
48
49
50 ///////////////////////////////////////////////////////////////////////////////
51
52
53 MapgenCarpathian::MapgenCarpathian(MapgenCarpathianParams *params, EmergeManager *emerge)
54         : MapgenBasic(MAPGEN_CARPATHIAN, params, emerge)
55 {
56         base_level       = params->base_level;
57         river_width      = params->river_width;
58         river_depth      = params->river_depth;
59         valley_width     = params->valley_width;
60
61         spflags            = params->spflags;
62         cave_width         = params->cave_width;
63         large_cave_depth   = params->large_cave_depth;
64         lava_depth         = params->lava_depth;
65         small_cave_num_min = params->small_cave_num_min;
66         small_cave_num_max = params->small_cave_num_max;
67         large_cave_num_min = params->large_cave_num_min;
68         large_cave_num_max = params->large_cave_num_max;
69         large_cave_flooded = params->large_cave_flooded;
70         cavern_limit       = params->cavern_limit;
71         cavern_taper       = params->cavern_taper;
72         cavern_threshold   = params->cavern_threshold;
73         dungeon_ymin       = params->dungeon_ymin;
74         dungeon_ymax       = params->dungeon_ymax;
75
76         grad_wl = 1 - water_level;
77
78         //// 2D Terrain noise
79         noise_filler_depth  = new Noise(&params->np_filler_depth,  seed, csize.X, csize.Z);
80         noise_height1       = new Noise(&params->np_height1,       seed, csize.X, csize.Z);
81         noise_height2       = new Noise(&params->np_height2,       seed, csize.X, csize.Z);
82         noise_height3       = new Noise(&params->np_height3,       seed, csize.X, csize.Z);
83         noise_height4       = new Noise(&params->np_height4,       seed, csize.X, csize.Z);
84         noise_hills_terrain = new Noise(&params->np_hills_terrain, seed, csize.X, csize.Z);
85         noise_ridge_terrain = new Noise(&params->np_ridge_terrain, seed, csize.X, csize.Z);
86         noise_step_terrain  = new Noise(&params->np_step_terrain,  seed, csize.X, csize.Z);
87         noise_hills         = new Noise(&params->np_hills,         seed, csize.X, csize.Z);
88         noise_ridge_mnt     = new Noise(&params->np_ridge_mnt,     seed, csize.X, csize.Z);
89         noise_step_mnt      = new Noise(&params->np_step_mnt,      seed, csize.X, csize.Z);
90         if (spflags & MGCARPATHIAN_RIVERS)
91                 noise_rivers    = new Noise(&params->np_rivers,        seed, csize.X, csize.Z);
92
93         //// 3D terrain noise
94         // 1 up 1 down overgeneration
95         noise_mnt_var = new Noise(&params->np_mnt_var, seed, csize.X, csize.Y + 2, csize.Z);
96
97         //// Cave noise
98         MapgenBasic::np_cave1  = params->np_cave1;
99         MapgenBasic::np_cave2  = params->np_cave2;
100         MapgenBasic::np_cavern = params->np_cavern;
101         MapgenBasic::np_dungeons = params->np_dungeons;
102 }
103
104
105 MapgenCarpathian::~MapgenCarpathian()
106 {
107         delete noise_filler_depth;
108         delete noise_height1;
109         delete noise_height2;
110         delete noise_height3;
111         delete noise_height4;
112         delete noise_hills_terrain;
113         delete noise_ridge_terrain;
114         delete noise_step_terrain;
115         delete noise_hills;
116         delete noise_ridge_mnt;
117         delete noise_step_mnt;
118         if (spflags & MGCARPATHIAN_RIVERS)
119                 delete noise_rivers;
120
121         delete noise_mnt_var;
122 }
123
124
125 MapgenCarpathianParams::MapgenCarpathianParams():
126         np_filler_depth  (0,   1,   v3f(128,  128,  128),  261,   3, 0.7,  2.0),
127         np_height1       (0,   5,   v3f(251,  251,  251),  9613,  5, 0.5,  2.0),
128         np_height2       (0,   5,   v3f(383,  383,  383),  1949,  5, 0.5,  2.0),
129         np_height3       (0,   5,   v3f(509,  509,  509),  3211,  5, 0.5,  2.0),
130         np_height4       (0,   5,   v3f(631,  631,  631),  1583,  5, 0.5,  2.0),
131         np_hills_terrain (1,   1,   v3f(1301, 1301, 1301), 1692,  5, 0.5,  2.0),
132         np_ridge_terrain (1,   1,   v3f(1889, 1889, 1889), 3568,  5, 0.5,  2.0),
133         np_step_terrain  (1,   1,   v3f(1889, 1889, 1889), 4157,  5, 0.5,  2.0),
134         np_hills         (0,   3,   v3f(257,  257,  257),  6604,  6, 0.5,  2.0),
135         np_ridge_mnt     (0,   12,  v3f(743,  743,  743),  5520,  6, 0.7,  2.0),
136         np_step_mnt      (0,   8,   v3f(509,  509,  509),  2590,  6, 0.6,  2.0),
137         np_rivers        (0,   1,   v3f(1000, 1000, 1000), 85039, 5, 0.6,  2.0),
138         np_mnt_var       (0,   1,   v3f(499,  499,  499),  2490,  5, 0.55, 2.0),
139         np_cave1         (0,   12,  v3f(61,   61,   61),   52534, 3, 0.5,  2.0),
140         np_cave2         (0,   12,  v3f(67,   67,   67),   10325, 3, 0.5,  2.0),
141         np_cavern        (0,   1,   v3f(384,  128,  384),  723,   5, 0.63, 2.0),
142         np_dungeons      (0.9, 0.5, v3f(500,  500,  500),  0,     2, 0.8,  2.0)
143 {
144 }
145
146
147 void MapgenCarpathianParams::readParams(const Settings *settings)
148 {
149         settings->getFlagStrNoEx("mgcarpathian_spflags", spflags, flagdesc_mapgen_carpathian);
150
151         settings->getFloatNoEx("mgcarpathian_base_level",   base_level);
152         settings->getFloatNoEx("mgcarpathian_river_width",  river_width);
153         settings->getFloatNoEx("mgcarpathian_river_depth",  river_depth);
154         settings->getFloatNoEx("mgcarpathian_valley_width", valley_width);
155
156         settings->getFloatNoEx("mgcarpathian_cave_width",         cave_width);
157         settings->getS16NoEx("mgcarpathian_large_cave_depth",     large_cave_depth);
158         settings->getS16NoEx("mgcarpathian_lava_depth",           lava_depth);
159         settings->getU16NoEx("mgcarpathian_small_cave_num_min",   small_cave_num_min);
160         settings->getU16NoEx("mgcarpathian_small_cave_num_max",   small_cave_num_max);
161         settings->getU16NoEx("mgcarpathian_large_cave_num_min",   large_cave_num_min);
162         settings->getU16NoEx("mgcarpathian_large_cave_num_max",   large_cave_num_max);
163         settings->getFloatNoEx("mgcarpathian_large_cave_flooded", large_cave_flooded);
164         settings->getS16NoEx("mgcarpathian_cavern_limit",         cavern_limit);
165         settings->getS16NoEx("mgcarpathian_cavern_taper",         cavern_taper);
166         settings->getFloatNoEx("mgcarpathian_cavern_threshold",   cavern_threshold);
167         settings->getS16NoEx("mgcarpathian_dungeon_ymin",         dungeon_ymin);
168         settings->getS16NoEx("mgcarpathian_dungeon_ymax",         dungeon_ymax);
169
170         settings->getNoiseParams("mgcarpathian_np_filler_depth",  np_filler_depth);
171         settings->getNoiseParams("mgcarpathian_np_height1",       np_height1);
172         settings->getNoiseParams("mgcarpathian_np_height2",       np_height2);
173         settings->getNoiseParams("mgcarpathian_np_height3",       np_height3);
174         settings->getNoiseParams("mgcarpathian_np_height4",       np_height4);
175         settings->getNoiseParams("mgcarpathian_np_hills_terrain", np_hills_terrain);
176         settings->getNoiseParams("mgcarpathian_np_ridge_terrain", np_ridge_terrain);
177         settings->getNoiseParams("mgcarpathian_np_step_terrain",  np_step_terrain);
178         settings->getNoiseParams("mgcarpathian_np_hills",         np_hills);
179         settings->getNoiseParams("mgcarpathian_np_ridge_mnt",     np_ridge_mnt);
180         settings->getNoiseParams("mgcarpathian_np_step_mnt",      np_step_mnt);
181         settings->getNoiseParams("mgcarpathian_np_rivers",        np_rivers);
182         settings->getNoiseParams("mgcarpathian_np_mnt_var",       np_mnt_var);
183         settings->getNoiseParams("mgcarpathian_np_cave1",         np_cave1);
184         settings->getNoiseParams("mgcarpathian_np_cave2",         np_cave2);
185         settings->getNoiseParams("mgcarpathian_np_cavern",        np_cavern);
186         settings->getNoiseParams("mgcarpathian_np_dungeons",      np_dungeons);
187 }
188
189
190 void MapgenCarpathianParams::writeParams(Settings *settings) const
191 {
192         settings->setFlagStr("mgcarpathian_spflags", spflags, flagdesc_mapgen_carpathian, U32_MAX);
193
194         settings->setFloat("mgcarpathian_base_level",   base_level);
195         settings->setFloat("mgcarpathian_river_width",  river_width);
196         settings->setFloat("mgcarpathian_river_depth",  river_depth);
197         settings->setFloat("mgcarpathian_valley_width", valley_width);
198
199         settings->setFloat("mgcarpathian_cave_width",         cave_width);
200         settings->setS16("mgcarpathian_large_cave_depth",     large_cave_depth);
201         settings->setS16("mgcarpathian_lava_depth",           lava_depth);
202         settings->setU16("mgcarpathian_small_cave_num_min",   small_cave_num_min);
203         settings->setU16("mgcarpathian_small_cave_num_max",   small_cave_num_max);
204         settings->setU16("mgcarpathian_large_cave_num_min",   large_cave_num_min);
205         settings->setU16("mgcarpathian_large_cave_num_max",   large_cave_num_max);
206         settings->setFloat("mgcarpathian_large_cave_flooded", large_cave_flooded);
207         settings->setS16("mgcarpathian_cavern_limit",         cavern_limit);
208         settings->setS16("mgcarpathian_cavern_taper",         cavern_taper);
209         settings->setFloat("mgcarpathian_cavern_threshold",   cavern_threshold);
210         settings->setS16("mgcarpathian_dungeon_ymin",         dungeon_ymin);
211         settings->setS16("mgcarpathian_dungeon_ymax",         dungeon_ymax);
212
213         settings->setNoiseParams("mgcarpathian_np_filler_depth",  np_filler_depth);
214         settings->setNoiseParams("mgcarpathian_np_height1",       np_height1);
215         settings->setNoiseParams("mgcarpathian_np_height2",       np_height2);
216         settings->setNoiseParams("mgcarpathian_np_height3",       np_height3);
217         settings->setNoiseParams("mgcarpathian_np_height4",       np_height4);
218         settings->setNoiseParams("mgcarpathian_np_hills_terrain", np_hills_terrain);
219         settings->setNoiseParams("mgcarpathian_np_ridge_terrain", np_ridge_terrain);
220         settings->setNoiseParams("mgcarpathian_np_step_terrain",  np_step_terrain);
221         settings->setNoiseParams("mgcarpathian_np_hills",         np_hills);
222         settings->setNoiseParams("mgcarpathian_np_ridge_mnt",     np_ridge_mnt);
223         settings->setNoiseParams("mgcarpathian_np_step_mnt",      np_step_mnt);
224         settings->setNoiseParams("mgcarpathian_np_rivers",        np_rivers);
225         settings->setNoiseParams("mgcarpathian_np_mnt_var",       np_mnt_var);
226         settings->setNoiseParams("mgcarpathian_np_cave1",         np_cave1);
227         settings->setNoiseParams("mgcarpathian_np_cave2",         np_cave2);
228         settings->setNoiseParams("mgcarpathian_np_cavern",        np_cavern);
229         settings->setNoiseParams("mgcarpathian_np_dungeons",      np_dungeons);
230 }
231
232
233 ////////////////////////////////////////////////////////////////////////////////
234
235
236 // Lerp function
237 inline float MapgenCarpathian::getLerp(float noise1, float noise2, float mod)
238 {
239         return noise1 + mod * (noise2 - noise1);
240 }
241
242 // Steps function
243 float MapgenCarpathian::getSteps(float noise)
244 {
245         float w = 0.5f;
246         float k = std::floor(noise / w);
247         float f = (noise - k * w) / w;
248         float s = std::fmin(2.f * f, 1.f);
249         return (k + s) * w;
250 }
251
252
253 ////////////////////////////////////////////////////////////////////////////////
254
255
256 void MapgenCarpathian::makeChunk(BlockMakeData *data)
257 {
258         // Pre-conditions
259         assert(data->vmanip);
260         assert(data->nodedef);
261         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
262                         data->blockpos_requested.Y >= data->blockpos_min.Y &&
263                         data->blockpos_requested.Z >= data->blockpos_min.Z);
264         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
265                         data->blockpos_requested.Y <= data->blockpos_max.Y &&
266                         data->blockpos_requested.Z <= data->blockpos_max.Z);
267
268         this->generating = true;
269         this->vm = data->vmanip;
270         this->ndef = data->nodedef;
271
272         v3s16 blockpos_min = data->blockpos_min;
273         v3s16 blockpos_max = data->blockpos_max;
274         node_min = blockpos_min * MAP_BLOCKSIZE;
275         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
276         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
277         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
278
279         // Create a block-specific seed
280         blockseed = getBlockSeed2(full_node_min, seed);
281
282         // Generate terrain
283         s16 stone_surface_max_y = generateTerrain();
284
285         // Create heightmap
286         updateHeightmap(node_min, node_max);
287
288         // Init biome generator, place biome-specific nodes, and build biomemap
289         if (flags & MG_BIOMES) {
290                 biomegen->calcBiomeNoise(node_min);
291                 generateBiomes();
292         }
293
294         // Generate tunnels, caverns and large randomwalk caves
295         if (flags & MG_CAVES) {
296                 // Generate tunnels first as caverns confuse them
297                 generateCavesNoiseIntersection(stone_surface_max_y);
298
299                 // Generate caverns
300                 bool near_cavern = false;
301                 if (spflags & MGCARPATHIAN_CAVERNS)
302                         near_cavern = generateCavernsNoise(stone_surface_max_y);
303
304                 // Generate large randomwalk caves
305                 if (near_cavern)
306                         // Disable large randomwalk caves in this mapchunk by setting
307                         // 'large cave depth' to world base. Avoids excessive liquid in
308                         // large caverns and floating blobs of overgenerated liquid.
309                         generateCavesRandomWalk(stone_surface_max_y,
310                                 -MAX_MAP_GENERATION_LIMIT);
311                 else
312                         generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
313         }
314
315         // Generate the registered ores
316         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
317
318         // Generate dungeons
319         if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
320                         full_node_max.Y <= dungeon_ymax)
321                 generateDungeons(stone_surface_max_y);
322
323         // Generate the registered decorations
324         if (flags & MG_DECORATIONS)
325                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
326
327         // Sprinkle some dust on top after everything else was generated
328         if (flags & MG_BIOMES)
329                 dustTopNodes();
330
331         // Update liquids
332         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
333
334         // Calculate lighting
335         if (flags & MG_LIGHT) {
336                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
337                                 full_node_min, full_node_max);
338         }
339
340         this->generating = false;
341 }
342
343
344 ////////////////////////////////////////////////////////////////////////////////
345
346
347 int MapgenCarpathian::getSpawnLevelAtPoint(v2s16 p)
348 {
349         // If rivers are enabled, first check if in a river channel
350         if (spflags & MGCARPATHIAN_RIVERS) {
351                 float river = std::fabs(NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed)) -
352                         river_width;
353                 if (river < 0.0f)
354                         return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
355         }
356
357         float height1 = NoisePerlin2D(&noise_height1->np, p.X, p.Y, seed);
358         float height2 = NoisePerlin2D(&noise_height2->np, p.X, p.Y, seed);
359         float height3 = NoisePerlin2D(&noise_height3->np, p.X, p.Y, seed);
360         float height4 = NoisePerlin2D(&noise_height4->np, p.X, p.Y, seed);
361
362         float hterabs = std::fabs(NoisePerlin2D(&noise_hills_terrain->np, p.X, p.Y, seed));
363         float n_hills = NoisePerlin2D(&noise_hills->np, p.X, p.Y, seed);
364         float hill_mnt = hterabs * hterabs * hterabs * n_hills * n_hills;
365
366         float rterabs = std::fabs(NoisePerlin2D(&noise_ridge_terrain->np, p.X, p.Y, seed));
367         float n_ridge_mnt = NoisePerlin2D(&noise_ridge_mnt->np, p.X, p.Y, seed);
368         float ridge_mnt = rterabs * rterabs * rterabs * (1.0f - std::fabs(n_ridge_mnt));
369
370         float sterabs = std::fabs(NoisePerlin2D(&noise_step_terrain->np, p.X, p.Y, seed));
371         float n_step_mnt = NoisePerlin2D(&noise_step_mnt->np, p.X, p.Y, seed);
372         float step_mnt = sterabs * sterabs * sterabs * getSteps(n_step_mnt);
373
374         float valley = 1.0f;
375         float river = 0.0f;
376
377         if ((spflags & MGCARPATHIAN_RIVERS) && node_max.Y >= water_level - 16) {
378                 river = std::fabs(NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed)) - river_width;
379                 if (river <= valley_width) {
380                         // Within river valley
381                         if (river < 0.0f) {
382                                 // River channel
383                                 valley = river;
384                         } else {
385                                 // Valley slopes.
386                                 // 0 at river edge, 1 at valley edge.
387                                 float riversc = river / valley_width;
388                                 // Smoothstep
389                                 valley = riversc * riversc * (3.0f - 2.0f * riversc);
390                         }
391                 }
392         }
393
394         bool solid_below = false;
395         u8 cons_non_solid = 0; // consecutive non-solid nodes
396
397         for (s16 y = water_level; y <= water_level + 32; y++) {
398                 float mnt_var = NoisePerlin3D(&noise_mnt_var->np, p.X, y, p.Y, seed);
399                 float hill1 = getLerp(height1, height2, mnt_var);
400                 float hill2 = getLerp(height3, height4, mnt_var);
401                 float hill3 = getLerp(height3, height2, mnt_var);
402                 float hill4 = getLerp(height1, height4, mnt_var);
403
404                 float hilliness = std::fmax(std::fmin(hill1, hill2), std::fmin(hill3, hill4));
405                 float hills = hill_mnt * hilliness;
406                 float ridged_mountains = ridge_mnt * hilliness;
407                 float step_mountains = step_mnt * hilliness;
408
409                 s32 grad = 1 - y;
410
411                 float mountains = hills + ridged_mountains + step_mountains;
412                 float surface_level = base_level + mountains + grad;
413
414                 if ((spflags & MGCARPATHIAN_RIVERS) && river <= valley_width) {
415                         if (valley < 0.0f) {
416                                 // River channel
417                                 surface_level = std::fmin(surface_level,
418                                         water_level - std::sqrt(-valley) * river_depth);
419                         } else if (surface_level > water_level) {
420                                 // Valley slopes
421                                 surface_level = water_level + (surface_level - water_level) * valley;
422                         }
423                 }
424
425                 if (y < surface_level) { //TODO '<=' fix from generateTerrain()
426                         // solid node
427                         solid_below = true;
428                         cons_non_solid = 0;
429                 } else {
430                         // non-solid node
431                         cons_non_solid++;
432                         if (cons_non_solid == 3 && solid_below)
433                                 return y - 1;
434                 }
435         }
436
437         return MAX_MAP_GENERATION_LIMIT; // No suitable spawn point found
438 }
439
440
441 ////////////////////////////////////////////////////////////////////////////////
442
443
444 int MapgenCarpathian::generateTerrain()
445 {
446         MapNode mn_air(CONTENT_AIR);
447         MapNode mn_stone(c_stone);
448         MapNode mn_water(c_water_source);
449
450         // Calculate noise for terrain generation
451         noise_height1->perlinMap2D(node_min.X, node_min.Z);
452         noise_height2->perlinMap2D(node_min.X, node_min.Z);
453         noise_height3->perlinMap2D(node_min.X, node_min.Z);
454         noise_height4->perlinMap2D(node_min.X, node_min.Z);
455         noise_hills_terrain->perlinMap2D(node_min.X, node_min.Z);
456         noise_ridge_terrain->perlinMap2D(node_min.X, node_min.Z);
457         noise_step_terrain->perlinMap2D(node_min.X, node_min.Z);
458         noise_hills->perlinMap2D(node_min.X, node_min.Z);
459         noise_ridge_mnt->perlinMap2D(node_min.X, node_min.Z);
460         noise_step_mnt->perlinMap2D(node_min.X, node_min.Z);
461         noise_mnt_var->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
462
463         if (spflags & MGCARPATHIAN_RIVERS)
464                 noise_rivers->perlinMap2D(node_min.X, node_min.Z);
465
466         //// Place nodes
467         const v3s16 &em = vm->m_area.getExtent();
468         s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
469         u32 index2d = 0;
470
471         for (s16 z = node_min.Z; z <= node_max.Z; z++)
472         for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
473                 // Hill/Mountain height (hilliness)
474                 float height1 = noise_height1->result[index2d];
475                 float height2 = noise_height2->result[index2d];
476                 float height3 = noise_height3->result[index2d];
477                 float height4 = noise_height4->result[index2d];
478
479                 // Rolling hills
480                 float hterabs = std::fabs(noise_hills_terrain->result[index2d]);
481                 float n_hills = noise_hills->result[index2d];
482                 float hill_mnt = hterabs * hterabs * hterabs * n_hills * n_hills;
483
484                 // Ridged mountains
485                 float rterabs = std::fabs(noise_ridge_terrain->result[index2d]);
486                 float n_ridge_mnt = noise_ridge_mnt->result[index2d];
487                 float ridge_mnt = rterabs * rterabs * rterabs *
488                         (1.0f - std::fabs(n_ridge_mnt));
489
490                 // Step (terraced) mountains
491                 float sterabs = std::fabs(noise_step_terrain->result[index2d]);
492                 float n_step_mnt = noise_step_mnt->result[index2d];
493                 float step_mnt = sterabs * sterabs * sterabs * getSteps(n_step_mnt);
494
495                 // Rivers
496                 float valley = 1.0f;
497                 float river = 0.0f;
498
499                 if ((spflags & MGCARPATHIAN_RIVERS) && node_max.Y >= water_level - 16) {
500                         river = std::fabs(noise_rivers->result[index2d]) - river_width;
501                         if (river <= valley_width) {
502                                 // Within river valley
503                                 if (river < 0.0f) {
504                                         // River channel
505                                         valley = river;
506                                 } else {
507                                         // Valley slopes.
508                                         // 0 at river edge, 1 at valley edge.
509                                         float riversc = river / valley_width;
510                                         // Smoothstep
511                                         valley = riversc * riversc * (3.0f - 2.0f * riversc);
512                                 }
513                         }
514                 }
515
516                 // Initialise 3D noise index and voxelmanip index to column base
517                 u32 index3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
518                 u32 vi = vm->m_area.index(x, node_min.Y - 1, z);
519
520                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1;
521                                 y++,
522                                 index3d += ystride,
523                                 VoxelArea::add_y(em, vi, 1)) {
524                         if (vm->m_data[vi].getContent() != CONTENT_IGNORE)
525                                 continue;
526
527                         // Combine height noises and apply 3D variation
528                         float mnt_var = noise_mnt_var->result[index3d];
529                         float hill1 = getLerp(height1, height2, mnt_var);
530                         float hill2 = getLerp(height3, height4, mnt_var);
531                         float hill3 = getLerp(height3, height2, mnt_var);
532                         float hill4 = getLerp(height1, height4, mnt_var);
533
534                         // 'hilliness' determines whether hills/mountains are
535                         // small or large
536                         float hilliness =
537                                 std::fmax(std::fmin(hill1, hill2), std::fmin(hill3, hill4));
538                         float hills = hill_mnt * hilliness;
539                         float ridged_mountains = ridge_mnt * hilliness;
540                         float step_mountains = step_mnt * hilliness;
541
542                         // Gradient & shallow seabed
543                         s32 grad = (y < water_level) ? grad_wl + (water_level - y) * 3 :
544                                 1 - y;
545
546                         // Final terrain level
547                         float mountains = hills + ridged_mountains + step_mountains;
548                         float surface_level = base_level + mountains + grad;
549
550                         // Rivers
551                         if ((spflags & MGCARPATHIAN_RIVERS) && node_max.Y >= water_level - 16 &&
552                                         river <= valley_width) {
553                                 if (valley < 0.0f) {
554                                         // River channel
555                                         surface_level = std::fmin(surface_level,
556                                                 water_level - std::sqrt(-valley) * river_depth);
557                                 } else if (surface_level > water_level) {
558                                         // Valley slopes
559                                         surface_level = water_level + (surface_level - water_level) * valley;
560                                 }
561                         }
562
563                         if (y < surface_level) { //TODO '<='
564                                 vm->m_data[vi] = mn_stone; // Stone
565                                 if (y > stone_surface_max_y)
566                                         stone_surface_max_y = y;
567                         } else if (y <= water_level) {
568                                 vm->m_data[vi] = mn_water; // Sea water
569                         } else {
570                                 vm->m_data[vi] = mn_air; // Air
571                         }
572                 }
573         }
574
575         return stone_surface_max_y;
576 }