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