]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen.cpp
Add flag string settings, flat map option
[dragonfireclient.git] / src / mapgen.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapgen.h"
21 #include "voxel.h"
22 #include "noise.h"
23 #include "biome.h"
24 #include "mapblock.h"
25 #include "mapnode.h"
26 #include "map.h"
27 //#include "serverobject.h"
28 #include "content_sao.h"
29 #include "nodedef.h"
30 #include "content_mapnode.h" // For content_mapnode_get_new_name
31 #include "voxelalgorithms.h"
32 #include "profiler.h"
33 #include "settings.h" // For g_settings
34 #include "main.h" // For g_profiler
35 #include "treegen.h"
36 #include "mapgen_v6.h"
37
38 FlagDesc flagdesc_mapgen[] = {
39         {"trees",          MG_TREES},
40         {"caves",          MG_CAVES},
41         {"dungeons",       MG_DUNGEONS},
42         {"v6_forests",     MGV6_FORESTS},
43         {"v6_biome_blend", MGV6_BIOME_BLEND},
44         {"flat",           MG_FLAT},
45         {NULL,                     0}
46 };
47
48 ///////////////////////////////////////////////////////////////////////////////
49 /////////////////////////////// Emerge Manager ////////////////////////////////
50
51
52 EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
53         //register built-in mapgens
54         registerMapgen("v6", new MapgenFactoryV6());
55                 
56         //the order of these assignments is pretty important
57         this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
58         this->params   = NULL;
59         this->mapgen   = NULL;
60 }
61
62
63 EmergeManager::~EmergeManager() {
64         delete biomedef;
65         delete mapgen;
66         delete params;
67 }
68
69
70 void EmergeManager::initMapgens(MapgenParams *mgparams) {
71         if (mapgen)
72                 return;
73         
74         this->params = mgparams;
75         this->mapgen = getMapgen(); //only one mapgen for now!
76 }
77
78
79 Mapgen *EmergeManager::getMapgen() {
80         if (!mapgen) {
81                 mapgen = createMapgen(params->mg_name, 0, params, this);
82                 if (!mapgen) {
83                         infostream << "EmergeManager: falling back to mapgen v6" << std::endl;
84                         delete params;
85                         params = createMapgenParams("v6");
86                         mapgen = createMapgen("v6", 0, params, this);
87                 }
88         }
89         return mapgen;
90 }
91
92 void EmergeManager::addBlockToQueue() {
93         //STUB
94 }
95
96
97 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
98         if (!mapgen)
99                 return 0;
100         return mapgen->getGroundLevelAtPoint(p);
101 }
102
103
104 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
105         /*
106         v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
107                                         (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
108         int ground_level = getGroundLevelAtPoint(p);
109         return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
110         */
111
112         //yuck, but then again, should i bother being accurate?
113         //the height of the nodes in a single block is quite variable
114         return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level;
115 }
116
117
118 u32 EmergeManager::getBlockSeed(v3s16 p) {
119         return (u32)(params->seed & 0xFFFFFFFF) +
120                 p.Z * 38134234 +
121                 p.Y * 42123 +
122                 p.Y * 23;
123 }
124
125
126 Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid,
127                                                                         MapgenParams *mgparams, EmergeManager *emerge) {
128         std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
129         if (iter == mglist.end()) {
130                 errorstream << "EmergeManager; mapgen " << mgname <<
131                  " not registered" << std::endl;
132                 return NULL;
133         }
134         
135         MapgenFactory *mgfactory = iter->second;
136         return mgfactory->createMapgen(mgid, mgparams, emerge);
137 }
138
139
140 MapgenParams *EmergeManager::createMapgenParams(std::string mgname) {
141         std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
142         if (iter == mglist.end()) {
143                 errorstream << "EmergeManager: mapgen " << mgname <<
144                  " not registered" << std::endl;
145                 return NULL;
146         }
147         
148         MapgenFactory *mgfactory = iter->second;
149         return mgfactory->createMapgenParams();
150 }
151
152
153 MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) {
154         std::string mg_name = settings->get("mg_name");
155         MapgenParams *mgparams = createMapgenParams(mg_name);
156         
157         mgparams->mg_name     = mg_name;
158         mgparams->seed        = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
159         mgparams->water_level = settings->getS16("water_level");
160         mgparams->chunksize   = settings->getS16("chunksize");
161         mgparams->flags       = settings->getFlagStr("mg_flags", flagdesc_mapgen);
162
163         if (!mgparams->readParams(settings)) {
164                 delete mgparams;
165                 return NULL;
166         }
167         return mgparams;
168 }
169
170
171 void EmergeManager::setParamsToSettings(Settings *settings) {
172         settings->set("mg_name",         params->mg_name);
173         settings->setU64("seed",         params->seed);
174         settings->setS16("water_level",  params->water_level);
175         settings->setS16("chunksize",    params->chunksize);
176         settings->setFlagStr("mg_flags", params->flags, flagdesc_mapgen);
177
178         params->writeParams(settings);
179 }
180
181
182 bool EmergeManager::registerMapgen(std::string mgname, MapgenFactory *mgfactory) {
183         mglist.insert(std::make_pair(mgname, mgfactory));
184         infostream << "EmergeManager: registered mapgen " << mgname << std::endl;
185 }
186
187
188 /////////////////////
189
190 bool MapgenV6Params::readParams(Settings *settings) {
191         freq_desert = settings->getFloat("mgv6_freq_desert");
192         freq_beach  = settings->getFloat("mgv6_freq_beach");
193
194         np_terrain_base   = settings->getNoiseParams("mgv6_np_terrain_base");
195         np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
196         np_steepness      = settings->getNoiseParams("mgv6_np_steepness");
197         np_height_select  = settings->getNoiseParams("mgv6_np_height_select");
198         np_trees          = settings->getNoiseParams("mgv6_np_trees");
199         np_mud            = settings->getNoiseParams("mgv6_np_mud");
200         np_beach          = settings->getNoiseParams("mgv6_np_beach");
201         np_biome          = settings->getNoiseParams("mgv6_np_biome");
202         np_cave           = settings->getNoiseParams("mgv6_np_cave");
203
204         bool success =
205                 np_terrain_base  && np_terrain_higher && np_steepness &&
206                 np_height_select && np_trees          && np_mud       &&
207                 np_beach         && np_biome          && np_cave;
208         return success;
209 }
210
211
212 void MapgenV6Params::writeParams(Settings *settings) {
213         settings->setFloat("mgv6_freq_desert", freq_desert);
214         settings->setFloat("mgv6_freq_beach",  freq_beach);
215         
216         settings->setNoiseParams("mgv6_np_terrain_base",   np_terrain_base);
217         settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
218         settings->setNoiseParams("mgv6_np_steepness",      np_steepness);
219         settings->setNoiseParams("mgv6_np_height_select",  np_height_select);
220         settings->setNoiseParams("mgv6_np_trees",          np_trees);
221         settings->setNoiseParams("mgv6_np_mud",            np_mud);
222         settings->setNoiseParams("mgv6_np_beach",          np_beach);
223         settings->setNoiseParams("mgv6_np_biome",          np_biome);
224         settings->setNoiseParams("mgv6_np_cave",           np_cave);
225 }
226
227
228 /////////////////////////////////// legacy static functions for farmesh
229
230
231 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
232         //just need to return something
233         s16 level = 5;
234         return level;
235 }
236
237
238 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
239         double sandnoise = noise2d_perlin(
240                         0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
241                         seed+59420, 3, 0.50);
242
243         return (sandnoise > 0.15);
244 }
245
246
247 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
248         double noise = noise2d_perlin(
249                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
250                         seed+2, 4, 0.66);
251         double zeroval = -0.39;
252         if(noise < zeroval)
253                 return 0;
254         else
255                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
256 }
257
258
259 #if 0 /// BIG COMMENT
260 namespace mapgen
261 {
262
263 /*
264         Some helper functions for the map generator
265 */
266
267 #if 1
268 // Returns Y one under area minimum if not found
269 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
270                 INodeDefManager *ndef)
271 {
272         v3s16 em = vmanip.m_area.getExtent();
273         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
274         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
275         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
276         s16 y;
277         for(y=y_nodes_max; y>=y_nodes_min; y--)
278         {
279                 MapNode &n = vmanip.m_data[i];
280                 if(ndef->get(n).walkable)
281                         break;
282
283                 vmanip.m_area.add_y(em, i, -1);
284         }
285         if(y >= y_nodes_min)
286                 return y;
287         else
288                 return y_nodes_min - 1;
289 }
290
291 #if 0
292 // Returns Y one under area minimum if not found
293 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
294                 INodeDefManager *ndef)
295 {
296         if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
297                 return vmanip.m_area.MinEdge.Y-1;
298         v3s16 em = vmanip.m_area.getExtent();
299         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
300         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
301         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
302         s16 y;
303         content_t c_tree = ndef->getId("mapgen_tree");
304         content_t c_leaves = ndef->getId("mapgen_leaves");
305         for(y=y_nodes_max; y>=y_nodes_min; y--)
306         {
307                 MapNode &n = vmanip.m_data[i];
308                 if(ndef->get(n).walkable
309                                 && n.getContent() != c_tree
310                                 && n.getContent() != c_leaves)
311                         break;
312
313                 vmanip.m_area.add_y(em, i, -1);
314         }
315         if(y >= y_nodes_min)
316                 return y;
317         else
318                 return y_nodes_min - 1;
319 }
320 #endif
321
322 // Returns Y one under area minimum if not found
323 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
324                 INodeDefManager *ndef)
325 {
326         v3s16 em = vmanip.m_area.getExtent();
327         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
328         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
329         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
330         s16 y;
331         content_t c_stone = ndef->getId("mapgen_stone");
332         content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
333         for(y=y_nodes_max; y>=y_nodes_min; y--)
334         {
335                 MapNode &n = vmanip.m_data[i];
336                 content_t c = n.getContent();
337                 if(c != CONTENT_IGNORE && (
338                                 c == c_stone || c == c_desert_stone))
339                         break;
340
341                 vmanip.m_area.add_y(em, i, -1);
342         }
343         if(y >= y_nodes_min)
344                 return y;
345         else
346                 return y_nodes_min - 1;
347 }
348 #endif
349
350
351 #if 0
352
353 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
354                 INodeDefManager *ndef)
355 {
356         MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
357
358         s16 trunk_h = myrand_range(2, 3);
359         v3s16 p1 = p0;
360         for(s16 ii=0; ii<trunk_h; ii++)
361         {
362                 if(vmanip.m_area.contains(p1))
363                         vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
364                 p1.Y++;
365         }
366 }
367
368 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
369                 INodeDefManager *ndef)
370 {
371         MapNode cactusnode(ndef->getId("mapgen_cactus"));
372
373         s16 trunk_h = 3;
374         v3s16 p1 = p0;
375         for(s16 ii=0; ii<trunk_h; ii++)
376         {
377                 if(vmanip.m_area.contains(p1))
378                         vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
379                 p1.Y++;
380         }
381 }
382 #endif
383
384 #if 0
385 /*
386         Dungeon making routines
387 */
388
389 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
390 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
391 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
392                 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
393
394 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
395                 INodeDefManager *ndef)
396 {
397         // Make +-X walls
398         for(s16 z=0; z<roomsize.Z; z++)
399         for(s16 y=0; y<roomsize.Y; y++)
400         {
401                 {
402                         v3s16 p = roomplace + v3s16(0,y,z);
403                         if(vmanip.m_area.contains(p) == false)
404                                 continue;
405                         u32 vi = vmanip.m_area.index(p);
406                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
407                                 continue;
408                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
409                 }
410                 {
411                         v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
412                         if(vmanip.m_area.contains(p) == false)
413                                 continue;
414                         u32 vi = vmanip.m_area.index(p);
415                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
416                                 continue;
417                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
418                 }
419         }
420
421         // Make +-Z walls
422         for(s16 x=0; x<roomsize.X; x++)
423         for(s16 y=0; y<roomsize.Y; y++)
424         {
425                 {
426                         v3s16 p = roomplace + v3s16(x,y,0);
427                         if(vmanip.m_area.contains(p) == false)
428                                 continue;
429                         u32 vi = vmanip.m_area.index(p);
430                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
431                                 continue;
432                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
433                 }
434                 {
435                         v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
436                         if(vmanip.m_area.contains(p) == false)
437                                 continue;
438                         u32 vi = vmanip.m_area.index(p);
439                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
440                                 continue;
441                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
442                 }
443         }
444
445         // Make +-Y walls (floor and ceiling)
446         for(s16 z=0; z<roomsize.Z; z++)
447         for(s16 x=0; x<roomsize.X; x++)
448         {
449                 {
450                         v3s16 p = roomplace + v3s16(x,0,z);
451                         if(vmanip.m_area.contains(p) == false)
452                                 continue;
453                         u32 vi = vmanip.m_area.index(p);
454                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
455                                 continue;
456                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
457                 }
458                 {
459                         v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
460                         if(vmanip.m_area.contains(p) == false)
461                                 continue;
462                         u32 vi = vmanip.m_area.index(p);
463                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
464                                 continue;
465                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
466                 }
467         }
468
469         // Fill with air
470         for(s16 z=1; z<roomsize.Z-1; z++)
471         for(s16 y=1; y<roomsize.Y-1; y++)
472         for(s16 x=1; x<roomsize.X-1; x++)
473         {
474                 v3s16 p = roomplace + v3s16(x,y,z);
475                 if(vmanip.m_area.contains(p) == false)
476                         continue;
477                 u32 vi = vmanip.m_area.index(p);
478                 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
479                 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
480         }
481 }
482
483 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
484                 u8 avoid_flags, MapNode n, u8 or_flags)
485 {
486         for(s16 z=0; z<size.Z; z++)
487         for(s16 y=0; y<size.Y; y++)
488         for(s16 x=0; x<size.X; x++)
489         {
490                 v3s16 p = place + v3s16(x,y,z);
491                 if(vmanip.m_area.contains(p) == false)
492                         continue;
493                 u32 vi = vmanip.m_area.index(p);
494                 if(vmanip.m_flags[vi] & avoid_flags)
495                         continue;
496                 vmanip.m_flags[vi] |= or_flags;
497                 vmanip.m_data[vi] = n;
498         }
499 }
500
501 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
502                 INodeDefManager *ndef)
503 {
504         make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
505                         VMANIP_FLAG_DUNGEON_INSIDE);
506 }
507
508 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
509                 INodeDefManager *ndef)
510 {
511         make_hole1(vmanip, doorplace, ndef);
512         // Place torch (for testing)
513         //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
514 }
515
516 static v3s16 rand_ortho_dir(PseudoRandom &random)
517 {
518         if(random.next()%2==0)
519                 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
520         else
521                 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
522 }
523
524 static v3s16 turn_xz(v3s16 olddir, int t)
525 {
526         v3s16 dir;
527         if(t == 0)
528         {
529                 // Turn right
530                 dir.X = olddir.Z;
531                 dir.Z = -olddir.X;
532                 dir.Y = olddir.Y;
533         }
534         else
535         {
536                 // Turn left
537                 dir.X = -olddir.Z;
538                 dir.Z = olddir.X;
539                 dir.Y = olddir.Y;
540         }
541         return dir;
542 }
543
544 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
545 {
546         int turn = random.range(0,2);
547         v3s16 dir;
548         if(turn == 0)
549         {
550                 // Go straight
551                 dir = olddir;
552         }
553         else if(turn == 1)
554                 // Turn right
555                 dir = turn_xz(olddir, 0);
556         else
557                 // Turn left
558                 dir = turn_xz(olddir, 1);
559         return dir;
560 }
561
562 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
563                 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
564                 PseudoRandom &random, INodeDefManager *ndef)
565 {
566         make_hole1(vmanip, doorplace, ndef);
567         v3s16 p0 = doorplace;
568         v3s16 dir = doordir;
569         u32 length;
570         if(random.next()%2)
571                 length = random.range(1,13);
572         else
573                 length = random.range(1,6);
574         length = random.range(1,13);
575         u32 partlength = random.range(1,13);
576         u32 partcount = 0;
577         s16 make_stairs = 0;
578         if(random.next()%2 == 0 && partlength >= 3)
579                 make_stairs = random.next()%2 ? 1 : -1;
580         for(u32 i=0; i<length; i++)
581         {
582                 v3s16 p = p0 + dir;
583                 if(partcount != 0)
584                         p.Y += make_stairs;
585
586                 /*// If already empty
587                 if(vmanip.getNodeNoExNoEmerge(p).getContent()
588                                 == CONTENT_AIR
589                 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
590                                 == CONTENT_AIR)
591                 {
592                 }*/
593
594                 if(vmanip.m_area.contains(p) == true
595                                 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
596                 {
597                         if(make_stairs)
598                         {
599                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
600                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
601                                 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
602                                                 VMANIP_FLAG_DUNGEON_INSIDE);
603                                 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
604                                                 VMANIP_FLAG_DUNGEON_INSIDE);
605                         }
606                         else
607                         {
608                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
609                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
610                                 make_hole1(vmanip, p, ndef);
611                                 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
612                                                 VMANIP_FLAG_DUNGEON_INSIDE);*/
613                         }
614
615                         p0 = p;
616                 }
617                 else
618                 {
619                         // Can't go here, turn away
620                         dir = turn_xz(dir, random.range(0,1));
621                         make_stairs = -make_stairs;
622                         partcount = 0;
623                         partlength = random.range(1,length);
624                         continue;
625                 }
626
627                 partcount++;
628                 if(partcount >= partlength)
629                 {
630                         partcount = 0;
631
632                         dir = random_turn(random, dir);
633
634                         partlength = random.range(1,length);
635
636                         make_stairs = 0;
637                         if(random.next()%2 == 0 && partlength >= 3)
638                                 make_stairs = random.next()%2 ? 1 : -1;
639                 }
640         }
641         result_place = p0;
642         result_dir = dir;
643 }
644
645 class RoomWalker
646 {
647 public:
648
649         RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
650                         INodeDefManager *ndef):
651                         vmanip(vmanip_),
652                         m_pos(pos),
653                         m_random(random),
654                         m_ndef(ndef)
655         {
656                 randomizeDir();
657         }
658
659         void randomizeDir()
660         {
661                 m_dir = rand_ortho_dir(m_random);
662         }
663
664         void setPos(v3s16 pos)
665         {
666                 m_pos = pos;
667         }
668
669         void setDir(v3s16 dir)
670         {
671                 m_dir = dir;
672         }
673
674         bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
675         {
676                 for(u32 i=0; i<100; i++)
677                 {
678                         v3s16 p = m_pos + m_dir;
679                         v3s16 p1 = p + v3s16(0,1,0);
680                         if(vmanip.m_area.contains(p) == false
681                                         || vmanip.m_area.contains(p1) == false
682                                         || i % 4 == 0)
683                         {
684                                 randomizeDir();
685                                 continue;
686                         }
687                         if(vmanip.getNodeNoExNoEmerge(p).getContent()
688                                         == m_ndef->getId("mapgen_cobble")
689                         && vmanip.getNodeNoExNoEmerge(p1).getContent()
690                                         == m_ndef->getId("mapgen_cobble"))
691                         {
692                                 // Found wall, this is a good place!
693                                 result_place = p;
694                                 result_dir = m_dir;
695                                 // Randomize next direction
696                                 randomizeDir();
697                                 return true;
698                         }
699                         /*
700                                 Determine where to move next
701                         */
702                         // Jump one up if the actual space is there
703                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
704                                         == m_ndef->getId("mapgen_cobble")
705                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
706                                         == CONTENT_AIR
707                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
708                                         == CONTENT_AIR)
709                                 p += v3s16(0,1,0);
710                         // Jump one down if the actual space is there
711                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
712                                         == m_ndef->getId("mapgen_cobble")
713                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
714                                         == CONTENT_AIR
715                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
716                                         == CONTENT_AIR)
717                                 p += v3s16(0,-1,0);
718                         // Check if walking is now possible
719                         if(vmanip.getNodeNoExNoEmerge(p).getContent()
720                                         != CONTENT_AIR
721                         || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
722                                         != CONTENT_AIR)
723                         {
724                                 // Cannot continue walking here
725                                 randomizeDir();
726                                 continue;
727                         }
728                         // Move there
729                         m_pos = p;
730                 }
731                 return false;
732         }
733
734         bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
735                         v3s16 &result_doordir, v3s16 &result_roomplace)
736         {
737                 for(s16 trycount=0; trycount<30; trycount++)
738                 {
739                         v3s16 doorplace;
740                         v3s16 doordir;
741                         bool r = findPlaceForDoor(doorplace, doordir);
742                         if(r == false)
743                                 continue;
744                         v3s16 roomplace;
745                         // X east, Z north, Y up
746 #if 1
747                         if(doordir == v3s16(1,0,0)) // X+
748                                 roomplace = doorplace +
749                                                 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
750                         if(doordir == v3s16(-1,0,0)) // X-
751                                 roomplace = doorplace +
752                                                 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
753                         if(doordir == v3s16(0,0,1)) // Z+
754                                 roomplace = doorplace +
755                                                 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
756                         if(doordir == v3s16(0,0,-1)) // Z-
757                                 roomplace = doorplace +
758                                                 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
759 #endif
760 #if 0
761                         if(doordir == v3s16(1,0,0)) // X+
762                                 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
763                         if(doordir == v3s16(-1,0,0)) // X-
764                                 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
765                         if(doordir == v3s16(0,0,1)) // Z+
766                                 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
767                         if(doordir == v3s16(0,0,-1)) // Z-
768                                 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
769 #endif
770
771                         // Check fit
772                         bool fits = true;
773                         for(s16 z=1; z<roomsize.Z-1; z++)
774                         for(s16 y=1; y<roomsize.Y-1; y++)
775                         for(s16 x=1; x<roomsize.X-1; x++)
776                         {
777                                 v3s16 p = roomplace + v3s16(x,y,z);
778                                 if(vmanip.m_area.contains(p) == false)
779                                 {
780                                         fits = false;
781                                         break;
782                                 }
783                                 if(vmanip.m_flags[vmanip.m_area.index(p)]
784                                                 & VMANIP_FLAG_DUNGEON_INSIDE)
785                                 {
786                                         fits = false;
787                                         break;
788                                 }
789                         }
790                         if(fits == false)
791                         {
792                                 // Find new place
793                                 continue;
794                         }
795                         result_doorplace = doorplace;
796                         result_doordir = doordir;
797                         result_roomplace = roomplace;
798                         return true;
799                 }
800                 return false;
801         }
802
803 private:
804         VoxelManipulator &vmanip;
805         v3s16 m_pos;
806         v3s16 m_dir;
807         PseudoRandom &m_random;
808         INodeDefManager *m_ndef;
809 };
810
811 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
812                 INodeDefManager *ndef)
813 {
814         v3s16 areasize = vmanip.m_area.getExtent();
815         v3s16 roomsize;
816         v3s16 roomplace;
817
818         /*
819                 Find place for first room
820         */
821         bool fits = false;
822         for(u32 i=0; i<100; i++)
823         {
824                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
825                 roomplace = vmanip.m_area.MinEdge + v3s16(
826                                 random.range(0,areasize.X-roomsize.X-1),
827                                 random.range(0,areasize.Y-roomsize.Y-1),
828                                 random.range(0,areasize.Z-roomsize.Z-1));
829                 /*
830                         Check that we're not putting the room to an unknown place,
831                         otherwise it might end up floating in the air
832                 */
833                 fits = true;
834                 for(s16 z=1; z<roomsize.Z-1; z++)
835                 for(s16 y=1; y<roomsize.Y-1; y++)
836                 for(s16 x=1; x<roomsize.X-1; x++)
837                 {
838                         v3s16 p = roomplace + v3s16(x,y,z);
839                         u32 vi = vmanip.m_area.index(p);
840                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
841                         {
842                                 fits = false;
843                                 break;
844                         }
845                         if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
846                         {
847                                 fits = false;
848                                 break;
849                         }
850                 }
851                 if(fits)
852                         break;
853         }
854         // No place found
855         if(fits == false)
856                 return;
857
858         /*
859                 Stores the center position of the last room made, so that
860                 a new corridor can be started from the last room instead of
861                 the new room, if chosen so.
862         */
863         v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
864
865         u32 room_count = random.range(2,7);
866         for(u32 i=0; i<room_count; i++)
867         {
868                 // Make a room to the determined place
869                 make_room1(vmanip, roomsize, roomplace, ndef);
870
871                 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
872
873                 // Place torch at room center (for testing)
874                 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
875
876                 // Quit if last room
877                 if(i == room_count-1)
878                         break;
879
880                 // Determine walker start position
881
882                 bool start_in_last_room = (random.range(0,2)!=0);
883                 //bool start_in_last_room = true;
884
885                 v3s16 walker_start_place;
886
887                 if(start_in_last_room)
888                 {
889                         walker_start_place = last_room_center;
890                 }
891                 else
892                 {
893                         walker_start_place = room_center;
894                         // Store center of current room as the last one
895                         last_room_center = room_center;
896                 }
897
898                 // Create walker and find a place for a door
899                 RoomWalker walker(vmanip, walker_start_place, random, ndef);
900                 v3s16 doorplace;
901                 v3s16 doordir;
902                 bool r = walker.findPlaceForDoor(doorplace, doordir);
903                 if(r == false)
904                         return;
905
906                 if(random.range(0,1)==0)
907                         // Make the door
908                         make_door1(vmanip, doorplace, doordir, ndef);
909                 else
910                         // Don't actually make a door
911                         doorplace -= doordir;
912
913                 // Make a random corridor starting from the door
914                 v3s16 corridor_end;
915                 v3s16 corridor_end_dir;
916                 make_corridor(vmanip, doorplace, doordir, corridor_end,
917                                 corridor_end_dir, random, ndef);
918
919                 // Find a place for a random sized room
920                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
921                 walker.setPos(corridor_end);
922                 walker.setDir(corridor_end_dir);
923                 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
924                 if(r == false)
925                         return;
926
927                 if(random.range(0,1)==0)
928                         // Make the door
929                         make_door1(vmanip, doorplace, doordir, ndef);
930                 else
931                         // Don't actually make a door
932                         roomplace -= doordir;
933
934         }
935 }
936 #endif
937
938 #if 0
939 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
940                 INodeDefManager *ndef)
941 {
942         v3s16 dir;
943         u8 facedir_i = 0;
944         s32 r = random.range(0, 3);
945         if(r == 0){
946                 dir = v3s16( 1, 0, 0);
947                 facedir_i = 3;
948         }
949         if(r == 1){
950                 dir = v3s16(-1, 0, 0);
951                 facedir_i = 1;
952         }
953         if(r == 2){
954                 dir = v3s16( 0, 0, 1);
955                 facedir_i = 2;
956         }
957         if(r == 3){
958                 dir = v3s16( 0, 0,-1);
959                 facedir_i = 0;
960         }
961         v3s16 p = vmanip.m_area.MinEdge + v3s16(
962                         16+random.range(0,15),
963                         16+random.range(0,15),
964                         16+random.range(0,15));
965         vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
966         u32 length = random.range(3,15);
967         for(u32 j=0; j<length; j++)
968         {
969                 p -= dir;
970                 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
971         }
972 }
973 #endif
974
975 /*
976         Noise functions. Make sure seed is mangled differently in each one.
977 */
978
979 #if 0
980 /*
981         Scaling the output of the noise function affects the overdrive of the
982         contour function, which affects the shape of the output considerably.
983 */
984 #define CAVE_NOISE_SCALE 12.0
985 //#define CAVE_NOISE_SCALE 10.0
986 //#define CAVE_NOISE_SCALE 7.5
987 //#define CAVE_NOISE_SCALE 5.0
988 //#define CAVE_NOISE_SCALE 1.0
989
990 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
991 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
992
993 NoiseParams get_cave_noise1_params(u64 seed)
994 {
995         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
996                         200, CAVE_NOISE_SCALE);*/
997         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
998                         100, CAVE_NOISE_SCALE);*/
999         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1000                         100, CAVE_NOISE_SCALE);*/
1001         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1002                         100, CAVE_NOISE_SCALE);*/
1003         return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1004                         50, CAVE_NOISE_SCALE);
1005         //return NoiseParams(NOISE_CONSTANT_ONE);
1006 }
1007
1008 NoiseParams get_cave_noise2_params(u64 seed)
1009 {
1010         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1011                         200, CAVE_NOISE_SCALE);*/
1012         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1013                         100, CAVE_NOISE_SCALE);*/
1014         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1015                         100, CAVE_NOISE_SCALE);*/
1016         return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1017                         50, CAVE_NOISE_SCALE);
1018         //return NoiseParams(NOISE_CONSTANT_ONE);
1019 }
1020
1021 NoiseParams get_ground_noise1_params(u64 seed)
1022 {
1023         return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1024                         0.55, 80.0, 40.0);
1025 }
1026
1027 NoiseParams get_ground_crumbleness_params(u64 seed)
1028 {
1029         return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1030                         1.3, 20.0, 1.0);
1031 }
1032
1033 NoiseParams get_ground_wetness_params(u64 seed)
1034 {
1035         return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1036                         1.1, 40.0, 1.0);
1037 }
1038
1039 bool is_cave(u64 seed, v3s16 p)
1040 {
1041         double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1042         double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1043         return d1*d2 > CAVE_NOISE_THRESHOLD;
1044 }
1045
1046 /*
1047         Ground density noise shall be interpreted by using this.
1048
1049         TODO: No perlin noises here, they should be outsourced
1050               and buffered
1051                   NOTE: The speed of these actually isn't terrible
1052 */
1053 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1054 {
1055         //return ((double)p.Y < ground_noise1_val);
1056
1057         double f = 0.55 + noise2d_perlin(
1058                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1059                         seed+920381, 3, 0.45);
1060         if(f < 0.01)
1061                 f = 0.01;
1062         else if(f >= 1.0)
1063                 f *= 1.6;
1064         double h = WATER_LEVEL + 10 * noise2d_perlin(
1065                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1066                         seed+84174, 4, 0.5);
1067         /*double f = 1;
1068         double h = 0;*/
1069         return ((double)p.Y - h < ground_noise1_val * f);
1070 }
1071
1072 /*
1073         Queries whether a position is ground or not.
1074 */
1075 bool is_ground(u64 seed, v3s16 p)
1076 {
1077         double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1078         return val_is_ground(val1, p, seed);
1079 }
1080 #endif
1081
1082 // Amount of trees per area in nodes
1083 double tree_amount_2d(u64 seed, v2s16 p)
1084 {
1085         /*double noise = noise2d_perlin(
1086                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1087                         seed+2, 5, 0.66);*/
1088         double noise = noise2d_perlin(
1089                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1090                         seed+2, 4, 0.66);
1091         double zeroval = -0.39;
1092         if(noise < zeroval)
1093                 return 0;
1094         else
1095                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1096 }
1097
1098 #if 0
1099 double surface_humidity_2d(u64 seed, v2s16 p)
1100 {
1101         double noise = noise2d_perlin(
1102                         0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1103                         seed+72384, 4, 0.66);
1104         noise = (noise + 1.0)/2.0;
1105         if(noise < 0.0)
1106                 noise = 0.0;
1107         if(noise > 1.0)
1108                 noise = 1.0;
1109         return noise;
1110 }
1111
1112 /*
1113         Incrementally find ground level from 3d noise
1114 */
1115 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1116 {
1117         // Start a bit fuzzy to make averaging lower precision values
1118         // more useful
1119         s16 level = myrand_range(-precision/2, precision/2);
1120         s16 dec[] = {31000, 100, 20, 4, 1, 0};
1121         s16 i;
1122         for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1123         {
1124                 // First find non-ground by going upwards
1125                 // Don't stop in caves.
1126                 {
1127                         s16 max = level+dec[i-1]*2;
1128                         v3s16 p(p2d.X, level, p2d.Y);
1129                         for(; p.Y < max; p.Y += dec[i])
1130                         {
1131                                 if(!is_ground(seed, p))
1132                                 {
1133                                         level = p.Y;
1134                                         break;
1135                                 }
1136                         }
1137                 }
1138                 // Then find ground by going downwards from there.
1139                 // Go in caves, too, when precision is 1.
1140                 {
1141                         s16 min = level-dec[i-1]*2;
1142                         v3s16 p(p2d.X, level, p2d.Y);
1143                         for(; p.Y>min; p.Y-=dec[i])
1144                         {
1145                                 bool ground = is_ground(seed, p);
1146                                 /*if(dec[i] == 1 && is_cave(seed, p))
1147                                         ground = false;*/
1148                                 if(ground)
1149                                 {
1150                                         level = p.Y;
1151                                         break;
1152                                 }
1153                         }
1154                 }
1155         }
1156
1157         // This is more like the actual ground level
1158         level += dec[i-1]/2;
1159
1160         return level;
1161 }
1162
1163 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1164
1165 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1166 {
1167         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1168         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1169         double a = 0;
1170         a += find_ground_level_from_noise(seed,
1171                         v2s16(node_min.X, node_min.Y), p);
1172         a += find_ground_level_from_noise(seed,
1173                         v2s16(node_min.X, node_max.Y), p);
1174         a += find_ground_level_from_noise(seed,
1175                         v2s16(node_max.X, node_max.Y), p);
1176         a += find_ground_level_from_noise(seed,
1177                         v2s16(node_max.X, node_min.Y), p);
1178         a += find_ground_level_from_noise(seed,
1179                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1180         a /= 5;
1181         return a;
1182 }
1183
1184 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1185
1186 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1187 {
1188         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1189         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1190         double a = -31000;
1191         // Corners
1192         a = MYMAX(a, find_ground_level_from_noise(seed,
1193                         v2s16(node_min.X, node_min.Y), p));
1194         a = MYMAX(a, find_ground_level_from_noise(seed,
1195                         v2s16(node_min.X, node_max.Y), p));
1196         a = MYMAX(a, find_ground_level_from_noise(seed,
1197                         v2s16(node_max.X, node_max.Y), p));
1198         a = MYMAX(a, find_ground_level_from_noise(seed,
1199                         v2s16(node_min.X, node_min.Y), p));
1200         // Center
1201         a = MYMAX(a, find_ground_level_from_noise(seed,
1202                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1203         // Side middle points
1204         a = MYMAX(a, find_ground_level_from_noise(seed,
1205                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1206         a = MYMAX(a, find_ground_level_from_noise(seed,
1207                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1208         a = MYMAX(a, find_ground_level_from_noise(seed,
1209                         v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1210         a = MYMAX(a, find_ground_level_from_noise(seed,
1211                         v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1212         return a;
1213 }
1214
1215 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1216
1217 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1218 {
1219         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1220         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1221         double a = 31000;
1222         // Corners
1223         a = MYMIN(a, find_ground_level_from_noise(seed,
1224                         v2s16(node_min.X, node_min.Y), p));
1225         a = MYMIN(a, find_ground_level_from_noise(seed,
1226                         v2s16(node_min.X, node_max.Y), p));
1227         a = MYMIN(a, find_ground_level_from_noise(seed,
1228                         v2s16(node_max.X, node_max.Y), p));
1229         a = MYMIN(a, find_ground_level_from_noise(seed,
1230                         v2s16(node_min.X, node_min.Y), p));
1231         // Center
1232         a = MYMIN(a, find_ground_level_from_noise(seed,
1233                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1234         // Side middle points
1235         a = MYMIN(a, find_ground_level_from_noise(seed,
1236                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1237         a = MYMIN(a, find_ground_level_from_noise(seed,
1238                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1239         a = MYMIN(a, find_ground_level_from_noise(seed,
1240                         v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1241         a = MYMIN(a, find_ground_level_from_noise(seed,
1242                         v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1243         return a;
1244 }
1245 #endif
1246
1247 // Required by mapgen.h
1248 bool block_is_underground(u64 seed, v3s16 blockpos)
1249 {
1250         /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1251                         seed, v2s16(blockpos.X, blockpos.Z));*/
1252         // Nah, this is just a heuristic, just return something
1253         s16 minimum_groundlevel = WATER_LEVEL;
1254
1255         if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1256                 return true;
1257         else
1258                 return false;
1259 }
1260
1261 #define AVERAGE_MUD_AMOUNT 4
1262
1263 double base_rock_level_2d(u64 seed, v2s16 p)
1264 {
1265         // The base ground level
1266         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1267                         + 20. * noise2d_perlin(
1268                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1269                         seed+82341, 5, 0.6);
1270
1271         /*// A bit hillier one
1272         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1273                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1274                         seed+93413, 6, 0.69);
1275         if(base2 > base)
1276                 base = base2;*/
1277 #if 1
1278         // Higher ground level
1279         double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1280                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1281                         seed+85039, 5, 0.6);
1282         //higher = 30; // For debugging
1283
1284         // Limit higher to at least base
1285         if(higher < base)
1286                 higher = base;
1287
1288         // Steepness factor of cliffs
1289         double b = 0.85 + 0.5 * noise2d_perlin(
1290                         0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1291                         seed-932, 5, 0.7);
1292         b = rangelim(b, 0.0, 1000.0);
1293         b = b*b*b*b*b*b*b;
1294         b *= 5;
1295         b = rangelim(b, 0.5, 1000.0);
1296         // Values 1.5...100 give quite horrible looking slopes
1297         if(b > 1.5 && b < 100.0){
1298                 if(b < 10.0)
1299                         b = 1.5;
1300                 else
1301                         b = 100.0;
1302         }
1303         //dstream<<"b="<<b<<std::endl;
1304         //double b = 20;
1305         //b = 0.25;
1306
1307         // Offset to more low
1308         double a_off = -0.20;
1309         // High/low selector
1310         /*double a = 0.5 + b * (a_off + noise2d_perlin(
1311                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1312                         seed+4213, 6, 0.7));*/
1313         double a = (double)0.5 + b * (a_off + noise2d_perlin(
1314                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1315                         seed+4213, 5, 0.69));
1316         // Limit
1317         a = rangelim(a, 0.0, 1.0);
1318
1319         //dstream<<"a="<<a<<std::endl;
1320
1321         double h = base*(1.0-a) + higher*a;
1322 #else
1323         double h = base;
1324 #endif
1325         return h;
1326 }
1327
1328 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1329 {
1330         return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1331 }
1332
1333 double get_mud_add_amount(u64 seed, v2s16 p)
1334 {
1335         return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1336                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1337                         seed+91013, 3, 0.55));
1338 }
1339
1340 bool get_have_beach(u64 seed, v2s16 p2d)
1341 {
1342         // Determine whether to have sand here
1343         double sandnoise = noise2d_perlin(
1344                         0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1345                         seed+59420, 3, 0.50);
1346
1347         return (sandnoise > 0.15);
1348 }
1349
1350 enum BiomeType
1351 {
1352         BT_NORMAL,
1353         BT_DESERT
1354 };
1355
1356 BiomeType get_biome(u64 seed, v2s16 p2d)
1357 {
1358         // Just do something very simple as for now
1359         double d = noise2d_perlin(
1360                         0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1361                         seed+9130, 3, 0.50);
1362         if(d > 0.45)
1363                 return BT_DESERT;
1364         if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0  )
1365                 return BT_DESERT;
1366         return BT_NORMAL;
1367 };
1368
1369 u32 get_blockseed(u64 seed, v3s16 p)
1370 {
1371         s32 x=p.X, y=p.Y, z=p.Z;
1372         return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1373 }
1374
1375 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1376
1377 void make_block(BlockMakeData *data)
1378 {
1379         if(data->no_op)
1380         {
1381                 //dstream<<"makeBlock: no-op"<<std::endl;
1382                 return;
1383         }
1384
1385         assert(data->vmanip);
1386         assert(data->nodedef);
1387         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1388                         data->blockpos_requested.Y >= data->blockpos_min.Y &&
1389                         data->blockpos_requested.Z >= data->blockpos_min.Z);
1390         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1391                         data->blockpos_requested.Y <= data->blockpos_max.Y &&
1392                         data->blockpos_requested.Z <= data->blockpos_max.Z);
1393
1394         INodeDefManager *ndef = data->nodedef;
1395
1396         // Hack: use minimum block coordinates for old code that assumes
1397         // a single block
1398         v3s16 blockpos = data->blockpos_requested;
1399
1400         /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1401                         <<blockpos.Z<<")"<<std::endl;*/
1402
1403         v3s16 blockpos_min = data->blockpos_min;
1404         v3s16 blockpos_max = data->blockpos_max;
1405         v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1406         v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1407
1408         ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1409         // Area of central chunk
1410         v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1411         v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1412         // Full allocated area
1413         v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1414         v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1415
1416         v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1417
1418         const s16 max_spread_amount = MAP_BLOCKSIZE;
1419
1420         int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1421                         * (blockpos_max.Y - blockpos_min.Y + 1)
1422                         * (blockpos_max.Z - blockpos_max.Z + 1);
1423
1424         int volume_nodes = volume_blocks *
1425                         MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1426
1427         // Generated surface area
1428         //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1429
1430         // Horribly wrong heuristic, but better than nothing
1431         bool block_is_underground = (WATER_LEVEL > node_max.Y);
1432
1433         /*
1434                 Create a block-specific seed
1435         */
1436         u32 blockseed = get_blockseed(data->seed, full_node_min);
1437
1438         /*
1439                 Cache some ground type values for speed
1440         */
1441
1442 // Creates variables c_name=id and n_name=node
1443 #define CONTENT_VARIABLE(ndef, name)\
1444         content_t c_##name = ndef->getId("mapgen_" #name);\
1445         MapNode n_##name(c_##name);
1446 // Default to something else if was CONTENT_IGNORE
1447 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1448         if(c_##name == CONTENT_IGNORE){\
1449                 c_##name = c_##dname;\
1450                 n_##name = n_##dname;\
1451         }
1452
1453         CONTENT_VARIABLE(ndef, stone);
1454         CONTENT_VARIABLE(ndef, air);
1455         CONTENT_VARIABLE(ndef, water_source);
1456         CONTENT_VARIABLE(ndef, dirt);
1457         CONTENT_VARIABLE(ndef, sand);
1458         CONTENT_VARIABLE(ndef, gravel);
1459         CONTENT_VARIABLE(ndef, clay);
1460         CONTENT_VARIABLE(ndef, lava_source);
1461         CONTENT_VARIABLE(ndef, cobble);
1462         CONTENT_VARIABLE(ndef, mossycobble);
1463         CONTENT_VARIABLE(ndef, dirt_with_grass);
1464         CONTENT_VARIABLE(ndef, junglegrass);
1465         CONTENT_VARIABLE(ndef, stone_with_coal);
1466         CONTENT_VARIABLE(ndef, stone_with_iron);
1467         CONTENT_VARIABLE(ndef, mese);
1468         CONTENT_VARIABLE(ndef, desert_sand);
1469         CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1470         CONTENT_VARIABLE(ndef, desert_stone);
1471         CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1472
1473         // Maximum height of the stone surface and obstacles.
1474         // This is used to guide the cave generation
1475         s16 stone_surface_max_y = 0;
1476
1477         /*
1478                 Generate general ground level to full area
1479         */
1480         {
1481 #if 1
1482         TimeTaker timer1("Generating ground level");
1483
1484         for(s16 x=node_min.X; x<=node_max.X; x++)
1485         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1486         {
1487                 // Node position
1488                 v2s16 p2d = v2s16(x,z);
1489
1490                 /*
1491                         Skip of already generated
1492                 */
1493                 /*{
1494                         v3s16 p(p2d.X, node_min.Y, p2d.Y);
1495                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1496                                 continue;
1497                 }*/
1498
1499                 // Ground height at this point
1500                 float surface_y_f = 0.0;
1501
1502                 // Use perlin noise for ground height
1503                 surface_y_f = base_rock_level_2d(data->seed, p2d);
1504
1505                 /*// Experimental stuff
1506                 {
1507                         float a = highlands_level_2d(data->seed, p2d);
1508                         if(a > surface_y_f)
1509                                 surface_y_f = a;
1510                 }*/
1511
1512                 // Convert to integer
1513                 s16 surface_y = (s16)surface_y_f;
1514
1515                 // Log it
1516                 if(surface_y > stone_surface_max_y)
1517                         stone_surface_max_y = surface_y;
1518
1519                 BiomeType bt = get_biome(data->seed, p2d);
1520                 /*
1521                         Fill ground with stone
1522                 */
1523                 {
1524                         // Use fast index incrementing
1525                         v3s16 em = vmanip.m_area.getExtent();
1526                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1527                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
1528                         {
1529                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1530                                         if(y <= surface_y){
1531                                                 if(y > WATER_LEVEL && bt == BT_DESERT)
1532                                                         vmanip.m_data[i] = n_desert_stone;
1533                                                 else
1534                                                         vmanip.m_data[i] = n_stone;
1535                                         } else if(y <= WATER_LEVEL){
1536                                                 vmanip.m_data[i] = MapNode(c_water_source);
1537                                         } else {
1538                                                 vmanip.m_data[i] = MapNode(c_air);
1539                                         }
1540                                 }
1541                                 vmanip.m_area.add_y(em, i, 1);
1542                         }
1543                 }
1544         }
1545 #endif
1546
1547         }//timer1
1548
1549         // Limit dirt flow area by 1 because mud is flown into neighbors.
1550         assert(central_area_size.X == central_area_size.Z);
1551         s16 mudflow_minpos = 0-max_spread_amount+1;
1552         s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1553
1554         /*
1555                 Loop this part, it will make stuff look older and newer nicely
1556         */
1557
1558         const u32 age_loops = 2;
1559         for(u32 i_age=0; i_age<age_loops; i_age++)
1560         { // Aging loop
1561         /******************************
1562                 BEGINNING OF AGING LOOP
1563         ******************************/
1564
1565 #if 1
1566         {
1567         // 24ms @cs=8
1568         //TimeTaker timer1("caves");
1569
1570         /*
1571                 Make caves (this code is relatively horrible)
1572         */
1573         double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1574                         0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1575                         data->seed+34329, 3, 0.50);
1576         cave_amount = MYMAX(0.0, cave_amount);
1577         u32 caves_count = cave_amount * volume_nodes / 50000;
1578         u32 bruises_count = 1;
1579         PseudoRandom ps(blockseed+21343);
1580         PseudoRandom ps2(blockseed+1032);
1581         if(ps.range(1, 6) == 1)
1582                 bruises_count = ps.range(0, ps.range(0, 2));
1583         if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1584                 caves_count /= 3;
1585                 bruises_count /= 3;
1586         }
1587         for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1588         {
1589                 bool large_cave = (jj >= caves_count);
1590                 s16 min_tunnel_diameter = 2;
1591                 s16 max_tunnel_diameter = ps.range(2,6);
1592                 int dswitchint = ps.range(1,14);
1593                 u16 tunnel_routepoints = 0;
1594                 int part_max_length_rs = 0;
1595                 if(large_cave){
1596                         part_max_length_rs = ps.range(2,4);
1597                         tunnel_routepoints = ps.range(5, ps.range(15,30));
1598                         min_tunnel_diameter = 5;
1599                         max_tunnel_diameter = ps.range(7, ps.range(8,24));
1600                 } else {
1601                         part_max_length_rs = ps.range(2,9);
1602                         tunnel_routepoints = ps.range(10, ps.range(15,30));
1603                 }
1604                 bool large_cave_is_flat = (ps.range(0,1) == 0);
1605
1606                 v3f main_direction(0,0,0);
1607
1608                 // Allowed route area size in nodes
1609                 v3s16 ar = central_area_size;
1610
1611                 // Area starting point in nodes
1612                 v3s16 of = node_min;
1613
1614                 // Allow a bit more
1615                 //(this should be more than the maximum radius of the tunnel)
1616                 //s16 insure = 5; // Didn't work with max_d = 20
1617                 s16 insure = 10;
1618                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1619                 ar += v3s16(1,0,1) * more * 2;
1620                 of -= v3s16(1,0,1) * more;
1621
1622                 s16 route_y_min = 0;
1623                 // Allow half a diameter + 7 over stone surface
1624                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1625
1626                 /*// If caves, don't go through surface too often
1627                 if(large_cave == false)
1628                         route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1629
1630                 // Limit maximum to area
1631                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1632
1633                 if(large_cave)
1634                 {
1635                         /*// Minimum is at y=0
1636                         route_y_min = -of.Y - 0;*/
1637                         // Minimum is at y=max_tunnel_diameter/4
1638                         //route_y_min = -of.Y + max_tunnel_diameter/4;
1639                         //s16 min = -of.Y + max_tunnel_diameter/4;
1640                         //s16 min = -of.Y + 0;
1641                         s16 min = 0;
1642                         if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1643                         {
1644                                 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1645                                 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1646                         }
1647                         route_y_min = ps.range(min, min + max_tunnel_diameter);
1648                         route_y_min = rangelim(route_y_min, 0, route_y_max);
1649                 }
1650
1651                 /*dstream<<"route_y_min = "<<route_y_min
1652                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
1653
1654                 s16 route_start_y_min = route_y_min;
1655                 s16 route_start_y_max = route_y_max;
1656
1657                 // Start every 4th cave from surface when applicable
1658                 /*bool coming_from_surface = false;
1659                 if(node_min.Y <= 0 && node_max.Y >= 0){
1660                         coming_from_surface = (jj % 4 == 0 && large_cave == false);
1661                         if(coming_from_surface)
1662                                 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1663                 }*/
1664
1665                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1666                 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1667
1668                 // Randomize starting position
1669                 v3f orp(
1670                         (float)(ps.next()%ar.X)+0.5,
1671                         (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1672                         (float)(ps.next()%ar.Z)+0.5
1673                 );
1674
1675                 v3s16 startp(orp.X, orp.Y, orp.Z);
1676                 startp += of;
1677
1678                 MapNode airnode(CONTENT_AIR);
1679                 MapNode waternode(c_water_source);
1680                 MapNode lavanode(c_lava_source);
1681
1682                 /*
1683                         Generate some tunnel starting from orp
1684                 */
1685
1686                 for(u16 j=0; j<tunnel_routepoints; j++)
1687                 {
1688                         if(j%dswitchint==0 && large_cave == false)
1689                         {
1690                                 main_direction = v3f(
1691                                         ((float)(ps.next()%20)-(float)10)/10,
1692                                         ((float)(ps.next()%20)-(float)10)/30,
1693                                         ((float)(ps.next()%20)-(float)10)/10
1694                                 );
1695                                 main_direction *= (float)ps.range(0, 10)/10;
1696                         }
1697
1698                         // Randomize size
1699                         s16 min_d = min_tunnel_diameter;
1700                         s16 max_d = max_tunnel_diameter;
1701                         s16 rs = ps.range(min_d, max_d);
1702
1703                         // Every second section is rough
1704                         bool randomize_xz = (ps2.range(1,2) == 1);
1705
1706                         v3s16 maxlen;
1707                         if(large_cave)
1708                         {
1709                                 maxlen = v3s16(
1710                                         rs*part_max_length_rs,
1711                                         rs*part_max_length_rs/2,
1712                                         rs*part_max_length_rs
1713                                 );
1714                         }
1715                         else
1716                         {
1717                                 maxlen = v3s16(
1718                                         rs*part_max_length_rs,
1719                                         ps.range(1, rs*part_max_length_rs),
1720                                         rs*part_max_length_rs
1721                                 );
1722                         }
1723
1724                         v3f vec;
1725
1726                         vec = v3f(
1727                                 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1728                                 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1729                                 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1730                         );
1731
1732                         // Jump downward sometimes
1733                         if(!large_cave && ps.range(0,12) == 0)
1734                         {
1735                                 vec = v3f(
1736                                         (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1737                                         (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1738                                         (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1739                                 );
1740                         }
1741
1742                         /*if(large_cave){
1743                                 v3f p = orp + vec;
1744                                 s16 h = find_ground_level_clever(vmanip,
1745                                                 v2s16(p.X, p.Z), ndef);
1746                                 route_y_min = h - rs/3;
1747                                 route_y_max = h + rs;
1748                         }*/
1749
1750                         vec += main_direction;
1751
1752                         v3f rp = orp + vec;
1753                         if(rp.X < 0)
1754                                 rp.X = 0;
1755                         else if(rp.X >= ar.X)
1756                                 rp.X = ar.X-1;
1757                         if(rp.Y < route_y_min)
1758                                 rp.Y = route_y_min;
1759                         else if(rp.Y >= route_y_max)
1760                                 rp.Y = route_y_max-1;
1761                         if(rp.Z < 0)
1762                                 rp.Z = 0;
1763                         else if(rp.Z >= ar.Z)
1764                                 rp.Z = ar.Z-1;
1765                         vec = rp - orp;
1766
1767                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
1768                         {
1769                                 v3f fp = orp + vec * f;
1770                                 fp.X += 0.1*ps.range(-10,10);
1771                                 fp.Z += 0.1*ps.range(-10,10);
1772                                 v3s16 cp(fp.X, fp.Y, fp.Z);
1773
1774                                 s16 d0 = -rs/2;
1775                                 s16 d1 = d0 + rs;
1776                                 if(randomize_xz){
1777                                         d0 += ps.range(-1,1);
1778                                         d1 += ps.range(-1,1);
1779                                 }
1780                                 for(s16 z0=d0; z0<=d1; z0++)
1781                                 {
1782                                         s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1783                                         for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1784                                         {
1785                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1786                                                 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1787                                                 for(s16 y0=-si2; y0<=si2; y0++)
1788                                                 {
1789                                                         /*// Make better floors in small caves
1790                                                         if(y0 <= -rs/2 && rs<=7)
1791                                                                 continue;*/
1792                                                         if(large_cave_is_flat){
1793                                                                 // Make large caves not so tall
1794                                                                 if(rs > 7 && abs(y0) >= rs/3)
1795                                                                         continue;
1796                                                         }
1797
1798                                                         s16 z = cp.Z + z0;
1799                                                         s16 y = cp.Y + y0;
1800                                                         s16 x = cp.X + x0;
1801                                                         v3s16 p(x,y,z);
1802                                                         p += of;
1803
1804                                                         if(vmanip.m_area.contains(p) == false)
1805                                                                 continue;
1806
1807                                                         u32 i = vmanip.m_area.index(p);
1808
1809                                                         if(large_cave)
1810                                                         {
1811                                                                 if(full_node_min.Y < WATER_LEVEL &&
1812                                                                         full_node_max.Y > WATER_LEVEL){
1813                                                                         if(p.Y <= WATER_LEVEL)
1814                                                                                 vmanip.m_data[i] = waternode;
1815                                                                         else
1816                                                                                 vmanip.m_data[i] = airnode;
1817                                                                 } else if(full_node_max.Y < WATER_LEVEL){
1818                                                                         if(p.Y < startp.Y - 2)
1819                                                                                 vmanip.m_data[i] = lavanode;
1820                                                                         else
1821                                                                                 vmanip.m_data[i] = airnode;
1822                                                                 } else {
1823                                                                         vmanip.m_data[i] = airnode;
1824                                                                 }
1825                                                         } else {
1826                                                                 // Don't replace air or water or lava or ignore
1827                                                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1828                                                                 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1829                                                                 vmanip.m_data[i].getContent() == c_water_source ||
1830                                                                 vmanip.m_data[i].getContent() == c_lava_source)
1831                                                                         continue;
1832
1833                                                                 vmanip.m_data[i] = airnode;
1834
1835                                                                 // Set tunnel flag
1836                                                                 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1837                                                         }
1838                                                 }
1839                                         }
1840                                 }
1841                         }
1842
1843                         orp = rp;
1844                 }
1845
1846         }
1847
1848         }//timer1
1849 #endif
1850
1851 #if 1
1852         {
1853         // 15ms @cs=8
1854         TimeTaker timer1("add mud");
1855
1856         /*
1857                 Add mud to the central chunk
1858         */
1859
1860         for(s16 x=node_min.X; x<=node_max.X; x++)
1861         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1862         {
1863                 // Node position in 2d
1864                 v2s16 p2d = v2s16(x,z);
1865
1866                 // Randomize mud amount
1867                 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1868
1869                 // Find ground level
1870                 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1871                 // Handle area not found
1872                 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1873                         continue;
1874
1875                 MapNode addnode(c_dirt);
1876                 BiomeType bt = get_biome(data->seed, p2d);
1877
1878                 if(bt == BT_DESERT)
1879                         addnode = MapNode(c_desert_sand);
1880
1881                 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1882                         addnode = MapNode(c_sand);
1883                 } else if(mud_add_amount <= 0){
1884                         mud_add_amount = 1 - mud_add_amount;
1885                         addnode = MapNode(c_gravel);
1886                 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1887                                 surface_y + mud_add_amount <= WATER_LEVEL+2){
1888                         addnode = MapNode(c_sand);
1889                 }
1890
1891                 if(bt == BT_DESERT){
1892                         if(surface_y > 20){
1893                                 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1894                         }
1895                 }
1896
1897                 /*
1898                         If topmost node is grass, change it to mud.
1899                         It might be if it was flown to there from a neighboring
1900                         chunk and then converted.
1901                 */
1902                 {
1903                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1904                         MapNode *n = &vmanip.m_data[i];
1905                         if(n->getContent() == c_dirt_with_grass)
1906                                 *n = MapNode(c_dirt);
1907                 }
1908
1909                 /*
1910                         Add mud on ground
1911                 */
1912                 {
1913                         s16 mudcount = 0;
1914                         v3s16 em = vmanip.m_area.getExtent();
1915                         s16 y_start = surface_y+1;
1916                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1917                         for(s16 y=y_start; y<=node_max.Y; y++)
1918                         {
1919                                 if(mudcount >= mud_add_amount)
1920                                         break;
1921
1922                                 MapNode &n = vmanip.m_data[i];
1923                                 n = addnode;
1924                                 mudcount++;
1925
1926                                 vmanip.m_area.add_y(em, i, 1);
1927                         }
1928                 }
1929
1930         }
1931
1932         }//timer1
1933 #endif
1934
1935         /*
1936                 Add blobs of dirt and gravel underground
1937         */
1938         if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1939         {
1940         PseudoRandom pr(blockseed+983);
1941         for(int i=0; i<volume_nodes/10/10/10; i++)
1942         {
1943                 bool only_fill_cave = (myrand_range(0,1) != 0);
1944                 v3s16 size(
1945                         pr.range(1, 8),
1946                         pr.range(1, 8),
1947                         pr.range(1, 8)
1948                 );
1949                 v3s16 p0(
1950                         pr.range(node_min.X, node_max.X)-size.X/2,
1951                         pr.range(node_min.Y, node_max.Y)-size.Y/2,
1952                         pr.range(node_min.Z, node_max.Z)-size.Z/2
1953                 );
1954                 MapNode n1;
1955                 if(p0.Y > -32 && pr.range(0,1) == 0)
1956                         n1 = MapNode(c_dirt);
1957                 else
1958                         n1 = MapNode(c_gravel);
1959                 for(int x1=0; x1<size.X; x1++)
1960                 for(int y1=0; y1<size.Y; y1++)
1961                 for(int z1=0; z1<size.Z; z1++)
1962                 {
1963                         v3s16 p = p0 + v3s16(x1,y1,z1);
1964                         u32 i = vmanip.m_area.index(p);
1965                         if(!vmanip.m_area.contains(i))
1966                                 continue;
1967                         // Cancel if not stone and not cave air
1968                         if(vmanip.m_data[i].getContent() != c_stone &&
1969                                         !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1970                                 continue;
1971                         if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1972                                 continue;
1973                         vmanip.m_data[i] = n1;
1974                 }
1975         }
1976         }
1977
1978 #if 1
1979         {
1980         // 340ms @cs=8
1981         TimeTaker timer1("flow mud");
1982
1983         /*
1984                 Flow mud away from steep edges
1985         */
1986
1987         // Iterate a few times
1988         for(s16 k=0; k<3; k++)
1989         {
1990
1991         for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1992         for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1993         {
1994                 // Invert coordinates every 2nd iteration
1995                 if(k%2 == 0)
1996                 {
1997                         x = mudflow_maxpos - (x-mudflow_minpos);
1998                         z = mudflow_maxpos - (z-mudflow_minpos);
1999                 }
2000
2001                 // Node position in 2d
2002                 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
2003
2004                 v3s16 em = vmanip.m_area.getExtent();
2005                 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2006                 s16 y=node_max.Y;
2007
2008                 while(y >= node_min.Y)
2009                 {
2010
2011                 for(;; y--)
2012                 {
2013                         MapNode *n = NULL;
2014                         // Find mud
2015                         for(; y>=node_min.Y; y--)
2016                         {
2017                                 n = &vmanip.m_data[i];
2018                                 //if(content_walkable(n->d))
2019                                 //      break;
2020                                 if(n->getContent() == c_dirt ||
2021                                                 n->getContent() == c_dirt_with_grass ||
2022                                                 n->getContent() == c_gravel)
2023                                         break;
2024
2025                                 vmanip.m_area.add_y(em, i, -1);
2026                         }
2027
2028                         // Stop if out of area
2029                         //if(vmanip.m_area.contains(i) == false)
2030                         if(y < node_min.Y)
2031                                 break;
2032
2033                         /*// If not mud, do nothing to it
2034                         MapNode *n = &vmanip.m_data[i];
2035                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2036                                 continue;*/
2037
2038                         if(n->getContent() == c_dirt ||
2039                                         n->getContent() == c_dirt_with_grass)
2040                         {
2041                                 // Make it exactly mud
2042                                 n->setContent(c_dirt);
2043
2044                                 /*
2045                                         Don't flow it if the stuff under it is not mud
2046                                 */
2047                                 {
2048                                         u32 i2 = i;
2049                                         vmanip.m_area.add_y(em, i2, -1);
2050                                         // Cancel if out of area
2051                                         if(vmanip.m_area.contains(i2) == false)
2052                                                 continue;
2053                                         MapNode *n2 = &vmanip.m_data[i2];
2054                                         if(n2->getContent() != c_dirt &&
2055                                                         n2->getContent() != c_dirt_with_grass)
2056                                                 continue;
2057                                 }
2058                         }
2059
2060                         /*s16 recurse_count = 0;
2061         mudflow_recurse:*/
2062
2063                         v3s16 dirs4[4] = {
2064                                 v3s16(0,0,1), // back
2065                                 v3s16(1,0,0), // right
2066                                 v3s16(0,0,-1), // front
2067                                 v3s16(-1,0,0), // left
2068                         };
2069
2070                         // Theck that upper is air or doesn't exist.
2071                         // Cancel dropping if upper keeps it in place
2072                         u32 i3 = i;
2073                         vmanip.m_area.add_y(em, i3, 1);
2074                         if(vmanip.m_area.contains(i3) == true
2075                                         && ndef->get(vmanip.m_data[i3]).walkable)
2076                         {
2077                                 continue;
2078                         }
2079
2080                         // Drop mud on side
2081
2082                         for(u32 di=0; di<4; di++)
2083                         {
2084                                 v3s16 dirp = dirs4[di];
2085                                 u32 i2 = i;
2086                                 // Move to side
2087                                 vmanip.m_area.add_p(em, i2, dirp);
2088                                 // Fail if out of area
2089                                 if(vmanip.m_area.contains(i2) == false)
2090                                         continue;
2091                                 // Check that side is air
2092                                 MapNode *n2 = &vmanip.m_data[i2];
2093                                 if(ndef->get(*n2).walkable)
2094                                         continue;
2095                                 // Check that under side is air
2096                                 vmanip.m_area.add_y(em, i2, -1);
2097                                 if(vmanip.m_area.contains(i2) == false)
2098                                         continue;
2099                                 n2 = &vmanip.m_data[i2];
2100                                 if(ndef->get(*n2).walkable)
2101                                         continue;
2102                                 /*// Check that under that is air (need a drop of 2)
2103                                 vmanip.m_area.add_y(em, i2, -1);
2104                                 if(vmanip.m_area.contains(i2) == false)
2105                                         continue;
2106                                 n2 = &vmanip.m_data[i2];
2107                                 if(content_walkable(n2->d))
2108                                         continue;*/
2109                                 // Loop further down until not air
2110                                 bool dropped_to_unknown = false;
2111                                 do{
2112                                         vmanip.m_area.add_y(em, i2, -1);
2113                                         n2 = &vmanip.m_data[i2];
2114                                         // if out of known area
2115                                         if(vmanip.m_area.contains(i2) == false
2116                                                         || n2->getContent() == CONTENT_IGNORE){
2117                                                 dropped_to_unknown = true;
2118                                                 break;
2119                                         }
2120                                 }while(ndef->get(*n2).walkable == false);
2121                                 // Loop one up so that we're in air
2122                                 vmanip.m_area.add_y(em, i2, 1);
2123                                 n2 = &vmanip.m_data[i2];
2124
2125                                 bool old_is_water = (n->getContent() == c_water_source);
2126                                 // Move mud to new place
2127                                 if(!dropped_to_unknown) {
2128                                         *n2 = *n;
2129                                         // Set old place to be air (or water)
2130                                         if(old_is_water)
2131                                                 *n = MapNode(c_water_source);
2132                                         else
2133                                                 *n = MapNode(CONTENT_AIR);
2134                                 }
2135
2136                                 // Done
2137                                 break;
2138                         }
2139                 }
2140                 }
2141         }
2142
2143         }
2144
2145         }//timer1
2146 #endif
2147
2148         } // Aging loop
2149         /***********************
2150                 END OF AGING LOOP
2151         ************************/
2152
2153         /*
2154                 Add top and bottom side of water to transforming_liquid queue
2155         */
2156
2157         for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2158         for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2159         {
2160                 // Node position
2161                 v2s16 p2d(x,z);
2162                 {
2163                         bool water_found = false;
2164                         // Use fast index incrementing
2165                         v3s16 em = vmanip.m_area.getExtent();
2166                         u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2167                         for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2168                         {
2169                                 if(y == full_node_max.Y){
2170                                         water_found =
2171                                                 (vmanip.m_data[i].getContent() == c_water_source ||
2172                                                 vmanip.m_data[i].getContent() == c_lava_source);
2173                                 }
2174                                 else if(water_found == false)
2175                                 {
2176                                         if(vmanip.m_data[i].getContent() == c_water_source ||
2177                                                         vmanip.m_data[i].getContent() == c_lava_source)
2178                                         {
2179                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2180                                                 data->transforming_liquid.push_back(p);
2181                                                 water_found = true;
2182                                         }
2183                                 }
2184                                 else
2185                                 {
2186                                         // This can be done because water_found can only
2187                                         // turn to true and end up here after going through
2188                                         // a single block.
2189                                         if(vmanip.m_data[i+1].getContent() != c_water_source ||
2190                                                         vmanip.m_data[i+1].getContent() != c_lava_source)
2191                                         {
2192                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2193                                                 data->transforming_liquid.push_back(p);
2194                                                 water_found = false;
2195                                         }
2196                                 }
2197
2198                                 vmanip.m_area.add_y(em, i, -1);
2199                         }
2200                 }
2201         }
2202
2203         /*
2204                 Grow grass
2205         */
2206
2207         for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2208         for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2209         {
2210                 // Node position in 2d
2211                 v2s16 p2d = v2s16(x,z);
2212
2213                 /*
2214                         Find the lowest surface to which enough light ends up
2215                         to make grass grow.
2216
2217                         Basically just wait until not air and not leaves.
2218                 */
2219                 s16 surface_y = 0;
2220                 {
2221                         v3s16 em = vmanip.m_area.getExtent();
2222                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2223                         s16 y;
2224                         // Go to ground level
2225                         for(y=node_max.Y; y>=full_node_min.Y; y--)
2226                         {
2227                                 MapNode &n = vmanip.m_data[i];
2228                                 if(ndef->get(n).param_type != CPT_LIGHT
2229                                                 || ndef->get(n).liquid_type != LIQUID_NONE)
2230                                         break;
2231                                 vmanip.m_area.add_y(em, i, -1);
2232                         }
2233                         if(y >= full_node_min.Y)
2234                                 surface_y = y;
2235                         else
2236                                 surface_y = full_node_min.Y;
2237                 }
2238
2239                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2240                 MapNode *n = &vmanip.m_data[i];
2241                 if(n->getContent() == c_dirt){
2242                         // Well yeah, this can't be overground...
2243                         if(surface_y < WATER_LEVEL - 20)
2244                                 continue;
2245                         n->setContent(c_dirt_with_grass);
2246                 }
2247         }
2248
2249         /*
2250                 Generate some trees
2251         */
2252         assert(central_area_size.X == central_area_size.Z);
2253         {
2254                 // Divide area into parts
2255                 s16 div = 8;
2256                 s16 sidelen = central_area_size.X / div;
2257                 double area = sidelen * sidelen;
2258                 for(s16 x0=0; x0<div; x0++)
2259                 for(s16 z0=0; z0<div; z0++)
2260                 {
2261                         // Center position of part of division
2262                         v2s16 p2d_center(
2263                                 node_min.X + sidelen/2 + sidelen*x0,
2264                                 node_min.Z + sidelen/2 + sidelen*z0
2265                         );
2266                         // Minimum edge of part of division
2267                         v2s16 p2d_min(
2268                                 node_min.X + sidelen*x0,
2269                                 node_min.Z + sidelen*z0
2270                         );
2271                         // Maximum edge of part of division
2272                         v2s16 p2d_max(
2273                                 node_min.X + sidelen + sidelen*x0 - 1,
2274                                 node_min.Z + sidelen + sidelen*z0 - 1
2275                         );
2276                         // Amount of trees
2277                         u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2278                         // Put trees in random places on part of division
2279                         for(u32 i=0; i<tree_count; i++)
2280                         {
2281                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2282                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2283                                 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2284                                 // Don't make a tree under water level
2285                                 if(y < WATER_LEVEL)
2286                                         continue;
2287                                 // Don't make a tree so high that it doesn't fit
2288                                 if(y > node_max.Y - 6)
2289                                         continue;
2290                                 v3s16 p(x,y,z);
2291                                 /*
2292                                         Trees grow only on mud and grass
2293                                 */
2294                                 {
2295                                         u32 i = vmanip.m_area.index(v3s16(p));
2296                                         MapNode *n = &vmanip.m_data[i];
2297                                         if(n->getContent() != c_dirt
2298                                                         && n->getContent() != c_dirt_with_grass)
2299                                                 continue;
2300                                 }
2301                                 p.Y++;
2302                                 // Make a tree
2303                                 treegen::make_tree(vmanip, p, false, ndef);
2304                         }
2305                 }
2306         }
2307
2308 #if 0
2309         /*
2310                 Make base ground level
2311         */
2312
2313         for(s16 x=node_min.X; x<=node_max.X; x++)
2314         for(s16 z=node_min.Z; z<=node_max.Z; z++)
2315         {
2316                 // Node position
2317                 v2s16 p2d(x,z);
2318                 {
2319                         // Use fast index incrementing
2320                         v3s16 em = vmanip.m_area.getExtent();
2321                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2322                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
2323                         {
2324                                 // Only modify places that have no content
2325                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2326                                 {
2327                                         // First priority: make air and water.
2328                                         // This avoids caves inside water.
2329                                         if(all_is_ground_except_caves == false
2330                                                         && val_is_ground(noisebuf_ground.get(x,y,z),
2331                                                         v3s16(x,y,z), data->seed) == false)
2332                                         {
2333                                                 if(y <= WATER_LEVEL)
2334                                                         vmanip.m_data[i] = n_water_source;
2335                                                 else
2336                                                         vmanip.m_data[i] = n_air;
2337                                         }
2338                                         else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2339                                                 vmanip.m_data[i] = n_air;
2340                                         else
2341                                                 vmanip.m_data[i] = n_stone;
2342                                 }
2343
2344                                 vmanip->m_area.add_y(em, i, 1);
2345                         }
2346                 }
2347         }
2348
2349         /*
2350                 Add mud and sand and others underground (in place of stone)
2351         */
2352
2353         for(s16 x=node_min.X; x<=node_max.X; x++)
2354         for(s16 z=node_min.Z; z<=node_max.Z; z++)
2355         {
2356                 // Node position
2357                 v2s16 p2d(x,z);
2358                 {
2359                         // Use fast index incrementing
2360                         v3s16 em = vmanip.m_area.getExtent();
2361                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2362                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
2363                         {
2364                                 if(vmanip.m_data[i].getContent() == c_stone)
2365                                 {
2366                                         if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2367                                         {
2368                                                 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2369                                                         vmanip.m_data[i] = n_dirt;
2370                                                 else
2371                                                         vmanip.m_data[i] = n_sand;
2372                                         }
2373                                         else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2374                                         {
2375                                                 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2376                                                         vmanip.m_data[i] = n_gravel;
2377                                         }
2378                                         else if(noisebuf_ground_crumbleness.get(x,y,z) <
2379                                                         -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2380                                         {
2381                                                 vmanip.m_data[i] = n_lava_source;
2382                                                 for(s16 x1=-1; x1<=1; x1++)
2383                                                 for(s16 y1=-1; y1<=1; y1++)
2384                                                 for(s16 z1=-1; z1<=1; z1++)
2385                                                         data->transforming_liquid.push_back(
2386                                                                         v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2387                                         }
2388                                 }
2389
2390                                 vmanip->m_area.add_y(em, i, -1);
2391                         }
2392                 }
2393         }
2394
2395         /*
2396                 Add dungeons
2397         */
2398
2399         //if(node_min.Y < approx_groundlevel)
2400         //if(myrand() % 3 == 0)
2401         //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2402         //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2403         //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2404         float dungeon_rarity = 0.02;
2405         if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2406                         < dungeon_rarity
2407                         && node_min.Y < approx_groundlevel)
2408         {
2409                 // Dungeon generator doesn't modify places which have this set
2410                 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2411                                 | VMANIP_FLAG_DUNGEON_PRESERVE);
2412
2413                 // Set all air and water to be untouchable to make dungeons open
2414                 // to caves and open air
2415                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2416                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2417                 {
2418                         // Node position
2419                         v2s16 p2d(x,z);
2420                         {
2421                                 // Use fast index incrementing
2422                                 v3s16 em = vmanip.m_area.getExtent();
2423                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2424                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2425                                 {
2426                                         if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2427                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2428                                         else if(vmanip.m_data[i].getContent() == c_water_source)
2429                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2430                                         vmanip->m_area.add_y(em, i, -1);
2431                                 }
2432                         }
2433                 }
2434
2435                 PseudoRandom random(blockseed+2);
2436
2437                 // Add it
2438                 make_dungeon1(vmanip, random, ndef);
2439
2440                 // Convert some cobble to mossy cobble
2441                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2442                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2443                 {
2444                         // Node position
2445                         v2s16 p2d(x,z);
2446                         {
2447                                 // Use fast index incrementing
2448                                 v3s16 em = vmanip.m_area.getExtent();
2449                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2450                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2451                                 {
2452                                         // (noisebuf not used because it doesn't contain the
2453                                         //  full area)
2454                                         double wetness = noise3d_param(
2455                                                         get_ground_wetness_params(data->seed), x,y,z);
2456                                         double d = noise3d_perlin((float)x/2.5,
2457                                                         (float)y/2.5,(float)z/2.5,
2458                                                         blockseed, 2, 1.4);
2459                                         if(vmanip.m_data[i].getContent() == c_cobble)
2460                                         {
2461                                                 if(d < wetness/3.0)
2462                                                 {
2463                                                         vmanip.m_data[i].setContent(c_mossycobble);
2464                                                 }
2465                                         }
2466                                         /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2467                                         {
2468                                                 if(wetness > 1.2)
2469                                                         vmanip.m_data[i].setContent(c_dirt);
2470                                         }*/
2471                                         vmanip->m_area.add_y(em, i, -1);
2472                                 }
2473                         }
2474                 }
2475         }
2476
2477         /*
2478                 Add NC
2479         */
2480         {
2481                 PseudoRandom ncrandom(blockseed+9324342);
2482                 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2483                 {
2484                         make_nc(vmanip, ncrandom, ndef);
2485                 }
2486         }
2487
2488         /*
2489                 Add top and bottom side of water to transforming_liquid queue
2490         */
2491
2492         for(s16 x=node_min.X; x<=node_max.X; x++)
2493         for(s16 z=node_min.Z; z<=node_max.Z; z++)
2494         {
2495                 // Node position
2496                 v2s16 p2d(x,z);
2497                 {
2498                         bool water_found = false;
2499                         // Use fast index incrementing
2500                         v3s16 em = vmanip.m_area.getExtent();
2501                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2502                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
2503                         {
2504                                 if(water_found == false)
2505                                 {
2506                                         if(vmanip.m_data[i].getContent() == c_water_source)
2507                                         {
2508                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2509                                                 data->transforming_liquid.push_back(p);
2510                                                 water_found = true;
2511                                         }
2512                                 }
2513                                 else
2514                                 {
2515                                         // This can be done because water_found can only
2516                                         // turn to true and end up here after going through
2517                                         // a single block.
2518                                         if(vmanip.m_data[i+1].getContent() != c_water_source)
2519                                         {
2520                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2521                                                 data->transforming_liquid.push_back(p);
2522                                                 water_found = false;
2523                                         }
2524                                 }
2525
2526                                 vmanip->m_area.add_y(em, i, -1);
2527                         }
2528                 }
2529         }
2530
2531         /*
2532                 If close to ground level
2533         */
2534
2535         //if(abs(approx_ground_depth) < 30)
2536         if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2537         {
2538                 /*
2539                         Add grass and mud
2540                 */
2541
2542                 for(s16 x=node_min.X; x<=node_max.X; x++)
2543                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2544                 {
2545                         // Node position
2546                         v2s16 p2d(x,z);
2547                         {
2548                                 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2549                                 bool have_sand = false;
2550                                 u32 current_depth = 0;
2551                                 bool air_detected = false;
2552                                 bool water_detected = false;
2553                                 bool have_clay = false;
2554
2555                                 // Use fast index incrementing
2556                                 s16 start_y = node_max.Y+2;
2557                                 v3s16 em = vmanip.m_area.getExtent();
2558                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2559                                 for(s16 y=start_y; y>=node_min.Y-3; y--)
2560                                 {
2561                                         if(vmanip.m_data[i].getContent() == c_water_source)
2562                                                 water_detected = true;
2563                                         if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2564                                                 air_detected = true;
2565
2566                                         if((vmanip.m_data[i].getContent() == c_stone
2567                                                         || vmanip.m_data[i].getContent() == c_dirt_with_grass
2568                                                         || vmanip.m_data[i].getContent() == c_dirt
2569                                                         || vmanip.m_data[i].getContent() == c_sand
2570                                                         || vmanip.m_data[i].getContent() == c_gravel
2571                                                         ) && (air_detected || water_detected))
2572                                         {
2573                                                 if(current_depth == 0 && y <= WATER_LEVEL+2
2574                                                                 && possibly_have_sand)
2575                                                         have_sand = true;
2576
2577                                                 if(current_depth < 4)
2578                                                 {
2579                                                         if(have_sand)
2580                                                         {
2581                                                                 vmanip.m_data[i] = MapNode(c_sand);
2582                                                         }
2583                                                         #if 1
2584                                                         else if(current_depth==0 && !water_detected
2585                                                                         && y >= WATER_LEVEL && air_detected)
2586                                                                 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2587                                                         #endif
2588                                                         else
2589                                                                 vmanip.m_data[i] = MapNode(c_dirt);
2590                                                 }
2591                                                 else
2592                                                 {
2593                                                         if(vmanip.m_data[i].getContent() == c_dirt
2594                                                                 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2595                                                                 vmanip.m_data[i] = MapNode(c_stone);
2596                                                 }
2597
2598                                                 current_depth++;
2599
2600                                                 if(current_depth >= 8)
2601                                                         break;
2602                                         }
2603                                         else if(current_depth != 0)
2604                                                 break;
2605
2606                                         vmanip->m_area.add_y(em, i, -1);
2607                                 }
2608                         }
2609                 }
2610
2611                 /*
2612                         Calculate some stuff
2613                 */
2614
2615                 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2616                 bool is_jungle = surface_humidity > 0.75;
2617                 // Amount of trees
2618                 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2619                 if(is_jungle)
2620                         tree_count *= 5;
2621
2622                 /*
2623                         Add trees
2624                 */
2625                 PseudoRandom treerandom(blockseed);
2626                 // Put trees in random places on part of division
2627                 for(u32 i=0; i<tree_count; i++)
2628                 {
2629                         s16 x = treerandom.range(node_min.X, node_max.X);
2630                         s16 z = treerandom.range(node_min.Z, node_max.Z);
2631                         //s16 y = find_ground_level(vmanip, v2s16(x,z));
2632                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2633                         // Don't make a tree under water level
2634                         if(y < WATER_LEVEL)
2635                                 continue;
2636                         // Make sure tree fits (only trees whose starting point is
2637                         // at this block are added)
2638                         if(y < node_min.Y || y > node_max.Y)
2639                                 continue;
2640                         /*
2641                                 Find exact ground level
2642                         */
2643                         v3s16 p(x,y+6,z);
2644                         bool found = false;
2645                         for(; p.Y >= y-6; p.Y--)
2646                         {
2647                                 u32 i = vmanip->m_area.index(p);
2648                                 MapNode *n = &vmanip->m_data[i];
2649                                 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2650                                 {
2651                                         found = true;
2652                                         break;
2653                                 }
2654                         }
2655                         // If not found, handle next one
2656                         if(found == false)
2657                                 continue;
2658
2659                         {
2660                                 u32 i = vmanip->m_area.index(p);
2661                                 MapNode *n = &vmanip->m_data[i];
2662
2663                                 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2664                                                 continue;
2665
2666                                 // Papyrus grows only on mud and in water
2667                                 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2668                                 {
2669                                         p.Y++;
2670                                         make_papyrus(vmanip, p, ndef);
2671                                 }
2672                                 // Trees grow only on mud and grass, on land
2673                                 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2674                                 {
2675                                         p.Y++;
2676                                         //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2677                                         if(is_jungle == false)
2678                                         {
2679                                                 bool is_apple_tree;
2680                                                 if(myrand_range(0,4) != 0)
2681                                                         is_apple_tree = false;
2682                                                 else
2683                                                         is_apple_tree = noise2d_perlin(
2684                                                                         0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2685                                                                         data->seed+342902, 3, 0.45) > 0.2;
2686                                                 make_tree(vmanip, p, is_apple_tree, ndef);
2687                                         }
2688                                         else
2689                                                 make_jungletree(vmanip, p, ndef);
2690                                 }
2691                                 // Cactii grow only on sand, on land
2692                                 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2693                                 {
2694                                         p.Y++;
2695                                         make_cactus(vmanip, p, ndef);
2696                                 }
2697                         }
2698                 }
2699
2700                 /*
2701                         Add jungle grass
2702                 */
2703                 if(is_jungle)
2704                 {
2705                         PseudoRandom grassrandom(blockseed);
2706                         for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2707                         {
2708                                 s16 x = grassrandom.range(node_min.X, node_max.X);
2709                                 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2710                                 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2711                                 if(y < WATER_LEVEL)
2712                                         continue;
2713                                 if(y < node_min.Y || y > node_max.Y)
2714                                         continue;
2715                                 /*
2716                                         Find exact ground level
2717                                 */
2718                                 v3s16 p(x,y+6,z);
2719                                 bool found = false;
2720                                 for(; p.Y >= y-6; p.Y--)
2721                                 {
2722                                         u32 i = vmanip->m_area.index(p);
2723                                         MapNode *n = &vmanip->m_data[i];
2724                                         if(data->nodedef->get(*n).is_ground_content)
2725                                         {
2726                                                 found = true;
2727                                                 break;
2728                                         }
2729                                 }
2730                                 // If not found, handle next one
2731                                 if(found == false)
2732                                         continue;
2733                                 p.Y++;
2734                                 if(vmanip.m_area.contains(p) == false)
2735                                         continue;
2736                                 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2737                                         continue;
2738                                 /*p.Y--;
2739                                 if(vmanip.m_area.contains(p))
2740                                         vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2741                                 p.Y++;*/
2742                                 if(vmanip.m_area.contains(p))
2743                                         vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2744                         }
2745                 }
2746
2747 #if 0
2748                 /*
2749                         Add some kind of random stones
2750                 */
2751
2752                 u32 random_stone_count = gen_area_nodes *
2753                                 randomstone_amount_2d(data->seed, p2d_center);
2754                 // Put in random places on part of division
2755                 for(u32 i=0; i<random_stone_count; i++)
2756                 {
2757                         s16 x = myrand_range(node_min.X, node_max.X);
2758                         s16 z = myrand_range(node_min.Z, node_max.Z);
2759                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2760                         // Don't add under water level
2761                         /*if(y < WATER_LEVEL)
2762                                 continue;*/
2763                         // Don't add if doesn't belong to this block
2764                         if(y < node_min.Y || y > node_max.Y)
2765                                 continue;
2766                         v3s16 p(x,y,z);
2767                         // Filter placement
2768                         /*{
2769                                 u32 i = vmanip->m_area.index(v3s16(p));
2770                                 MapNode *n = &vmanip->m_data[i];
2771                                 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2772                                         continue;
2773                         }*/
2774                         // Will be placed one higher
2775                         p.Y++;
2776                         // Add it
2777                         make_randomstone(vmanip, p);
2778                 }
2779 #endif
2780
2781 #if 0
2782                 /*
2783                         Add larger stones
2784                 */
2785
2786                 u32 large_stone_count = gen_area_nodes *
2787                                 largestone_amount_2d(data->seed, p2d_center);
2788                 //u32 large_stone_count = 1;
2789                 // Put in random places on part of division
2790                 for(u32 i=0; i<large_stone_count; i++)
2791                 {
2792                         s16 x = myrand_range(node_min.X, node_max.X);
2793                         s16 z = myrand_range(node_min.Z, node_max.Z);
2794                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2795                         // Don't add under water level
2796                         /*if(y < WATER_LEVEL)
2797                                 continue;*/
2798                         // Don't add if doesn't belong to this block
2799                         if(y < node_min.Y || y > node_max.Y)
2800                                 continue;
2801                         v3s16 p(x,y,z);
2802                         // Filter placement
2803                         /*{
2804                                 u32 i = vmanip->m_area.index(v3s16(p));
2805                                 MapNode *n = &vmanip->m_data[i];
2806                                 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2807                                         continue;
2808                         }*/
2809                         // Will be placed one lower
2810                         p.Y--;
2811                         // Add it
2812                         make_largestone(vmanip, p);
2813                 }
2814 #endif
2815         }
2816
2817         /*
2818                 Add minerals
2819         */
2820
2821         {
2822                 PseudoRandom mineralrandom(blockseed);
2823
2824                 /*
2825                         Add meseblocks
2826                 */
2827                 for(s16 i=0; i<approx_ground_depth/4; i++)
2828                 {
2829                         if(mineralrandom.next()%50 == 0)
2830                         {
2831                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2832                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2833                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2834                                 for(u16 i=0; i<27; i++)
2835                                 {
2836                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2837                                         u32 vi = vmanip.m_area.index(p);
2838                                         if(vmanip.m_data[vi].getContent() == c_stone)
2839                                                 if(mineralrandom.next()%8 == 0)
2840                                                         vmanip.m_data[vi] = MapNode(c_mese);
2841                                 }
2842
2843                         }
2844                 }
2845                 /*
2846                         Add others
2847                 */
2848                 {
2849                         u16 a = mineralrandom.range(0,15);
2850                         a = a*a*a;
2851                         u16 amount = 20 * a/1000;
2852                         for(s16 i=0; i<amount; i++)
2853                         {
2854                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2855                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2856                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2857
2858                                 u8 base_content = c_stone;
2859                                 MapNode new_content(CONTENT_IGNORE);
2860                                 u32 sparseness = 6;
2861
2862                                 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2863                                 {
2864                                         new_content = MapNode(c_stone_with_coal);
2865                                 }
2866                                 else
2867                                 {
2868                                         if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2869                                                 new_content = MapNode(c_stone_with_iron);
2870                                         /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2871                                                 vmanip.m_data[i] = MapNode(c_dirt);
2872                                         else
2873                                                 vmanip.m_data[i] = MapNode(c_sand);*/
2874                                 }
2875                                 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2876                                 {
2877                                 }*/
2878
2879                                 if(new_content.getContent() != CONTENT_IGNORE)
2880                                 {
2881                                         for(u16 i=0; i<27; i++)
2882                                         {
2883                                                 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2884                                                 u32 vi = vmanip.m_area.index(p);
2885                                                 if(vmanip.m_data[vi].getContent() == base_content)
2886                                                 {
2887                                                         if(mineralrandom.next()%sparseness == 0)
2888                                                                 vmanip.m_data[vi] = new_content;
2889                                                 }
2890                                         }
2891                                 }
2892                         }
2893                 }
2894                 /*
2895                         Add coal
2896                 */
2897                 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2898                 //for(s16 i=0; i<50; i++)
2899                 u16 coal_amount = 30;
2900                 u16 coal_rareness = 60 / coal_amount;
2901                 if(coal_rareness == 0)
2902                         coal_rareness = 1;
2903                 if(mineralrandom.next()%coal_rareness == 0)
2904                 {
2905                         u16 a = mineralrandom.next() % 16;
2906                         u16 amount = coal_amount * a*a*a / 1000;
2907                         for(s16 i=0; i<amount; i++)
2908                         {
2909                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2910                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2911                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2912                                 for(u16 i=0; i<27; i++)
2913                                 {
2914                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2915                                         u32 vi = vmanip.m_area.index(p);
2916                                         if(vmanip.m_data[vi].getContent() == c_stone)
2917                                                 if(mineralrandom.next()%8 == 0)
2918                                                         vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2919                                 }
2920                         }
2921                 }
2922                 /*
2923                         Add iron
2924                 */
2925                 u16 iron_amount = 8;
2926                 u16 iron_rareness = 60 / iron_amount;
2927                 if(iron_rareness == 0)
2928                         iron_rareness = 1;
2929                 if(mineralrandom.next()%iron_rareness == 0)
2930                 {
2931                         u16 a = mineralrandom.next() % 16;
2932                         u16 amount = iron_amount * a*a*a / 1000;
2933                         for(s16 i=0; i<amount; i++)
2934                         {
2935                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2936                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2937                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2938                                 for(u16 i=0; i<27; i++)
2939                                 {
2940                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2941                                         u32 vi = vmanip.m_area.index(p);
2942                                         if(vmanip.m_data[vi].getContent() == c_stone)
2943                                                 if(mineralrandom.next()%8 == 0)
2944                                                         vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2945                                 }
2946                         }
2947                 }
2948         }
2949 #endif
2950
2951         /*
2952                 Calculate lighting
2953         */
2954         {
2955         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2956                         SPT_AVG);
2957         //VoxelArea a(node_min, node_max);
2958         VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2959                         node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2960         /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2961                         node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2962         enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2963         for(int i=0; i<2; i++)
2964         {
2965                 enum LightBank bank = banks[i];
2966
2967                 core::map<v3s16, bool> light_sources;
2968                 core::map<v3s16, u8> unlight_from;
2969
2970                 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2971                                 light_sources, unlight_from);
2972
2973                 bool inexistent_top_provides_sunlight = !block_is_underground;
2974                 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2975                                 vmanip, a, inexistent_top_provides_sunlight,
2976                                 light_sources, ndef);
2977                 // TODO: Do stuff according to bottom_sunlight_valid
2978
2979                 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2980
2981                 vmanip.spreadLight(bank, light_sources, ndef);
2982         }
2983         }
2984 }
2985
2986 #endif ///BIG COMMENT
2987
2988 BlockMakeData::BlockMakeData():
2989         no_op(false),
2990         vmanip(NULL),
2991         seed(0),
2992         nodedef(NULL)
2993 {}
2994
2995 BlockMakeData::~BlockMakeData()
2996 {
2997         delete vmanip;
2998 }
2999
3000 //}; // namespace mapgen
3001
3002