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