]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_v6.cpp
Dungeons: Add Y limits in all mapgens
[dragonfireclient.git] / src / mapgen / mapgen_v6.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
5 Copyright (C) 2014-2018 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         dungeon_ymin = params->dungeon_ymin;
70         dungeon_ymax = params->dungeon_ymax;
71
72         np_cave        = &params->np_cave;
73         np_humidity    = &params->np_humidity;
74         np_trees       = &params->np_trees;
75         np_apple_trees = &params->np_apple_trees;
76
77         //// Create noise objects
78         noise_terrain_base   = new Noise(&params->np_terrain_base,   seed, csize.X, csize.Y);
79         noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
80         noise_steepness      = new Noise(&params->np_steepness,      seed, csize.X, csize.Y);
81         noise_height_select  = new Noise(&params->np_height_select,  seed, csize.X, csize.Y);
82         noise_mud            = new Noise(&params->np_mud,            seed, csize.X, csize.Y);
83         noise_beach          = new Noise(&params->np_beach,          seed, csize.X, csize.Y);
84         noise_biome          = new Noise(&params->np_biome,          seed,
85                         csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
86         noise_humidity       = new Noise(&params->np_humidity,       seed,
87                         csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
88
89         //// Resolve nodes to be used
90         const NodeDefManager *ndef = emerge->ndef;
91
92         c_stone           = ndef->getId("mapgen_stone");
93         c_dirt            = ndef->getId("mapgen_dirt");
94         c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
95         c_sand            = ndef->getId("mapgen_sand");
96         c_water_source    = ndef->getId("mapgen_water_source");
97         c_lava_source     = ndef->getId("mapgen_lava_source");
98         c_gravel          = ndef->getId("mapgen_gravel");
99         c_desert_stone    = ndef->getId("mapgen_desert_stone");
100         c_desert_sand     = ndef->getId("mapgen_desert_sand");
101         c_dirt_with_snow  = ndef->getId("mapgen_dirt_with_snow");
102         c_snow            = ndef->getId("mapgen_snow");
103         c_snowblock       = ndef->getId("mapgen_snowblock");
104         c_ice             = ndef->getId("mapgen_ice");
105
106         if (c_gravel == CONTENT_IGNORE)
107                 c_gravel = c_stone;
108         if (c_desert_stone == CONTENT_IGNORE)
109                 c_desert_stone = c_stone;
110         if (c_desert_sand == CONTENT_IGNORE)
111                 c_desert_sand = c_sand;
112         if (c_dirt_with_snow == CONTENT_IGNORE)
113                 c_dirt_with_snow = c_dirt_with_grass;
114         if (c_snow == CONTENT_IGNORE)
115                 c_snow = CONTENT_AIR;
116         if (c_snowblock == CONTENT_IGNORE)
117                 c_snowblock = c_dirt_with_grass;
118         if (c_ice == CONTENT_IGNORE)
119                 c_ice = c_water_source;
120
121         c_cobble             = ndef->getId("mapgen_cobble");
122         c_mossycobble        = ndef->getId("mapgen_mossycobble");
123         c_stair_cobble       = ndef->getId("mapgen_stair_cobble");
124         c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
125
126         if (c_mossycobble == CONTENT_IGNORE)
127                 c_mossycobble = c_cobble;
128         if (c_stair_cobble == CONTENT_IGNORE)
129                 c_stair_cobble = c_cobble;
130         if (c_stair_desert_stone == CONTENT_IGNORE)
131                 c_stair_desert_stone = c_desert_stone;
132 }
133
134
135 MapgenV6::~MapgenV6()
136 {
137         delete noise_terrain_base;
138         delete noise_terrain_higher;
139         delete noise_steepness;
140         delete noise_height_select;
141         delete noise_mud;
142         delete noise_beach;
143         delete noise_biome;
144         delete noise_humidity;
145
146         delete[] heightmap;
147 }
148
149
150 MapgenV6Params::MapgenV6Params():
151         np_terrain_base   (-4,   20.0, v3f(250.0, 250.0, 250.0), 82341,  5, 0.6,  2.0),
152         np_terrain_higher (20,   16.0, v3f(500.0, 500.0, 500.0), 85039,  5, 0.6,  2.0),
153         np_steepness      (0.85, 0.5,  v3f(125.0, 125.0, 125.0), -932,   5, 0.7,  2.0),
154         np_height_select  (0,    1.0,  v3f(250.0, 250.0, 250.0), 4213,   5, 0.69, 2.0),
155         np_mud            (4,    2.0,  v3f(200.0, 200.0, 200.0), 91013,  3, 0.55, 2.0),
156         np_beach          (0,    1.0,  v3f(250.0, 250.0, 250.0), 59420,  3, 0.50, 2.0),
157         np_biome          (0,    1.0,  v3f(500.0, 500.0, 500.0), 9130,   3, 0.50, 2.0),
158         np_cave           (6,    6.0,  v3f(250.0, 250.0, 250.0), 34329,  3, 0.50, 2.0),
159         np_humidity       (0.5,  0.5,  v3f(500.0, 500.0, 500.0), 72384,  3, 0.50, 2.0),
160         np_trees          (0,    1.0,  v3f(125.0, 125.0, 125.0), 2,      4, 0.66, 2.0),
161         np_apple_trees    (0,    1.0,  v3f(100.0, 100.0, 100.0), 342902, 3, 0.45, 2.0)
162 {
163 }
164
165
166 void MapgenV6Params::readParams(const Settings *settings)
167 {
168         settings->getFlagStrNoEx("mgv6_spflags", spflags, flagdesc_mapgen_v6);
169         settings->getFloatNoEx("mgv6_freq_desert", freq_desert);
170         settings->getFloatNoEx("mgv6_freq_beach",  freq_beach);
171         settings->getS16NoEx("mgv6_dungeon_ymin",  dungeon_ymin);
172         settings->getS16NoEx("mgv6_dungeon_ymax",  dungeon_ymax);
173
174         settings->getNoiseParams("mgv6_np_terrain_base",   np_terrain_base);
175         settings->getNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
176         settings->getNoiseParams("mgv6_np_steepness",      np_steepness);
177         settings->getNoiseParams("mgv6_np_height_select",  np_height_select);
178         settings->getNoiseParams("mgv6_np_mud",            np_mud);
179         settings->getNoiseParams("mgv6_np_beach",          np_beach);
180         settings->getNoiseParams("mgv6_np_biome",          np_biome);
181         settings->getNoiseParams("mgv6_np_cave",           np_cave);
182         settings->getNoiseParams("mgv6_np_humidity",       np_humidity);
183         settings->getNoiseParams("mgv6_np_trees",          np_trees);
184         settings->getNoiseParams("mgv6_np_apple_trees",    np_apple_trees);
185 }
186
187
188 void MapgenV6Params::writeParams(Settings *settings) const
189 {
190         settings->setFlagStr("mgv6_spflags", spflags, flagdesc_mapgen_v6, U32_MAX);
191         settings->setFloat("mgv6_freq_desert", freq_desert);
192         settings->setFloat("mgv6_freq_beach",  freq_beach);
193         settings->setS16("mgv6_dungeon_ymin",  dungeon_ymin);
194         settings->setS16("mgv6_dungeon_ymax",  dungeon_ymax);
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         const 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
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
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
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
453                         return BT_DESERT;
454                 }
455
456                 if (d < MGV6_FREQ_SNOW + blend) {
457                         if (h > MGV6_FREQ_TAIGA + blend)
458                                 return BT_TAIGA;
459
460                         return BT_TUNDRA;
461                 }
462
463                 return BT_NORMAL;
464         }
465
466         if (d > freq_desert)
467                 return BT_DESERT;
468
469         if ((spflags & MGV6_BIOMEBLEND) && (d > freq_desert - 0.10) &&
470                         ((noise2d(p.X, p.Y, seed) + 1.0) > (freq_desert - d) * 20.0))
471                 return BT_DESERT;
472
473         if ((spflags & MGV6_JUNGLES) && h > 0.75)
474                 return BT_JUNGLE;
475
476         return BT_NORMAL;
477
478 }
479
480
481 u32 MapgenV6::get_blockseed(u64 seed, v3s16 p)
482 {
483         s32 x = p.X, y = p.Y, z = p.Z;
484         return (u32)(seed % 0x100000000ULL) + z * 38134234 + y * 42123 + x * 23;
485 }
486
487
488 //////////////////////// Map generator
489
490 void MapgenV6::makeChunk(BlockMakeData *data)
491 {
492         // Pre-conditions
493         assert(data->vmanip);
494         assert(data->nodedef);
495         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
496                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
497                 data->blockpos_requested.Z >= data->blockpos_min.Z);
498         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
499                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
500                 data->blockpos_requested.Z <= data->blockpos_max.Z);
501
502         this->generating = true;
503         this->vm   = data->vmanip;
504         this->ndef = data->nodedef;
505
506         // Hack: use minimum block coords for old code that assumes a single block
507         v3s16 blockpos_min = data->blockpos_min;
508         v3s16 blockpos_max = data->blockpos_max;
509
510         // Area of central chunk
511         node_min = blockpos_min * MAP_BLOCKSIZE;
512         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
513
514         // Full allocated area
515         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
516         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
517
518         central_area_size = node_max - node_min + v3s16(1, 1, 1);
519         assert(central_area_size.X == central_area_size.Z);
520
521         // Create a block-specific seed
522         blockseed = get_blockseed(data->seed, full_node_min);
523
524         // Make some noise
525         calculateNoise();
526
527         // Maximum height of the stone surface and obstacles.
528         // This is used to guide the cave generation
529         s16 stone_surface_max_y;
530
531         // Generate general ground level to full area
532         stone_surface_max_y = generateGround();
533
534         // Create initial heightmap to limit caves
535         updateHeightmap(node_min, node_max);
536
537         const s16 max_spread_amount = MAP_BLOCKSIZE;
538         // Limit dirt flow area by 1 because mud is flown into neighbors.
539         s16 mudflow_minpos = -max_spread_amount + 1;
540         s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2;
541
542         // Loop this part, it will make stuff look older and newer nicely
543         const u32 age_loops = 2;
544         for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop
545                 // Make caves (this code is relatively horrible)
546                 if (flags & MG_CAVES)
547                         generateCaves(stone_surface_max_y);
548
549                 // Add mud to the central chunk
550                 addMud();
551
552                 // Flow mud away from steep edges
553                 if (spflags & MGV6_MUDFLOW)
554                         flowMud(mudflow_minpos, mudflow_maxpos);
555
556         }
557
558         // Update heightmap after mudflow
559         updateHeightmap(node_min, node_max);
560
561         // Add dungeons
562         if ((flags & MG_DUNGEONS) && stone_surface_max_y >= node_min.Y &&
563                         full_node_min.Y >= dungeon_ymin && full_node_max.Y <= dungeon_ymax) {
564                 DungeonParams dp;
565
566                 dp.seed             = seed;
567
568                 dp.only_in_ground   = true;
569                 dp.corridor_len_min = 1;
570                 dp.corridor_len_max = 13;
571                 dp.rooms_min        = 2;
572                 dp.rooms_max        = 16;
573                 dp.y_min            = -MAX_MAP_GENERATION_LIMIT;
574                 dp.y_max            = MAX_MAP_GENERATION_LIMIT;
575
576                 dp.np_density
577                         = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
578                 dp.np_alt_wall
579                         = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
580
581                 if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
582                         dp.c_wall              = c_desert_stone;
583                         dp.c_alt_wall          = CONTENT_IGNORE;
584                         dp.c_stair             = c_stair_desert_stone;
585
586                         dp.diagonal_dirs       = true;
587                         dp.holesize            = v3s16(2, 3, 2);
588                         dp.room_size_min       = v3s16(6, 9, 6);
589                         dp.room_size_max       = v3s16(10, 11, 10);
590                         dp.room_size_large_min = v3s16(10, 13, 10);
591                         dp.room_size_large_max = v3s16(18, 21, 18);
592                         dp.notifytype          = GENNOTIFY_TEMPLE;
593                 } else {
594                         dp.c_wall              = c_cobble;
595                         dp.c_alt_wall          = c_mossycobble;
596                         dp.c_stair             = c_stair_cobble;
597
598                         dp.diagonal_dirs       = false;
599                         dp.holesize            = v3s16(1, 2, 1);
600                         dp.room_size_min       = v3s16(4, 4, 4);
601                         dp.room_size_max       = v3s16(8, 6, 8);
602                         dp.room_size_large_min = v3s16(8, 8, 8);
603                         dp.room_size_large_max = v3s16(16, 16, 16);
604                         dp.notifytype          = GENNOTIFY_DUNGEON;
605                 }
606
607                 DungeonGen dgen(ndef, &gennotify, &dp);
608                 dgen.generate(vm, blockseed, full_node_min, full_node_max);
609         }
610
611         // Add top and bottom side of water to transforming_liquid queue
612         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
613
614         // Add surface nodes
615         growGrass();
616
617         // Generate some trees, and add grass, if a jungle
618         if (spflags & MGV6_TREES)
619                 placeTreesAndJungleGrass();
620
621         // Generate the registered decorations
622         if (flags & MG_DECORATIONS)
623                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
624
625         // Generate the registered ores
626         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
627
628         // Calculate lighting
629         if (flags & MG_LIGHT)
630                 calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
631                         node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE,
632                         full_node_min, full_node_max);
633
634         this->generating = false;
635 }
636
637
638 void MapgenV6::calculateNoise()
639 {
640         int x = node_min.X;
641         int z = node_min.Z;
642         int fx = full_node_min.X;
643         int fz = full_node_min.Z;
644
645         if (!(spflags & MGV6_FLAT)) {
646                 noise_terrain_base->perlinMap2D_PO(x, 0.5, z, 0.5);
647                 noise_terrain_higher->perlinMap2D_PO(x, 0.5, z, 0.5);
648                 noise_steepness->perlinMap2D_PO(x, 0.5, z, 0.5);
649                 noise_height_select->perlinMap2D_PO(x, 0.5, z, 0.5);
650                 noise_mud->perlinMap2D_PO(x, 0.5, z, 0.5);
651         }
652
653         noise_beach->perlinMap2D_PO(x, 0.2, z, 0.7);
654
655         noise_biome->perlinMap2D_PO(fx, 0.6, fz, 0.2);
656         noise_humidity->perlinMap2D_PO(fx, 0.0, fz, 0.0);
657         // Humidity map does not need range limiting 0 to 1,
658         // only humidity at point does
659 }
660
661
662 int MapgenV6::generateGround()
663 {
664         //TimeTaker timer1("Generating ground level");
665         MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
666         MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
667         MapNode n_ice(c_ice);
668         int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
669
670         u32 index = 0;
671         for (s16 z = node_min.Z; z <= node_max.Z; z++)
672         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
673                 // Surface height
674                 s16 surface_y = (s16)baseTerrainLevelFromMap(index);
675
676                 // Log it
677                 if (surface_y > stone_surface_max_y)
678                         stone_surface_max_y = surface_y;
679
680                 BiomeV6Type bt = getBiome(v2s16(x, z));
681
682                 // Fill ground with stone
683                 const v3s16 &em = vm->m_area.getExtent();
684                 u32 i = vm->m_area.index(x, node_min.Y, z);
685                 for (s16 y = node_min.Y; y <= node_max.Y; y++) {
686                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
687                                 if (y <= surface_y) {
688                                         vm->m_data[i] = (y >= MGV6_DESERT_STONE_BASE
689                                                         && bt == BT_DESERT) ?
690                                                 n_desert_stone : n_stone;
691                                 } else if (y <= water_level) {
692                                         vm->m_data[i] = (y >= MGV6_ICE_BASE
693                                                         && bt == BT_TUNDRA) ?
694                                                 n_ice : n_water_source;
695                                 } else {
696                                         vm->m_data[i] = n_air;
697                                 }
698                         }
699                         vm->m_area.add_y(em, i, 1);
700                 }
701         }
702
703         return stone_surface_max_y;
704 }
705
706
707 void MapgenV6::addMud()
708 {
709         // 15ms @cs=8
710         //TimeTaker timer1("add mud");
711         MapNode n_dirt(c_dirt), n_gravel(c_gravel);
712         MapNode n_sand(c_sand), n_desert_sand(c_desert_sand);
713         MapNode addnode;
714
715         u32 index = 0;
716         for (s16 z = node_min.Z; z <= node_max.Z; z++)
717         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
718                 // Randomize mud amount
719                 s16 mud_add_amount = getMudAmount(index) / 2.0 + 0.5;
720
721                 // Find ground level
722                 s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!
723
724                 // Handle area not found
725                 if (surface_y == vm->m_area.MinEdge.Y - 1)
726                         continue;
727
728                 BiomeV6Type bt = getBiome(v2s16(x, z));
729                 addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;
730
731                 if (bt == BT_DESERT && surface_y + mud_add_amount <= water_level + 1) {
732                         addnode = n_sand;
733                 } else if (mud_add_amount <= 0) {
734                         mud_add_amount = 1 - mud_add_amount;
735                         addnode = n_gravel;
736                 } else if (bt != BT_DESERT && getHaveBeach(index) &&
737                                 surface_y + mud_add_amount <= water_level + 2) {
738                         addnode = n_sand;
739                 }
740
741                 if ((bt == BT_DESERT || bt == BT_TUNDRA) && surface_y > 20)
742                         mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20) / 5);
743
744                 /* If topmost node is grass, change it to mud.  It might be if it was
745                 // flown to there from a neighboring chunk and then converted.
746                 u32 i = vm->m_area.index(x, surface_y, z);
747                 if (vm->m_data[i].getContent() == c_dirt_with_grass)
748                         vm->m_data[i] = n_dirt;*/
749
750                 // Add mud on ground
751                 s16 mudcount = 0;
752                 const v3s16 &em = vm->m_area.getExtent();
753                 s16 y_start = surface_y + 1;
754                 u32 i = vm->m_area.index(x, y_start, z);
755                 for (s16 y = y_start; y <= node_max.Y; y++) {
756                         if (mudcount >= mud_add_amount)
757                                 break;
758
759                         vm->m_data[i] = addnode;
760                         mudcount++;
761
762                         vm->m_area.add_y(em, i, 1);
763                 }
764         }
765 }
766
767
768 void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
769 {
770         // 340ms @cs=8
771         //TimeTaker timer1("flow mud");
772
773         // Iterate a few times
774         for (s16 k = 0; k < 3; k++) {
775                 for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
776                 for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
777                         // Invert coordinates every 2nd iteration
778                         if (k % 2 == 0) {
779                                 x = mudflow_maxpos - (x - mudflow_minpos);
780                                 z = mudflow_maxpos - (z - mudflow_minpos);
781                         }
782
783                         // Node position in 2d
784                         v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
785
786                         const v3s16 &em = vm->m_area.getExtent();
787                         u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
788                         s16 y = node_max.Y;
789
790                         while (y >= node_min.Y) {
791
792                         for (;; y--) {
793                                 MapNode *n = NULL;
794                                 // Find mud
795                                 for (; y >= node_min.Y; y--) {
796                                         n = &vm->m_data[i];
797                                         if (n->getContent() == c_dirt ||
798                                                         n->getContent() == c_dirt_with_grass ||
799                                                         n->getContent() == c_gravel)
800                                                 break;
801
802                                         vm->m_area.add_y(em, i, -1);
803                                 }
804
805                                 // Stop if out of area
806                                 //if(vmanip.m_area.contains(i) == false)
807                                 if (y < node_min.Y)
808                                         break;
809
810                                 if (n->getContent() == c_dirt ||
811                                                 n->getContent() == c_dirt_with_grass) {
812                                         // Make it exactly mud
813                                         n->setContent(c_dirt);
814
815                                         // Don't flow it if the stuff under it is not mud
816                                         {
817                                                 u32 i2 = i;
818                                                 vm->m_area.add_y(em, i2, -1);
819                                                 // Cancel if out of area
820                                                 if (!vm->m_area.contains(i2))
821                                                         continue;
822                                                 MapNode *n2 = &vm->m_data[i2];
823                                                 if (n2->getContent() != c_dirt &&
824                                                                 n2->getContent() != c_dirt_with_grass)
825                                                         continue;
826                                         }
827                                 }
828
829                                 v3s16 dirs4[4] = {
830                                         v3s16(0, 0, 1), // back
831                                         v3s16(1, 0, 0), // right
832                                         v3s16(0, 0, -1), // front
833                                         v3s16(-1, 0, 0), // left
834                                 };
835
836                                 // Check that upper is walkable. Cancel
837                                 // dropping if upper keeps it in place.
838                                 u32 i3 = i;
839                                 vm->m_area.add_y(em, i3, 1);
840                                 MapNode *n3 = NULL;
841
842                                 if (vm->m_area.contains(i3)) {
843                                         n3 = &vm->m_data[i3];
844                                         if (ndef->get(*n3).walkable)
845                                                 continue;
846                                 }
847
848                                 // Drop mud on side
849                                 for (const v3s16 &dirp : dirs4) {
850                                         u32 i2 = i;
851                                         // Move to side
852                                         vm->m_area.add_p(em, i2, dirp);
853                                         // Fail if out of area
854                                         if (!vm->m_area.contains(i2))
855                                                 continue;
856                                         // Check that side is air
857                                         MapNode *n2 = &vm->m_data[i2];
858                                         if (ndef->get(*n2).walkable)
859                                                 continue;
860                                         // Check that under side is air
861                                         vm->m_area.add_y(em, i2, -1);
862                                         if (!vm->m_area.contains(i2))
863                                                 continue;
864                                         n2 = &vm->m_data[i2];
865                                         if (ndef->get(*n2).walkable)
866                                                 continue;
867                                         // Loop further down until not air
868                                         bool dropped_to_unknown = false;
869                                         do {
870                                                 vm->m_area.add_y(em, i2, -1);
871                                                 n2 = &vm->m_data[i2];
872                                                 // if out of known area
873                                                 if (!vm->m_area.contains(i2) ||
874                                                                 n2->getContent() == CONTENT_IGNORE) {
875                                                         dropped_to_unknown = true;
876                                                         break;
877                                                 }
878                                         } while (!ndef->get(*n2).walkable);
879                                         // Loop one up so that we're in air
880                                         vm->m_area.add_y(em, i2, 1);
881
882                                         // Move mud to new place. Outside mapchunk remove
883                                         // any decorations above removed or placed mud.
884                                         if (!dropped_to_unknown)
885                                                 moveMud(i, i2, i3, p2d, em);
886
887                                         // Done
888                                         break;
889                                 }
890                         }
891                         }
892                 }
893         }
894 }
895
896
897 void MapgenV6::moveMud(u32 remove_index, u32 place_index,
898         u32 above_remove_index, v2s16 pos, v3s16 em)
899 {
900         MapNode n_air(CONTENT_AIR);
901         // Copy mud from old place to new place
902         vm->m_data[place_index] = vm->m_data[remove_index];
903         // Set old place to be air
904         vm->m_data[remove_index] = n_air;
905         // Outside the mapchunk decorations may need to be removed if above removed
906         // mud or if half-buried in placed mud. Placed mud is to the side of pos so
907         // use 'pos.X >= node_max.X' etc.
908         if (pos.X >= node_max.X || pos.X <= node_min.X ||
909                         pos.Y >= node_max.Z || pos.Y <= node_min.Z) {
910                 // 'above remove' node is above removed mud. If it is not air, water or
911                 // 'ignore' it is a decoration that needs removing. Also search upwards
912                 // to remove a possible stacked decoration.
913                 // Check for 'ignore' because stacked decorations can penetrate into
914                 // 'ignore' nodes above the mapchunk.
915                 while (vm->m_area.contains(above_remove_index) &&
916                                 vm->m_data[above_remove_index].getContent() != CONTENT_AIR &&
917                                 vm->m_data[above_remove_index].getContent() != c_water_source &&
918                                 vm->m_data[above_remove_index].getContent() != CONTENT_IGNORE) {
919                         vm->m_data[above_remove_index] = n_air;
920                         vm->m_area.add_y(em, above_remove_index, 1);
921                 }
922                 // Mud placed may have partially-buried a stacked decoration, search
923                 // above and remove.
924                 vm->m_area.add_y(em, place_index, 1);
925                 while (vm->m_area.contains(place_index) &&
926                                 vm->m_data[place_index].getContent() != CONTENT_AIR &&
927                                 vm->m_data[place_index].getContent() != c_water_source &&
928                                 vm->m_data[place_index].getContent() != CONTENT_IGNORE) {
929                         vm->m_data[place_index] = n_air;
930                         vm->m_area.add_y(em, place_index, 1);
931                 }
932         }
933 }
934
935
936 void MapgenV6::placeTreesAndJungleGrass()
937 {
938         //TimeTaker t("placeTrees");
939         if (node_max.Y < water_level)
940                 return;
941
942         PseudoRandom grassrandom(blockseed + 53);
943         content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
944         // if we don't have junglegrass, don't place cignore... that's bad
945         if (c_junglegrass == CONTENT_IGNORE)
946                 c_junglegrass = CONTENT_AIR;
947         MapNode n_junglegrass(c_junglegrass);
948         const v3s16 &em = vm->m_area.getExtent();
949
950         // Divide area into parts
951         s16 div = 8;
952         s16 sidelen = central_area_size.X / div;
953         double area = sidelen * sidelen;
954
955         // N.B.  We must add jungle grass first, since tree leaves will
956         // obstruct the ground, giving us a false ground level
957         for (s16 z0 = 0; z0 < div; z0++)
958         for (s16 x0 = 0; x0 < div; x0++) {
959                 // Center position of part of division
960                 v2s16 p2d_center(
961                         node_min.X + sidelen / 2 + sidelen * x0,
962                         node_min.Z + sidelen / 2 + sidelen * z0
963                 );
964                 // Minimum edge of part of division
965                 v2s16 p2d_min(
966                         node_min.X + sidelen * x0,
967                         node_min.Z + sidelen * z0
968                 );
969                 // Maximum edge of part of division
970                 v2s16 p2d_max(
971                         node_min.X + sidelen + sidelen * x0 - 1,
972                         node_min.Z + sidelen + sidelen * z0 - 1
973                 );
974
975                 // Get biome at center position of part of division
976                 BiomeV6Type bt = getBiome(p2d_center);
977
978                 // Amount of trees
979                 u32 tree_count;
980                 if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) {
981                         tree_count = area * getTreeAmount(p2d_center);
982                         if (bt == BT_JUNGLE)
983                                 tree_count *= 4;
984                 } else {
985                         tree_count = 0;
986                 }
987
988                 // Add jungle grass
989                 if (bt == BT_JUNGLE) {
990                         float humidity = getHumidity(p2d_center);
991                         u32 grass_count = 5 * humidity * tree_count;
992                         for (u32 i = 0; i < grass_count; i++) {
993                                 s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
994                                 s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
995                                 int mapindex = central_area_size.X * (z - node_min.Z)
996                                                                 + (x - node_min.X);
997                                 s16 y = heightmap[mapindex];
998                                 if (y < water_level)
999                                         continue;
1000
1001                                 u32 vi = vm->m_area.index(x, y, z);
1002                                 // place on dirt_with_grass, since we know it is exposed to sunlight
1003                                 if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
1004                                         vm->m_area.add_y(em, vi, 1);
1005                                         vm->m_data[vi] = n_junglegrass;
1006                                 }
1007                         }
1008                 }
1009
1010                 // Put trees in random places on part of division
1011                 for (u32 i = 0; i < tree_count; i++) {
1012                         s16 x = myrand_range(p2d_min.X, p2d_max.X);
1013                         s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
1014                         int mapindex = central_area_size.X * (z - node_min.Z)
1015                                                         + (x - node_min.X);
1016                         s16 y = heightmap[mapindex];
1017                         // Don't make a tree under water level
1018                         // Don't make a tree so high that it doesn't fit
1019                         if (y < water_level || y > node_max.Y - 6)
1020                                 continue;
1021
1022                         v3s16 p(x, y, z);
1023                         // Trees grow only on mud and grass
1024                         {
1025                                 u32 i = vm->m_area.index(p);
1026                                 content_t c = vm->m_data[i].getContent();
1027                                 if (c != c_dirt &&
1028                                                 c != c_dirt_with_grass &&
1029                                                 c != c_dirt_with_snow)
1030                                         continue;
1031                         }
1032                         p.Y++;
1033
1034                         // Make a tree
1035                         if (bt == BT_JUNGLE) {
1036                                 treegen::make_jungletree(*vm, p, ndef, myrand());
1037                         } else if (bt == BT_TAIGA) {
1038                                 treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand());
1039                         } else if (bt == BT_NORMAL) {
1040                                 bool is_apple_tree = (myrand_range(0, 3) == 0) &&
1041                                                         getHaveAppleTree(v2s16(x, z));
1042                                 treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
1043                         }
1044                 }
1045         }
1046         //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
1047 }
1048
1049
1050 void MapgenV6::growGrass() // Add surface nodes
1051 {
1052         MapNode n_dirt_with_grass(c_dirt_with_grass);
1053         MapNode n_dirt_with_snow(c_dirt_with_snow);
1054         MapNode n_snowblock(c_snowblock);
1055         MapNode n_snow(c_snow);
1056         const v3s16 &em = vm->m_area.getExtent();
1057
1058         u32 index = 0;
1059         for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
1060         for (s16 x = full_node_min.X; x <= full_node_max.X; x++, index++) {
1061                 // Find the lowest surface to which enough light ends up to make
1062                 // grass grow.  Basically just wait until not air and not leaves.
1063                 s16 surface_y = 0;
1064                 {
1065                         u32 i = vm->m_area.index(x, node_max.Y, z);
1066                         s16 y;
1067                         // Go to ground level
1068                         for (y = node_max.Y; y >= full_node_min.Y; y--) {
1069                                 MapNode &n = vm->m_data[i];
1070                                 if (ndef->get(n).param_type != CPT_LIGHT ||
1071                                                 ndef->get(n).liquid_type != LIQUID_NONE ||
1072                                                 n.getContent() == c_ice)
1073                                         break;
1074                                 vm->m_area.add_y(em, i, -1);
1075                         }
1076                         surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
1077                 }
1078
1079                 BiomeV6Type bt = getBiome(index, v2s16(x, z));
1080                 u32 i = vm->m_area.index(x, surface_y, z);
1081                 content_t c = vm->m_data[i].getContent();
1082                 if (surface_y >= water_level - 20) {
1083                         if (bt == BT_TAIGA && c == c_dirt) {
1084                                 vm->m_data[i] = n_dirt_with_snow;
1085                         } else if (bt == BT_TUNDRA) {
1086                                 if (c == c_dirt) {
1087                                         vm->m_data[i] = n_snowblock;
1088                                         vm->m_area.add_y(em, i, -1);
1089                                         vm->m_data[i] = n_dirt_with_snow;
1090                                 } else if (c == c_stone && surface_y < node_max.Y) {
1091                                         vm->m_area.add_y(em, i, 1);
1092                                         vm->m_data[i] = n_snowblock;
1093                                 }
1094                         } else if (c == c_dirt) {
1095                                 vm->m_data[i] = n_dirt_with_grass;
1096                         }
1097                 }
1098         }
1099 }
1100
1101
1102 void MapgenV6::generateCaves(int max_stone_y)
1103 {
1104         float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
1105         int volume_nodes = (node_max.X - node_min.X + 1) *
1106                                            (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE;
1107         cave_amount = MYMAX(0.0, cave_amount);
1108         u32 caves_count = cave_amount * volume_nodes / 50000;
1109         u32 bruises_count = 1;
1110         PseudoRandom ps(blockseed + 21343);
1111         PseudoRandom ps2(blockseed + 1032);
1112
1113         if (ps.range(1, 6) == 1)
1114                 bruises_count = ps.range(0, ps.range(0, 2));
1115
1116         if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
1117                 caves_count   /= 3;
1118                 bruises_count /= 3;
1119         }
1120
1121         for (u32 i = 0; i < caves_count + bruises_count; i++) {
1122                 CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source);
1123
1124                 bool large_cave = (i >= caves_count);
1125                 cave.makeCave(vm, node_min, node_max, &ps, &ps2,
1126                         large_cave, max_stone_y, heightmap);
1127         }
1128 }