e67e78f6c8b2c81025390a65842805827891bfc4
[oweals/minetest.git] / src / mapgen_v6.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
5 Copyright (C) 2014-2017 paramat
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22
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 "serverobject.h"
30 #include "content_sao.h"
31 #include "nodedef.h"
32 #include "voxelalgorithms.h"
33 //#include "profiler.h" // For TimeTaker
34 #include "settings.h" // For g_settings
35 #include "emerge.h"
36 #include "dungeongen.h"
37 #include "cavegen.h"
38 #include "treegen.h"
39 #include "mg_ore.h"
40 #include "mg_decoration.h"
41 #include "mapgen_v6.h"
42
43
44 FlagDesc flagdesc_mapgen_v6[] = {
45         {"jungles",    MGV6_JUNGLES},
46         {"biomeblend", MGV6_BIOMEBLEND},
47         {"mudflow",    MGV6_MUDFLOW},
48         {"snowbiomes", MGV6_SNOWBIOMES},
49         {"flat",       MGV6_FLAT},
50         {"trees",      MGV6_TREES},
51         {NULL,         0}
52 };
53
54
55 /////////////////////////////////////////////////////////////////////////////
56
57
58 MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
59         : Mapgen(mapgenid, params, emerge)
60 {
61         m_emerge = emerge;
62         ystride = csize.X; //////fix this
63
64         heightmap = new s16[csize.X * csize.Z];
65
66         spflags     = params->spflags;
67         freq_desert = params->freq_desert;
68         freq_beach  = params->freq_beach;
69
70         np_cave        = &params->np_cave;
71         np_humidity    = &params->np_humidity;
72         np_trees       = &params->np_trees;
73         np_apple_trees = &params->np_apple_trees;
74
75         //// Create noise objects
76         noise_terrain_base   = new Noise(&params->np_terrain_base,   seed, csize.X, csize.Y);
77         noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
78         noise_steepness      = new Noise(&params->np_steepness,      seed, csize.X, csize.Y);
79         noise_height_select  = new Noise(&params->np_height_select,  seed, csize.X, csize.Y);
80         noise_mud            = new Noise(&params->np_mud,            seed, csize.X, csize.Y);
81         noise_beach          = new Noise(&params->np_beach,          seed, csize.X, csize.Y);
82         noise_biome          = new Noise(&params->np_biome,          seed,
83                         csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
84         noise_humidity       = new Noise(&params->np_humidity,       seed,
85                         csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
86
87         //// Resolve nodes to be used
88         INodeDefManager *ndef = emerge->ndef;
89
90         c_stone           = ndef->getId("mapgen_stone");
91         c_dirt            = ndef->getId("mapgen_dirt");
92         c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
93         c_sand            = ndef->getId("mapgen_sand");
94         c_water_source    = ndef->getId("mapgen_water_source");
95         c_lava_source     = ndef->getId("mapgen_lava_source");
96         c_gravel          = ndef->getId("mapgen_gravel");
97         c_desert_stone    = ndef->getId("mapgen_desert_stone");
98         c_desert_sand     = ndef->getId("mapgen_desert_sand");
99         c_dirt_with_snow  = ndef->getId("mapgen_dirt_with_snow");
100         c_snow            = ndef->getId("mapgen_snow");
101         c_snowblock       = ndef->getId("mapgen_snowblock");
102         c_ice             = ndef->getId("mapgen_ice");
103
104         if (c_gravel == CONTENT_IGNORE)
105                 c_gravel = c_stone;
106         if (c_desert_stone == CONTENT_IGNORE)
107                 c_desert_stone = c_stone;
108         if (c_desert_sand == CONTENT_IGNORE)
109                 c_desert_sand = c_sand;
110         if (c_dirt_with_snow == CONTENT_IGNORE)
111                 c_dirt_with_snow = c_dirt_with_grass;
112         if (c_snow == CONTENT_IGNORE)
113                 c_snow = CONTENT_AIR;
114         if (c_snowblock == CONTENT_IGNORE)
115                 c_snowblock = c_dirt_with_grass;
116         if (c_ice == CONTENT_IGNORE)
117                 c_ice = c_water_source;
118
119         c_cobble             = ndef->getId("mapgen_cobble");
120         c_mossycobble        = ndef->getId("mapgen_mossycobble");
121         c_stair_cobble       = ndef->getId("mapgen_stair_cobble");
122         c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
123
124         if (c_mossycobble == CONTENT_IGNORE)
125                 c_mossycobble = c_cobble;
126         if (c_stair_cobble == CONTENT_IGNORE)
127                 c_stair_cobble = c_cobble;
128         if (c_stair_desert_stone == CONTENT_IGNORE)
129                 c_stair_desert_stone = c_desert_stone;
130 }
131
132
133 MapgenV6::~MapgenV6()
134 {
135         delete noise_terrain_base;
136         delete noise_terrain_higher;
137         delete noise_steepness;
138         delete noise_height_select;
139         delete noise_mud;
140         delete noise_beach;
141         delete noise_biome;
142         delete noise_humidity;
143
144         delete[] heightmap;
145 }
146
147
148 MapgenV6Params::MapgenV6Params()
149 {
150         np_terrain_base   = NoiseParams(-4,   20.0, v3f(250.0, 250.0, 250.0), 82341,  5, 0.6,  2.0);
151         np_terrain_higher = NoiseParams(20,   16.0, v3f(500.0, 500.0, 500.0), 85039,  5, 0.6,  2.0);
152         np_steepness      = NoiseParams(0.85, 0.5,  v3f(125.0, 125.0, 125.0), -932,   5, 0.7,  2.0);
153         np_height_select  = NoiseParams(0,    1.0,  v3f(250.0, 250.0, 250.0), 4213,   5, 0.69, 2.0);
154         np_mud            = NoiseParams(4,    2.0,  v3f(200.0, 200.0, 200.0), 91013,  3, 0.55, 2.0);
155         np_beach          = NoiseParams(0,    1.0,  v3f(250.0, 250.0, 250.0), 59420,  3, 0.50, 2.0);
156         np_biome          = NoiseParams(0,    1.0,  v3f(500.0, 500.0, 500.0), 9130,   3, 0.50, 2.0);
157         np_cave           = NoiseParams(6,    6.0,  v3f(250.0, 250.0, 250.0), 34329,  3, 0.50, 2.0);
158         np_humidity       = NoiseParams(0.5,  0.5,  v3f(500.0, 500.0, 500.0), 72384,  3, 0.50, 2.0);
159         np_trees          = NoiseParams(0,    1.0,  v3f(125.0, 125.0, 125.0), 2,      4, 0.66, 2.0);
160         np_apple_trees    = NoiseParams(0,    1.0,  v3f(100.0, 100.0, 100.0), 342902, 3, 0.45, 2.0);
161 }
162
163
164 void MapgenV6Params::readParams(const Settings *settings)
165 {
166         settings->getFlagStrNoEx("mgv6_spflags", spflags, flagdesc_mapgen_v6);
167         settings->getFloatNoEx("mgv6_freq_desert", freq_desert);
168         settings->getFloatNoEx("mgv6_freq_beach",  freq_beach);
169
170         settings->getNoiseParams("mgv6_np_terrain_base",   np_terrain_base);
171         settings->getNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
172         settings->getNoiseParams("mgv6_np_steepness",      np_steepness);
173         settings->getNoiseParams("mgv6_np_height_select",  np_height_select);
174         settings->getNoiseParams("mgv6_np_mud",            np_mud);
175         settings->getNoiseParams("mgv6_np_beach",          np_beach);
176         settings->getNoiseParams("mgv6_np_biome",          np_biome);
177         settings->getNoiseParams("mgv6_np_cave",           np_cave);
178         settings->getNoiseParams("mgv6_np_humidity",       np_humidity);
179         settings->getNoiseParams("mgv6_np_trees",          np_trees);
180         settings->getNoiseParams("mgv6_np_apple_trees",    np_apple_trees);
181 }
182
183
184 void MapgenV6Params::writeParams(Settings *settings) const
185 {
186         settings->setFlagStr("mgv6_spflags", spflags, flagdesc_mapgen_v6, U32_MAX);
187         settings->setFloat("mgv6_freq_desert", freq_desert);
188         settings->setFloat("mgv6_freq_beach",  freq_beach);
189
190         settings->setNoiseParams("mgv6_np_terrain_base",   np_terrain_base);
191         settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
192         settings->setNoiseParams("mgv6_np_steepness",      np_steepness);
193         settings->setNoiseParams("mgv6_np_height_select",  np_height_select);
194         settings->setNoiseParams("mgv6_np_mud",            np_mud);
195         settings->setNoiseParams("mgv6_np_beach",          np_beach);
196         settings->setNoiseParams("mgv6_np_biome",          np_biome);
197         settings->setNoiseParams("mgv6_np_cave",           np_cave);
198         settings->setNoiseParams("mgv6_np_humidity",       np_humidity);
199         settings->setNoiseParams("mgv6_np_trees",          np_trees);
200         settings->setNoiseParams("mgv6_np_apple_trees",    np_apple_trees);
201 }
202
203
204 //////////////////////// Some helper functions for the map generator
205
206 // Returns Y one under area minimum if not found
207 s16 MapgenV6::find_stone_level(v2s16 p2d)
208 {
209         const v3s16 &em = vm->m_area.getExtent();
210         s16 y_nodes_max = vm->m_area.MaxEdge.Y;
211         s16 y_nodes_min = vm->m_area.MinEdge.Y;
212         u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
213         s16 y;
214
215         for (y = y_nodes_max; y >= y_nodes_min; y--) {
216                 content_t c = vm->m_data[i].getContent();
217                 if (c != CONTENT_IGNORE && (c == c_stone || c == c_desert_stone))
218                         break;
219
220                 vm->m_area.add_y(em, i, -1);
221         }
222         return (y >= y_nodes_min) ? y : y_nodes_min - 1;
223 }
224
225
226 // Required by mapgen.h
227 bool MapgenV6::block_is_underground(u64 seed, v3s16 blockpos)
228 {
229         /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
230                         seed, v2s16(blockpos.X, blockpos.Z));*/
231         // Nah, this is just a heuristic, just return something
232         s16 minimum_groundlevel = water_level;
233
234         if(blockpos.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
235                 return true;
236
237         return false;
238 }
239
240
241 //////////////////////// Base terrain height functions
242
243 float MapgenV6::baseTerrainLevel(float terrain_base, float terrain_higher,
244         float steepness, float height_select)
245 {
246         float base   = 1 + terrain_base;
247         float higher = 1 + terrain_higher;
248
249         // Limit higher ground level to at least base
250         if(higher < base)
251                 higher = base;
252
253         // Steepness factor of cliffs
254         float b = steepness;
255         b = rangelim(b, 0.0, 1000.0);
256         b = 5 * b * b * b * b * b * b * b;
257         b = rangelim(b, 0.5, 1000.0);
258
259         // Values 1.5...100 give quite horrible looking slopes
260         if (b > 1.5 && b < 100.0)
261                 b = (b < 10.0) ? 1.5 : 100.0;
262
263         float a_off = -0.20; // Offset to more low
264         float a = 0.5 + b * (a_off + height_select);
265         a = rangelim(a, 0.0, 1.0); // Limit
266
267         return base * (1.0 - a) + higher * a;
268 }
269
270
271 float MapgenV6::baseTerrainLevelFromNoise(v2s16 p)
272 {
273         if (spflags & MGV6_FLAT)
274                 return water_level;
275
276         float terrain_base   = NoisePerlin2D_PO(&noise_terrain_base->np,
277                                                         p.X, 0.5, p.Y, 0.5, seed);
278         float terrain_higher = NoisePerlin2D_PO(&noise_terrain_higher->np,
279                                                         p.X, 0.5, p.Y, 0.5, seed);
280         float steepness      = NoisePerlin2D_PO(&noise_steepness->np,
281                                                         p.X, 0.5, p.Y, 0.5, seed);
282         float height_select  = NoisePerlin2D_PO(&noise_height_select->np,
283                                                         p.X, 0.5, p.Y, 0.5, seed);
284
285         return baseTerrainLevel(terrain_base, terrain_higher,
286                                                         steepness, height_select);
287 }
288
289
290 float MapgenV6::baseTerrainLevelFromMap(v2s16 p)
291 {
292         int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
293         return baseTerrainLevelFromMap(index);
294 }
295
296
297 float MapgenV6::baseTerrainLevelFromMap(int index)
298 {
299         if (spflags & MGV6_FLAT)
300                 return water_level;
301
302         float terrain_base   = noise_terrain_base->result[index];
303         float terrain_higher = noise_terrain_higher->result[index];
304         float steepness      = noise_steepness->result[index];
305         float height_select  = noise_height_select->result[index];
306
307         return baseTerrainLevel(terrain_base, terrain_higher,
308                                                         steepness, height_select);
309 }
310
311
312 s16 MapgenV6::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
313 {
314         return baseTerrainLevelFromNoise(p2d) + MGV6_AVERAGE_MUD_AMOUNT;
315 }
316
317
318 int MapgenV6::getGroundLevelAtPoint(v2s16 p)
319 {
320         return baseTerrainLevelFromNoise(p) + MGV6_AVERAGE_MUD_AMOUNT;
321 }
322
323
324 int MapgenV6::getSpawnLevelAtPoint(v2s16 p)
325 {
326         s16 level_at_point = baseTerrainLevelFromNoise(p) + MGV6_AVERAGE_MUD_AMOUNT;
327         if (level_at_point <= water_level ||
328                         level_at_point > water_level + 16)
329                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
330
331         return level_at_point;
332 }
333
334
335 //////////////////////// Noise functions
336
337 float MapgenV6::getMudAmount(v2s16 p)
338 {
339         int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
340         return getMudAmount(index);
341 }
342
343
344 bool MapgenV6::getHaveBeach(v2s16 p)
345 {
346         int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
347         return getHaveBeach(index);
348 }
349
350
351 BiomeV6Type MapgenV6::getBiome(v2s16 p)
352 {
353         int index = (p.Y - full_node_min.Z) * (ystride + 2 * MAP_BLOCKSIZE)
354                         + (p.X - full_node_min.X);
355         return getBiome(index, p);
356 }
357
358
359 float MapgenV6::getHumidity(v2s16 p)
360 {
361         /*double noise = noise2d_perlin(
362                 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
363                 seed+72384, 4, 0.66);
364         noise = (noise + 1.0)/2.0;*/
365
366         int index = (p.Y - full_node_min.Z) * (ystride + 2 * MAP_BLOCKSIZE)
367                         + (p.X - full_node_min.X);
368         float noise = noise_humidity->result[index];
369
370         if (noise < 0.0)
371                 noise = 0.0;
372         if (noise > 1.0)
373                 noise = 1.0;
374         return noise;
375 }
376
377
378 float MapgenV6::getTreeAmount(v2s16 p)
379 {
380         /*double noise = noise2d_perlin(
381                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
382                         seed+2, 4, 0.66);*/
383
384         float noise = NoisePerlin2D(np_trees, p.X, p.Y, seed);
385         float zeroval = -0.39;
386         if (noise < zeroval)
387                 return 0;
388
389         return 0.04 * (noise - zeroval) / (1.0 - zeroval);
390 }
391
392
393 bool MapgenV6::getHaveAppleTree(v2s16 p)
394 {
395         /*is_apple_tree = noise2d_perlin(
396                 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
397                 data->seed+342902, 3, 0.45) > 0.2;*/
398
399         float noise = NoisePerlin2D(np_apple_trees, p.X, p.Y, seed);
400
401         return noise > 0.2;
402 }
403
404
405 float MapgenV6::getMudAmount(int index)
406 {
407         if (spflags & MGV6_FLAT)
408                 return MGV6_AVERAGE_MUD_AMOUNT;
409
410         /*return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
411                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
412                         seed+91013, 3, 0.55));*/
413
414         return noise_mud->result[index];
415 }
416
417
418 bool MapgenV6::getHaveBeach(int index)
419 {
420         // Determine whether to have sand here
421         /*double sandnoise = noise2d_perlin(
422                         0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
423                         seed+59420, 3, 0.50);*/
424
425         float sandnoise = noise_beach->result[index];
426         return (sandnoise > freq_beach);
427 }
428
429
430 BiomeV6Type MapgenV6::getBiome(int index, v2s16 p)
431 {
432         // Just do something very simple as for now
433         /*double d = noise2d_perlin(
434                         0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
435                         seed+9130, 3, 0.50);*/
436
437         float d = noise_biome->result[index];
438         float h = noise_humidity->result[index];
439
440         if (spflags & MGV6_SNOWBIOMES) {
441                 float blend = (spflags & MGV6_BIOMEBLEND) ? noise2d(p.X, p.Y, seed) / 40 : 0;
442
443                 if (d > MGV6_FREQ_HOT + blend) {
444                         if (h > MGV6_FREQ_JUNGLE + blend)
445                                 return BT_JUNGLE;
446
447                         return BT_DESERT;
448                 }
449
450                 if (d < MGV6_FREQ_SNOW + blend) {
451                         if (h > MGV6_FREQ_TAIGA + blend)
452                                 return BT_TAIGA;
453
454                         return BT_TUNDRA;
455                 }
456
457                 return BT_NORMAL;
458         }
459
460         if (d > freq_desert)
461                 return BT_DESERT;
462
463         if ((spflags & MGV6_BIOMEBLEND) && (d > freq_desert - 0.10) &&
464                         ((noise2d(p.X, p.Y, seed) + 1.0) > (freq_desert - d) * 20.0))
465                 return BT_DESERT;
466
467         if ((spflags & MGV6_JUNGLES) && h > 0.75)
468                 return BT_JUNGLE;
469
470         return BT_NORMAL;
471
472 }
473
474
475 u32 MapgenV6::get_blockseed(u64 seed, v3s16 p)
476 {
477         s32 x = p.X, y = p.Y, z = p.Z;
478         return (u32)(seed % 0x100000000ULL) + z * 38134234 + y * 42123 + x * 23;
479 }
480
481
482 //////////////////////// Map generator
483
484 void MapgenV6::makeChunk(BlockMakeData *data)
485 {
486         // Pre-conditions
487         assert(data->vmanip);
488         assert(data->nodedef);
489         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
490                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
491                 data->blockpos_requested.Z >= data->blockpos_min.Z);
492         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
493                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
494                 data->blockpos_requested.Z <= data->blockpos_max.Z);
495
496         this->generating = true;
497         this->vm   = data->vmanip;
498         this->ndef = data->nodedef;
499
500         // Hack: use minimum block coords for old code that assumes a single block
501         v3s16 blockpos_min = data->blockpos_min;
502         v3s16 blockpos_max = data->blockpos_max;
503
504         // Area of central chunk
505         node_min = blockpos_min * MAP_BLOCKSIZE;
506         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
507
508         // Full allocated area
509         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
510         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
511
512         central_area_size = node_max - node_min + v3s16(1, 1, 1);
513         assert(central_area_size.X == central_area_size.Z);
514
515         int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
516                                           * (blockpos_max.Y - blockpos_min.Y + 1)
517                                           * (blockpos_max.Z - blockpos_max.Z + 1);
518
519         volume_nodes = volume_blocks *
520                 MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
521
522         // Create a block-specific seed
523         blockseed = get_blockseed(data->seed, full_node_min);
524
525         // Make some noise
526         calculateNoise();
527
528         // Maximum height of the stone surface and obstacles.
529         // This is used to guide the cave generation
530         s16 stone_surface_max_y;
531
532         // Generate general ground level to full area
533         stone_surface_max_y = generateGround();
534
535         // Create initial heightmap to limit caves
536         updateHeightmap(node_min, node_max);
537
538         const s16 max_spread_amount = MAP_BLOCKSIZE;
539         // Limit dirt flow area by 1 because mud is flown into neighbors.
540         s16 mudflow_minpos = -max_spread_amount + 1;
541         s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2;
542
543         // Loop this part, it will make stuff look older and newer nicely
544         const u32 age_loops = 2;
545         for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop
546                 // Make caves (this code is relatively horrible)
547                 if (flags & MG_CAVES)
548                         generateCaves(stone_surface_max_y);
549
550                 // Add mud to the central chunk
551                 addMud();
552
553                 // Flow mud away from steep edges
554                 if (spflags & MGV6_MUDFLOW)
555                         flowMud(mudflow_minpos, mudflow_maxpos);
556
557         }
558
559         // Update heightmap after mudflow
560         updateHeightmap(node_min, node_max);
561
562         // Add dungeons
563         if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
564                 DungeonParams dp;
565
566                 dp.seed             = seed;
567                 dp.c_water          = c_water_source;
568                 dp.c_river_water    = c_water_source;
569
570                 dp.only_in_ground   = true;
571                 dp.corridor_len_min = 1;
572                 dp.corridor_len_max = 13;
573                 dp.rooms_min        = 2;
574                 dp.rooms_max        = 16;
575                 dp.y_min            = -MAX_MAP_GENERATION_LIMIT;
576                 dp.y_max            = MAX_MAP_GENERATION_LIMIT;
577
578                 dp.np_density
579                         = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
580                 dp.np_alt_wall
581                         = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
582
583                 if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
584                         dp.c_wall              = c_desert_stone;
585                         dp.c_alt_wall          = CONTENT_IGNORE;
586                         dp.c_stair             = c_stair_desert_stone;
587
588                         dp.diagonal_dirs       = true;
589                         dp.holesize            = v3s16(2, 3, 2);
590                         dp.room_size_min       = v3s16(6, 9, 6);
591                         dp.room_size_max       = v3s16(10, 11, 10);
592                         dp.room_size_large_min = v3s16(10, 13, 10);
593                         dp.room_size_large_max = v3s16(18, 21, 18);
594                         dp.notifytype          = GENNOTIFY_TEMPLE;
595                 } else {
596                         dp.c_wall              = c_cobble;
597                         dp.c_alt_wall          = c_mossycobble;
598                         dp.c_stair             = c_stair_cobble;
599
600                         dp.diagonal_dirs       = false;
601                         dp.holesize            = v3s16(1, 2, 1);
602                         dp.room_size_min       = v3s16(4, 4, 4);
603                         dp.room_size_max       = v3s16(8, 6, 8);
604                         dp.room_size_large_min = v3s16(8, 8, 8);
605                         dp.room_size_large_max = v3s16(16, 16, 16);
606                         dp.notifytype          = GENNOTIFY_DUNGEON;
607                 }
608
609                 DungeonGen dgen(ndef, &gennotify, &dp);
610                 dgen.generate(vm, blockseed, full_node_min, full_node_max);
611         }
612
613         // Add top and bottom side of water to transforming_liquid queue
614         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
615
616         // Add surface nodes
617         growGrass();
618
619         // Generate some trees, and add grass, if a jungle
620         if (spflags & MGV6_TREES)
621                 placeTreesAndJungleGrass();
622
623         // Generate the registered decorations
624         if (flags & MG_DECORATIONS)
625                 m_emerge->decomgr->placeAllDecos(this, blockseed,
626                         node_min, node_max, water_level - 1);
627
628         // Generate the registered ores
629         m_emerge->oremgr->placeAllOres(this, blockseed,
630                 node_min, node_max, water_level - 1);
631
632         // Calculate lighting
633         if (flags & MG_LIGHT)
634                 calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
635                         node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE,
636                         full_node_min, full_node_max);
637
638         this->generating = false;
639 }
640
641
642 void MapgenV6::calculateNoise()
643 {
644         int x = node_min.X;
645         int z = node_min.Z;
646         int fx = full_node_min.X;
647         int fz = full_node_min.Z;
648
649         if (!(spflags & MGV6_FLAT)) {
650                 noise_terrain_base->perlinMap2D_PO(x, 0.5, z, 0.5);
651                 noise_terrain_higher->perlinMap2D_PO(x, 0.5, z, 0.5);
652                 noise_steepness->perlinMap2D_PO(x, 0.5, z, 0.5);
653                 noise_height_select->perlinMap2D_PO(x, 0.5, z, 0.5);
654                 noise_mud->perlinMap2D_PO(x, 0.5, z, 0.5);
655         }
656
657         noise_beach->perlinMap2D_PO(x, 0.2, z, 0.7);
658
659         noise_biome->perlinMap2D_PO(fx, 0.6, fz, 0.2);
660         noise_humidity->perlinMap2D_PO(fx, 0.0, fz, 0.0);
661         // Humidity map does not need range limiting 0 to 1,
662         // only humidity at point does
663 }
664
665
666 int MapgenV6::generateGround()
667 {
668         //TimeTaker timer1("Generating ground level");
669         MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
670         MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
671         MapNode n_ice(c_ice);
672         int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
673
674         u32 index = 0;
675         for (s16 z = node_min.Z; z <= node_max.Z; z++)
676         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
677                 // Surface height
678                 s16 surface_y = (s16)baseTerrainLevelFromMap(index);
679
680                 // Log it
681                 if (surface_y > stone_surface_max_y)
682                         stone_surface_max_y = surface_y;
683
684                 BiomeV6Type bt = getBiome(v2s16(x, z));
685
686                 // Fill ground with stone
687                 const v3s16 &em = vm->m_area.getExtent();
688                 u32 i = vm->m_area.index(x, node_min.Y, z);
689                 for (s16 y = node_min.Y; y <= node_max.Y; y++) {
690                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
691                                 if (y <= surface_y) {
692                                         vm->m_data[i] = (y >= MGV6_DESERT_STONE_BASE
693                                                         && bt == BT_DESERT) ?
694                                                 n_desert_stone : n_stone;
695                                 } else if (y <= water_level) {
696                                         vm->m_data[i] = (y >= MGV6_ICE_BASE
697                                                         && bt == BT_TUNDRA) ?
698                                                 n_ice : n_water_source;
699                                 } else {
700                                         vm->m_data[i] = n_air;
701                                 }
702                         }
703                         vm->m_area.add_y(em, i, 1);
704                 }
705         }
706
707         return stone_surface_max_y;
708 }
709
710
711 void MapgenV6::addMud()
712 {
713         // 15ms @cs=8
714         //TimeTaker timer1("add mud");
715         MapNode n_dirt(c_dirt), n_gravel(c_gravel);
716         MapNode n_sand(c_sand), n_desert_sand(c_desert_sand);
717         MapNode addnode;
718
719         u32 index = 0;
720         for (s16 z = node_min.Z; z <= node_max.Z; z++)
721         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
722                 // Randomize mud amount
723                 s16 mud_add_amount = getMudAmount(index) / 2.0 + 0.5;
724
725                 // Find ground level
726                 s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!
727
728                 // Handle area not found
729                 if (surface_y == vm->m_area.MinEdge.Y - 1)
730                         continue;
731
732                 BiomeV6Type bt = getBiome(v2s16(x, z));
733                 addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;
734
735                 if (bt == BT_DESERT && surface_y + mud_add_amount <= water_level + 1) {
736                         addnode = n_sand;
737                 } else if (mud_add_amount <= 0) {
738                         mud_add_amount = 1 - mud_add_amount;
739                         addnode = n_gravel;
740                 } else if (bt != BT_DESERT && getHaveBeach(index) &&
741                                 surface_y + mud_add_amount <= water_level + 2) {
742                         addnode = n_sand;
743                 }
744
745                 if ((bt == BT_DESERT || bt == BT_TUNDRA) && surface_y > 20)
746                         mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20) / 5);
747
748                 /* If topmost node is grass, change it to mud.  It might be if it was
749                 // flown to there from a neighboring chunk and then converted.
750                 u32 i = vm->m_area.index(x, surface_y, z);
751                 if (vm->m_data[i].getContent() == c_dirt_with_grass)
752                         vm->m_data[i] = n_dirt;*/
753
754                 // Add mud on ground
755                 s16 mudcount = 0;
756                 const v3s16 &em = vm->m_area.getExtent();
757                 s16 y_start = surface_y + 1;
758                 u32 i = vm->m_area.index(x, y_start, z);
759                 for (s16 y = y_start; y <= node_max.Y; y++) {
760                         if (mudcount >= mud_add_amount)
761                                 break;
762
763                         vm->m_data[i] = addnode;
764                         mudcount++;
765
766                         vm->m_area.add_y(em, i, 1);
767                 }
768         }
769 }
770
771
772 void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
773 {
774         // 340ms @cs=8
775         //TimeTaker timer1("flow mud");
776
777         // Iterate a few times
778         for (s16 k = 0; k < 3; k++) {
779                 for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
780                 for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
781                         // Invert coordinates every 2nd iteration
782                         if (k % 2 == 0) {
783                                 x = mudflow_maxpos - (x - mudflow_minpos);
784                                 z = mudflow_maxpos - (z - mudflow_minpos);
785                         }
786
787                         // Node position in 2d
788                         v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
789
790                         const v3s16 &em = vm->m_area.getExtent();
791                         u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
792                         s16 y = node_max.Y;
793
794                         while (y >= node_min.Y) {
795
796                         for (;; y--) {
797                                 MapNode *n = NULL;
798                                 // Find mud
799                                 for (; y >= node_min.Y; y--) {
800                                         n = &vm->m_data[i];
801                                         if (n->getContent() == c_dirt ||
802                                                         n->getContent() == c_dirt_with_grass ||
803                                                         n->getContent() == c_gravel)
804                                                 break;
805
806                                         vm->m_area.add_y(em, i, -1);
807                                 }
808
809                                 // Stop if out of area
810                                 //if(vmanip.m_area.contains(i) == false)
811                                 if (y < node_min.Y)
812                                         break;
813
814                                 if (n->getContent() == c_dirt ||
815                                                 n->getContent() == c_dirt_with_grass) {
816                                         // Make it exactly mud
817                                         n->setContent(c_dirt);
818
819                                         // Don't flow it if the stuff under it is not mud
820                                         {
821                                                 u32 i2 = i;
822                                                 vm->m_area.add_y(em, i2, -1);
823                                                 // Cancel if out of area
824                                                 if (!vm->m_area.contains(i2))
825                                                         continue;
826                                                 MapNode *n2 = &vm->m_data[i2];
827                                                 if (n2->getContent() != c_dirt &&
828                                                                 n2->getContent() != c_dirt_with_grass)
829                                                         continue;
830                                         }
831                                 }
832
833                                 v3s16 dirs4[4] = {
834                                         v3s16(0, 0, 1), // back
835                                         v3s16(1, 0, 0), // right
836                                         v3s16(0, 0, -1), // front
837                                         v3s16(-1, 0, 0), // left
838                                 };
839
840                                 // Check that upper is walkable. Cancel
841                                 // dropping if upper keeps it in place.
842                                 u32 i3 = i;
843                                 vm->m_area.add_y(em, i3, 1);
844                                 MapNode *n3 = NULL;
845
846                                 if (vm->m_area.contains(i3)) {
847                                         n3 = &vm->m_data[i3];
848                                         if (ndef->get(*n3).walkable)
849                                                 continue;
850                                 }
851
852                                 // Drop mud on side
853                                 for (const v3s16 &dirp : dirs4) {
854                                         u32 i2 = i;
855                                         // Move to side
856                                         vm->m_area.add_p(em, i2, dirp);
857                                         // Fail if out of area
858                                         if (!vm->m_area.contains(i2))
859                                                 continue;
860                                         // Check that side is air
861                                         MapNode *n2 = &vm->m_data[i2];
862                                         if (ndef->get(*n2).walkable)
863                                                 continue;
864                                         // Check that under side is air
865                                         vm->m_area.add_y(em, i2, -1);
866                                         if (!vm->m_area.contains(i2))
867                                                 continue;
868                                         n2 = &vm->m_data[i2];
869                                         if (ndef->get(*n2).walkable)
870                                                 continue;
871                                         // Loop further down until not air
872                                         bool dropped_to_unknown = false;
873                                         do {
874                                                 vm->m_area.add_y(em, i2, -1);
875                                                 n2 = &vm->m_data[i2];
876                                                 // if out of known area
877                                                 if (!vm->m_area.contains(i2) ||
878                                                                 n2->getContent() == CONTENT_IGNORE) {
879                                                         dropped_to_unknown = true;
880                                                         break;
881                                                 }
882                                         } while (!ndef->get(*n2).walkable);
883                                         // Loop one up so that we're in air
884                                         vm->m_area.add_y(em, i2, 1);
885
886                                         // Move mud to new place. Outside mapchunk remove
887                                         // any decorations above removed or placed mud.
888                                         if (!dropped_to_unknown)
889                                                 moveMud(i, i2, i3, p2d, em);
890
891                                         // Done
892                                         break;
893                                 }
894                         }
895                         }
896                 }
897         }
898 }
899
900
901 void MapgenV6::moveMud(u32 remove_index, u32 place_index,
902         u32 above_remove_index, v2s16 pos, v3s16 em)
903 {
904         MapNode n_air(CONTENT_AIR);
905         // Copy mud from old place to new place
906         vm->m_data[place_index] = vm->m_data[remove_index];
907         // Set old place to be air
908         vm->m_data[remove_index] = n_air;
909         // Outside the mapchunk decorations may need to be removed if above removed
910         // mud or if half-buried in placed mud. Placed mud is to the side of pos so
911         // use 'pos.X >= node_max.X' etc.
912         if (pos.X >= node_max.X || pos.X <= node_min.X ||
913                         pos.Y >= node_max.Z || pos.Y <= node_min.Z) {
914                 // 'above remove' node is above removed mud. If it is not air, water or
915                 // 'ignore' it is a decoration that needs removing. Also search upwards
916                 // to remove a possible stacked decoration.
917                 // Check for 'ignore' because stacked decorations can penetrate into
918                 // 'ignore' nodes above the mapchunk.
919                 while (vm->m_area.contains(above_remove_index) &&
920                                 vm->m_data[above_remove_index].getContent() != CONTENT_AIR &&
921                                 vm->m_data[above_remove_index].getContent() != c_water_source &&
922                                 vm->m_data[above_remove_index].getContent() != CONTENT_IGNORE) {
923                         vm->m_data[above_remove_index] = n_air;
924                         vm->m_area.add_y(em, above_remove_index, 1);
925                 }
926                 // Mud placed may have partially-buried a stacked decoration, search
927                 // above and remove.
928                 vm->m_area.add_y(em, place_index, 1);
929                 while (vm->m_area.contains(place_index) &&
930                                 vm->m_data[place_index].getContent() != CONTENT_AIR &&
931                                 vm->m_data[place_index].getContent() != c_water_source &&
932                                 vm->m_data[place_index].getContent() != CONTENT_IGNORE) {
933                         vm->m_data[place_index] = n_air;
934                         vm->m_area.add_y(em, place_index, 1);
935                 }
936         }
937 }
938
939
940 void MapgenV6::placeTreesAndJungleGrass()
941 {
942         //TimeTaker t("placeTrees");
943         if (node_max.Y < water_level)
944                 return;
945
946         PseudoRandom grassrandom(blockseed + 53);
947         content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
948         // if we don't have junglegrass, don't place cignore... that's bad
949         if (c_junglegrass == CONTENT_IGNORE)
950                 c_junglegrass = CONTENT_AIR;
951         MapNode n_junglegrass(c_junglegrass);
952         const v3s16 &em = vm->m_area.getExtent();
953
954         // Divide area into parts
955         s16 div = 8;
956         s16 sidelen = central_area_size.X / div;
957         double area = sidelen * sidelen;
958
959         // N.B.  We must add jungle grass first, since tree leaves will
960         // obstruct the ground, giving us a false ground level
961         for (s16 z0 = 0; z0 < div; z0++)
962         for (s16 x0 = 0; x0 < div; x0++) {
963                 // Center position of part of division
964                 v2s16 p2d_center(
965                         node_min.X + sidelen / 2 + sidelen * x0,
966                         node_min.Z + sidelen / 2 + sidelen * z0
967                 );
968                 // Minimum edge of part of division
969                 v2s16 p2d_min(
970                         node_min.X + sidelen * x0,
971                         node_min.Z + sidelen * z0
972                 );
973                 // Maximum edge of part of division
974                 v2s16 p2d_max(
975                         node_min.X + sidelen + sidelen * x0 - 1,
976                         node_min.Z + sidelen + sidelen * z0 - 1
977                 );
978
979                 // Get biome at center position of part of division
980                 BiomeV6Type bt = getBiome(p2d_center);
981
982                 // Amount of trees
983                 u32 tree_count;
984                 if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) {
985                         tree_count = area * getTreeAmount(p2d_center);
986                         if (bt == BT_JUNGLE)
987                                 tree_count *= 4;
988                 } else {
989                         tree_count = 0;
990                 }
991
992                 // Add jungle grass
993                 if (bt == BT_JUNGLE) {
994                         float humidity = getHumidity(p2d_center);
995                         u32 grass_count = 5 * humidity * tree_count;
996                         for (u32 i = 0; i < grass_count; i++) {
997                                 s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
998                                 s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
999                                 int mapindex = central_area_size.X * (z - node_min.Z)
1000                                                                 + (x - node_min.X);
1001                                 s16 y = heightmap[mapindex];
1002                                 if (y < water_level)
1003                                         continue;
1004
1005                                 u32 vi = vm->m_area.index(x, y, z);
1006                                 // place on dirt_with_grass, since we know it is exposed to sunlight
1007                                 if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
1008                                         vm->m_area.add_y(em, vi, 1);
1009                                         vm->m_data[vi] = n_junglegrass;
1010                                 }
1011                         }
1012                 }
1013
1014                 // Put trees in random places on part of division
1015                 for (u32 i = 0; i < tree_count; i++) {
1016                         s16 x = myrand_range(p2d_min.X, p2d_max.X);
1017                         s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
1018                         int mapindex = central_area_size.X * (z - node_min.Z)
1019                                                         + (x - node_min.X);
1020                         s16 y = heightmap[mapindex];
1021                         // Don't make a tree under water level
1022                         // Don't make a tree so high that it doesn't fit
1023                         if (y < water_level || y > node_max.Y - 6)
1024                                 continue;
1025
1026                         v3s16 p(x, y, z);
1027                         // Trees grow only on mud and grass
1028                         {
1029                                 u32 i = vm->m_area.index(p);
1030                                 content_t c = vm->m_data[i].getContent();
1031                                 if (c != c_dirt &&
1032                                                 c != c_dirt_with_grass &&
1033                                                 c != c_dirt_with_snow)
1034                                         continue;
1035                         }
1036                         p.Y++;
1037
1038                         // Make a tree
1039                         if (bt == BT_JUNGLE) {
1040                                 treegen::make_jungletree(*vm, p, ndef, myrand());
1041                         } else if (bt == BT_TAIGA) {
1042                                 treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand());
1043                         } else if (bt == BT_NORMAL) {
1044                                 bool is_apple_tree = (myrand_range(0, 3) == 0) &&
1045                                                         getHaveAppleTree(v2s16(x, z));
1046                                 treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
1047                         }
1048                 }
1049         }
1050         //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
1051 }
1052
1053
1054 void MapgenV6::growGrass() // Add surface nodes
1055 {
1056         MapNode n_dirt_with_grass(c_dirt_with_grass);
1057         MapNode n_dirt_with_snow(c_dirt_with_snow);
1058         MapNode n_snowblock(c_snowblock);
1059         MapNode n_snow(c_snow);
1060         const v3s16 &em = vm->m_area.getExtent();
1061
1062         u32 index = 0;
1063         for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
1064         for (s16 x = full_node_min.X; x <= full_node_max.X; x++, index++) {
1065                 // Find the lowest surface to which enough light ends up to make
1066                 // grass grow.  Basically just wait until not air and not leaves.
1067                 s16 surface_y = 0;
1068                 {
1069                         u32 i = vm->m_area.index(x, node_max.Y, z);
1070                         s16 y;
1071                         // Go to ground level
1072                         for (y = node_max.Y; y >= full_node_min.Y; y--) {
1073                                 MapNode &n = vm->m_data[i];
1074                                 if (ndef->get(n).param_type != CPT_LIGHT ||
1075                                                 ndef->get(n).liquid_type != LIQUID_NONE ||
1076                                                 n.getContent() == c_ice)
1077                                         break;
1078                                 vm->m_area.add_y(em, i, -1);
1079                         }
1080                         surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
1081                 }
1082
1083                 BiomeV6Type bt = getBiome(index, v2s16(x, z));
1084                 u32 i = vm->m_area.index(x, surface_y, z);
1085                 content_t c = vm->m_data[i].getContent();
1086                 if (surface_y >= water_level - 20) {
1087                         if (bt == BT_TAIGA && c == c_dirt) {
1088                                 vm->m_data[i] = n_dirt_with_snow;
1089                         } else if (bt == BT_TUNDRA) {
1090                                 if (c == c_dirt) {
1091                                         vm->m_data[i] = n_snowblock;
1092                                         vm->m_area.add_y(em, i, -1);
1093                                         vm->m_data[i] = n_dirt_with_snow;
1094                                 } else if (c == c_stone && surface_y < node_max.Y) {
1095                                         vm->m_area.add_y(em, i, 1);
1096                                         vm->m_data[i] = n_snowblock;
1097                                 }
1098                         } else if (c == c_dirt) {
1099                                 vm->m_data[i] = n_dirt_with_grass;
1100                         }
1101                 }
1102         }
1103 }
1104
1105
1106 void MapgenV6::generateCaves(int max_stone_y)
1107 {
1108         float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
1109         int volume_nodes = (node_max.X - node_min.X + 1) *
1110                                            (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE;
1111         cave_amount = MYMAX(0.0, cave_amount);
1112         u32 caves_count = cave_amount * volume_nodes / 50000;
1113         u32 bruises_count = 1;
1114         PseudoRandom ps(blockseed + 21343);
1115         PseudoRandom ps2(blockseed + 1032);
1116
1117         if (ps.range(1, 6) == 1)
1118                 bruises_count = ps.range(0, ps.range(0, 2));
1119
1120         if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
1121                 caves_count   /= 3;
1122                 bruises_count /= 3;
1123         }
1124
1125         for (u32 i = 0; i < caves_count + bruises_count; i++) {
1126                 CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source);
1127
1128                 bool large_cave = (i >= caves_count);
1129                 cave.makeCave(vm, node_min, node_max, &ps, &ps2,
1130                         large_cave, max_stone_y, heightmap);
1131         }
1132 }