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