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