]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen.cpp
moved mapgen stuff around abit
[dragonfireclient.git] / src / mapgen.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapgen.h"
21 #include "voxel.h"
22 #include "content_mapnode.h"
23 #include "noise.h"
24 #include "mapblock.h"
25 #include "map.h"
26 #include "serverobject.h"
27 #include "mineral.h"
28
29 namespace mapgen
30 {
31
32 /*
33         Some helper functions for the map generator
34 */
35
36 #if 0
37 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
38 {
39         v3s16 em = vmanip.m_area.getExtent();
40         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
41         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
42         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
43         s16 y;
44         for(y=y_nodes_max; y>=y_nodes_min; y--)
45         {
46                 MapNode &n = vmanip.m_data[i];
47                 if(content_walkable(n.d))
48                         break;
49
50                 vmanip.m_area.add_y(em, i, -1);
51         }
52         if(y >= y_nodes_min)
53                 return y;
54         else
55                 return y_nodes_min;
56 }
57
58 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
59 {
60         v3s16 em = vmanip.m_area.getExtent();
61         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
62         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
63         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
64         s16 y;
65         for(y=y_nodes_max; y>=y_nodes_min; y--)
66         {
67                 MapNode &n = vmanip.m_data[i];
68                 if(content_walkable(n.d)
69                                 && n.d != CONTENT_TREE
70                                 && n.d != CONTENT_LEAVES)
71                         break;
72
73                 vmanip.m_area.add_y(em, i, -1);
74         }
75         if(y >= y_nodes_min)
76                 return y;
77         else
78                 return y_nodes_min;
79 }
80 #endif
81
82 static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
83 {
84         MapNode treenode(CONTENT_TREE);
85         MapNode leavesnode(CONTENT_LEAVES);
86
87         s16 trunk_h = myrand_range(3, 6);
88         v3s16 p1 = p0;
89         for(s16 ii=0; ii<trunk_h; ii++)
90         {
91                 if(vmanip.m_area.contains(p1))
92                         vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
93                 p1.Y++;
94         }
95
96         // p1 is now the last piece of the trunk
97         p1.Y -= 1;
98
99         VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
100         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
101         Buffer<u8> leaves_d(leaves_a.getVolume());
102         for(s32 i=0; i<leaves_a.getVolume(); i++)
103                 leaves_d[i] = 0;
104
105         // Force leaves at near the end of the trunk
106         {
107                 s16 d = 1;
108                 for(s16 z=-d; z<=d; z++)
109                 for(s16 y=-d; y<=d; y++)
110                 for(s16 x=-d; x<=d; x++)
111                 {
112                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
113                 }
114         }
115
116         // Add leaves randomly
117         for(u32 iii=0; iii<7; iii++)
118         {
119                 s16 d = 1;
120
121                 v3s16 p(
122                         myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
123                         myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
124                         myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
125                 );
126
127                 for(s16 z=0; z<=d; z++)
128                 for(s16 y=0; y<=d; y++)
129                 for(s16 x=0; x<=d; x++)
130                 {
131                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
132                 }
133         }
134
135         // Blit leaves to vmanip
136         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
137         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
138         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
139         {
140                 v3s16 p(x,y,z);
141                 p += p1;
142                 if(vmanip.m_area.contains(p) == false)
143                         continue;
144                 u32 vi = vmanip.m_area.index(p);
145                 if(vmanip.m_data[vi].d != CONTENT_AIR
146                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
147                         continue;
148                 u32 i = leaves_a.index(x,y,z);
149                 if(leaves_d[i] == 1)
150                         vmanip.m_data[vi] = leavesnode;
151         }
152 }
153
154 #if 0
155 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
156 {
157         MapNode stonenode(CONTENT_STONE);
158
159         s16 size = myrand_range(3, 6);
160         
161         VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
162         Buffer<u8> stone_d(stone_a.getVolume());
163         for(s32 i=0; i<stone_a.getVolume(); i++)
164                 stone_d[i] = 0;
165
166         // Force stone at bottom to make it usually touch the ground
167         {
168                 for(s16 z=0; z<=0; z++)
169                 for(s16 y=0; y<=0; y++)
170                 for(s16 x=0; x<=0; x++)
171                 {
172                         stone_d[stone_a.index(v3s16(x,y,z))] = 1;
173                 }
174         }
175
176         // Generate from perlin noise
177         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
178         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
179         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
180         {
181                 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
182                                 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
183                 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
184                         d -= 0.3;
185                 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
186                         d -= 0.3;
187                 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
188                         d -= 0.3;
189                 if(d > 0.0)
190                 {
191                         u32 vi = stone_a.index(v3s16(x,y,z));
192                         stone_d[vi] = 1;
193                 }
194         }
195
196         /*// Add stone randomly
197         for(u32 iii=0; iii<7; iii++)
198         {
199                 s16 d = 1;
200
201                 v3s16 p(
202                         myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
203                         myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
204                         myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
205                 );
206
207                 for(s16 z=0; z<=d; z++)
208                 for(s16 y=0; y<=d; y++)
209                 for(s16 x=0; x<=d; x++)
210                 {
211                         stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
212                 }
213         }*/
214
215         // Blit stone to vmanip
216         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
217         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
218         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
219         {
220                 v3s16 p(x,y,z);
221                 p += p0;
222                 if(vmanip.m_area.contains(p) == false)
223                         continue;
224                 u32 vi = vmanip.m_area.index(p);
225                 if(vmanip.m_data[vi].d != CONTENT_AIR
226                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
227                         continue;
228                 u32 i = stone_a.index(x,y,z);
229                 if(stone_d[i] == 1)
230                         vmanip.m_data[vi] = stonenode;
231         }
232 }
233 #endif
234
235 #if 0
236 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
237 {
238         MapNode stonenode(CONTENT_STONE);
239
240         s16 size = myrand_range(8, 16);
241         
242         VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
243         Buffer<u8> stone_d(stone_a.getVolume());
244         for(s32 i=0; i<stone_a.getVolume(); i++)
245                 stone_d[i] = 0;
246
247         // Force stone at bottom to make it usually touch the ground
248         {
249                 for(s16 z=0; z<=0; z++)
250                 for(s16 y=0; y<=0; y++)
251                 for(s16 x=0; x<=0; x++)
252                 {
253                         stone_d[stone_a.index(v3s16(x,y,z))] = 1;
254                 }
255         }
256
257         // Generate from perlin noise
258         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
259         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
260         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
261         {
262                 double d = 1.0;
263                 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
264                                 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
265                 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
266                 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
267                 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
268                 double dz = (double)z-mid_z;
269                 double dx = (double)x-mid_x;
270                 double dy = MYMAX(0, (double)y-mid_y);
271                 double r = sqrt(dz*dz+dx*dx+dy*dy);
272                 d /= (2*r/size)*2 + 0.01;
273                 if(d > 1.0)
274                 {
275                         u32 vi = stone_a.index(v3s16(x,y,z));
276                         stone_d[vi] = 1;
277                 }
278         }
279
280         /*// Add stone randomly
281         for(u32 iii=0; iii<7; iii++)
282         {
283                 s16 d = 1;
284
285                 v3s16 p(
286                         myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
287                         myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
288                         myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
289                 );
290
291                 for(s16 z=0; z<=d; z++)
292                 for(s16 y=0; y<=d; y++)
293                 for(s16 x=0; x<=d; x++)
294                 {
295                         stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
296                 }
297         }*/
298
299         // Blit stone to vmanip
300         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
301         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
302         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
303         {
304                 v3s16 p(x,y,z);
305                 p += p0;
306                 if(vmanip.m_area.contains(p) == false)
307                         continue;
308                 u32 vi = vmanip.m_area.index(p);
309                 /*if(vmanip.m_data[vi].d != CONTENT_AIR
310                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
311                         continue;*/
312                 u32 i = stone_a.index(x,y,z);
313                 if(stone_d[i] == 1)
314                         vmanip.m_data[vi] = stonenode;
315         }
316 }
317 #endif
318
319 /*
320         Dungeon making routines
321 */
322
323 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
324 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
325 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
326                 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
327
328 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
329 {
330         // Make +-X walls
331         for(s16 z=0; z<roomsize.Z; z++)
332         for(s16 y=0; y<roomsize.Y; y++)
333         {
334                 {
335                         v3s16 p = roomplace + v3s16(0,y,z);
336                         if(vmanip.m_area.contains(p) == false)
337                                 continue;
338                         u32 vi = vmanip.m_area.index(p);
339                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
340                                 continue;
341                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
342                 }
343                 {
344                         v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
345                         if(vmanip.m_area.contains(p) == false)
346                                 continue;
347                         u32 vi = vmanip.m_area.index(p);
348                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
349                                 continue;
350                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
351                 }
352         }
353         
354         // Make +-Z walls
355         for(s16 x=0; x<roomsize.X; x++)
356         for(s16 y=0; y<roomsize.Y; y++)
357         {
358                 {
359                         v3s16 p = roomplace + v3s16(x,y,0);
360                         if(vmanip.m_area.contains(p) == false)
361                                 continue;
362                         u32 vi = vmanip.m_area.index(p);
363                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
364                                 continue;
365                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
366                 }
367                 {
368                         v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
369                         if(vmanip.m_area.contains(p) == false)
370                                 continue;
371                         u32 vi = vmanip.m_area.index(p);
372                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
373                                 continue;
374                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
375                 }
376         }
377         
378         // Make +-Y walls (floor and ceiling)
379         for(s16 z=0; z<roomsize.Z; z++)
380         for(s16 x=0; x<roomsize.X; x++)
381         {
382                 {
383                         v3s16 p = roomplace + v3s16(x,0,z);
384                         if(vmanip.m_area.contains(p) == false)
385                                 continue;
386                         u32 vi = vmanip.m_area.index(p);
387                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
388                                 continue;
389                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
390                 }
391                 {
392                         v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
393                         if(vmanip.m_area.contains(p) == false)
394                                 continue;
395                         u32 vi = vmanip.m_area.index(p);
396                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
397                                 continue;
398                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
399                 }
400         }
401         
402         // Fill with air
403         for(s16 z=1; z<roomsize.Z-1; z++)
404         for(s16 y=1; y<roomsize.Y-1; y++)
405         for(s16 x=1; x<roomsize.X-1; x++)
406         {
407                 v3s16 p = roomplace + v3s16(x,y,z);
408                 if(vmanip.m_area.contains(p) == false)
409                         continue;
410                 u32 vi = vmanip.m_area.index(p);
411                 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
412                 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
413         }
414 }
415
416 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
417                 u8 avoid_flags, MapNode n, u8 or_flags)
418 {
419         for(s16 z=0; z<size.Z; z++)
420         for(s16 y=0; y<size.Y; y++)
421         for(s16 x=0; x<size.X; x++)
422         {
423                 v3s16 p = place + v3s16(x,y,z);
424                 if(vmanip.m_area.contains(p) == false)
425                         continue;
426                 u32 vi = vmanip.m_area.index(p);
427                 if(vmanip.m_flags[vi] & avoid_flags)
428                         continue;
429                 vmanip.m_flags[vi] |= or_flags;
430                 vmanip.m_data[vi] = n;
431         }
432 }
433
434 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
435 {
436         make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
437                         VMANIP_FLAG_DUNGEON_INSIDE);
438 }
439
440 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
441 {
442         make_hole1(vmanip, doorplace);
443         // Place torch (for testing)
444         //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
445 }
446
447 static v3s16 rand_ortho_dir(PseudoRandom &random)
448 {
449         if(random.next()%2==0)
450                 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
451         else
452                 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
453 }
454
455 static v3s16 turn_xz(v3s16 olddir, int t)
456 {
457         v3s16 dir;
458         if(t == 0)
459         {
460                 // Turn right
461                 dir.X = olddir.Z;
462                 dir.Z = -olddir.X;
463                 dir.Y = olddir.Y;
464         }
465         else
466         {
467                 // Turn left
468                 dir.X = -olddir.Z;
469                 dir.Z = olddir.X;
470                 dir.Y = olddir.Y;
471         }
472         return dir;
473 }
474
475 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
476 {
477         int turn = random.range(0,2);
478         v3s16 dir;
479         if(turn == 0)
480         {
481                 // Go straight
482                 dir = olddir;
483         }
484         else if(turn == 1)
485                 // Turn right
486                 dir = turn_xz(olddir, 0);
487         else
488                 // Turn left
489                 dir = turn_xz(olddir, 1);
490         return dir;
491 }
492
493 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
494                 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
495                 PseudoRandom &random)
496 {
497         make_hole1(vmanip, doorplace);
498         v3s16 p0 = doorplace;
499         v3s16 dir = doordir;
500         u32 length;
501         if(random.next()%2)
502                 length = random.range(1,13);
503         else
504                 length = random.range(1,6);
505         length = random.range(1,13);
506         u32 partlength = random.range(1,length);
507         u32 partcount = 0;
508         s16 make_stairs = 0;
509         if(random.next()%2 == 0 && partlength >= 3)
510                 make_stairs = random.next()%2 ? 1 : -1;
511         for(u32 i=0; i<length; i++)
512         {
513                 v3s16 p = p0 + dir;
514                 if(partcount != 0)
515                         p.Y += make_stairs;
516
517                 /*// If already empty
518                 if(vmanip.getNodeNoExNoEmerge(p).d
519                                 == CONTENT_AIR
520                 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
521                                 == CONTENT_AIR)
522                 {
523                 }*/
524
525                 if(vmanip.m_area.contains(p) == true
526                                 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
527                 {
528                         if(make_stairs)
529                         {
530                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
531                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
532                                 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
533                                                 VMANIP_FLAG_DUNGEON_INSIDE);
534                                 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
535                                                 VMANIP_FLAG_DUNGEON_INSIDE);
536                         }
537                         else
538                         {
539                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
540                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
541                                 make_hole1(vmanip, p);
542                                 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
543                                                 VMANIP_FLAG_DUNGEON_INSIDE);*/
544                         }
545
546                         p0 = p;
547                 }
548                 else
549                 {
550                         // Can't go here, turn away
551                         dir = turn_xz(dir, random.range(0,1));
552                         make_stairs = -make_stairs;
553                         partcount = 0;
554                         partlength = random.range(1,length);
555                         continue;
556                 }
557
558                 partcount++;
559                 if(partcount >= partlength)
560                 {
561                         partcount = 0;
562                         
563                         dir = random_turn(random, dir);
564                         
565                         partlength = random.range(1,length);
566
567                         make_stairs = 0;
568                         if(random.next()%2 == 0 && partlength >= 3)
569                                 make_stairs = random.next()%2 ? 1 : -1;
570                 }
571         }
572         result_place = p0;
573         result_dir = dir;
574 }
575
576 class RoomWalker
577 {
578 public:
579
580         RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
581                         vmanip(vmanip_),
582                         m_pos(pos),
583                         m_random(random)
584         {
585                 randomizeDir();
586         }
587
588         void randomizeDir()
589         {
590                 m_dir = rand_ortho_dir(m_random);
591         }
592
593         void setPos(v3s16 pos)
594         {
595                 m_pos = pos;
596         }
597
598         void setDir(v3s16 dir)
599         {
600                 m_dir = dir;
601         }
602         
603         bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
604         {
605                 for(u32 i=0; i<100; i++)
606                 {
607                         v3s16 p = m_pos + m_dir;
608                         v3s16 p1 = p + v3s16(0,1,0);
609                         if(vmanip.m_area.contains(p) == false
610                                         || vmanip.m_area.contains(p1) == false
611                                         || i % 4 == 0)
612                         {
613                                 randomizeDir();
614                                 continue;
615                         }
616                         if(vmanip.getNodeNoExNoEmerge(p).d
617                                         == CONTENT_COBBLE
618                         && vmanip.getNodeNoExNoEmerge(p1).d
619                                         == CONTENT_COBBLE)
620                         {
621                                 // Found wall, this is a good place!
622                                 result_place = p;
623                                 result_dir = m_dir;
624                                 // Randomize next direction
625                                 randomizeDir();
626                                 return true;
627                         }
628                         /*
629                                 Determine where to move next
630                         */
631                         // Jump one up if the actual space is there
632                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
633                                         == CONTENT_COBBLE
634                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
635                                         == CONTENT_AIR
636                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d
637                                         == CONTENT_AIR)
638                                 p += v3s16(0,1,0);
639                         // Jump one down if the actual space is there
640                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
641                                         == CONTENT_COBBLE
642                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
643                                         == CONTENT_AIR
644                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d
645                                         == CONTENT_AIR)
646                                 p += v3s16(0,-1,0);
647                         // Check if walking is now possible
648                         if(vmanip.getNodeNoExNoEmerge(p).d
649                                         != CONTENT_AIR
650                         || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
651                                         != CONTENT_AIR)
652                         {
653                                 // Cannot continue walking here
654                                 randomizeDir();
655                                 continue;
656                         }
657                         // Move there
658                         m_pos = p;
659                 }
660                 return false;
661         }
662
663         bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
664                         v3s16 &result_doordir, v3s16 &result_roomplace)
665         {
666                 for(s16 trycount=0; trycount<30; trycount++)
667                 {
668                         v3s16 doorplace;
669                         v3s16 doordir;
670                         bool r = findPlaceForDoor(doorplace, doordir);
671                         if(r == false)
672                                 continue;
673                         v3s16 roomplace;
674                         // X east, Z north, Y up
675                         if(doordir == v3s16(1,0,0)) // X+
676                                 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
677                         if(doordir == v3s16(-1,0,0)) // X-
678                                 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
679                         if(doordir == v3s16(0,0,1)) // Z+
680                                 roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0);
681                         if(doordir == v3s16(0,0,-1)) // Z-
682                                 roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,-roomsize.Z+1);
683                         
684                         // Check fit
685                         bool fits = true;
686                         for(s16 z=1; z<roomsize.Z-1; z++)
687                         for(s16 y=1; y<roomsize.Y-1; y++)
688                         for(s16 x=1; x<roomsize.X-1; x++)
689                         {
690                                 v3s16 p = roomplace + v3s16(x,y,z);
691                                 if(vmanip.m_area.contains(p) == false)
692                                 {
693                                         fits = false;
694                                         break;
695                                 }
696                                 if(vmanip.m_flags[vmanip.m_area.index(p)]
697                                                 & VMANIP_FLAG_DUNGEON_INSIDE)
698                                 {
699                                         fits = false;
700                                         break;
701                                 }
702                         }
703                         if(fits == false)
704                         {
705                                 // Find new place
706                                 continue;
707                         }
708                         result_doorplace = doorplace;
709                         result_doordir = doordir;
710                         result_roomplace = roomplace;
711                         return true;
712                 }
713                 return false;
714         }
715
716 private:
717         VoxelManipulator &vmanip;
718         v3s16 m_pos;
719         v3s16 m_dir;
720         PseudoRandom &m_random;
721 };
722
723 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
724 {
725         v3s16 areasize = vmanip.m_area.getExtent();
726         v3s16 roomsize;
727         v3s16 roomplace;
728         
729         /*
730                 Find place for first room
731         */
732         bool fits = false;
733         for(u32 i=0; i<100; i++)
734         {
735                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
736                 roomplace = vmanip.m_area.MinEdge + v3s16(
737                                 random.range(0,areasize.X-roomsize.X-1),
738                                 random.range(0,areasize.Y-roomsize.Y-1),
739                                 random.range(0,areasize.Z-roomsize.Z-1));
740                 /*
741                         Check that we're not putting the room to an unknown place,
742                         otherwise it might end up floating in the air
743                 */
744                 fits = true;
745                 for(s16 z=1; z<roomsize.Z-1; z++)
746                 for(s16 y=1; y<roomsize.Y-1; y++)
747                 for(s16 x=1; x<roomsize.X-1; x++)
748                 {
749                         v3s16 p = roomplace + v3s16(x,y,z);
750                         u32 vi = vmanip.m_area.index(p);
751                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
752                         {
753                                 fits = false;
754                                 break;
755                         }
756                         if(vmanip.m_data[vi].d == CONTENT_IGNORE)
757                         {
758                                 fits = false;
759                                 break;
760                         }
761                 }
762                 if(fits)
763                         break;
764         }
765         // No place found
766         if(fits == false)
767                 return;
768         
769         /*
770                 Stores the center position of the last room made, so that
771                 a new corridor can be started from the last room instead of
772                 the new room, if chosen so.
773         */
774         v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
775         
776         u32 room_count = random.range(2,7);
777         for(u32 i=0; i<room_count; i++)
778         {
779                 // Make a room to the determined place
780                 make_room1(vmanip, roomsize, roomplace);
781                 
782                 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
783
784                 // Place torch at room center (for testing)
785                 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
786
787                 // Quit if last room
788                 if(i == room_count-1)
789                         break;
790                 
791                 // Determine walker start position
792
793                 bool start_in_last_room = (random.range(0,1)==0);
794                 //bool start_in_last_room = true;
795
796                 v3s16 walker_start_place;
797
798                 if(start_in_last_room)
799                 {
800                         walker_start_place = last_room_center;
801                 }
802                 else
803                 {
804                         walker_start_place = room_center;
805                         // Store center of current room as the last one
806                         last_room_center = room_center;
807                 }
808                 
809                 // Create walker and find a place for a door
810                 RoomWalker walker(vmanip, walker_start_place, random);
811                 v3s16 doorplace;
812                 v3s16 doordir;
813                 bool r = walker.findPlaceForDoor(doorplace, doordir);
814                 if(r == false)
815                         return;
816                 
817                 if(random.range(0,1)==0)
818                         // Make the door
819                         make_door1(vmanip, doorplace, doordir);
820                 else
821                         // Don't actually make a door
822                         doorplace -= doordir;
823                 
824                 // Make a random corridor starting from the door
825                 v3s16 corridor_end;
826                 v3s16 corridor_end_dir;
827                 make_corridor(vmanip, doorplace, doordir, corridor_end,
828                                 corridor_end_dir, random);
829                 
830                 // Find a place for a random sized room
831                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
832                 walker.setPos(corridor_end);
833                 walker.setDir(corridor_end_dir);
834                 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
835                 if(r == false)
836                         return;
837
838                 if(random.range(0,1)==0)
839                         // Make the door
840                         make_door1(vmanip, doorplace, doordir);
841                 else
842                         // Don't actually make a door
843                         roomplace -= doordir;
844                 
845         }
846 }
847
848 /*
849         Noise functions. Make sure seed is mangled differently in each one.
850 */
851
852 // This affects the shape of the contour
853 //#define CAVE_NOISE_SCALE 10.0
854 //#define CAVE_NOISE_SCALE 7.5
855 #define CAVE_NOISE_SCALE 5.0
856
857 NoiseParams get_cave_noise1_params(u64 seed)
858 {
859         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
860                         200, CAVE_NOISE_SCALE);*/
861         return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
862                         100, CAVE_NOISE_SCALE);
863 }
864
865 NoiseParams get_cave_noise2_params(u64 seed)
866 {
867         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
868                         200, CAVE_NOISE_SCALE);*/
869         return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
870                         100, CAVE_NOISE_SCALE);
871 }
872
873 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
874 #define CAVE_NOISE_THRESHOLD (2.0/CAVE_NOISE_SCALE)
875
876 NoiseParams get_ground_noise1_params(u64 seed)
877 {
878         return NoiseParams(NOISE_PERLIN, seed+983240, 5,
879                         0.60, 100.0, 30.0);
880 }
881
882 NoiseParams get_ground_crumbleness_params(u64 seed)
883 {
884         return NoiseParams(NOISE_PERLIN, seed+34413, 3,
885                         1.3, 20.0, 1.0);
886 }
887
888 NoiseParams get_ground_wetness_params(u64 seed)
889 {
890         return NoiseParams(NOISE_PERLIN, seed+32474, 4,
891                         1.1, 40.0, 1.0);
892 }
893
894 bool is_cave(u64 seed, v3s16 p)
895 {
896         double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
897         double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
898         return d1*d2 > CAVE_NOISE_THRESHOLD;
899 }
900
901 /*
902         Ground density noise shall be interpreted by using this.
903
904         TODO: No perlin noises here, they should be outsourced
905               and buffered
906                   NOTE: The speed of these actually isn't terrible
907 */
908 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
909 {
910         //return ((double)p.Y < ground_noise1_val);
911
912         double f = 0.8 + noise2d_perlin(
913                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
914                         seed+920381, 3, 0.5);
915         if(f < 0.01)
916                 f = 0.01;
917         else if(f >= 1.0)
918                 f *= 2.0;
919         double h = WATER_LEVEL + 10 * noise2d_perlin(
920                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
921                         seed+84174, 4, 0.5);
922         /*double f = 1;
923         double h = 0;*/
924         return ((double)p.Y - h < ground_noise1_val * f);
925 }
926
927 /*
928         Queries whether a position is ground or not.
929 */
930 bool is_ground(u64 seed, v3s16 p)
931 {
932         double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
933         return val_is_ground(val1, p, seed);
934 }
935
936 // Amount of trees per area in nodes
937 double tree_amount_2d(u64 seed, v2s16 p)
938 {
939         /*double noise = noise2d_perlin(
940                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
941                         seed+2, 5, 0.66);*/
942         double noise = noise2d_perlin(
943                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
944                         seed+2, 4, 0.66);
945         double zeroval = -0.35;
946         if(noise < zeroval)
947                 return 0;
948         else
949                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
950 }
951
952 #if 0
953 double randomstone_amount_2d(u64 seed, v2s16 p)
954 {
955         double noise = noise2d_perlin(
956                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
957                         seed+3829434, 5, 0.66);
958         double zeroval = 0.1;
959         if(noise < zeroval)
960                 return 0;
961         else
962                 return 0.01 * (noise-zeroval) / (1.0-zeroval);
963 }
964 #endif
965
966 double largestone_amount_2d(u64 seed, v2s16 p)
967 {
968         double noise = noise2d_perlin(
969                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
970                         seed+14143242, 5, 0.66);
971         double zeroval = 0.3;
972         if(noise < zeroval)
973                 return 0;
974         else
975                 return 0.005 * (noise-zeroval) / (1.0-zeroval);
976 }
977
978 /*
979         Incrementally find ground level from 3d noise
980 */
981 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
982 {
983         // Start a bit fuzzy to make averaging lower precision values
984         // more useful
985         s16 level = myrand_range(-precision/2, precision/2);
986         s16 dec[] = {31000, 100, 20, 4, 1, 0};
987         s16 i;
988         for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
989         {
990                 // First find non-ground by going upwards
991                 // Don't stop in caves.
992                 {
993                         s16 max = level+dec[i-1]*2;
994                         v3s16 p(p2d.X, level, p2d.Y);
995                         for(; p.Y < max; p.Y += dec[i])
996                         {
997                                 if(!is_ground(seed, p))
998                                 {
999                                         level = p.Y;
1000                                         break;
1001                                 }
1002                         }
1003                 }
1004                 // Then find ground by going downwards from there.
1005                 // Go in caves, too, when precision is 1.
1006                 {
1007                         s16 min = level-dec[i-1]*2;
1008                         v3s16 p(p2d.X, level, p2d.Y);
1009                         for(; p.Y>min; p.Y-=dec[i])
1010                         {
1011                                 bool ground = is_ground(seed, p);
1012                                 /*if(dec[i] == 1 && is_cave(seed, p))
1013                                         ground = false;*/
1014                                 if(ground)
1015                                 {
1016                                         level = p.Y;
1017                                         break;
1018                                 }
1019                         }
1020                 }
1021         }
1022         
1023         // This is more like the actual ground level
1024         level += dec[i-1]/2;
1025
1026         return level;
1027 }
1028
1029 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1030
1031 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1032 {
1033         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1034         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1035         double a = 0;
1036         a += find_ground_level_from_noise(seed,
1037                         v2s16(node_min.X, node_min.Y), p);
1038         a += find_ground_level_from_noise(seed,
1039                         v2s16(node_min.X, node_max.Y), p);
1040         a += find_ground_level_from_noise(seed,
1041                         v2s16(node_max.X, node_max.Y), p);
1042         a += find_ground_level_from_noise(seed,
1043                         v2s16(node_max.X, node_min.Y), p);
1044         a += find_ground_level_from_noise(seed,
1045                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1046         a /= 5;
1047         return a;
1048 }
1049
1050 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1051
1052 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1053 {
1054         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1055         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1056         double a = -31000;
1057         a = MYMAX(a, find_ground_level_from_noise(seed,
1058                         v2s16(node_min.X, node_min.Y), p));
1059         a = MYMAX(a, find_ground_level_from_noise(seed,
1060                         v2s16(node_min.X, node_max.Y), p));
1061         a = MYMAX(a, find_ground_level_from_noise(seed,
1062                         v2s16(node_max.X, node_max.Y), p));
1063         a = MYMAX(a, find_ground_level_from_noise(seed,
1064                         v2s16(node_min.X, node_min.Y), p));
1065         a = MYMAX(a, find_ground_level_from_noise(seed,
1066                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1067         return a;
1068 }
1069
1070 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1071
1072 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1073 {
1074         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1075         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1076         double a = 31000;
1077         a = MYMIN(a, find_ground_level_from_noise(seed,
1078                         v2s16(node_min.X, node_min.Y), p));
1079         a = MYMIN(a, find_ground_level_from_noise(seed,
1080                         v2s16(node_min.X, node_max.Y), p));
1081         a = MYMIN(a, find_ground_level_from_noise(seed,
1082                         v2s16(node_max.X, node_max.Y), p));
1083         a = MYMIN(a, find_ground_level_from_noise(seed,
1084                         v2s16(node_min.X, node_min.Y), p));
1085         a = MYMIN(a, find_ground_level_from_noise(seed,
1086                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1087         return a;
1088 }
1089
1090 bool block_is_underground(u64 seed, v3s16 blockpos)
1091 {
1092         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1093                         seed, v2s16(blockpos.X, blockpos.Z));
1094         
1095         if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1096                 return true;
1097         else
1098                 return false;
1099 }
1100
1101 #if 0
1102 #define AVERAGE_MUD_AMOUNT 4
1103
1104 double base_rock_level_2d(u64 seed, v2s16 p)
1105 {
1106         // The base ground level
1107         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1108                         + 20. * noise2d_perlin(
1109                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1110                         (seed>>32)+654879876, 6, 0.6);
1111
1112         /*// A bit hillier one
1113         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1114                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1115                         (seed>>27)+90340, 6, 0.69);
1116         if(base2 > base)
1117                 base = base2;*/
1118 #if 1
1119         // Higher ground level
1120         double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1121                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1122                         seed+85039, 5, 0.69);
1123         //higher = 30; // For debugging
1124
1125         // Limit higher to at least base
1126         if(higher < base)
1127                 higher = base;
1128
1129         // Steepness factor of cliffs
1130         double b = 1.0 + 1.0 * noise2d_perlin(
1131                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1132                         seed-932, 7, 0.7);
1133         b = rangelim(b, 0.0, 1000.0);
1134         b = pow(b, 5);
1135         b *= 7;
1136         b = rangelim(b, 3.0, 1000.0);
1137         //dstream<<"b="<<b<<std::endl;
1138         //double b = 20;
1139
1140         // Offset to more low
1141         double a_off = -0.2;
1142         // High/low selector
1143         /*double a = 0.5 + b * (a_off + noise2d_perlin(
1144                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1145                         seed-359, 6, 0.7));*/
1146         double a = (double)0.5 + b * (a_off + noise2d_perlin(
1147                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1148                         seed-359, 5, 0.60));
1149         // Limit
1150         a = rangelim(a, 0.0, 1.0);
1151
1152         //dstream<<"a="<<a<<std::endl;
1153
1154         double h = base*(1.0-a) + higher*a;
1155 #else
1156         double h = base;
1157 #endif
1158         return h;
1159 }
1160
1161 double get_mud_add_amount(u64 seed, v2s16 p)
1162 {
1163         return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1164                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1165                         seed+91013, 3, 0.55));
1166 }
1167 #endif
1168
1169 bool get_have_sand(u64 seed, v2s16 p2d)
1170 {
1171         // Determine whether to have sand here
1172         double sandnoise = noise2d_perlin(
1173                         0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1174                         seed+59420, 3, 0.50);
1175
1176         return (sandnoise > -0.15);
1177 }
1178
1179 /*
1180         Adds random objects to block, depending on the content of the block
1181 */
1182 void add_random_objects(MapBlock *block)
1183 {
1184         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1185         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1186         {
1187                 bool last_node_walkable = false;
1188                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1189                 {
1190                         v3s16 p(x0,y0,z0);
1191                         MapNode n = block->getNodeNoEx(p);
1192                         if(n.d == CONTENT_IGNORE)
1193                                 continue;
1194                         if(content_features(n.d).liquid_type != LIQUID_NONE)
1195                                 continue;
1196                         if(content_features(n.d).walkable)
1197                         {
1198                                 last_node_walkable = true;
1199                                 continue;
1200                         }
1201                         if(last_node_walkable)
1202                         {
1203                                 // If block contains light information
1204                                 if(content_features(n.d).param_type == CPT_LIGHT)
1205                                 {
1206                                         if(n.getLight(LIGHTBANK_DAY) <= 3)
1207                                         {
1208                                                 if(myrand() % 300 == 0)
1209                                                 {
1210                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1211                                                         pos_f.Y -= BS*0.4;
1212                                                         ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1213                                                         std::string data = obj->getStaticData();
1214                                                         StaticObject s_obj(obj->getType(),
1215                                                                         obj->getBasePosition(), data);
1216                                                         // Add some
1217                                                         block->m_static_objects.insert(0, s_obj);
1218                                                         block->m_static_objects.insert(0, s_obj);
1219                                                         block->m_static_objects.insert(0, s_obj);
1220                                                         block->m_static_objects.insert(0, s_obj);
1221                                                         block->m_static_objects.insert(0, s_obj);
1222                                                         block->m_static_objects.insert(0, s_obj);
1223                                                         delete obj;
1224                                                 }
1225                                                 if(myrand() % 1000 == 0)
1226                                                 {
1227                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1228                                                         pos_f.Y -= BS*0.4;
1229                                                         ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1230                                                         std::string data = obj->getStaticData();
1231                                                         StaticObject s_obj(obj->getType(),
1232                                                                         obj->getBasePosition(), data);
1233                                                         // Add one
1234                                                         block->m_static_objects.insert(0, s_obj);
1235                                                         delete obj;
1236                                                 }
1237                                         }
1238                                 }
1239                         }
1240                         last_node_walkable = false;
1241                 }
1242         }
1243         block->setChangedFlag();
1244 }
1245
1246 void make_block(BlockMakeData *data)
1247 {
1248         if(data->no_op)
1249         {
1250                 dstream<<"makeBlock: no-op"<<std::endl;
1251                 return;
1252         }
1253
1254         v3s16 blockpos = data->blockpos;
1255         
1256         /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1257                         <<blockpos.Z<<")"<<std::endl;*/
1258
1259         ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1260         v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1261         v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1262         // Area of center block
1263         v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1264         v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1265         // Full allocated area
1266         v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1267         v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1268         // Area of a block
1269         double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1270
1271         v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1272
1273         /*
1274                 Get average ground level from noise
1275         */
1276         
1277         s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1278                         data->seed, v2s16(blockpos.X, blockpos.Z));
1279         //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1280         
1281         s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1282         
1283         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1284                         data->seed, v2s16(blockpos.X, blockpos.Z));
1285         // Minimum amount of ground above the top of the central block
1286         s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1287
1288         s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1289                         data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1290         // Maximum amount of ground above the bottom of the central block
1291         s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1292         
1293         /*
1294                 Special case for high air or water: Just fill with air and water.
1295         */
1296         if(maximum_ground_depth < -20)
1297         {
1298                 for(s16 x=node_min.X; x<=node_max.X; x++)
1299                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1300                 {
1301                         // Node position
1302                         v2s16 p2d(x,z);
1303                         {
1304                                 // Use fast index incrementing
1305                                 v3s16 em = vmanip.m_area.getExtent();
1306                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1307                                 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1308                                 {
1309                                         // Only modify places that have no content
1310                                         if(vmanip.m_data[i].d == CONTENT_IGNORE)
1311                                         {
1312                                                 if(y <= WATER_LEVEL)
1313                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1314                                                 else
1315                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
1316                                         }
1317                                 
1318                                         data->vmanip->m_area.add_y(em, i, 1);
1319                                 }
1320                         }
1321                 }
1322                 
1323                 // We're done
1324                 return;
1325         }
1326
1327         /*
1328                 If block is deep underground, this is set to true and ground
1329                 density noise is not generated, for speed optimization.
1330         */
1331         bool all_is_ground_except_caves = (minimum_ground_depth > 16);
1332         
1333         /*
1334                 Create a block-specific seed
1335         */
1336         u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234
1337                         + full_node_min.Y*42123 + full_node_min.X*23;
1338         
1339         /*
1340                 Make some 3D noise
1341         */
1342         
1343         //NoiseBuffer noisebuf1;
1344         //NoiseBuffer noisebuf2;
1345         NoiseBuffer noisebuf_cave;
1346         NoiseBuffer noisebuf_ground;
1347         NoiseBuffer noisebuf_ground_crumbleness;
1348         NoiseBuffer noisebuf_ground_wetness;
1349         {
1350                 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1351                 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1352
1353                 //TimeTaker timer("noisebuf.create");
1354
1355                 /*
1356                         Cave noise
1357                 */
1358
1359                 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1360                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
1361                                 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1362                                 4, 3, 4);
1363                 
1364                 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1365
1366                 /*
1367                         Ground noise
1368                 */
1369                 
1370                 // Sample length
1371                 v3f sl = v3f(4.0, 4.0, 4.0);
1372                 
1373                 /*
1374                         Density noise
1375                 */
1376                 if(all_is_ground_except_caves == false)
1377                         //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1378                         noisebuf_ground.create(get_ground_noise1_params(data->seed),
1379                                         minpos_f.X, minpos_f.Y, minpos_f.Z,
1380                                         maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1381                                         sl.X, sl.Y, sl.Z);
1382                 
1383                 /*
1384                         Ground property noise
1385                 */
1386                 sl = v3f(2.5, 2.5, 2.5);
1387                 noisebuf_ground_crumbleness.create(
1388                                 get_ground_crumbleness_params(data->seed),
1389                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
1390                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1391                                 sl.X, sl.Y, sl.Z);
1392                 noisebuf_ground_wetness.create(
1393                                 get_ground_wetness_params(data->seed),
1394                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
1395                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1396                                 sl.X, sl.Y, sl.Z);
1397         }
1398         
1399         /*
1400                 Make base ground level
1401         */
1402
1403         for(s16 x=node_min.X; x<=node_max.X; x++)
1404         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1405         {
1406                 // Node position
1407                 v2s16 p2d(x,z);
1408                 {
1409                         // Use fast index incrementing
1410                         v3s16 em = vmanip.m_area.getExtent();
1411                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1412                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
1413                         {
1414                                 // Only modify places that have no content
1415                                 if(vmanip.m_data[i].d == CONTENT_IGNORE)
1416                                 {
1417                                         // First priority: make air and water.
1418                                         // This avoids caves inside water.
1419                                         if(all_is_ground_except_caves == false
1420                                                         && val_is_ground(noisebuf_ground.get(x,y,z),
1421                                                         v3s16(x,y,z), data->seed) == false)
1422                                         {
1423                                                 if(y <= WATER_LEVEL)
1424                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1425                                                 else
1426                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
1427                                         }
1428                                         else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1429                                                 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1430                                         else
1431                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1432                                 }
1433                         
1434                                 data->vmanip->m_area.add_y(em, i, 1);
1435                         }
1436                 }
1437         }
1438
1439         /*
1440                 Add minerals
1441         */
1442
1443         {
1444                 PseudoRandom mineralrandom(blockseed);
1445
1446                 /*
1447                         Add meseblocks
1448                 */
1449                 for(s16 i=0; i<approx_ground_depth/4; i++)
1450                 {
1451                         if(mineralrandom.next()%50 == 0)
1452                         {
1453                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1454                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1455                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1456                                 for(u16 i=0; i<27; i++)
1457                                 {
1458                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1459                                         u32 vi = vmanip.m_area.index(p);
1460                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
1461                                                 if(mineralrandom.next()%8 == 0)
1462                                                         vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1463                                 }
1464                                         
1465                         }
1466                 }
1467                 /*
1468                         Add others
1469                 */
1470                 {
1471                         u16 a = mineralrandom.range(0,15);
1472                         a = a*a*a;
1473                         u16 amount = 20 * a/1000;
1474                         for(s16 i=0; i<amount; i++)
1475                         {
1476                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1477                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1478                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1479
1480                                 u8 base_content = CONTENT_STONE;
1481                                 MapNode new_content(CONTENT_IGNORE);
1482                                 u32 sparseness = 6;
1483
1484                                 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1485                                 {
1486                                         new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1487                                 }
1488                                 else
1489                                 {
1490                                         if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1491                                                 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1492                                         /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1493                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1494                                         else
1495                                                 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1496                                 }
1497                                 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1498                                 {
1499                                 }*/
1500
1501                                 if(new_content.d != CONTENT_IGNORE)
1502                                 {
1503                                         for(u16 i=0; i<27; i++)
1504                                         {
1505                                                 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1506                                                 u32 vi = vmanip.m_area.index(p);
1507                                                 if(vmanip.m_data[vi].d == base_content)
1508                                                 {
1509                                                         if(mineralrandom.next()%sparseness == 0)
1510                                                                 vmanip.m_data[vi] = new_content;
1511                                                 }
1512                                         }
1513                                 }
1514                         }
1515                 }
1516                 /*
1517                         Add coal
1518                 */
1519                 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1520                 //for(s16 i=0; i<50; i++)
1521                 u16 coal_amount = 30;
1522                 u16 coal_rareness = 60 / coal_amount;
1523                 if(coal_rareness == 0)
1524                         coal_rareness = 1;
1525                 if(mineralrandom.next()%coal_rareness == 0)
1526                 {
1527                         u16 a = mineralrandom.next() % 16;
1528                         u16 amount = coal_amount * a*a*a / 1000;
1529                         for(s16 i=0; i<amount; i++)
1530                         {
1531                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1532                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1533                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1534                                 for(u16 i=0; i<27; i++)
1535                                 {
1536                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1537                                         u32 vi = vmanip.m_area.index(p);
1538                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
1539                                                 if(mineralrandom.next()%8 == 0)
1540                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1541                                 }
1542                         }
1543                 }
1544                 /*
1545                         Add iron
1546                 */
1547                 u16 iron_amount = 8;
1548                 u16 iron_rareness = 60 / iron_amount;
1549                 if(iron_rareness == 0)
1550                         iron_rareness = 1;
1551                 if(mineralrandom.next()%iron_rareness == 0)
1552                 {
1553                         u16 a = mineralrandom.next() % 16;
1554                         u16 amount = iron_amount * a*a*a / 1000;
1555                         for(s16 i=0; i<amount; i++)
1556                         {
1557                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1558                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1559                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1560                                 for(u16 i=0; i<27; i++)
1561                                 {
1562                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1563                                         u32 vi = vmanip.m_area.index(p);
1564                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
1565                                                 if(mineralrandom.next()%8 == 0)
1566                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1567                                 }
1568                         }
1569                 }
1570         }
1571
1572         /*
1573                 Add mud and sand and others underground (in place of stone)
1574         */
1575
1576         for(s16 x=node_min.X; x<=node_max.X; x++)
1577         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1578         {
1579                 // Node position
1580                 v2s16 p2d(x,z);
1581                 {
1582                         // Use fast index incrementing
1583                         v3s16 em = vmanip.m_area.getExtent();
1584                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1585                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
1586                         {
1587                                 if(vmanip.m_data[i].d == CONTENT_STONE)
1588                                 {
1589                                         if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1590                                         {
1591                                                 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1592                                                         vmanip.m_data[i] = MapNode(CONTENT_MUD);
1593                                                 else
1594                                                         vmanip.m_data[i] = MapNode(CONTENT_SAND);
1595                                         }
1596                                         else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1597                                         {
1598                                                 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1599                                                         vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1600                                         }
1601                                 }
1602
1603                                 data->vmanip->m_area.add_y(em, i, -1);
1604                         }
1605                 }
1606         }
1607
1608         /*
1609                 Add dungeons
1610         */
1611         
1612         //if(node_min.Y < approx_groundlevel)
1613         //if(myrand() % 3 == 0)
1614         //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1615         //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1616         //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1617         float dungeon_rarity = 0.02;
1618         if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1619                         < dungeon_rarity
1620                         && node_min.Y < approx_groundlevel)
1621         {
1622                 // Dungeon generator doesn't modify places which have this set
1623                 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1624                                 | VMANIP_FLAG_DUNGEON_PRESERVE);
1625                 
1626                 // Set all air and water to be untouchable to make dungeons open
1627                 // to caves and open air
1628                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1629                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1630                 {
1631                         // Node position
1632                         v2s16 p2d(x,z);
1633                         {
1634                                 // Use fast index incrementing
1635                                 v3s16 em = vmanip.m_area.getExtent();
1636                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1637                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1638                                 {
1639                                         if(vmanip.m_data[i].d == CONTENT_AIR)
1640                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1641                                         else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1642                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1643                                         data->vmanip->m_area.add_y(em, i, -1);
1644                                 }
1645                         }
1646                 }
1647                 
1648                 PseudoRandom random(blockseed+2);
1649
1650                 // Add it
1651                 make_dungeon1(vmanip, random);
1652                 
1653                 // Convert some cobble to mossy cobble
1654                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1655                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1656                 {
1657                         // Node position
1658                         v2s16 p2d(x,z);
1659                         {
1660                                 // Use fast index incrementing
1661                                 v3s16 em = vmanip.m_area.getExtent();
1662                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1663                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1664                                 {
1665                                         // (noisebuf not used because it doesn't contain the
1666                                         //  full area)
1667                                         double wetness = noise3d_param(
1668                                                         get_ground_wetness_params(data->seed), x,y,z);
1669                                         double d = noise3d_perlin((float)x/2.5,
1670                                                         (float)y/2.5,(float)z/2.5,
1671                                                         blockseed, 2, 1.4);
1672                                         if(vmanip.m_data[i].d == CONTENT_COBBLE)
1673                                         {
1674                                                 if(d < wetness/3.0)
1675                                                 {
1676                                                         vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE;
1677                                                 }
1678                                         }
1679                                         /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1680                                         {
1681                                                 if(wetness > 1.2)
1682                                                         vmanip.m_data[i].d = CONTENT_MUD;
1683                                         }*/
1684                                         data->vmanip->m_area.add_y(em, i, -1);
1685                                 }
1686                         }
1687                 }
1688         }
1689         
1690         /*
1691                 Add top and bottom side of water to transforming_liquid queue
1692         */
1693
1694         for(s16 x=node_min.X; x<=node_max.X; x++)
1695         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1696         {
1697                 // Node position
1698                 v2s16 p2d(x,z);
1699                 {
1700                         bool water_found = false;
1701                         // Use fast index incrementing
1702                         v3s16 em = vmanip.m_area.getExtent();
1703                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1704                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
1705                         {
1706                                 if(water_found == false)
1707                                 {
1708                                         if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1709                                         {
1710                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1711                                                 data->transforming_liquid.push_back(p);
1712                                                 water_found = true;
1713                                         }
1714                                 }
1715                                 else
1716                                 {
1717                                         // This can be done because water_found can only
1718                                         // turn to true and end up here after going through
1719                                         // a single block.
1720                                         if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE)
1721                                         {
1722                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1723                                                 data->transforming_liquid.push_back(p);
1724                                                 water_found = false;
1725                                         }
1726                                 }
1727
1728                                 data->vmanip->m_area.add_y(em, i, -1);
1729                         }
1730                 }
1731         }
1732
1733         /*
1734                 If close to ground level
1735         */
1736
1737         //if(abs(approx_ground_depth) < 30)
1738         if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1739         {
1740                 /*
1741                         Add grass and mud
1742                 */
1743
1744                 for(s16 x=node_min.X; x<=node_max.X; x++)
1745                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1746                 {
1747                         // Node position
1748                         v2s16 p2d(x,z);
1749                         {
1750                                 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1751                                 bool have_sand = false;
1752                                 u32 current_depth = 0;
1753                                 bool air_detected = false;
1754                                 bool water_detected = false;
1755                                 // Use fast index incrementing
1756                                 s16 start_y = node_max.Y+2;
1757                                 v3s16 em = vmanip.m_area.getExtent();
1758                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1759                                 for(s16 y=start_y; y>=node_min.Y-3; y--)
1760                                 {
1761                                         if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1762                                                 water_detected = true;
1763                                         if(vmanip.m_data[i].d == CONTENT_AIR)
1764                                                 air_detected = true;
1765
1766                                         if((vmanip.m_data[i].d == CONTENT_STONE
1767                                                         || vmanip.m_data[i].d == CONTENT_GRASS
1768                                                         || vmanip.m_data[i].d == CONTENT_MUD
1769                                                         || vmanip.m_data[i].d == CONTENT_SAND
1770                                                         || vmanip.m_data[i].d == CONTENT_GRAVEL
1771                                                         ) && (air_detected || water_detected))
1772                                         {
1773                                                 if(current_depth == 0 && y <= WATER_LEVEL+2
1774                                                                 && possibly_have_sand)
1775                                                         have_sand = true;
1776                                                 
1777                                                 if(current_depth < 4)
1778                                                 {
1779                                                         if(have_sand)
1780                                                         {
1781                                                                 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1782                                                         }
1783                                                         #if 1
1784                                                         else if(current_depth==0 && !water_detected
1785                                                                         && y >= WATER_LEVEL && air_detected)
1786                                                                 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
1787                                                         #endif
1788                                                         else
1789                                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1790                                                 }
1791                                                 else
1792                                                 {
1793                                                         if(vmanip.m_data[i].d == CONTENT_MUD
1794                                                                 || vmanip.m_data[i].d == CONTENT_GRASS)
1795                                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1796                                                 }
1797
1798                                                 current_depth++;
1799
1800                                                 if(current_depth >= 8)
1801                                                         break;
1802                                         }
1803                                         else if(current_depth != 0)
1804                                                 break;
1805
1806                                         data->vmanip->m_area.add_y(em, i, -1);
1807                                 }
1808                         }
1809                 }
1810
1811                 /*
1812                         Add trees
1813                 */
1814                 
1815                 // Amount of trees
1816                 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
1817                 PseudoRandom treerandom(blockseed);
1818                 // Put trees in random places on part of division
1819                 for(u32 i=0; i<tree_count; i++)
1820                 {
1821                         s16 x = treerandom.range(node_min.X, node_max.X);
1822                         s16 z = treerandom.range(node_min.Z, node_max.Z);
1823                         //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
1824                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
1825                         // Don't make a tree under water level
1826                         if(y < WATER_LEVEL)
1827                                 continue;
1828                         // Make sure tree fits (only trees whose starting point is
1829                         // at this block are added)
1830                         if(y < node_min.Y || y > node_max.Y)
1831                                 continue;
1832                         /*
1833                                 Find exact ground level
1834                         */
1835                         v3s16 p(x,y+6,z);
1836                         bool found = false;
1837                         for(; p.Y >= y-6; p.Y--)
1838                         {
1839                                 u32 i = data->vmanip->m_area.index(p);
1840                                 MapNode *n = &data->vmanip->m_data[i];
1841                                 if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE)
1842                                 {
1843                                         found = true;
1844                                         break;
1845                                 }
1846                         }
1847                         // If not found, handle next one
1848                         if(found == false)
1849                                 continue;
1850                         /*
1851                                 Trees grow only on mud and grass
1852                         */
1853                         {
1854                                 u32 i = data->vmanip->m_area.index(p);
1855                                 MapNode *n = &data->vmanip->m_data[i];
1856                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1857                                         continue;
1858                         }
1859                         // Tree will be placed one higher
1860                         p.Y++;
1861                         // Make a tree
1862                         make_tree(vmanip, p);
1863                 }
1864
1865 #if 0
1866                 /*
1867                         Add some kind of random stones
1868                 */
1869                 
1870                 u32 random_stone_count = block_area_nodes *
1871                                 randomstone_amount_2d(data->seed, p2d_center);
1872                 // Put in random places on part of division
1873                 for(u32 i=0; i<random_stone_count; i++)
1874                 {
1875                         s16 x = myrand_range(node_min.X, node_max.X);
1876                         s16 z = myrand_range(node_min.Z, node_max.Z);
1877                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
1878                         // Don't add under water level
1879                         /*if(y < WATER_LEVEL)
1880                                 continue;*/
1881                         // Don't add if doesn't belong to this block
1882                         if(y < node_min.Y || y > node_max.Y)
1883                                 continue;
1884                         v3s16 p(x,y,z);
1885                         // Filter placement
1886                         /*{
1887                                 u32 i = data->vmanip->m_area.index(v3s16(p));
1888                                 MapNode *n = &data->vmanip->m_data[i];
1889                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1890                                         continue;
1891                         }*/
1892                         // Will be placed one higher
1893                         p.Y++;
1894                         // Add it
1895                         make_randomstone(data->vmanip, p);
1896                 }
1897 #endif
1898
1899 #if 0
1900                 /*
1901                         Add larger stones
1902                 */
1903                 
1904                 u32 large_stone_count = block_area_nodes *
1905                                 largestone_amount_2d(data->seed, p2d_center);
1906                 //u32 large_stone_count = 1;
1907                 // Put in random places on part of division
1908                 for(u32 i=0; i<large_stone_count; i++)
1909                 {
1910                         s16 x = myrand_range(node_min.X, node_max.X);
1911                         s16 z = myrand_range(node_min.Z, node_max.Z);
1912                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
1913                         // Don't add under water level
1914                         /*if(y < WATER_LEVEL)
1915                                 continue;*/
1916                         // Don't add if doesn't belong to this block
1917                         if(y < node_min.Y || y > node_max.Y)
1918                                 continue;
1919                         v3s16 p(x,y,z);
1920                         // Filter placement
1921                         /*{
1922                                 u32 i = data->vmanip->m_area.index(v3s16(p));
1923                                 MapNode *n = &data->vmanip->m_data[i];
1924                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1925                                         continue;
1926                         }*/
1927                         // Will be placed one lower
1928                         p.Y--;
1929                         // Add it
1930                         make_largestone(data->vmanip, p);
1931                 }
1932 #endif
1933         }
1934
1935 }
1936
1937 BlockMakeData::BlockMakeData():
1938         no_op(false),
1939         vmanip(NULL),
1940         seed(0)
1941 {}
1942
1943 BlockMakeData::~BlockMakeData()
1944 {
1945         delete vmanip;
1946 }
1947
1948 }; // namespace mapgen
1949
1950