]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen.cpp
merged jungle and bluish shadows
[dragonfireclient.git] / src / mapgen.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapgen.h"
21 #include "voxel.h"
22 #include "content_mapnode.h"
23 #include "noise.h"
24 #include "mapblock.h"
25 #include "map.h"
26 #include "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 /*
980         Noise functions. Make sure seed is mangled differently in each one.
981 */
982
983 /*
984         Scaling the output of the noise function affects the overdrive of the
985         contour function, which affects the shape of the output considerably.
986 */
987 #define CAVE_NOISE_SCALE 12.0
988 //#define CAVE_NOISE_SCALE 10.0
989 //#define CAVE_NOISE_SCALE 7.5
990 //#define CAVE_NOISE_SCALE 5.0
991 //#define CAVE_NOISE_SCALE 1.0
992
993 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
994 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
995
996 NoiseParams get_cave_noise1_params(u64 seed)
997 {
998         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
999                         200, CAVE_NOISE_SCALE);*/
1000         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1001                         100, CAVE_NOISE_SCALE);*/
1002         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1003                         100, CAVE_NOISE_SCALE);*/
1004         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1005                         100, CAVE_NOISE_SCALE);*/
1006         return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1007                         50, CAVE_NOISE_SCALE);
1008         //return NoiseParams(NOISE_CONSTANT_ONE);
1009 }
1010
1011 NoiseParams get_cave_noise2_params(u64 seed)
1012 {
1013         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1014                         200, CAVE_NOISE_SCALE);*/
1015         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1016                         100, CAVE_NOISE_SCALE);*/
1017         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1018                         100, CAVE_NOISE_SCALE);*/
1019         return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1020                         50, CAVE_NOISE_SCALE);
1021         //return NoiseParams(NOISE_CONSTANT_ONE);
1022 }
1023
1024 NoiseParams get_ground_noise1_params(u64 seed)
1025 {
1026         return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1027                         0.55, 80.0, 40.0);
1028 }
1029
1030 NoiseParams get_ground_crumbleness_params(u64 seed)
1031 {
1032         return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1033                         1.3, 20.0, 1.0);
1034 }
1035
1036 NoiseParams get_ground_wetness_params(u64 seed)
1037 {
1038         return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1039                         1.1, 40.0, 1.0);
1040 }
1041
1042 bool is_cave(u64 seed, v3s16 p)
1043 {
1044         double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1045         double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1046         return d1*d2 > CAVE_NOISE_THRESHOLD;
1047 }
1048
1049 /*
1050         Ground density noise shall be interpreted by using this.
1051
1052         TODO: No perlin noises here, they should be outsourced
1053               and buffered
1054                   NOTE: The speed of these actually isn't terrible
1055 */
1056 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1057 {
1058         //return ((double)p.Y < ground_noise1_val);
1059
1060         double f = 0.55 + noise2d_perlin(
1061                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1062                         seed+920381, 3, 0.45);
1063         if(f < 0.01)
1064                 f = 0.01;
1065         else if(f >= 1.0)
1066                 f *= 1.6;
1067         double h = WATER_LEVEL + 10 * noise2d_perlin(
1068                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1069                         seed+84174, 4, 0.5);
1070         /*double f = 1;
1071         double h = 0;*/
1072         return ((double)p.Y - h < ground_noise1_val * f);
1073 }
1074
1075 /*
1076         Queries whether a position is ground or not.
1077 */
1078 bool is_ground(u64 seed, v3s16 p)
1079 {
1080         double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1081         return val_is_ground(val1, p, seed);
1082 }
1083
1084 // Amount of trees per area in nodes
1085 double tree_amount_2d(u64 seed, v2s16 p)
1086 {
1087         /*double noise = noise2d_perlin(
1088                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1089                         seed+2, 5, 0.66);*/
1090         double noise = noise2d_perlin(
1091                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1092                         seed+2, 4, 0.66);
1093         double zeroval = -0.39;
1094         if(noise < zeroval)
1095                 return 0;
1096         else
1097                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1098 }
1099
1100 double surface_humidity_2d(u64 seed, v2s16 p)
1101 {
1102         double noise = noise2d_perlin(
1103                         0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1104                         seed+72384, 4, 0.66);
1105         noise = (noise + 1.0)/2.0;
1106         if(noise < 0.0)
1107                 noise = 0.0;
1108         if(noise > 1.0)
1109                 noise = 1.0;
1110         return noise;
1111 }
1112
1113 #if 0
1114 double randomstone_amount_2d(u64 seed, v2s16 p)
1115 {
1116         double noise = noise2d_perlin(
1117                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1118                         seed+3829434, 5, 0.66);
1119         double zeroval = 0.1;
1120         if(noise < zeroval)
1121                 return 0;
1122         else
1123                 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1124 }
1125 #endif
1126
1127 double largestone_amount_2d(u64 seed, v2s16 p)
1128 {
1129         double noise = noise2d_perlin(
1130                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1131                         seed+14143242, 5, 0.66);
1132         double zeroval = 0.3;
1133         if(noise < zeroval)
1134                 return 0;
1135         else
1136                 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1137 }
1138
1139 /*
1140         Incrementally find ground level from 3d noise
1141 */
1142 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1143 {
1144         // Start a bit fuzzy to make averaging lower precision values
1145         // more useful
1146         s16 level = myrand_range(-precision/2, precision/2);
1147         s16 dec[] = {31000, 100, 20, 4, 1, 0};
1148         s16 i;
1149         for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1150         {
1151                 // First find non-ground by going upwards
1152                 // Don't stop in caves.
1153                 {
1154                         s16 max = level+dec[i-1]*2;
1155                         v3s16 p(p2d.X, level, p2d.Y);
1156                         for(; p.Y < max; p.Y += dec[i])
1157                         {
1158                                 if(!is_ground(seed, p))
1159                                 {
1160                                         level = p.Y;
1161                                         break;
1162                                 }
1163                         }
1164                 }
1165                 // Then find ground by going downwards from there.
1166                 // Go in caves, too, when precision is 1.
1167                 {
1168                         s16 min = level-dec[i-1]*2;
1169                         v3s16 p(p2d.X, level, p2d.Y);
1170                         for(; p.Y>min; p.Y-=dec[i])
1171                         {
1172                                 bool ground = is_ground(seed, p);
1173                                 /*if(dec[i] == 1 && is_cave(seed, p))
1174                                         ground = false;*/
1175                                 if(ground)
1176                                 {
1177                                         level = p.Y;
1178                                         break;
1179                                 }
1180                         }
1181                 }
1182         }
1183         
1184         // This is more like the actual ground level
1185         level += dec[i-1]/2;
1186
1187         return level;
1188 }
1189
1190 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1191
1192 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1193 {
1194         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1195         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1196         double a = 0;
1197         a += find_ground_level_from_noise(seed,
1198                         v2s16(node_min.X, node_min.Y), p);
1199         a += find_ground_level_from_noise(seed,
1200                         v2s16(node_min.X, node_max.Y), p);
1201         a += find_ground_level_from_noise(seed,
1202                         v2s16(node_max.X, node_max.Y), p);
1203         a += find_ground_level_from_noise(seed,
1204                         v2s16(node_max.X, node_min.Y), p);
1205         a += find_ground_level_from_noise(seed,
1206                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1207         a /= 5;
1208         return a;
1209 }
1210
1211 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1212
1213 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1214 {
1215         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1216         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1217         double a = -31000;
1218         // Corners
1219         a = MYMAX(a, find_ground_level_from_noise(seed,
1220                         v2s16(node_min.X, node_min.Y), p));
1221         a = MYMAX(a, find_ground_level_from_noise(seed,
1222                         v2s16(node_min.X, node_max.Y), p));
1223         a = MYMAX(a, find_ground_level_from_noise(seed,
1224                         v2s16(node_max.X, node_max.Y), p));
1225         a = MYMAX(a, find_ground_level_from_noise(seed,
1226                         v2s16(node_min.X, node_min.Y), p));
1227         // Center
1228         a = MYMAX(a, find_ground_level_from_noise(seed,
1229                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1230         // Side middle points
1231         a = MYMAX(a, find_ground_level_from_noise(seed,
1232                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1233         a = MYMAX(a, find_ground_level_from_noise(seed,
1234                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1235         a = MYMAX(a, find_ground_level_from_noise(seed,
1236                         v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1237         a = MYMAX(a, find_ground_level_from_noise(seed,
1238                         v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1239         return a;
1240 }
1241
1242 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1243
1244 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1245 {
1246         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1247         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1248         double a = 31000;
1249         // Corners
1250         a = MYMIN(a, find_ground_level_from_noise(seed,
1251                         v2s16(node_min.X, node_min.Y), p));
1252         a = MYMIN(a, find_ground_level_from_noise(seed,
1253                         v2s16(node_min.X, node_max.Y), p));
1254         a = MYMIN(a, find_ground_level_from_noise(seed,
1255                         v2s16(node_max.X, node_max.Y), p));
1256         a = MYMIN(a, find_ground_level_from_noise(seed,
1257                         v2s16(node_min.X, node_min.Y), p));
1258         // Center
1259         a = MYMIN(a, find_ground_level_from_noise(seed,
1260                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1261         // Side middle points
1262         a = MYMIN(a, find_ground_level_from_noise(seed,
1263                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1264         a = MYMIN(a, find_ground_level_from_noise(seed,
1265                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1266         a = MYMIN(a, find_ground_level_from_noise(seed,
1267                         v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1268         a = MYMIN(a, find_ground_level_from_noise(seed,
1269                         v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1270         return a;
1271 }
1272
1273 bool block_is_underground(u64 seed, v3s16 blockpos)
1274 {
1275         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1276                         seed, v2s16(blockpos.X, blockpos.Z));
1277         
1278         if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1279                 return true;
1280         else
1281                 return false;
1282 }
1283
1284 #if 0
1285 #define AVERAGE_MUD_AMOUNT 4
1286
1287 double base_rock_level_2d(u64 seed, v2s16 p)
1288 {
1289         // The base ground level
1290         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1291                         + 20. * noise2d_perlin(
1292                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1293                         (seed>>32)+654879876, 6, 0.6);
1294
1295         /*// A bit hillier one
1296         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1297                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1298                         (seed>>27)+90340, 6, 0.69);
1299         if(base2 > base)
1300                 base = base2;*/
1301 #if 1
1302         // Higher ground level
1303         double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1304                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1305                         seed+85039, 5, 0.69);
1306         //higher = 30; // For debugging
1307
1308         // Limit higher to at least base
1309         if(higher < base)
1310                 higher = base;
1311
1312         // Steepness factor of cliffs
1313         double b = 1.0 + 1.0 * noise2d_perlin(
1314                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1315                         seed-932, 7, 0.7);
1316         b = rangelim(b, 0.0, 1000.0);
1317         b = pow(b, 5);
1318         b *= 7;
1319         b = rangelim(b, 3.0, 1000.0);
1320         //dstream<<"b="<<b<<std::endl;
1321         //double b = 20;
1322
1323         // Offset to more low
1324         double a_off = -0.2;
1325         // High/low selector
1326         /*double a = 0.5 + b * (a_off + noise2d_perlin(
1327                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1328                         seed-359, 6, 0.7));*/
1329         double a = (double)0.5 + b * (a_off + noise2d_perlin(
1330                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1331                         seed-359, 5, 0.60));
1332         // Limit
1333         a = rangelim(a, 0.0, 1.0);
1334
1335         //dstream<<"a="<<a<<std::endl;
1336
1337         double h = base*(1.0-a) + higher*a;
1338 #else
1339         double h = base;
1340 #endif
1341         return h;
1342 }
1343
1344 double get_mud_add_amount(u64 seed, v2s16 p)
1345 {
1346         return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1347                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1348                         seed+91013, 3, 0.55));
1349 }
1350 #endif
1351
1352 bool get_have_sand(u64 seed, v2s16 p2d)
1353 {
1354         // Determine whether to have sand here
1355         double sandnoise = noise2d_perlin(
1356                         0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1357                         seed+59420, 3, 0.50);
1358
1359         return (sandnoise > -0.15);
1360 }
1361
1362 /*
1363         Adds random objects to block, depending on the content of the block
1364 */
1365 void add_random_objects(MapBlock *block)
1366 {
1367         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1368         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1369         {
1370                 bool last_node_walkable = false;
1371                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1372                 {
1373                         v3s16 p(x0,y0,z0);
1374                         MapNode n = block->getNodeNoEx(p);
1375                         if(n.getContent() == CONTENT_IGNORE)
1376                                 continue;
1377                         if(content_features(n).liquid_type != LIQUID_NONE)
1378                                 continue;
1379                         if(content_features(n).walkable)
1380                         {
1381                                 last_node_walkable = true;
1382                                 continue;
1383                         }
1384                         if(last_node_walkable)
1385                         {
1386                                 // If block contains light information
1387                                 if(content_features(n).param_type == CPT_LIGHT)
1388                                 {
1389                                         if(n.getLight(LIGHTBANK_DAY) <= 3)
1390                                         {
1391                                                 if(myrand() % 300 == 0)
1392                                                 {
1393                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1394                                                         pos_f.Y -= BS*0.4;
1395                                                         ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1396                                                         std::string data = obj->getStaticData();
1397                                                         StaticObject s_obj(obj->getType(),
1398                                                                         obj->getBasePosition(), data);
1399                                                         // Add some
1400                                                         block->m_static_objects.insert(0, s_obj);
1401                                                         block->m_static_objects.insert(0, s_obj);
1402                                                         block->m_static_objects.insert(0, s_obj);
1403                                                         block->m_static_objects.insert(0, s_obj);
1404                                                         block->m_static_objects.insert(0, s_obj);
1405                                                         block->m_static_objects.insert(0, s_obj);
1406                                                         delete obj;
1407                                                 }
1408                                                 if(myrand() % 1000 == 0)
1409                                                 {
1410                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1411                                                         pos_f.Y -= BS*0.4;
1412                                                         ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1413                                                         std::string data = obj->getStaticData();
1414                                                         StaticObject s_obj(obj->getType(),
1415                                                                         obj->getBasePosition(), data);
1416                                                         // Add one
1417                                                         block->m_static_objects.insert(0, s_obj);
1418                                                         delete obj;
1419                                                 }
1420                                         }
1421                                 }
1422                         }
1423                         last_node_walkable = false;
1424                 }
1425         }
1426         block->setChangedFlag();
1427 }
1428
1429 void make_block(BlockMakeData *data)
1430 {
1431         if(data->no_op)
1432         {
1433                 //dstream<<"makeBlock: no-op"<<std::endl;
1434                 return;
1435         }
1436
1437         v3s16 blockpos = data->blockpos;
1438         
1439         /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1440                         <<blockpos.Z<<")"<<std::endl;*/
1441
1442         ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1443         v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1444         v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1445         // Area of center block
1446         v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1447         v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1448         // Full allocated area
1449         v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1450         v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1451         // Area of a block
1452         double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1453
1454         v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1455
1456         /*
1457                 Get average ground level from noise
1458         */
1459         
1460         s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1461                         data->seed, v2s16(blockpos.X, blockpos.Z));
1462         //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1463         
1464         s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1465         
1466         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1467                         data->seed, v2s16(blockpos.X, blockpos.Z));
1468         // Minimum amount of ground above the top of the central block
1469         s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1470
1471         s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1472                         data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1473         // Maximum amount of ground above the bottom of the central block
1474         s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1475
1476         #if 0
1477         /*
1478                 Special case for high air or water: Just fill with air and water.
1479         */
1480         if(maximum_ground_depth < -20)
1481         {
1482                 for(s16 x=node_min.X; x<=node_max.X; x++)
1483                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1484                 {
1485                         // Node position
1486                         v2s16 p2d(x,z);
1487                         {
1488                                 // Use fast index incrementing
1489                                 v3s16 em = vmanip.m_area.getExtent();
1490                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1491                                 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1492                                 {
1493                                         // Only modify places that have no content
1494                                         if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1495                                         {
1496                                                 if(y <= WATER_LEVEL)
1497                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1498                                                 else
1499                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
1500                                         }
1501                                 
1502                                         data->vmanip->m_area.add_y(em, i, 1);
1503                                 }
1504                         }
1505                 }
1506                 
1507                 // We're done
1508                 return;
1509         }
1510         #endif
1511
1512         /*
1513                 If block is deep underground, this is set to true and ground
1514                 density noise is not generated, for speed optimization.
1515         */
1516         bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1517         
1518         /*
1519                 Create a block-specific seed
1520         */
1521         u32 blockseed = (u32)(data->seed%0x100000000) + full_node_min.Z*38134234
1522                         + full_node_min.Y*42123 + full_node_min.X*23;
1523         
1524         /*
1525                 Make some 3D noise
1526         */
1527         
1528         //NoiseBuffer noisebuf1;
1529         //NoiseBuffer noisebuf2;
1530         NoiseBuffer noisebuf_cave;
1531         NoiseBuffer noisebuf_ground;
1532         NoiseBuffer noisebuf_ground_crumbleness;
1533         NoiseBuffer noisebuf_ground_wetness;
1534         {
1535                 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1536                 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1537
1538                 //TimeTaker timer("noisebuf.create");
1539
1540                 /*
1541                         Cave noise
1542                 */
1543 #if 1
1544                 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1545                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
1546                                 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1547                                 2, 2, 2);
1548                 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1549 #endif
1550
1551                 /*
1552                         Ground noise
1553                 */
1554                 
1555                 // Sample length
1556                 v3f sl = v3f(4.0, 4.0, 4.0);
1557                 
1558                 /*
1559                         Density noise
1560                 */
1561                 if(all_is_ground_except_caves == false)
1562                         //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1563                         noisebuf_ground.create(get_ground_noise1_params(data->seed),
1564                                         minpos_f.X, minpos_f.Y, minpos_f.Z,
1565                                         maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1566                                         sl.X, sl.Y, sl.Z);
1567                 
1568                 /*
1569                         Ground property noise
1570                 */
1571                 sl = v3f(2.5, 2.5, 2.5);
1572                 noisebuf_ground_crumbleness.create(
1573                                 get_ground_crumbleness_params(data->seed),
1574                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
1575                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1576                                 sl.X, sl.Y, sl.Z);
1577                 noisebuf_ground_wetness.create(
1578                                 get_ground_wetness_params(data->seed),
1579                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
1580                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1581                                 sl.X, sl.Y, sl.Z);
1582         }
1583         
1584         /*
1585                 Make base ground level
1586         */
1587
1588         for(s16 x=node_min.X; x<=node_max.X; x++)
1589         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1590         {
1591                 // Node position
1592                 v2s16 p2d(x,z);
1593                 {
1594                         // Use fast index incrementing
1595                         v3s16 em = vmanip.m_area.getExtent();
1596                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1597                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
1598                         {
1599                                 // Only modify places that have no content
1600                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1601                                 {
1602                                         // First priority: make air and water.
1603                                         // This avoids caves inside water.
1604                                         if(all_is_ground_except_caves == false
1605                                                         && val_is_ground(noisebuf_ground.get(x,y,z),
1606                                                         v3s16(x,y,z), data->seed) == false)
1607                                         {
1608                                                 if(y <= WATER_LEVEL)
1609                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1610                                                 else
1611                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
1612                                         }
1613                                         else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1614                                                 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1615                                         else
1616                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1617                                 }
1618                         
1619                                 data->vmanip->m_area.add_y(em, i, 1);
1620                         }
1621                 }
1622         }
1623
1624         /*
1625                 Add minerals
1626         */
1627
1628         {
1629                 PseudoRandom mineralrandom(blockseed);
1630
1631                 /*
1632                         Add meseblocks
1633                 */
1634                 for(s16 i=0; i<approx_ground_depth/4; i++)
1635                 {
1636                         if(mineralrandom.next()%50 == 0)
1637                         {
1638                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1639                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1640                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1641                                 for(u16 i=0; i<27; i++)
1642                                 {
1643                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1644                                         u32 vi = vmanip.m_area.index(p);
1645                                         if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1646                                                 if(mineralrandom.next()%8 == 0)
1647                                                         vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1648                                 }
1649                                         
1650                         }
1651                 }
1652                 /*
1653                         Add others
1654                 */
1655                 {
1656                         u16 a = mineralrandom.range(0,15);
1657                         a = a*a*a;
1658                         u16 amount = 20 * a/1000;
1659                         for(s16 i=0; i<amount; i++)
1660                         {
1661                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1662                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1663                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1664
1665                                 u8 base_content = CONTENT_STONE;
1666                                 MapNode new_content(CONTENT_IGNORE);
1667                                 u32 sparseness = 6;
1668
1669                                 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1670                                 {
1671                                         new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1672                                 }
1673                                 else
1674                                 {
1675                                         if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1676                                                 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1677                                         /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1678                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1679                                         else
1680                                                 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1681                                 }
1682                                 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1683                                 {
1684                                 }*/
1685
1686                                 if(new_content.getContent() != CONTENT_IGNORE)
1687                                 {
1688                                         for(u16 i=0; i<27; i++)
1689                                         {
1690                                                 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1691                                                 u32 vi = vmanip.m_area.index(p);
1692                                                 if(vmanip.m_data[vi].getContent() == base_content)
1693                                                 {
1694                                                         if(mineralrandom.next()%sparseness == 0)
1695                                                                 vmanip.m_data[vi] = new_content;
1696                                                 }
1697                                         }
1698                                 }
1699                         }
1700                 }
1701                 /*
1702                         Add coal
1703                 */
1704                 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1705                 //for(s16 i=0; i<50; i++)
1706                 u16 coal_amount = 30;
1707                 u16 coal_rareness = 60 / coal_amount;
1708                 if(coal_rareness == 0)
1709                         coal_rareness = 1;
1710                 if(mineralrandom.next()%coal_rareness == 0)
1711                 {
1712                         u16 a = mineralrandom.next() % 16;
1713                         u16 amount = coal_amount * a*a*a / 1000;
1714                         for(s16 i=0; i<amount; i++)
1715                         {
1716                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1717                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1718                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1719                                 for(u16 i=0; i<27; i++)
1720                                 {
1721                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1722                                         u32 vi = vmanip.m_area.index(p);
1723                                         if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1724                                                 if(mineralrandom.next()%8 == 0)
1725                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1726                                 }
1727                         }
1728                 }
1729                 /*
1730                         Add iron
1731                 */
1732                 u16 iron_amount = 8;
1733                 u16 iron_rareness = 60 / iron_amount;
1734                 if(iron_rareness == 0)
1735                         iron_rareness = 1;
1736                 if(mineralrandom.next()%iron_rareness == 0)
1737                 {
1738                         u16 a = mineralrandom.next() % 16;
1739                         u16 amount = iron_amount * a*a*a / 1000;
1740                         for(s16 i=0; i<amount; i++)
1741                         {
1742                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1743                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1744                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1745                                 for(u16 i=0; i<27; i++)
1746                                 {
1747                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1748                                         u32 vi = vmanip.m_area.index(p);
1749                                         if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1750                                                 if(mineralrandom.next()%8 == 0)
1751                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1752                                 }
1753                         }
1754                 }
1755         }
1756
1757         /*
1758                 Add mud and sand and others underground (in place of stone)
1759         */
1760
1761         for(s16 x=node_min.X; x<=node_max.X; x++)
1762         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1763         {
1764                 // Node position
1765                 v2s16 p2d(x,z);
1766                 {
1767                         // Use fast index incrementing
1768                         v3s16 em = vmanip.m_area.getExtent();
1769                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1770                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
1771                         {
1772                                 if(vmanip.m_data[i].getContent() == CONTENT_STONE)
1773                                 {
1774                                         if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1775                                         {
1776                                                 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1777                                                         vmanip.m_data[i] = MapNode(CONTENT_MUD);
1778                                                 else
1779                                                         vmanip.m_data[i] = MapNode(CONTENT_SAND);
1780                                         }
1781                                         else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1782                                         {
1783                                                 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1784                                                         vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1785                                         }
1786                                 }
1787
1788                                 data->vmanip->m_area.add_y(em, i, -1);
1789                         }
1790                 }
1791         }
1792
1793         /*
1794                 Add dungeons
1795         */
1796         
1797         //if(node_min.Y < approx_groundlevel)
1798         //if(myrand() % 3 == 0)
1799         //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1800         //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1801         //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1802         float dungeon_rarity = 0.02;
1803         if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1804                         < dungeon_rarity
1805                         && node_min.Y < approx_groundlevel)
1806         {
1807                 // Dungeon generator doesn't modify places which have this set
1808                 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1809                                 | VMANIP_FLAG_DUNGEON_PRESERVE);
1810                 
1811                 // Set all air and water to be untouchable to make dungeons open
1812                 // to caves and open air
1813                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1814                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1815                 {
1816                         // Node position
1817                         v2s16 p2d(x,z);
1818                         {
1819                                 // Use fast index incrementing
1820                                 v3s16 em = vmanip.m_area.getExtent();
1821                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1822                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1823                                 {
1824                                         if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1825                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1826                                         else if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1827                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1828                                         data->vmanip->m_area.add_y(em, i, -1);
1829                                 }
1830                         }
1831                 }
1832                 
1833                 PseudoRandom random(blockseed+2);
1834
1835                 // Add it
1836                 make_dungeon1(vmanip, random);
1837                 
1838                 // Convert some cobble to mossy cobble
1839                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1840                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1841                 {
1842                         // Node position
1843                         v2s16 p2d(x,z);
1844                         {
1845                                 // Use fast index incrementing
1846                                 v3s16 em = vmanip.m_area.getExtent();
1847                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1848                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1849                                 {
1850                                         // (noisebuf not used because it doesn't contain the
1851                                         //  full area)
1852                                         double wetness = noise3d_param(
1853                                                         get_ground_wetness_params(data->seed), x,y,z);
1854                                         double d = noise3d_perlin((float)x/2.5,
1855                                                         (float)y/2.5,(float)z/2.5,
1856                                                         blockseed, 2, 1.4);
1857                                         if(vmanip.m_data[i].getContent() == CONTENT_COBBLE)
1858                                         {
1859                                                 if(d < wetness/3.0)
1860                                                 {
1861                                                         vmanip.m_data[i].setContent(CONTENT_MOSSYCOBBLE);
1862                                                 }
1863                                         }
1864                                         /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1865                                         {
1866                                                 if(wetness > 1.2)
1867                                                         vmanip.m_data[i].setContent(CONTENT_MUD);
1868                                         }*/
1869                                         data->vmanip->m_area.add_y(em, i, -1);
1870                                 }
1871                         }
1872                 }
1873         }
1874         
1875         /*
1876                 Add top and bottom side of water to transforming_liquid queue
1877         */
1878
1879         for(s16 x=node_min.X; x<=node_max.X; x++)
1880         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1881         {
1882                 // Node position
1883                 v2s16 p2d(x,z);
1884                 {
1885                         bool water_found = false;
1886                         // Use fast index incrementing
1887                         v3s16 em = vmanip.m_area.getExtent();
1888                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1889                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
1890                         {
1891                                 if(water_found == false)
1892                                 {
1893                                         if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1894                                         {
1895                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1896                                                 data->transforming_liquid.push_back(p);
1897                                                 water_found = true;
1898                                         }
1899                                 }
1900                                 else
1901                                 {
1902                                         // This can be done because water_found can only
1903                                         // turn to true and end up here after going through
1904                                         // a single block.
1905                                         if(vmanip.m_data[i+1].getContent() != CONTENT_WATERSOURCE)
1906                                         {
1907                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1908                                                 data->transforming_liquid.push_back(p);
1909                                                 water_found = false;
1910                                         }
1911                                 }
1912
1913                                 data->vmanip->m_area.add_y(em, i, -1);
1914                         }
1915                 }
1916         }
1917
1918         /*
1919                 If close to ground level
1920         */
1921
1922         //if(abs(approx_ground_depth) < 30)
1923         if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1924         {
1925                 /*
1926                         Add grass and mud
1927                 */
1928
1929                 for(s16 x=node_min.X; x<=node_max.X; x++)
1930                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1931                 {
1932                         // Node position
1933                         v2s16 p2d(x,z);
1934                         {
1935                                 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1936                                 bool have_sand = false;
1937                                 u32 current_depth = 0;
1938                                 bool air_detected = false;
1939                                 bool water_detected = false;
1940                                 bool have_clay = false;
1941
1942                                 // Use fast index incrementing
1943                                 s16 start_y = node_max.Y+2;
1944                                 v3s16 em = vmanip.m_area.getExtent();
1945                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1946                                 for(s16 y=start_y; y>=node_min.Y-3; y--)
1947                                 {
1948                                         if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1949                                                 water_detected = true;
1950                                         if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1951                                                 air_detected = true;
1952
1953                                         if((vmanip.m_data[i].getContent() == CONTENT_STONE
1954                                                         || vmanip.m_data[i].getContent() == CONTENT_GRASS
1955                                                         || vmanip.m_data[i].getContent() == CONTENT_MUD
1956                                                         || vmanip.m_data[i].getContent() == CONTENT_SAND
1957                                                         || vmanip.m_data[i].getContent() == CONTENT_GRAVEL
1958                                                         ) && (air_detected || water_detected))
1959                                         {
1960                                                 if(current_depth == 0 && y <= WATER_LEVEL+2
1961                                                                 && possibly_have_sand)
1962                                                         have_sand = true;
1963                                                 
1964                                                 if(current_depth < 4)
1965                                                 {
1966                                                         if(have_sand)
1967                                                         {
1968                                                                 // Determine whether to have clay in the sand here
1969                                                                 double claynoise = noise2d_perlin(
1970                                                                                 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1971                                                                                 data->seed+4321, 6, 0.95) + 0.5;
1972                                 
1973                                                                 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
1974                                                                         ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
1975                                                                         ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
1976                                                                         );
1977                                                                 if (have_clay)
1978                                                                         vmanip.m_data[i] = MapNode(CONTENT_CLAY);
1979                                                                 else
1980                                                                         vmanip.m_data[i] = MapNode(CONTENT_SAND);
1981                                                         }
1982                                                         #if 1
1983                                                         else if(current_depth==0 && !water_detected
1984                                                                         && y >= WATER_LEVEL && air_detected)
1985                                                                 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
1986                                                         #endif
1987                                                         else
1988                                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1989                                                 }
1990                                                 else
1991                                                 {
1992                                                         if(vmanip.m_data[i].getContent() == CONTENT_MUD
1993                                                                 || vmanip.m_data[i].getContent() == CONTENT_GRASS)
1994                                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1995                                                 }
1996
1997                                                 current_depth++;
1998
1999                                                 if(current_depth >= 8)
2000                                                         break;
2001                                         }
2002                                         else if(current_depth != 0)
2003                                                 break;
2004
2005                                         data->vmanip->m_area.add_y(em, i, -1);
2006                                 }
2007                         }
2008                 }
2009
2010                 /*
2011                         Calculate some stuff
2012                 */
2013                 
2014                 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2015                 bool is_jungle = surface_humidity > 0.75;
2016                 // Amount of trees
2017                 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
2018                 if(is_jungle)
2019                         tree_count *= 5;
2020
2021                 /*
2022                         Add trees
2023                 */
2024                 PseudoRandom treerandom(blockseed);
2025                 // Put trees in random places on part of division
2026                 for(u32 i=0; i<tree_count; i++)
2027                 {
2028                         s16 x = treerandom.range(node_min.X, node_max.X);
2029                         s16 z = treerandom.range(node_min.Z, node_max.Z);
2030                         //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2031                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2032                         // Don't make a tree under water level
2033                         if(y < WATER_LEVEL)
2034                                 continue;
2035                         // Make sure tree fits (only trees whose starting point is
2036                         // at this block are added)
2037                         if(y < node_min.Y || y > node_max.Y)
2038                                 continue;
2039                         /*
2040                                 Find exact ground level
2041                         */
2042                         v3s16 p(x,y+6,z);
2043                         bool found = false;
2044                         for(; p.Y >= y-6; p.Y--)
2045                         {
2046                                 u32 i = data->vmanip->m_area.index(p);
2047                                 MapNode *n = &data->vmanip->m_data[i];
2048                                 if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
2049                                 {
2050                                         found = true;
2051                                         break;
2052                                 }
2053                         }
2054                         // If not found, handle next one
2055                         if(found == false)
2056                                 continue;
2057
2058                         {
2059                                 u32 i = data->vmanip->m_area.index(p);
2060                                 MapNode *n = &data->vmanip->m_data[i];
2061
2062                                 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
2063                                                 continue;
2064
2065                                 // Papyrus grows only on mud and in water
2066                                 if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
2067                                 {
2068                                         p.Y++;
2069                                         make_papyrus(vmanip, p);
2070                                 }
2071                                 // Trees grow only on mud and grass, on land
2072                                 else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
2073                                 {
2074                                         p.Y++;
2075                                         //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2076                                         if(is_jungle == false)
2077                                                 make_tree(vmanip, p);
2078                                         else
2079                                                 make_jungletree(vmanip, p);
2080                                 }
2081                                 // Cactii grow only on sand, on land
2082                                 else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
2083                                 {
2084                                         p.Y++;
2085                                         make_cactus(vmanip, p);
2086                                 }
2087                         }
2088                 }
2089
2090                 /*
2091                         Add jungle grass
2092                 */
2093                 if(is_jungle)
2094                 {
2095                         PseudoRandom grassrandom(blockseed);
2096                         for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2097                         {
2098                                 s16 x = grassrandom.range(node_min.X, node_max.X);
2099                                 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2100                                 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2101                                 if(y < WATER_LEVEL)
2102                                         continue;
2103                                 if(y < node_min.Y || y > node_max.Y)
2104                                         continue;
2105                                 /*
2106                                         Find exact ground level
2107                                 */
2108                                 v3s16 p(x,y+6,z);
2109                                 bool found = false;
2110                                 for(; p.Y >= y-6; p.Y--)
2111                                 {
2112                                         u32 i = data->vmanip->m_area.index(p);
2113                                         MapNode *n = &data->vmanip->m_data[i];
2114                                         if(content_features(*n).is_ground_content
2115                                                         || n->getContent() == CONTENT_JUNGLETREE)
2116                                         {
2117                                                 found = true;
2118                                                 break;
2119                                         }
2120                                 }
2121                                 // If not found, handle next one
2122                                 if(found == false)
2123                                         continue;
2124                                 p.Y++;
2125                                 if(vmanip.m_area.contains(p) == false)
2126                                         continue;
2127                                 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2128                                         continue;
2129                                 /*p.Y--;
2130                                 if(vmanip.m_area.contains(p))
2131                                         vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
2132                                 p.Y++;*/
2133                                 if(vmanip.m_area.contains(p))
2134                                         vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
2135                         }
2136                 }
2137
2138 #if 0
2139                 /*
2140                         Add some kind of random stones
2141                 */
2142                 
2143                 u32 random_stone_count = block_area_nodes *
2144                                 randomstone_amount_2d(data->seed, p2d_center);
2145                 // Put in random places on part of division
2146                 for(u32 i=0; i<random_stone_count; i++)
2147                 {
2148                         s16 x = myrand_range(node_min.X, node_max.X);
2149                         s16 z = myrand_range(node_min.Z, node_max.Z);
2150                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2151                         // Don't add under water level
2152                         /*if(y < WATER_LEVEL)
2153                                 continue;*/
2154                         // Don't add if doesn't belong to this block
2155                         if(y < node_min.Y || y > node_max.Y)
2156                                 continue;
2157                         v3s16 p(x,y,z);
2158                         // Filter placement
2159                         /*{
2160                                 u32 i = data->vmanip->m_area.index(v3s16(p));
2161                                 MapNode *n = &data->vmanip->m_data[i];
2162                                 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2163                                         continue;
2164                         }*/
2165                         // Will be placed one higher
2166                         p.Y++;
2167                         // Add it
2168                         make_randomstone(data->vmanip, p);
2169                 }
2170 #endif
2171
2172 #if 0
2173                 /*
2174                         Add larger stones
2175                 */
2176                 
2177                 u32 large_stone_count = block_area_nodes *
2178                                 largestone_amount_2d(data->seed, p2d_center);
2179                 //u32 large_stone_count = 1;
2180                 // Put in random places on part of division
2181                 for(u32 i=0; i<large_stone_count; i++)
2182                 {
2183                         s16 x = myrand_range(node_min.X, node_max.X);
2184                         s16 z = myrand_range(node_min.Z, node_max.Z);
2185                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2186                         // Don't add under water level
2187                         /*if(y < WATER_LEVEL)
2188                                 continue;*/
2189                         // Don't add if doesn't belong to this block
2190                         if(y < node_min.Y || y > node_max.Y)
2191                                 continue;
2192                         v3s16 p(x,y,z);
2193                         // Filter placement
2194                         /*{
2195                                 u32 i = data->vmanip->m_area.index(v3s16(p));
2196                                 MapNode *n = &data->vmanip->m_data[i];
2197                                 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2198                                         continue;
2199                         }*/
2200                         // Will be placed one lower
2201                         p.Y--;
2202                         // Add it
2203                         make_largestone(data->vmanip, p);
2204                 }
2205 #endif
2206         }
2207
2208 }
2209
2210 BlockMakeData::BlockMakeData():
2211         no_op(false),
2212         vmanip(NULL),
2213         seed(0)
2214 {}
2215
2216 BlockMakeData::~BlockMakeData()
2217 {
2218         delete vmanip;
2219 }
2220
2221 }; // namespace mapgen
2222
2223