3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
34 Some helper functions for the map generator
38 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
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));
45 for(y=y_nodes_max; y>=y_nodes_min; y--)
47 MapNode &n = vmanip.m_data[i];
48 if(content_walkable(n.d))
51 vmanip.m_area.add_y(em, i, -1);
59 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
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));
66 for(y=y_nodes_max; y>=y_nodes_min; y--)
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"))
74 vmanip.m_area.add_y(em, i, -1);
83 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
84 bool is_apple_tree, INodeDefManager *ndef)
86 MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
87 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
88 MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
90 s16 trunk_h = myrand_range(4, 5);
92 for(s16 ii=0; ii<trunk_h; ii++)
94 if(vmanip.m_area.contains(p1))
95 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
99 // p1 is now the last piece of the trunk
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++)
108 // Force leaves at near the end of the trunk
111 for(s16 z=-d; z<=d; z++)
112 for(s16 y=-d; y<=d; y++)
113 for(s16 x=-d; x<=d; x++)
115 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
119 // Add leaves randomly
120 for(u32 iii=0; iii<7; iii++)
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)
130 for(s16 z=0; z<=d; z++)
131 for(s16 y=0; y<=d; y++)
132 for(s16 x=0; x<=d; x++)
134 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
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++)
145 if(vmanip.m_area.contains(p) == false)
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)
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;
157 vmanip.m_data[vi] = leavesnode;
163 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
164 INodeDefManager *ndef)
166 MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
167 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
169 for(s16 x=-1; x<=1; x++)
170 for(s16 z=-1; z<=1; z++)
172 if(myrand_range(0, 2) == 0)
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;
183 s16 trunk_h = myrand_range(8, 12);
185 for(s16 ii=0; ii<trunk_h; ii++)
187 if(vmanip.m_area.contains(p1))
188 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
192 // p1 is now the last piece of the trunk
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++)
201 // Force leaves at near the end of the trunk
204 for(s16 z=-d; z<=d; z++)
205 for(s16 y=-d; y<=d; y++)
206 for(s16 x=-d; x<=d; x++)
208 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
212 // Add leaves randomly
213 for(u32 iii=0; iii<30; iii++)
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)
223 for(s16 z=0; z<=d; z++)
224 for(s16 y=0; y<=d; y++)
225 for(s16 x=0; x<=d; x++)
227 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
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++)
238 if(vmanip.m_area.contains(p) == false)
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)
244 u32 i = leaves_a.index(x,y,z);
246 vmanip.m_data[vi] = leavesnode;
250 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
251 INodeDefManager *ndef)
253 MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
255 s16 trunk_h = myrand_range(2, 3);
257 for(s16 ii=0; ii<trunk_h; ii++)
259 if(vmanip.m_area.contains(p1))
260 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
265 void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
266 INodeDefManager *ndef)
268 MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
272 for(s16 ii=0; ii<trunk_h; ii++)
274 if(vmanip.m_area.contains(p1))
275 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
281 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
283 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
285 s16 size = myrand_range(3, 6);
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++)
292 // Force stone at bottom to make it usually touch the ground
294 for(s16 z=0; z<=0; z++)
295 for(s16 y=0; y<=0; y++)
296 for(s16 x=0; x<=0; x++)
298 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
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++)
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)
311 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
313 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
317 u32 vi = stone_a.index(v3s16(x,y,z));
322 /*// Add stone randomly
323 for(u32 iii=0; iii<7; iii++)
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)
333 for(s16 z=0; z<=d; z++)
334 for(s16 y=0; y<=d; y++)
335 for(s16 x=0; x<=d; x++)
337 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
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++)
348 if(vmanip.m_area.contains(p) == false)
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)
354 u32 i = stone_a.index(x,y,z);
356 vmanip.m_data[vi] = stonenode;
362 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
364 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
366 s16 size = myrand_range(8, 16);
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++)
373 // Force stone at bottom to make it usually touch the ground
375 for(s16 z=0; z<=0; z++)
376 for(s16 y=0; y<=0; y++)
377 for(s16 x=0; x<=0; x++)
379 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
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++)
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;
401 u32 vi = stone_a.index(v3s16(x,y,z));
406 /*// Add stone randomly
407 for(u32 iii=0; iii<7; iii++)
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)
417 for(s16 z=0; z<=d; z++)
418 for(s16 y=0; y<=d; y++)
419 for(s16 x=0; x<=d; x++)
421 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
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++)
432 if(vmanip.m_area.contains(p) == false)
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)
438 u32 i = stone_a.index(x,y,z);
440 vmanip.m_data[vi] = stonenode;
446 Dungeon making routines
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)
454 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
455 INodeDefManager *ndef)
458 for(s16 z=0; z<roomsize.Z; z++)
459 for(s16 y=0; y<roomsize.Y; y++)
462 v3s16 p = roomplace + v3s16(0,y,z);
463 if(vmanip.m_area.contains(p) == false)
465 u32 vi = vmanip.m_area.index(p);
466 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
468 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
471 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
472 if(vmanip.m_area.contains(p) == false)
474 u32 vi = vmanip.m_area.index(p);
475 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
477 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
482 for(s16 x=0; x<roomsize.X; x++)
483 for(s16 y=0; y<roomsize.Y; y++)
486 v3s16 p = roomplace + v3s16(x,y,0);
487 if(vmanip.m_area.contains(p) == false)
489 u32 vi = vmanip.m_area.index(p);
490 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
492 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
495 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
496 if(vmanip.m_area.contains(p) == false)
498 u32 vi = vmanip.m_area.index(p);
499 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
501 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
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++)
510 v3s16 p = roomplace + v3s16(x,0,z);
511 if(vmanip.m_area.contains(p) == false)
513 u32 vi = vmanip.m_area.index(p);
514 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
516 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
519 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
520 if(vmanip.m_area.contains(p) == false)
522 u32 vi = vmanip.m_area.index(p);
523 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
525 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
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++)
534 v3s16 p = roomplace + v3s16(x,y,z);
535 if(vmanip.m_area.contains(p) == false)
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);
543 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
544 u8 avoid_flags, MapNode n, u8 or_flags)
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++)
550 v3s16 p = place + v3s16(x,y,z);
551 if(vmanip.m_area.contains(p) == false)
553 u32 vi = vmanip.m_area.index(p);
554 if(vmanip.m_flags[vi] & avoid_flags)
556 vmanip.m_flags[vi] |= or_flags;
557 vmanip.m_data[vi] = n;
561 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
562 INodeDefManager *ndef)
564 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
565 VMANIP_FLAG_DUNGEON_INSIDE);
568 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
569 INodeDefManager *ndef)
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"));
576 static v3s16 rand_ortho_dir(PseudoRandom &random)
578 if(random.next()%2==0)
579 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
581 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
584 static v3s16 turn_xz(v3s16 olddir, int t)
604 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
606 int turn = random.range(0,2);
615 dir = turn_xz(olddir, 0);
618 dir = turn_xz(olddir, 1);
622 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
623 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
624 PseudoRandom &random, INodeDefManager *ndef)
626 make_hole1(vmanip, doorplace, ndef);
627 v3s16 p0 = doorplace;
631 length = random.range(1,13);
633 length = random.range(1,6);
634 length = random.range(1,13);
635 u32 partlength = random.range(1,13);
638 if(random.next()%2 == 0 && partlength >= 3)
639 make_stairs = random.next()%2 ? 1 : -1;
640 for(u32 i=0; i<length; i++)
646 /*// If already empty
647 if(vmanip.getNodeNoExNoEmerge(p).getContent()
649 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
654 if(vmanip.m_area.contains(p) == true
655 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
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);
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);*/
679 // Can't go here, turn away
680 dir = turn_xz(dir, random.range(0,1));
681 make_stairs = -make_stairs;
683 partlength = random.range(1,length);
688 if(partcount >= partlength)
692 dir = random_turn(random, dir);
694 partlength = random.range(1,length);
697 if(random.next()%2 == 0 && partlength >= 3)
698 make_stairs = random.next()%2 ? 1 : -1;
709 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
710 INodeDefManager *ndef):
721 m_dir = rand_ortho_dir(m_random);
724 void setPos(v3s16 pos)
729 void setDir(v3s16 dir)
734 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
736 for(u32 i=0; i<100; i++)
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
747 if(vmanip.getNodeNoExNoEmerge(p).getContent()
748 == LEGN(m_ndef, "CONTENT_COBBLE")
749 && vmanip.getNodeNoExNoEmerge(p1).getContent()
750 == LEGN(m_ndef, "CONTENT_COBBLE"))
752 // Found wall, this is a good place!
755 // Randomize next direction
760 Determine where to move next
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"))
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"))
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"))
784 // Cannot continue walking here
794 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
795 v3s16 &result_doordir, v3s16 &result_roomplace)
797 for(s16 trycount=0; trycount<30; trycount++)
801 bool r = findPlaceForDoor(doorplace, doordir);
805 // X east, Z north, Y up
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);
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);
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++)
837 v3s16 p = roomplace + v3s16(x,y,z);
838 if(vmanip.m_area.contains(p) == false)
843 if(vmanip.m_flags[vmanip.m_area.index(p)]
844 & VMANIP_FLAG_DUNGEON_INSIDE)
855 result_doorplace = doorplace;
856 result_doordir = doordir;
857 result_roomplace = roomplace;
864 VoxelManipulator &vmanip;
867 PseudoRandom &m_random;
868 INodeDefManager *m_ndef;
871 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
872 INodeDefManager *ndef)
874 v3s16 areasize = vmanip.m_area.getExtent();
879 Find place for first room
882 for(u32 i=0; i<100; i++)
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));
890 Check that we're not putting the room to an unknown place,
891 otherwise it might end up floating in the air
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++)
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)
905 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
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.
923 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
925 u32 room_count = random.range(2,7);
926 for(u32 i=0; i<room_count; i++)
928 // Make a room to the determined place
929 make_room1(vmanip, roomsize, roomplace, ndef);
931 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
933 // Place torch at room center (for testing)
934 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
937 if(i == room_count-1)
940 // Determine walker start position
942 bool start_in_last_room = (random.range(0,2)!=0);
943 //bool start_in_last_room = true;
945 v3s16 walker_start_place;
947 if(start_in_last_room)
949 walker_start_place = last_room_center;
953 walker_start_place = room_center;
954 // Store center of current room as the last one
955 last_room_center = room_center;
958 // Create walker and find a place for a door
959 RoomWalker walker(vmanip, walker_start_place, random, ndef);
962 bool r = walker.findPlaceForDoor(doorplace, doordir);
966 if(random.range(0,1)==0)
968 make_door1(vmanip, doorplace, doordir, ndef);
970 // Don't actually make a door
971 doorplace -= doordir;
973 // Make a random corridor starting from the door
975 v3s16 corridor_end_dir;
976 make_corridor(vmanip, doorplace, doordir, corridor_end,
977 corridor_end_dir, random, ndef);
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);
987 if(random.range(0,1)==0)
989 make_door1(vmanip, doorplace, doordir, ndef);
991 // Don't actually make a door
992 roomplace -= doordir;
997 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
998 INodeDefManager *ndef)
1002 s32 r = random.range(0, 3);
1004 dir = v3s16( 1, 0, 0);
1008 dir = v3s16(-1, 0, 0);
1012 dir = v3s16( 0, 0, 1);
1016 dir = v3s16( 0, 0,-1);
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++)
1028 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
1033 Noise functions. Make sure seed is mangled differently in each one.
1037 Scaling the output of the noise function affects the overdrive of the
1038 contour function, which affects the shape of the output considerably.
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
1046 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1047 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1049 NoiseParams get_cave_noise1_params(u64 seed)
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);
1064 NoiseParams get_cave_noise2_params(u64 seed)
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);
1077 NoiseParams get_ground_noise1_params(u64 seed)
1079 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1083 NoiseParams get_ground_crumbleness_params(u64 seed)
1085 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1089 NoiseParams get_ground_wetness_params(u64 seed)
1091 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1095 bool is_cave(u64 seed, v3s16 p)
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;
1103 Ground density noise shall be interpreted by using this.
1105 TODO: No perlin noises here, they should be outsourced
1107 NOTE: The speed of these actually isn't terrible
1109 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1111 //return ((double)p.Y < ground_noise1_val);
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);
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);
1125 return ((double)p.Y - h < ground_noise1_val * f);
1129 Queries whether a position is ground or not.
1131 bool is_ground(u64 seed, v3s16 p)
1133 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1134 return val_is_ground(val1, p, seed);
1137 // Amount of trees per area in nodes
1138 double tree_amount_2d(u64 seed, v2s16 p)
1140 /*double noise = noise2d_perlin(
1141 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1143 double noise = noise2d_perlin(
1144 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1146 double zeroval = -0.39;
1150 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1153 double surface_humidity_2d(u64 seed, v2s16 p)
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;
1167 double randomstone_amount_2d(u64 seed, v2s16 p)
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;
1176 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1180 double largestone_amount_2d(u64 seed, v2s16 p)
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;
1189 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1193 Incrementally find ground level from 3d noise
1195 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1197 // Start a bit fuzzy to make averaging lower precision values
1199 s16 level = myrand_range(-precision/2, precision/2);
1200 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1202 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1204 // First find non-ground by going upwards
1205 // Don't stop in caves.
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])
1211 if(!is_ground(seed, p))
1218 // Then find ground by going downwards from there.
1219 // Go in caves, too, when precision is 1.
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])
1225 bool ground = is_ground(seed, p);
1226 /*if(dec[i] == 1 && is_cave(seed, p))
1237 // This is more like the actual ground level
1238 level += dec[i-1]/2;
1243 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1245 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1247 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1248 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
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);
1264 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1266 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1268 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1269 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
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));
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));
1295 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1297 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1299 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1300 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
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));
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));
1326 bool block_is_underground(u64 seed, v3s16 blockpos)
1328 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1329 seed, v2s16(blockpos.X, blockpos.Z));
1331 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1338 #define AVERAGE_MUD_AMOUNT 4
1340 double base_rock_level_2d(u64 seed, v2s16 p)
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);
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);
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
1361 // Limit higher to at least base
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.,
1369 b = rangelim(b, 0.0, 1000.0);
1372 b = rangelim(b, 3.0, 1000.0);
1373 //dstream<<"b="<<b<<std::endl;
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));
1386 a = rangelim(a, 0.0, 1.0);
1388 //dstream<<"a="<<a<<std::endl;
1390 double h = base*(1.0-a) + higher*a;
1397 double get_mud_add_amount(u64 seed, v2s16 p)
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));
1405 bool get_have_sand(u64 seed, v2s16 p2d)
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);
1412 return (sandnoise > -0.15);
1416 Adds random objects to block, depending on the content of the block
1418 void add_random_objects(MapBlock *block)
1421 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1422 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1424 bool last_node_walkable = false;
1425 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1428 MapNode n = block->getNodeNoEx(p);
1429 if(n.getContent() == CONTENT_IGNORE)
1431 if(data->nodedef->get(n)->liquid_type != LIQUID_NONE)
1433 if(data->nodedef->get(n)->walkable)
1435 last_node_walkable = true;
1438 if(last_node_walkable)
1440 // If block contains light information
1441 if(content_features(n).param_type == CPT_LIGHT)
1443 if(n.getLight(LIGHTBANK_DAY) <= 3)
1445 if(myrand() % 300 == 0)
1447 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
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);
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);
1462 if(myrand() % 1000 == 0)
1464 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
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);
1471 block->m_static_objects.insert(0, s_obj);
1477 last_node_walkable = false;
1480 block->raiseModified(MOD_STATE_WRITE_NEEDED, "mapgen::add_random_objects");
1484 void make_block(BlockMakeData *data)
1488 //dstream<<"makeBlock: no-op"<<std::endl;
1492 assert(data->vmanip);
1493 assert(data->nodedef);
1494 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1495 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1496 data->blockpos_requested.Z >= data->blockpos_min.Z);
1497 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1498 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1499 data->blockpos_requested.Z <= data->blockpos_max.Z);
1501 INodeDefManager *ndef = data->nodedef;
1503 // Hack: use minimum block coordinates for old code that assumes
1505 v3s16 blockpos = data->blockpos_min;
1507 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1508 <<blockpos.Z<<")"<<std::endl;*/
1510 v3s16 blockpos_min = data->blockpos_min;
1511 v3s16 blockpos_max = data->blockpos_max;
1512 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1513 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1515 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1516 // Area of center block
1517 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1518 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1519 // Full allocated area
1520 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1521 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1523 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1525 int rel_volume = (blockpos_max.X - blockpos_min.X + 1)
1526 * (blockpos_max.Y - blockpos_min.Y + 1)
1527 * (blockpos_max.Z - blockpos_max.Z + 1);
1529 // Area of the block we are generating
1530 double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1533 Get average ground level from noise
1536 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1537 data->seed, v2s16(blockpos.X, blockpos.Z));
1538 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1540 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1542 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1543 data->seed, v2s16(blockpos.X, blockpos.Z));
1544 // Minimum amount of ground above the top of the central block
1545 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1547 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1548 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1549 // Maximum amount of ground above the bottom of the central block
1550 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1554 Special case for high air or water: Just fill with air and water.
1556 if(maximum_ground_depth < -20)
1558 for(s16 x=node_min.X; x<=node_max.X; x++)
1559 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1564 // Use fast index incrementing
1565 v3s16 em = vmanip.m_area.getExtent();
1566 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1567 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1569 // Only modify places that have no content
1570 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1572 if(y <= WATER_LEVEL)
1573 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_WATERSOURCE"));
1575 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1578 data->vmanip->m_area.add_y(em, i, 1);
1589 If block is deep underground, this is set to true and ground
1590 density noise is not generated, for speed optimization.
1592 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1595 Create a block-specific seed
1597 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1598 + full_node_min.Y*42123 + full_node_min.X*23;
1604 //NoiseBuffer noisebuf1;
1605 //NoiseBuffer noisebuf2;
1606 NoiseBuffer noisebuf_cave;
1607 NoiseBuffer noisebuf_ground;
1608 NoiseBuffer noisebuf_ground_crumbleness;
1609 NoiseBuffer noisebuf_ground_wetness;
1611 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1612 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1614 //TimeTaker timer("noisebuf.create");
1620 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1621 minpos_f.X, minpos_f.Y, minpos_f.Z,
1622 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1624 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1632 v3f sl = v3f(4.0, 4.0, 4.0);
1637 if(all_is_ground_except_caves == false)
1638 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1639 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1640 minpos_f.X, minpos_f.Y, minpos_f.Z,
1641 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1645 Ground property noise
1647 sl = v3f(2.5, 2.5, 2.5);
1648 noisebuf_ground_crumbleness.create(
1649 get_ground_crumbleness_params(data->seed),
1650 minpos_f.X, minpos_f.Y, minpos_f.Z,
1651 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1653 noisebuf_ground_wetness.create(
1654 get_ground_wetness_params(data->seed),
1655 minpos_f.X, minpos_f.Y, minpos_f.Z,
1656 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1661 Cache some ground type values for speed
1664 // Creates variables c_name=id and n_name=node
1665 #define CONTENT_VARIABLE(ndef, name)\
1666 content_t c_##name = ndef->getId(#name);\
1667 MapNode n_##name(c_##name);
1669 CONTENT_VARIABLE(ndef, stone);
1670 CONTENT_VARIABLE(ndef, air);
1671 CONTENT_VARIABLE(ndef, water_source);
1672 CONTENT_VARIABLE(ndef, dirt);
1673 CONTENT_VARIABLE(ndef, sand);
1674 CONTENT_VARIABLE(ndef, gravel);
1675 CONTENT_VARIABLE(ndef, clay);
1676 CONTENT_VARIABLE(ndef, lava_source);
1677 CONTENT_VARIABLE(ndef, cobble);
1678 CONTENT_VARIABLE(ndef, mossycobble);
1679 CONTENT_VARIABLE(ndef, dirt_with_grass);
1680 CONTENT_VARIABLE(ndef, junglegrass);
1681 CONTENT_VARIABLE(ndef, stone_with_coal);
1682 CONTENT_VARIABLE(ndef, stone_with_iron);
1683 CONTENT_VARIABLE(ndef, mese);
1686 Make base ground level
1689 for(s16 x=node_min.X; x<=node_max.X; x++)
1690 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1695 // Use fast index incrementing
1696 v3s16 em = vmanip.m_area.getExtent();
1697 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1698 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1700 // Only modify places that have no content
1701 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1703 // First priority: make air and water.
1704 // This avoids caves inside water.
1705 if(all_is_ground_except_caves == false
1706 && val_is_ground(noisebuf_ground.get(x,y,z),
1707 v3s16(x,y,z), data->seed) == false)
1709 if(y <= WATER_LEVEL)
1710 vmanip.m_data[i] = n_water_source;
1712 vmanip.m_data[i] = n_air;
1714 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1715 vmanip.m_data[i] = n_air;
1717 vmanip.m_data[i] = n_stone;
1720 data->vmanip->m_area.add_y(em, i, 1);
1726 Add mud and sand and others underground (in place of stone)
1729 for(s16 x=node_min.X; x<=node_max.X; x++)
1730 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1735 // Use fast index incrementing
1736 v3s16 em = vmanip.m_area.getExtent();
1737 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1738 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1740 if(vmanip.m_data[i].getContent() == c_stone)
1742 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1744 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1745 vmanip.m_data[i] = n_dirt;
1747 vmanip.m_data[i] = n_sand;
1749 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1751 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1752 vmanip.m_data[i] = n_gravel;
1754 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1755 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1757 vmanip.m_data[i] = n_lava_source;
1758 for(s16 x1=-1; x1<=1; x1++)
1759 for(s16 y1=-1; y1<=1; y1++)
1760 for(s16 z1=-1; z1<=1; z1++)
1761 data->transforming_liquid.push_back(
1762 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1766 data->vmanip->m_area.add_y(em, i, -1);
1775 //if(node_min.Y < approx_groundlevel)
1776 //if(myrand() % 3 == 0)
1777 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1778 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1779 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1780 float dungeon_rarity = 0.02;
1781 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1783 && node_min.Y < approx_groundlevel)
1785 // Dungeon generator doesn't modify places which have this set
1786 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1787 | VMANIP_FLAG_DUNGEON_PRESERVE);
1789 // Set all air and water to be untouchable to make dungeons open
1790 // to caves and open air
1791 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1792 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1797 // Use fast index incrementing
1798 v3s16 em = vmanip.m_area.getExtent();
1799 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1800 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1802 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1803 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1804 else if(vmanip.m_data[i].getContent() == c_water_source)
1805 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1806 data->vmanip->m_area.add_y(em, i, -1);
1811 PseudoRandom random(blockseed+2);
1814 make_dungeon1(vmanip, random, ndef);
1816 // Convert some cobble to mossy cobble
1817 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1818 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1823 // Use fast index incrementing
1824 v3s16 em = vmanip.m_area.getExtent();
1825 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1826 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1828 // (noisebuf not used because it doesn't contain the
1830 double wetness = noise3d_param(
1831 get_ground_wetness_params(data->seed), x,y,z);
1832 double d = noise3d_perlin((float)x/2.5,
1833 (float)y/2.5,(float)z/2.5,
1835 if(vmanip.m_data[i].getContent() == c_cobble)
1839 vmanip.m_data[i].setContent(c_mossycobble);
1842 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1845 vmanip.m_data[i].setContent(c_dirt);
1847 data->vmanip->m_area.add_y(em, i, -1);
1857 PseudoRandom ncrandom(blockseed+9324342);
1858 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1860 make_nc(vmanip, ncrandom, ndef);
1865 Add top and bottom side of water to transforming_liquid queue
1868 for(s16 x=node_min.X; x<=node_max.X; x++)
1869 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1874 bool water_found = false;
1875 // Use fast index incrementing
1876 v3s16 em = vmanip.m_area.getExtent();
1877 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1878 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1880 if(water_found == false)
1882 if(vmanip.m_data[i].getContent() == c_water_source)
1884 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1885 data->transforming_liquid.push_back(p);
1891 // This can be done because water_found can only
1892 // turn to true and end up here after going through
1894 if(vmanip.m_data[i+1].getContent() != c_water_source)
1896 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1897 data->transforming_liquid.push_back(p);
1898 water_found = false;
1902 data->vmanip->m_area.add_y(em, i, -1);
1908 If close to ground level
1911 //if(abs(approx_ground_depth) < 30)
1912 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1918 for(s16 x=node_min.X; x<=node_max.X; x++)
1919 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1924 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1925 bool have_sand = false;
1926 u32 current_depth = 0;
1927 bool air_detected = false;
1928 bool water_detected = false;
1929 bool have_clay = false;
1931 // Use fast index incrementing
1932 s16 start_y = node_max.Y+2;
1933 v3s16 em = vmanip.m_area.getExtent();
1934 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1935 for(s16 y=start_y; y>=node_min.Y-3; y--)
1937 if(vmanip.m_data[i].getContent() == c_water_source)
1938 water_detected = true;
1939 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1940 air_detected = true;
1942 if((vmanip.m_data[i].getContent() == c_stone
1943 || vmanip.m_data[i].getContent() == c_dirt_with_grass
1944 || vmanip.m_data[i].getContent() == c_dirt
1945 || vmanip.m_data[i].getContent() == c_sand
1946 || vmanip.m_data[i].getContent() == c_gravel
1947 ) && (air_detected || water_detected))
1949 if(current_depth == 0 && y <= WATER_LEVEL+2
1950 && possibly_have_sand)
1953 if(current_depth < 4)
1957 // Determine whether to have clay in the sand here
1958 double claynoise = noise2d_perlin(
1959 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1960 data->seed+4321, 6, 0.95) + 0.5;
1962 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
1963 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
1964 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
1967 vmanip.m_data[i] = MapNode(c_clay);
1969 vmanip.m_data[i] = MapNode(c_sand);
1972 else if(current_depth==0 && !water_detected
1973 && y >= WATER_LEVEL && air_detected)
1974 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
1977 vmanip.m_data[i] = MapNode(c_dirt);
1981 if(vmanip.m_data[i].getContent() == c_dirt
1982 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
1983 vmanip.m_data[i] = MapNode(c_stone);
1988 if(current_depth >= 8)
1991 else if(current_depth != 0)
1994 data->vmanip->m_area.add_y(em, i, -1);
2000 Calculate some stuff
2003 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2004 bool is_jungle = surface_humidity > 0.75;
2006 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2013 PseudoRandom treerandom(blockseed);
2014 // Put trees in random places on part of division
2015 for(u32 i=0; i<tree_count; i++)
2017 s16 x = treerandom.range(node_min.X, node_max.X);
2018 s16 z = treerandom.range(node_min.Z, node_max.Z);
2019 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2020 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2021 // Don't make a tree under water level
2024 // Make sure tree fits (only trees whose starting point is
2025 // at this block are added)
2026 if(y < node_min.Y || y > node_max.Y)
2029 Find exact ground level
2033 for(; p.Y >= y-6; p.Y--)
2035 u32 i = data->vmanip->m_area.index(p);
2036 MapNode *n = &data->vmanip->m_data[i];
2037 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2043 // If not found, handle next one
2048 u32 i = data->vmanip->m_area.index(p);
2049 MapNode *n = &data->vmanip->m_data[i];
2051 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2054 // Papyrus grows only on mud and in water
2055 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2058 make_papyrus(vmanip, p, ndef);
2060 // Trees grow only on mud and grass, on land
2061 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2064 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2065 if(is_jungle == false)
2068 if(myrand_range(0,4) != 0)
2069 is_apple_tree = false;
2071 is_apple_tree = noise2d_perlin(
2072 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2073 data->seed+342902, 3, 0.45) > 0.2;
2074 make_tree(vmanip, p, is_apple_tree, ndef);
2077 make_jungletree(vmanip, p, ndef);
2079 // Cactii grow only on sand, on land
2080 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2083 make_cactus(vmanip, p, ndef);
2093 PseudoRandom grassrandom(blockseed);
2094 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2096 s16 x = grassrandom.range(node_min.X, node_max.X);
2097 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2098 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2101 if(y < node_min.Y || y > node_max.Y)
2104 Find exact ground level
2108 for(; p.Y >= y-6; p.Y--)
2110 u32 i = data->vmanip->m_area.index(p);
2111 MapNode *n = &data->vmanip->m_data[i];
2112 if(data->nodedef->get(*n).is_ground_content)
2118 // If not found, handle next one
2122 if(vmanip.m_area.contains(p) == false)
2124 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2127 if(vmanip.m_area.contains(p))
2128 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2130 if(vmanip.m_area.contains(p))
2131 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2137 Add some kind of random stones
2140 u32 random_stone_count = gen_area_nodes *
2141 randomstone_amount_2d(data->seed, p2d_center);
2142 // Put in random places on part of division
2143 for(u32 i=0; i<random_stone_count; i++)
2145 s16 x = myrand_range(node_min.X, node_max.X);
2146 s16 z = myrand_range(node_min.Z, node_max.Z);
2147 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2148 // Don't add under water level
2149 /*if(y < WATER_LEVEL)
2151 // Don't add if doesn't belong to this block
2152 if(y < node_min.Y || y > node_max.Y)
2157 u32 i = data->vmanip->m_area.index(v3s16(p));
2158 MapNode *n = &data->vmanip->m_data[i];
2159 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2162 // Will be placed one higher
2165 make_randomstone(data->vmanip, p);
2174 u32 large_stone_count = gen_area_nodes *
2175 largestone_amount_2d(data->seed, p2d_center);
2176 //u32 large_stone_count = 1;
2177 // Put in random places on part of division
2178 for(u32 i=0; i<large_stone_count; i++)
2180 s16 x = myrand_range(node_min.X, node_max.X);
2181 s16 z = myrand_range(node_min.Z, node_max.Z);
2182 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2183 // Don't add under water level
2184 /*if(y < WATER_LEVEL)
2186 // Don't add if doesn't belong to this block
2187 if(y < node_min.Y || y > node_max.Y)
2192 u32 i = data->vmanip->m_area.index(v3s16(p));
2193 MapNode *n = &data->vmanip->m_data[i];
2194 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2197 // Will be placed one lower
2200 make_largestone(data->vmanip, p);
2210 PseudoRandom mineralrandom(blockseed);
2215 for(s16 i=0; i<approx_ground_depth/4; i++)
2217 if(mineralrandom.next()%50 == 0)
2219 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2220 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2221 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2222 for(u16 i=0; i<27; i++)
2224 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2225 u32 vi = vmanip.m_area.index(p);
2226 if(vmanip.m_data[vi].getContent() == c_stone)
2227 if(mineralrandom.next()%8 == 0)
2228 vmanip.m_data[vi] = MapNode(c_mese);
2237 u16 a = mineralrandom.range(0,15);
2239 u16 amount = 20 * a/1000;
2240 for(s16 i=0; i<amount; i++)
2242 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2243 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2244 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2246 u8 base_content = c_stone;
2247 MapNode new_content(CONTENT_IGNORE);
2250 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2252 new_content = MapNode(c_stone_with_coal);
2256 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2257 new_content = MapNode(c_stone_with_iron);
2258 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2259 vmanip.m_data[i] = MapNode(c_dirt);
2261 vmanip.m_data[i] = MapNode(c_sand);*/
2263 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2267 if(new_content.getContent() != CONTENT_IGNORE)
2269 for(u16 i=0; i<27; i++)
2271 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2272 u32 vi = vmanip.m_area.index(p);
2273 if(vmanip.m_data[vi].getContent() == base_content)
2275 if(mineralrandom.next()%sparseness == 0)
2276 vmanip.m_data[vi] = new_content;
2285 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2286 //for(s16 i=0; i<50; i++)
2287 u16 coal_amount = 30;
2288 u16 coal_rareness = 60 / coal_amount;
2289 if(coal_rareness == 0)
2291 if(mineralrandom.next()%coal_rareness == 0)
2293 u16 a = mineralrandom.next() % 16;
2294 u16 amount = coal_amount * a*a*a / 1000;
2295 for(s16 i=0; i<amount; i++)
2297 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2298 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2299 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2300 for(u16 i=0; i<27; i++)
2302 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2303 u32 vi = vmanip.m_area.index(p);
2304 if(vmanip.m_data[vi].getContent() == c_stone)
2305 if(mineralrandom.next()%8 == 0)
2306 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2313 u16 iron_amount = 8;
2314 u16 iron_rareness = 60 / iron_amount;
2315 if(iron_rareness == 0)
2317 if(mineralrandom.next()%iron_rareness == 0)
2319 u16 a = mineralrandom.next() % 16;
2320 u16 amount = iron_amount * a*a*a / 1000;
2321 for(s16 i=0; i<amount; i++)
2323 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2324 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2325 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2326 for(u16 i=0; i<27; i++)
2328 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2329 u32 vi = vmanip.m_area.index(p);
2330 if(vmanip.m_data[vi].getContent() == c_stone)
2331 if(mineralrandom.next()%8 == 0)
2332 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2340 BlockMakeData::BlockMakeData():
2347 BlockMakeData::~BlockMakeData()
2352 }; // namespace mapgen