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