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