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
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
37 Some helper functions for the map generator
41 // Returns Y one under area minimum if not found
42 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
43 INodeDefManager *ndef)
45 v3s16 em = vmanip.m_area.getExtent();
46 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
47 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
48 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
50 for(y=y_nodes_max; y>=y_nodes_min; y--)
52 MapNode &n = vmanip.m_data[i];
53 if(ndef->get(n).walkable)
56 vmanip.m_area.add_y(em, i, -1);
61 return y_nodes_min - 1;
65 // Returns Y one under area minimum if not found
66 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
67 INodeDefManager *ndef)
69 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
70 return vmanip.m_area.MinEdge.Y-1;
71 v3s16 em = vmanip.m_area.getExtent();
72 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
73 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
74 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
76 content_t c_tree = ndef->getId("mapgen_tree");
77 content_t c_leaves = ndef->getId("mapgen_leaves");
78 for(y=y_nodes_max; y>=y_nodes_min; y--)
80 MapNode &n = vmanip.m_data[i];
81 if(ndef->get(n).walkable
82 && n.getContent() != c_tree
83 && n.getContent() != c_leaves)
86 vmanip.m_area.add_y(em, i, -1);
91 return y_nodes_min - 1;
95 // Returns Y one under area minimum if not found
96 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
97 INodeDefManager *ndef)
99 v3s16 em = vmanip.m_area.getExtent();
100 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
101 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
102 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
104 content_t c_stone = ndef->getId("mapgen_stone");
105 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
106 for(y=y_nodes_max; y>=y_nodes_min; y--)
108 MapNode &n = vmanip.m_data[i];
109 content_t c = n.getContent();
110 if(c != CONTENT_IGNORE && (
111 c == c_stone || c == c_desert_stone))
114 vmanip.m_area.add_y(em, i, -1);
119 return y_nodes_min - 1;
123 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
124 bool is_apple_tree, INodeDefManager *ndef)
126 MapNode treenode(ndef->getId("mapgen_tree"));
127 MapNode leavesnode(ndef->getId("mapgen_leaves"));
128 MapNode applenode(ndef->getId("mapgen_apple"));
130 s16 trunk_h = myrand_range(4, 5);
132 for(s16 ii=0; ii<trunk_h; ii++)
134 if(vmanip.m_area.contains(p1))
135 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
139 // p1 is now the last piece of the trunk
142 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
143 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
144 Buffer<u8> leaves_d(leaves_a.getVolume());
145 for(s32 i=0; i<leaves_a.getVolume(); i++)
148 // Force leaves at near the end of the trunk
151 for(s16 z=-d; z<=d; z++)
152 for(s16 y=-d; y<=d; y++)
153 for(s16 x=-d; x<=d; x++)
155 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
159 // Add leaves randomly
160 for(u32 iii=0; iii<7; iii++)
165 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
166 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
167 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
170 for(s16 z=0; z<=d; z++)
171 for(s16 y=0; y<=d; y++)
172 for(s16 x=0; x<=d; x++)
174 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
178 // Blit leaves to vmanip
179 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
180 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
181 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
185 if(vmanip.m_area.contains(p) == false)
187 u32 vi = vmanip.m_area.index(p);
188 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
189 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
191 u32 i = leaves_a.index(x,y,z);
192 if(leaves_d[i] == 1) {
193 bool is_apple = myrand_range(0,99) < 10;
194 if(is_apple_tree && is_apple) {
195 vmanip.m_data[vi] = applenode;
197 vmanip.m_data[vi] = leavesnode;
204 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
205 INodeDefManager *ndef)
207 MapNode treenode(ndef->getId("mapgen_jungletree"));
208 MapNode leavesnode(ndef->getId("mapgen_leaves"));
210 for(s16 x=-1; x<=1; x++)
211 for(s16 z=-1; z<=1; z++)
213 if(myrand_range(0, 2) == 0)
215 v3s16 p1 = p0 + v3s16(x,0,z);
216 v3s16 p2 = p0 + v3s16(x,-1,z);
217 if(vmanip.m_area.contains(p2)
218 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
219 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
220 else if(vmanip.m_area.contains(p1))
221 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
224 s16 trunk_h = myrand_range(8, 12);
226 for(s16 ii=0; ii<trunk_h; ii++)
228 if(vmanip.m_area.contains(p1))
229 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
233 // p1 is now the last piece of the trunk
236 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
237 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
238 Buffer<u8> leaves_d(leaves_a.getVolume());
239 for(s32 i=0; i<leaves_a.getVolume(); i++)
242 // Force leaves at near the end of the trunk
245 for(s16 z=-d; z<=d; z++)
246 for(s16 y=-d; y<=d; y++)
247 for(s16 x=-d; x<=d; x++)
249 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
253 // Add leaves randomly
254 for(u32 iii=0; iii<30; iii++)
259 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
260 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
261 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
264 for(s16 z=0; z<=d; z++)
265 for(s16 y=0; y<=d; y++)
266 for(s16 x=0; x<=d; x++)
268 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
272 // Blit leaves to vmanip
273 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
274 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
275 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
279 if(vmanip.m_area.contains(p) == false)
281 u32 vi = vmanip.m_area.index(p);
282 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
283 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
285 u32 i = leaves_a.index(x,y,z);
287 vmanip.m_data[vi] = leavesnode;
291 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
292 INodeDefManager *ndef)
294 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
296 s16 trunk_h = myrand_range(2, 3);
298 for(s16 ii=0; ii<trunk_h; ii++)
300 if(vmanip.m_area.contains(p1))
301 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
306 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
307 INodeDefManager *ndef)
309 MapNode cactusnode(ndef->getId("mapgen_cactus"));
313 for(s16 ii=0; ii<trunk_h; ii++)
315 if(vmanip.m_area.contains(p1))
316 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
324 Dungeon making routines
327 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
328 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
329 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
330 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
332 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
333 INodeDefManager *ndef)
336 for(s16 z=0; z<roomsize.Z; z++)
337 for(s16 y=0; y<roomsize.Y; y++)
340 v3s16 p = roomplace + v3s16(0,y,z);
341 if(vmanip.m_area.contains(p) == false)
343 u32 vi = vmanip.m_area.index(p);
344 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
346 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
349 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
350 if(vmanip.m_area.contains(p) == false)
352 u32 vi = vmanip.m_area.index(p);
353 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
355 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
360 for(s16 x=0; x<roomsize.X; x++)
361 for(s16 y=0; y<roomsize.Y; y++)
364 v3s16 p = roomplace + v3s16(x,y,0);
365 if(vmanip.m_area.contains(p) == false)
367 u32 vi = vmanip.m_area.index(p);
368 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
370 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
373 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
374 if(vmanip.m_area.contains(p) == false)
376 u32 vi = vmanip.m_area.index(p);
377 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
379 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
383 // Make +-Y walls (floor and ceiling)
384 for(s16 z=0; z<roomsize.Z; z++)
385 for(s16 x=0; x<roomsize.X; x++)
388 v3s16 p = roomplace + v3s16(x,0,z);
389 if(vmanip.m_area.contains(p) == false)
391 u32 vi = vmanip.m_area.index(p);
392 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
394 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
397 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
398 if(vmanip.m_area.contains(p) == false)
400 u32 vi = vmanip.m_area.index(p);
401 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
403 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
408 for(s16 z=1; z<roomsize.Z-1; z++)
409 for(s16 y=1; y<roomsize.Y-1; y++)
410 for(s16 x=1; x<roomsize.X-1; x++)
412 v3s16 p = roomplace + v3s16(x,y,z);
413 if(vmanip.m_area.contains(p) == false)
415 u32 vi = vmanip.m_area.index(p);
416 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
417 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
421 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
422 u8 avoid_flags, MapNode n, u8 or_flags)
424 for(s16 z=0; z<size.Z; z++)
425 for(s16 y=0; y<size.Y; y++)
426 for(s16 x=0; x<size.X; x++)
428 v3s16 p = place + v3s16(x,y,z);
429 if(vmanip.m_area.contains(p) == false)
431 u32 vi = vmanip.m_area.index(p);
432 if(vmanip.m_flags[vi] & avoid_flags)
434 vmanip.m_flags[vi] |= or_flags;
435 vmanip.m_data[vi] = n;
439 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
440 INodeDefManager *ndef)
442 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
443 VMANIP_FLAG_DUNGEON_INSIDE);
446 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
447 INodeDefManager *ndef)
449 make_hole1(vmanip, doorplace, ndef);
450 // Place torch (for testing)
451 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
454 static v3s16 rand_ortho_dir(PseudoRandom &random)
456 if(random.next()%2==0)
457 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
459 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
462 static v3s16 turn_xz(v3s16 olddir, int t)
482 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
484 int turn = random.range(0,2);
493 dir = turn_xz(olddir, 0);
496 dir = turn_xz(olddir, 1);
500 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
501 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
502 PseudoRandom &random, INodeDefManager *ndef)
504 make_hole1(vmanip, doorplace, ndef);
505 v3s16 p0 = doorplace;
509 length = random.range(1,13);
511 length = random.range(1,6);
512 length = random.range(1,13);
513 u32 partlength = random.range(1,13);
516 if(random.next()%2 == 0 && partlength >= 3)
517 make_stairs = random.next()%2 ? 1 : -1;
518 for(u32 i=0; i<length; i++)
524 /*// If already empty
525 if(vmanip.getNodeNoExNoEmerge(p).getContent()
527 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
532 if(vmanip.m_area.contains(p) == true
533 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
537 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
538 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
539 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
540 VMANIP_FLAG_DUNGEON_INSIDE);
541 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
542 VMANIP_FLAG_DUNGEON_INSIDE);
546 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
547 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
548 make_hole1(vmanip, p, ndef);
549 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
550 VMANIP_FLAG_DUNGEON_INSIDE);*/
557 // Can't go here, turn away
558 dir = turn_xz(dir, random.range(0,1));
559 make_stairs = -make_stairs;
561 partlength = random.range(1,length);
566 if(partcount >= partlength)
570 dir = random_turn(random, dir);
572 partlength = random.range(1,length);
575 if(random.next()%2 == 0 && partlength >= 3)
576 make_stairs = random.next()%2 ? 1 : -1;
587 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
588 INodeDefManager *ndef):
599 m_dir = rand_ortho_dir(m_random);
602 void setPos(v3s16 pos)
607 void setDir(v3s16 dir)
612 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
614 for(u32 i=0; i<100; i++)
616 v3s16 p = m_pos + m_dir;
617 v3s16 p1 = p + v3s16(0,1,0);
618 if(vmanip.m_area.contains(p) == false
619 || vmanip.m_area.contains(p1) == false
625 if(vmanip.getNodeNoExNoEmerge(p).getContent()
626 == m_ndef->getId("mapgen_cobble")
627 && vmanip.getNodeNoExNoEmerge(p1).getContent()
628 == m_ndef->getId("mapgen_cobble"))
630 // Found wall, this is a good place!
633 // Randomize next direction
638 Determine where to move next
640 // Jump one up if the actual space is there
641 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
642 == m_ndef->getId("mapgen_cobble")
643 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
645 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
648 // Jump one down if the actual space is there
649 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
650 == m_ndef->getId("mapgen_cobble")
651 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
653 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
656 // Check if walking is now possible
657 if(vmanip.getNodeNoExNoEmerge(p).getContent()
659 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
662 // Cannot continue walking here
672 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
673 v3s16 &result_doordir, v3s16 &result_roomplace)
675 for(s16 trycount=0; trycount<30; trycount++)
679 bool r = findPlaceForDoor(doorplace, doordir);
683 // X east, Z north, Y up
685 if(doordir == v3s16(1,0,0)) // X+
686 roomplace = doorplace +
687 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
688 if(doordir == v3s16(-1,0,0)) // X-
689 roomplace = doorplace +
690 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
691 if(doordir == v3s16(0,0,1)) // Z+
692 roomplace = doorplace +
693 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
694 if(doordir == v3s16(0,0,-1)) // Z-
695 roomplace = doorplace +
696 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
699 if(doordir == v3s16(1,0,0)) // X+
700 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
701 if(doordir == v3s16(-1,0,0)) // X-
702 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
703 if(doordir == v3s16(0,0,1)) // Z+
704 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
705 if(doordir == v3s16(0,0,-1)) // Z-
706 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
711 for(s16 z=1; z<roomsize.Z-1; z++)
712 for(s16 y=1; y<roomsize.Y-1; y++)
713 for(s16 x=1; x<roomsize.X-1; x++)
715 v3s16 p = roomplace + v3s16(x,y,z);
716 if(vmanip.m_area.contains(p) == false)
721 if(vmanip.m_flags[vmanip.m_area.index(p)]
722 & VMANIP_FLAG_DUNGEON_INSIDE)
733 result_doorplace = doorplace;
734 result_doordir = doordir;
735 result_roomplace = roomplace;
742 VoxelManipulator &vmanip;
745 PseudoRandom &m_random;
746 INodeDefManager *m_ndef;
749 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
750 INodeDefManager *ndef)
752 v3s16 areasize = vmanip.m_area.getExtent();
757 Find place for first room
760 for(u32 i=0; i<100; i++)
762 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
763 roomplace = vmanip.m_area.MinEdge + v3s16(
764 random.range(0,areasize.X-roomsize.X-1),
765 random.range(0,areasize.Y-roomsize.Y-1),
766 random.range(0,areasize.Z-roomsize.Z-1));
768 Check that we're not putting the room to an unknown place,
769 otherwise it might end up floating in the air
772 for(s16 z=1; z<roomsize.Z-1; z++)
773 for(s16 y=1; y<roomsize.Y-1; y++)
774 for(s16 x=1; x<roomsize.X-1; x++)
776 v3s16 p = roomplace + v3s16(x,y,z);
777 u32 vi = vmanip.m_area.index(p);
778 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
783 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
797 Stores the center position of the last room made, so that
798 a new corridor can be started from the last room instead of
799 the new room, if chosen so.
801 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
803 u32 room_count = random.range(2,7);
804 for(u32 i=0; i<room_count; i++)
806 // Make a room to the determined place
807 make_room1(vmanip, roomsize, roomplace, ndef);
809 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
811 // Place torch at room center (for testing)
812 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
815 if(i == room_count-1)
818 // Determine walker start position
820 bool start_in_last_room = (random.range(0,2)!=0);
821 //bool start_in_last_room = true;
823 v3s16 walker_start_place;
825 if(start_in_last_room)
827 walker_start_place = last_room_center;
831 walker_start_place = room_center;
832 // Store center of current room as the last one
833 last_room_center = room_center;
836 // Create walker and find a place for a door
837 RoomWalker walker(vmanip, walker_start_place, random, ndef);
840 bool r = walker.findPlaceForDoor(doorplace, doordir);
844 if(random.range(0,1)==0)
846 make_door1(vmanip, doorplace, doordir, ndef);
848 // Don't actually make a door
849 doorplace -= doordir;
851 // Make a random corridor starting from the door
853 v3s16 corridor_end_dir;
854 make_corridor(vmanip, doorplace, doordir, corridor_end,
855 corridor_end_dir, random, ndef);
857 // Find a place for a random sized room
858 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
859 walker.setPos(corridor_end);
860 walker.setDir(corridor_end_dir);
861 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
865 if(random.range(0,1)==0)
867 make_door1(vmanip, doorplace, doordir, ndef);
869 // Don't actually make a door
870 roomplace -= doordir;
877 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
878 INodeDefManager *ndef)
882 s32 r = random.range(0, 3);
884 dir = v3s16( 1, 0, 0);
888 dir = v3s16(-1, 0, 0);
892 dir = v3s16( 0, 0, 1);
896 dir = v3s16( 0, 0,-1);
899 v3s16 p = vmanip.m_area.MinEdge + v3s16(
900 16+random.range(0,15),
901 16+random.range(0,15),
902 16+random.range(0,15));
903 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
904 u32 length = random.range(3,15);
905 for(u32 j=0; j<length; j++)
908 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
914 Noise functions. Make sure seed is mangled differently in each one.
919 Scaling the output of the noise function affects the overdrive of the
920 contour function, which affects the shape of the output considerably.
922 #define CAVE_NOISE_SCALE 12.0
923 //#define CAVE_NOISE_SCALE 10.0
924 //#define CAVE_NOISE_SCALE 7.5
925 //#define CAVE_NOISE_SCALE 5.0
926 //#define CAVE_NOISE_SCALE 1.0
928 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
929 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
931 NoiseParams get_cave_noise1_params(u64 seed)
933 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
934 200, CAVE_NOISE_SCALE);*/
935 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
936 100, CAVE_NOISE_SCALE);*/
937 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
938 100, CAVE_NOISE_SCALE);*/
939 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
940 100, CAVE_NOISE_SCALE);*/
941 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
942 50, CAVE_NOISE_SCALE);
943 //return NoiseParams(NOISE_CONSTANT_ONE);
946 NoiseParams get_cave_noise2_params(u64 seed)
948 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
949 200, CAVE_NOISE_SCALE);*/
950 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
951 100, CAVE_NOISE_SCALE);*/
952 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
953 100, CAVE_NOISE_SCALE);*/
954 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
955 50, CAVE_NOISE_SCALE);
956 //return NoiseParams(NOISE_CONSTANT_ONE);
959 NoiseParams get_ground_noise1_params(u64 seed)
961 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
965 NoiseParams get_ground_crumbleness_params(u64 seed)
967 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
971 NoiseParams get_ground_wetness_params(u64 seed)
973 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
977 bool is_cave(u64 seed, v3s16 p)
979 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
980 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
981 return d1*d2 > CAVE_NOISE_THRESHOLD;
985 Ground density noise shall be interpreted by using this.
987 TODO: No perlin noises here, they should be outsourced
989 NOTE: The speed of these actually isn't terrible
991 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
993 //return ((double)p.Y < ground_noise1_val);
995 double f = 0.55 + noise2d_perlin(
996 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
997 seed+920381, 3, 0.45);
1002 double h = WATER_LEVEL + 10 * noise2d_perlin(
1003 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1004 seed+84174, 4, 0.5);
1007 return ((double)p.Y - h < ground_noise1_val * f);
1011 Queries whether a position is ground or not.
1013 bool is_ground(u64 seed, v3s16 p)
1015 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1016 return val_is_ground(val1, p, seed);
1020 // Amount of trees per area in nodes
1021 double tree_amount_2d(u64 seed, v2s16 p)
1023 /*double noise = noise2d_perlin(
1024 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1026 double noise = noise2d_perlin(
1027 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1029 double zeroval = -0.39;
1033 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1037 double surface_humidity_2d(u64 seed, v2s16 p)
1039 double noise = noise2d_perlin(
1040 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1041 seed+72384, 4, 0.66);
1042 noise = (noise + 1.0)/2.0;
1051 Incrementally find ground level from 3d noise
1053 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1055 // Start a bit fuzzy to make averaging lower precision values
1057 s16 level = myrand_range(-precision/2, precision/2);
1058 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1060 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1062 // First find non-ground by going upwards
1063 // Don't stop in caves.
1065 s16 max = level+dec[i-1]*2;
1066 v3s16 p(p2d.X, level, p2d.Y);
1067 for(; p.Y < max; p.Y += dec[i])
1069 if(!is_ground(seed, p))
1076 // Then find ground by going downwards from there.
1077 // Go in caves, too, when precision is 1.
1079 s16 min = level-dec[i-1]*2;
1080 v3s16 p(p2d.X, level, p2d.Y);
1081 for(; p.Y>min; p.Y-=dec[i])
1083 bool ground = is_ground(seed, p);
1084 /*if(dec[i] == 1 && is_cave(seed, p))
1095 // This is more like the actual ground level
1096 level += dec[i-1]/2;
1101 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1103 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1105 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1106 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1108 a += find_ground_level_from_noise(seed,
1109 v2s16(node_min.X, node_min.Y), p);
1110 a += find_ground_level_from_noise(seed,
1111 v2s16(node_min.X, node_max.Y), p);
1112 a += find_ground_level_from_noise(seed,
1113 v2s16(node_max.X, node_max.Y), p);
1114 a += find_ground_level_from_noise(seed,
1115 v2s16(node_max.X, node_min.Y), p);
1116 a += find_ground_level_from_noise(seed,
1117 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1122 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1124 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1126 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1127 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1130 a = MYMAX(a, find_ground_level_from_noise(seed,
1131 v2s16(node_min.X, node_min.Y), p));
1132 a = MYMAX(a, find_ground_level_from_noise(seed,
1133 v2s16(node_min.X, node_max.Y), p));
1134 a = MYMAX(a, find_ground_level_from_noise(seed,
1135 v2s16(node_max.X, node_max.Y), p));
1136 a = MYMAX(a, find_ground_level_from_noise(seed,
1137 v2s16(node_min.X, node_min.Y), p));
1139 a = MYMAX(a, find_ground_level_from_noise(seed,
1140 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1141 // Side middle points
1142 a = MYMAX(a, find_ground_level_from_noise(seed,
1143 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1144 a = MYMAX(a, find_ground_level_from_noise(seed,
1145 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1146 a = MYMAX(a, find_ground_level_from_noise(seed,
1147 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1148 a = MYMAX(a, find_ground_level_from_noise(seed,
1149 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1153 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1155 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1157 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1158 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1161 a = MYMIN(a, find_ground_level_from_noise(seed,
1162 v2s16(node_min.X, node_min.Y), p));
1163 a = MYMIN(a, find_ground_level_from_noise(seed,
1164 v2s16(node_min.X, node_max.Y), p));
1165 a = MYMIN(a, find_ground_level_from_noise(seed,
1166 v2s16(node_max.X, node_max.Y), p));
1167 a = MYMIN(a, find_ground_level_from_noise(seed,
1168 v2s16(node_min.X, node_min.Y), p));
1170 a = MYMIN(a, find_ground_level_from_noise(seed,
1171 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1172 // Side middle points
1173 a = MYMIN(a, find_ground_level_from_noise(seed,
1174 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1175 a = MYMIN(a, find_ground_level_from_noise(seed,
1176 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1177 a = MYMIN(a, find_ground_level_from_noise(seed,
1178 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1179 a = MYMIN(a, find_ground_level_from_noise(seed,
1180 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1185 // Required by mapgen.h
1186 bool block_is_underground(u64 seed, v3s16 blockpos)
1188 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1189 seed, v2s16(blockpos.X, blockpos.Z));*/
1190 // Nah, this is just a heuristic, just return something
1191 s16 minimum_groundlevel = WATER_LEVEL;
1193 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1199 #define AVERAGE_MUD_AMOUNT 4
1201 double base_rock_level_2d(u64 seed, v2s16 p)
1203 // The base ground level
1204 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1205 + 20. * noise2d_perlin(
1206 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1207 seed+82341, 5, 0.6);
1209 /*// A bit hillier one
1210 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1211 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1212 seed+93413, 6, 0.69);
1216 // Higher ground level
1217 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1218 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1219 seed+85039, 5, 0.6);
1220 //higher = 30; // For debugging
1222 // Limit higher to at least base
1226 // Steepness factor of cliffs
1227 double b = 0.85 + 0.5 * noise2d_perlin(
1228 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1230 b = rangelim(b, 0.0, 1000.0);
1233 b = rangelim(b, 0.5, 1000.0);
1234 // Values 1.5...100 give quite horrible looking slopes
1235 if(b > 1.5 && b < 100.0){
1241 //dstream<<"b="<<b<<std::endl;
1245 // Offset to more low
1246 double a_off = -0.20;
1247 // High/low selector
1248 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1249 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1250 seed+4213, 6, 0.7));*/
1251 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1252 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1253 seed+4213, 5, 0.69));
1255 a = rangelim(a, 0.0, 1.0);
1257 //dstream<<"a="<<a<<std::endl;
1259 double h = base*(1.0-a) + higher*a;
1266 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1268 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1271 double get_mud_add_amount(u64 seed, v2s16 p)
1273 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1274 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1275 seed+91013, 3, 0.55));
1278 bool get_have_beach(u64 seed, v2s16 p2d)
1280 // Determine whether to have sand here
1281 double sandnoise = noise2d_perlin(
1282 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1283 seed+59420, 3, 0.50);
1285 return (sandnoise > 0.15);
1294 BiomeType get_biome(u64 seed, v2s16 p2d)
1296 // Just do something very simple as for now
1297 double d = noise2d_perlin(
1298 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1299 seed+9130, 3, 0.50);
1305 u32 get_blockseed(u64 seed, v3s16 p)
1307 s32 x=p.X, y=p.Y, z=p.Z;
1308 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1311 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1313 void make_block(BlockMakeData *data)
1317 //dstream<<"makeBlock: no-op"<<std::endl;
1321 assert(data->vmanip);
1322 assert(data->nodedef);
1323 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1324 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1325 data->blockpos_requested.Z >= data->blockpos_min.Z);
1326 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1327 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1328 data->blockpos_requested.Z <= data->blockpos_max.Z);
1330 INodeDefManager *ndef = data->nodedef;
1332 // Hack: use minimum block coordinates for old code that assumes
1334 v3s16 blockpos = data->blockpos_requested;
1336 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1337 <<blockpos.Z<<")"<<std::endl;*/
1339 v3s16 blockpos_min = data->blockpos_min;
1340 v3s16 blockpos_max = data->blockpos_max;
1341 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1342 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1344 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1345 // Area of central chunk
1346 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1347 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1348 // Full allocated area
1349 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1350 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1352 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1354 const s16 max_spread_amount = MAP_BLOCKSIZE;
1356 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1357 * (blockpos_max.Y - blockpos_min.Y + 1)
1358 * (blockpos_max.Z - blockpos_max.Z + 1);
1360 int volume_nodes = volume_blocks *
1361 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1363 // Generated surface area
1364 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1366 // Horribly wrong heuristic, but better than nothing
1367 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1370 Create a block-specific seed
1372 u32 blockseed = get_blockseed(data->seed, full_node_min);
1375 Cache some ground type values for speed
1378 // Creates variables c_name=id and n_name=node
1379 #define CONTENT_VARIABLE(ndef, name)\
1380 content_t c_##name = ndef->getId("mapgen_" #name);\
1381 MapNode n_##name(c_##name);
1382 // Default to something else if was CONTENT_IGNORE
1383 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1384 if(c_##name == CONTENT_IGNORE){\
1385 c_##name = c_##dname;\
1386 n_##name = n_##dname;\
1389 CONTENT_VARIABLE(ndef, stone);
1390 CONTENT_VARIABLE(ndef, air);
1391 CONTENT_VARIABLE(ndef, water_source);
1392 CONTENT_VARIABLE(ndef, dirt);
1393 CONTENT_VARIABLE(ndef, sand);
1394 CONTENT_VARIABLE(ndef, gravel);
1395 CONTENT_VARIABLE(ndef, clay);
1396 CONTENT_VARIABLE(ndef, lava_source);
1397 CONTENT_VARIABLE(ndef, cobble);
1398 CONTENT_VARIABLE(ndef, mossycobble);
1399 CONTENT_VARIABLE(ndef, dirt_with_grass);
1400 CONTENT_VARIABLE(ndef, junglegrass);
1401 CONTENT_VARIABLE(ndef, stone_with_coal);
1402 CONTENT_VARIABLE(ndef, stone_with_iron);
1403 CONTENT_VARIABLE(ndef, mese);
1404 CONTENT_VARIABLE(ndef, desert_sand);
1405 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1406 CONTENT_VARIABLE(ndef, desert_stone);
1407 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1409 // Maximum height of the stone surface and obstacles.
1410 // This is used to guide the cave generation
1411 s16 stone_surface_max_y = 0;
1414 Generate general ground level to full area
1418 TimeTaker timer1("Generating ground level");
1420 for(s16 x=node_min.X; x<=node_max.X; x++)
1421 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1424 v2s16 p2d = v2s16(x,z);
1427 Skip of already generated
1430 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1431 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1435 // Ground height at this point
1436 float surface_y_f = 0.0;
1438 // Use perlin noise for ground height
1439 surface_y_f = base_rock_level_2d(data->seed, p2d);
1441 /*// Experimental stuff
1443 float a = highlands_level_2d(data->seed, p2d);
1448 // Convert to integer
1449 s16 surface_y = (s16)surface_y_f;
1452 if(surface_y > stone_surface_max_y)
1453 stone_surface_max_y = surface_y;
1455 BiomeType bt = get_biome(data->seed, p2d);
1457 Fill ground with stone
1460 // Use fast index incrementing
1461 v3s16 em = vmanip.m_area.getExtent();
1462 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1463 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1465 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1467 if(y > WATER_LEVEL && bt == BT_DESERT)
1468 vmanip.m_data[i] = n_desert_stone;
1470 vmanip.m_data[i] = n_stone;
1471 } else if(y <= WATER_LEVEL){
1472 vmanip.m_data[i] = MapNode(c_water_source);
1474 vmanip.m_data[i] = MapNode(c_air);
1477 vmanip.m_area.add_y(em, i, 1);
1485 // Limit dirt flow area by 1 because mud is flown into neighbors.
1486 assert(central_area_size.X == central_area_size.Z);
1487 s16 mudflow_minpos = 0-max_spread_amount+1;
1488 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1491 Loop this part, it will make stuff look older and newer nicely
1494 const u32 age_loops = 2;
1495 for(u32 i_age=0; i_age<age_loops; i_age++)
1497 /******************************
1498 BEGINNING OF AGING LOOP
1499 ******************************/
1504 //TimeTaker timer1("caves");
1507 Make caves (this code is relatively horrible)
1509 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1510 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1511 data->seed+34329, 3, 0.50);
1512 cave_amount = MYMAX(0.0, cave_amount);
1513 u32 caves_count = cave_amount * volume_nodes / 50000;
1514 u32 bruises_count = 1;
1515 PseudoRandom ps(blockseed+21343);
1516 PseudoRandom ps2(blockseed+1032);
1517 if(ps.range(1, 6) == 1)
1518 bruises_count = ps.range(0, ps.range(0, 2));
1519 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1523 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1525 bool large_cave = (jj >= caves_count);
1526 s16 min_tunnel_diameter = 2;
1527 s16 max_tunnel_diameter = ps.range(2,6);
1528 int dswitchint = ps.range(1,14);
1529 u16 tunnel_routepoints = 0;
1530 int part_max_length_rs = 0;
1532 part_max_length_rs = ps.range(2,4);
1533 tunnel_routepoints = ps.range(5, ps.range(15,30));
1534 min_tunnel_diameter = 5;
1535 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1537 part_max_length_rs = ps.range(2,9);
1538 tunnel_routepoints = ps.range(10, ps.range(15,30));
1540 bool large_cave_is_flat = (ps.range(0,1) == 0);
1542 v3f main_direction(0,0,0);
1544 // Allowed route area size in nodes
1545 v3s16 ar = central_area_size;
1547 // Area starting point in nodes
1548 v3s16 of = node_min;
1551 //(this should be more than the maximum radius of the tunnel)
1552 //s16 insure = 5; // Didn't work with max_d = 20
1554 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1555 ar += v3s16(1,0,1) * more * 2;
1556 of -= v3s16(1,0,1) * more;
1558 s16 route_y_min = 0;
1559 // Allow half a diameter + 7 over stone surface
1560 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1562 /*// If caves, don't go through surface too often
1563 if(large_cave == false)
1564 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1566 // Limit maximum to area
1567 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1571 /*// Minimum is at y=0
1572 route_y_min = -of.Y - 0;*/
1573 // Minimum is at y=max_tunnel_diameter/4
1574 //route_y_min = -of.Y + max_tunnel_diameter/4;
1575 //s16 min = -of.Y + max_tunnel_diameter/4;
1576 //s16 min = -of.Y + 0;
1578 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1580 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1581 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1583 route_y_min = ps.range(min, min + max_tunnel_diameter);
1584 route_y_min = rangelim(route_y_min, 0, route_y_max);
1587 /*dstream<<"route_y_min = "<<route_y_min
1588 <<", route_y_max = "<<route_y_max<<std::endl;*/
1590 s16 route_start_y_min = route_y_min;
1591 s16 route_start_y_max = route_y_max;
1593 // Start every 4th cave from surface when applicable
1594 /*bool coming_from_surface = false;
1595 if(node_min.Y <= 0 && node_max.Y >= 0){
1596 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1597 if(coming_from_surface)
1598 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1601 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1602 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1604 // Randomize starting position
1606 (float)(ps.next()%ar.X)+0.5,
1607 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1608 (float)(ps.next()%ar.Z)+0.5
1611 v3s16 startp(orp.X, orp.Y, orp.Z);
1614 MapNode airnode(CONTENT_AIR);
1615 MapNode waternode(c_water_source);
1616 MapNode lavanode(c_lava_source);
1619 Generate some tunnel starting from orp
1622 for(u16 j=0; j<tunnel_routepoints; j++)
1624 if(j%dswitchint==0 && large_cave == false)
1626 main_direction = v3f(
1627 ((float)(ps.next()%20)-(float)10)/10,
1628 ((float)(ps.next()%20)-(float)10)/30,
1629 ((float)(ps.next()%20)-(float)10)/10
1631 main_direction *= (float)ps.range(0, 10)/10;
1635 s16 min_d = min_tunnel_diameter;
1636 s16 max_d = max_tunnel_diameter;
1637 s16 rs = ps.range(min_d, max_d);
1639 // Every second section is rough
1640 bool randomize_xz = (ps2.range(1,2) == 1);
1646 rs*part_max_length_rs,
1647 rs*part_max_length_rs/2,
1648 rs*part_max_length_rs
1654 rs*part_max_length_rs,
1655 ps.range(1, rs*part_max_length_rs),
1656 rs*part_max_length_rs
1663 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1664 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1665 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1668 // Jump downward sometimes
1669 if(!large_cave && ps.range(0,12) == 0)
1672 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1673 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1674 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1680 s16 h = find_ground_level_clever(vmanip,
1681 v2s16(p.X, p.Z), ndef);
1682 route_y_min = h - rs/3;
1683 route_y_max = h + rs;
1686 vec += main_direction;
1691 else if(rp.X >= ar.X)
1693 if(rp.Y < route_y_min)
1695 else if(rp.Y >= route_y_max)
1696 rp.Y = route_y_max-1;
1699 else if(rp.Z >= ar.Z)
1703 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1705 v3f fp = orp + vec * f;
1706 fp.X += 0.1*ps.range(-10,10);
1707 fp.Z += 0.1*ps.range(-10,10);
1708 v3s16 cp(fp.X, fp.Y, fp.Z);
1713 d0 += ps.range(-1,1);
1714 d1 += ps.range(-1,1);
1716 for(s16 z0=d0; z0<=d1; z0++)
1718 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1719 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1721 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1722 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1723 for(s16 y0=-si2; y0<=si2; y0++)
1725 /*// Make better floors in small caves
1726 if(y0 <= -rs/2 && rs<=7)
1728 if(large_cave_is_flat){
1729 // Make large caves not so tall
1730 if(rs > 7 && abs(y0) >= rs/3)
1740 if(vmanip.m_area.contains(p) == false)
1743 u32 i = vmanip.m_area.index(p);
1747 if(full_node_min.Y < WATER_LEVEL &&
1748 full_node_max.Y > WATER_LEVEL){
1749 if(p.Y <= WATER_LEVEL)
1750 vmanip.m_data[i] = waternode;
1752 vmanip.m_data[i] = airnode;
1753 } else if(full_node_max.Y < WATER_LEVEL){
1754 if(p.Y < startp.Y - 2)
1755 vmanip.m_data[i] = lavanode;
1757 vmanip.m_data[i] = airnode;
1759 vmanip.m_data[i] = airnode;
1762 // Don't replace air or water or lava
1763 if(vmanip.m_data[i].getContent() == CONTENT_AIR ||
1764 vmanip.m_data[i].getContent() == c_water_source ||
1765 vmanip.m_data[i].getContent() == c_lava_source)
1768 vmanip.m_data[i] = airnode;
1771 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1789 TimeTaker timer1("add mud");
1792 Add mud to the central chunk
1795 for(s16 x=node_min.X; x<=node_max.X; x++)
1796 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1798 // Node position in 2d
1799 v2s16 p2d = v2s16(x,z);
1801 // Randomize mud amount
1802 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1804 // Find ground level
1805 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1806 // Handle area not found
1807 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1810 MapNode addnode(c_dirt);
1811 BiomeType bt = get_biome(data->seed, p2d);
1814 addnode = MapNode(c_desert_sand);
1816 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1817 addnode = MapNode(c_sand);
1818 } else if(mud_add_amount <= 0){
1819 mud_add_amount = 1 - mud_add_amount;
1820 addnode = MapNode(c_gravel);
1821 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1822 surface_y + mud_add_amount <= WATER_LEVEL+2){
1823 addnode = MapNode(c_sand);
1826 if(bt == BT_DESERT){
1828 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1833 If topmost node is grass, change it to mud.
1834 It might be if it was flown to there from a neighboring
1835 chunk and then converted.
1838 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1839 MapNode *n = &vmanip.m_data[i];
1840 if(n->getContent() == c_dirt_with_grass)
1841 *n = MapNode(c_dirt);
1849 v3s16 em = vmanip.m_area.getExtent();
1850 s16 y_start = surface_y+1;
1851 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1852 for(s16 y=y_start; y<=node_max.Y; y++)
1854 if(mudcount >= mud_add_amount)
1857 MapNode &n = vmanip.m_data[i];
1861 vmanip.m_area.add_y(em, i, 1);
1871 Add blobs of dirt and gravel underground
1873 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1875 PseudoRandom pr(blockseed+983);
1876 for(int i=0; i<volume_nodes/10/10/10; i++)
1878 bool only_fill_cave = (myrand_range(0,1) != 0);
1885 pr.range(node_min.X, node_max.X)-size.X/2,
1886 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1887 pr.range(node_min.Z, node_max.Z)-size.Z/2
1890 if(p0.Y > -32 && pr.range(0,1) == 0)
1891 n1 = MapNode(c_dirt);
1893 n1 = MapNode(c_gravel);
1894 for(int x1=0; x1<size.X; x1++)
1895 for(int y1=0; y1<size.Y; y1++)
1896 for(int z1=0; z1<size.Z; z1++)
1898 v3s16 p = p0 + v3s16(x1,y1,z1);
1899 u32 i = vmanip.m_area.index(p);
1900 if(!vmanip.m_area.contains(i))
1902 // Cancel if not stone and not cave air
1903 if(vmanip.m_data[i].getContent() != c_stone &&
1904 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1906 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1908 vmanip.m_data[i] = n1;
1916 TimeTaker timer1("flow mud");
1919 Flow mud away from steep edges
1922 // Iterate a few times
1923 for(s16 k=0; k<3; k++)
1926 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1927 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1929 // Invert coordinates every 2nd iteration
1932 x = mudflow_maxpos - (x-mudflow_minpos);
1933 z = mudflow_maxpos - (z-mudflow_minpos);
1936 // Node position in 2d
1937 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1939 v3s16 em = vmanip.m_area.getExtent();
1940 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1943 while(y >= node_min.Y)
1950 for(; y>=node_min.Y; y--)
1952 n = &vmanip.m_data[i];
1953 //if(content_walkable(n->d))
1955 if(n->getContent() == c_dirt ||
1956 n->getContent() == c_dirt_with_grass ||
1957 n->getContent() == c_gravel)
1960 vmanip.m_area.add_y(em, i, -1);
1963 // Stop if out of area
1964 //if(vmanip.m_area.contains(i) == false)
1968 /*// If not mud, do nothing to it
1969 MapNode *n = &vmanip.m_data[i];
1970 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1973 if(n->getContent() == c_dirt ||
1974 n->getContent() == c_dirt_with_grass)
1976 // Make it exactly mud
1977 n->setContent(c_dirt);
1980 Don't flow it if the stuff under it is not mud
1984 vmanip.m_area.add_y(em, i2, -1);
1985 // Cancel if out of area
1986 if(vmanip.m_area.contains(i2) == false)
1988 MapNode *n2 = &vmanip.m_data[i2];
1989 if(n2->getContent() != c_dirt &&
1990 n2->getContent() != c_dirt_with_grass)
1995 /*s16 recurse_count = 0;
1999 v3s16(0,0,1), // back
2000 v3s16(1,0,0), // right
2001 v3s16(0,0,-1), // front
2002 v3s16(-1,0,0), // left
2005 // Theck that upper is air or doesn't exist.
2006 // Cancel dropping if upper keeps it in place
2008 vmanip.m_area.add_y(em, i3, 1);
2009 if(vmanip.m_area.contains(i3) == true
2010 && ndef->get(vmanip.m_data[i3]).walkable)
2017 for(u32 di=0; di<4; di++)
2019 v3s16 dirp = dirs4[di];
2022 vmanip.m_area.add_p(em, i2, dirp);
2023 // Fail if out of area
2024 if(vmanip.m_area.contains(i2) == false)
2026 // Check that side is air
2027 MapNode *n2 = &vmanip.m_data[i2];
2028 if(ndef->get(*n2).walkable)
2030 // Check that under side is air
2031 vmanip.m_area.add_y(em, i2, -1);
2032 if(vmanip.m_area.contains(i2) == false)
2034 n2 = &vmanip.m_data[i2];
2035 if(ndef->get(*n2).walkable)
2037 /*// Check that under that is air (need a drop of 2)
2038 vmanip.m_area.add_y(em, i2, -1);
2039 if(vmanip.m_area.contains(i2) == false)
2041 n2 = &vmanip.m_data[i2];
2042 if(content_walkable(n2->d))
2044 // Loop further down until not air
2045 bool dropped_to_unknown = false;
2047 vmanip.m_area.add_y(em, i2, -1);
2048 n2 = &vmanip.m_data[i2];
2049 // if out of known area
2050 if(vmanip.m_area.contains(i2) == false
2051 || n2->getContent() == CONTENT_IGNORE){
2052 dropped_to_unknown = true;
2055 }while(ndef->get(*n2).walkable == false);
2056 // Loop one up so that we're in air
2057 vmanip.m_area.add_y(em, i2, 1);
2058 n2 = &vmanip.m_data[i2];
2060 bool old_is_water = (n->getContent() == c_water_source);
2061 // Move mud to new place
2062 if(!dropped_to_unknown)
2064 // Set old place to be air (or water)
2066 *n = MapNode(c_water_source);
2068 *n = MapNode(CONTENT_AIR);
2083 /***********************
2085 ************************/
2088 Add top and bottom side of water to transforming_liquid queue
2091 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2092 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2097 bool water_found = false;
2098 // Use fast index incrementing
2099 v3s16 em = vmanip.m_area.getExtent();
2100 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2101 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2103 if(y == full_node_max.Y){
2105 (vmanip.m_data[i].getContent() == c_water_source ||
2106 vmanip.m_data[i].getContent() == c_lava_source);
2108 else if(water_found == false)
2110 if(vmanip.m_data[i].getContent() == c_water_source ||
2111 vmanip.m_data[i].getContent() == c_lava_source)
2113 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2114 data->transforming_liquid.push_back(p);
2120 // This can be done because water_found can only
2121 // turn to true and end up here after going through
2123 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2124 vmanip.m_data[i+1].getContent() != c_lava_source)
2126 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2127 data->transforming_liquid.push_back(p);
2128 water_found = false;
2132 vmanip.m_area.add_y(em, i, -1);
2141 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2142 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2144 // Node position in 2d
2145 v2s16 p2d = v2s16(x,z);
2148 Find the lowest surface to which enough light ends up
2151 Basically just wait until not air and not leaves.
2155 v3s16 em = vmanip.m_area.getExtent();
2156 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2158 // Go to ground level
2159 for(y=node_max.Y; y>=full_node_min.Y; y--)
2161 MapNode &n = vmanip.m_data[i];
2162 if(ndef->get(n).param_type != CPT_LIGHT
2163 || ndef->get(n).liquid_type != LIQUID_NONE)
2165 vmanip.m_area.add_y(em, i, -1);
2167 if(y >= full_node_min.Y)
2170 surface_y = full_node_min.Y;
2173 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2174 MapNode *n = &vmanip.m_data[i];
2175 if(n->getContent() == c_dirt){
2176 // Well yeah, this can't be overground...
2177 if(surface_y < WATER_LEVEL - 20)
2179 n->setContent(c_dirt_with_grass);
2186 assert(central_area_size.X == central_area_size.Z);
2188 // Divide area into parts
2190 s16 sidelen = central_area_size.X / div;
2191 double area = sidelen * sidelen;
2192 for(s16 x0=0; x0<div; x0++)
2193 for(s16 z0=0; z0<div; z0++)
2195 // Center position of part of division
2197 node_min.X + sidelen/2 + sidelen*x0,
2198 node_min.Z + sidelen/2 + sidelen*z0
2200 // Minimum edge of part of division
2202 node_min.X + sidelen*x0,
2203 node_min.Z + sidelen*z0
2205 // Maximum edge of part of division
2207 node_min.X + sidelen + sidelen*x0 - 1,
2208 node_min.Z + sidelen + sidelen*z0 - 1
2211 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2212 // Put trees in random places on part of division
2213 for(u32 i=0; i<tree_count; i++)
2215 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2216 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2217 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2218 // Don't make a tree under water level
2221 // Don't make a tree so high that it doesn't fit
2222 if(y > node_max.Y - 6)
2226 Trees grow only on mud and grass
2229 u32 i = vmanip.m_area.index(v3s16(p));
2230 MapNode *n = &vmanip.m_data[i];
2231 if(n->getContent() != c_dirt
2232 && n->getContent() != c_dirt_with_grass)
2237 make_tree(vmanip, p, false, ndef);
2244 Make base ground level
2247 for(s16 x=node_min.X; x<=node_max.X; x++)
2248 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2253 // Use fast index incrementing
2254 v3s16 em = vmanip.m_area.getExtent();
2255 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2256 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2258 // Only modify places that have no content
2259 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2261 // First priority: make air and water.
2262 // This avoids caves inside water.
2263 if(all_is_ground_except_caves == false
2264 && val_is_ground(noisebuf_ground.get(x,y,z),
2265 v3s16(x,y,z), data->seed) == false)
2267 if(y <= WATER_LEVEL)
2268 vmanip.m_data[i] = n_water_source;
2270 vmanip.m_data[i] = n_air;
2272 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2273 vmanip.m_data[i] = n_air;
2275 vmanip.m_data[i] = n_stone;
2278 vmanip->m_area.add_y(em, i, 1);
2284 Add mud and sand and others underground (in place of stone)
2287 for(s16 x=node_min.X; x<=node_max.X; x++)
2288 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2293 // Use fast index incrementing
2294 v3s16 em = vmanip.m_area.getExtent();
2295 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2296 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2298 if(vmanip.m_data[i].getContent() == c_stone)
2300 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2302 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2303 vmanip.m_data[i] = n_dirt;
2305 vmanip.m_data[i] = n_sand;
2307 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2309 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2310 vmanip.m_data[i] = n_gravel;
2312 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2313 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2315 vmanip.m_data[i] = n_lava_source;
2316 for(s16 x1=-1; x1<=1; x1++)
2317 for(s16 y1=-1; y1<=1; y1++)
2318 for(s16 z1=-1; z1<=1; z1++)
2319 data->transforming_liquid.push_back(
2320 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2324 vmanip->m_area.add_y(em, i, -1);
2333 //if(node_min.Y < approx_groundlevel)
2334 //if(myrand() % 3 == 0)
2335 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2336 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2337 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2338 float dungeon_rarity = 0.02;
2339 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2341 && node_min.Y < approx_groundlevel)
2343 // Dungeon generator doesn't modify places which have this set
2344 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2345 | VMANIP_FLAG_DUNGEON_PRESERVE);
2347 // Set all air and water to be untouchable to make dungeons open
2348 // to caves and open air
2349 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2350 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2355 // Use fast index incrementing
2356 v3s16 em = vmanip.m_area.getExtent();
2357 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2358 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2360 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2361 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2362 else if(vmanip.m_data[i].getContent() == c_water_source)
2363 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2364 vmanip->m_area.add_y(em, i, -1);
2369 PseudoRandom random(blockseed+2);
2372 make_dungeon1(vmanip, random, ndef);
2374 // Convert some cobble to mossy cobble
2375 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2376 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2381 // Use fast index incrementing
2382 v3s16 em = vmanip.m_area.getExtent();
2383 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2384 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2386 // (noisebuf not used because it doesn't contain the
2388 double wetness = noise3d_param(
2389 get_ground_wetness_params(data->seed), x,y,z);
2390 double d = noise3d_perlin((float)x/2.5,
2391 (float)y/2.5,(float)z/2.5,
2393 if(vmanip.m_data[i].getContent() == c_cobble)
2397 vmanip.m_data[i].setContent(c_mossycobble);
2400 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2403 vmanip.m_data[i].setContent(c_dirt);
2405 vmanip->m_area.add_y(em, i, -1);
2415 PseudoRandom ncrandom(blockseed+9324342);
2416 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2418 make_nc(vmanip, ncrandom, ndef);
2423 Add top and bottom side of water to transforming_liquid queue
2426 for(s16 x=node_min.X; x<=node_max.X; x++)
2427 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2432 bool water_found = false;
2433 // Use fast index incrementing
2434 v3s16 em = vmanip.m_area.getExtent();
2435 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2436 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2438 if(water_found == false)
2440 if(vmanip.m_data[i].getContent() == c_water_source)
2442 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2443 data->transforming_liquid.push_back(p);
2449 // This can be done because water_found can only
2450 // turn to true and end up here after going through
2452 if(vmanip.m_data[i+1].getContent() != c_water_source)
2454 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2455 data->transforming_liquid.push_back(p);
2456 water_found = false;
2460 vmanip->m_area.add_y(em, i, -1);
2466 If close to ground level
2469 //if(abs(approx_ground_depth) < 30)
2470 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2476 for(s16 x=node_min.X; x<=node_max.X; x++)
2477 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2482 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2483 bool have_sand = false;
2484 u32 current_depth = 0;
2485 bool air_detected = false;
2486 bool water_detected = false;
2487 bool have_clay = false;
2489 // Use fast index incrementing
2490 s16 start_y = node_max.Y+2;
2491 v3s16 em = vmanip.m_area.getExtent();
2492 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2493 for(s16 y=start_y; y>=node_min.Y-3; y--)
2495 if(vmanip.m_data[i].getContent() == c_water_source)
2496 water_detected = true;
2497 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2498 air_detected = true;
2500 if((vmanip.m_data[i].getContent() == c_stone
2501 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2502 || vmanip.m_data[i].getContent() == c_dirt
2503 || vmanip.m_data[i].getContent() == c_sand
2504 || vmanip.m_data[i].getContent() == c_gravel
2505 ) && (air_detected || water_detected))
2507 if(current_depth == 0 && y <= WATER_LEVEL+2
2508 && possibly_have_sand)
2511 if(current_depth < 4)
2515 // Determine whether to have clay in the sand here
2516 double claynoise = noise2d_perlin(
2517 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2518 data->seed+4321, 6, 0.95) + 0.5;
2520 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2521 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2522 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2525 vmanip.m_data[i] = MapNode(c_clay);
2527 vmanip.m_data[i] = MapNode(c_sand);
2530 else if(current_depth==0 && !water_detected
2531 && y >= WATER_LEVEL && air_detected)
2532 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2535 vmanip.m_data[i] = MapNode(c_dirt);
2539 if(vmanip.m_data[i].getContent() == c_dirt
2540 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2541 vmanip.m_data[i] = MapNode(c_stone);
2546 if(current_depth >= 8)
2549 else if(current_depth != 0)
2552 vmanip->m_area.add_y(em, i, -1);
2558 Calculate some stuff
2561 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2562 bool is_jungle = surface_humidity > 0.75;
2564 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2571 PseudoRandom treerandom(blockseed);
2572 // Put trees in random places on part of division
2573 for(u32 i=0; i<tree_count; i++)
2575 s16 x = treerandom.range(node_min.X, node_max.X);
2576 s16 z = treerandom.range(node_min.Z, node_max.Z);
2577 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2578 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2579 // Don't make a tree under water level
2582 // Make sure tree fits (only trees whose starting point is
2583 // at this block are added)
2584 if(y < node_min.Y || y > node_max.Y)
2587 Find exact ground level
2591 for(; p.Y >= y-6; p.Y--)
2593 u32 i = vmanip->m_area.index(p);
2594 MapNode *n = &vmanip->m_data[i];
2595 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2601 // If not found, handle next one
2606 u32 i = vmanip->m_area.index(p);
2607 MapNode *n = &vmanip->m_data[i];
2609 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2612 // Papyrus grows only on mud and in water
2613 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2616 make_papyrus(vmanip, p, ndef);
2618 // Trees grow only on mud and grass, on land
2619 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2622 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2623 if(is_jungle == false)
2626 if(myrand_range(0,4) != 0)
2627 is_apple_tree = false;
2629 is_apple_tree = noise2d_perlin(
2630 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2631 data->seed+342902, 3, 0.45) > 0.2;
2632 make_tree(vmanip, p, is_apple_tree, ndef);
2635 make_jungletree(vmanip, p, ndef);
2637 // Cactii grow only on sand, on land
2638 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2641 make_cactus(vmanip, p, ndef);
2651 PseudoRandom grassrandom(blockseed);
2652 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2654 s16 x = grassrandom.range(node_min.X, node_max.X);
2655 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2656 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2659 if(y < node_min.Y || y > node_max.Y)
2662 Find exact ground level
2666 for(; p.Y >= y-6; p.Y--)
2668 u32 i = vmanip->m_area.index(p);
2669 MapNode *n = &vmanip->m_data[i];
2670 if(data->nodedef->get(*n).is_ground_content)
2676 // If not found, handle next one
2680 if(vmanip.m_area.contains(p) == false)
2682 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2685 if(vmanip.m_area.contains(p))
2686 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2688 if(vmanip.m_area.contains(p))
2689 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2695 Add some kind of random stones
2698 u32 random_stone_count = gen_area_nodes *
2699 randomstone_amount_2d(data->seed, p2d_center);
2700 // Put in random places on part of division
2701 for(u32 i=0; i<random_stone_count; i++)
2703 s16 x = myrand_range(node_min.X, node_max.X);
2704 s16 z = myrand_range(node_min.Z, node_max.Z);
2705 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2706 // Don't add under water level
2707 /*if(y < WATER_LEVEL)
2709 // Don't add if doesn't belong to this block
2710 if(y < node_min.Y || y > node_max.Y)
2715 u32 i = vmanip->m_area.index(v3s16(p));
2716 MapNode *n = &vmanip->m_data[i];
2717 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2720 // Will be placed one higher
2723 make_randomstone(vmanip, p);
2732 u32 large_stone_count = gen_area_nodes *
2733 largestone_amount_2d(data->seed, p2d_center);
2734 //u32 large_stone_count = 1;
2735 // Put in random places on part of division
2736 for(u32 i=0; i<large_stone_count; i++)
2738 s16 x = myrand_range(node_min.X, node_max.X);
2739 s16 z = myrand_range(node_min.Z, node_max.Z);
2740 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2741 // Don't add under water level
2742 /*if(y < WATER_LEVEL)
2744 // Don't add if doesn't belong to this block
2745 if(y < node_min.Y || y > node_max.Y)
2750 u32 i = vmanip->m_area.index(v3s16(p));
2751 MapNode *n = &vmanip->m_data[i];
2752 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2755 // Will be placed one lower
2758 make_largestone(vmanip, p);
2768 PseudoRandom mineralrandom(blockseed);
2773 for(s16 i=0; i<approx_ground_depth/4; i++)
2775 if(mineralrandom.next()%50 == 0)
2777 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2778 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2779 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2780 for(u16 i=0; i<27; i++)
2782 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2783 u32 vi = vmanip.m_area.index(p);
2784 if(vmanip.m_data[vi].getContent() == c_stone)
2785 if(mineralrandom.next()%8 == 0)
2786 vmanip.m_data[vi] = MapNode(c_mese);
2795 u16 a = mineralrandom.range(0,15);
2797 u16 amount = 20 * a/1000;
2798 for(s16 i=0; i<amount; i++)
2800 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2801 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2802 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2804 u8 base_content = c_stone;
2805 MapNode new_content(CONTENT_IGNORE);
2808 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2810 new_content = MapNode(c_stone_with_coal);
2814 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2815 new_content = MapNode(c_stone_with_iron);
2816 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2817 vmanip.m_data[i] = MapNode(c_dirt);
2819 vmanip.m_data[i] = MapNode(c_sand);*/
2821 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2825 if(new_content.getContent() != CONTENT_IGNORE)
2827 for(u16 i=0; i<27; i++)
2829 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2830 u32 vi = vmanip.m_area.index(p);
2831 if(vmanip.m_data[vi].getContent() == base_content)
2833 if(mineralrandom.next()%sparseness == 0)
2834 vmanip.m_data[vi] = new_content;
2843 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2844 //for(s16 i=0; i<50; i++)
2845 u16 coal_amount = 30;
2846 u16 coal_rareness = 60 / coal_amount;
2847 if(coal_rareness == 0)
2849 if(mineralrandom.next()%coal_rareness == 0)
2851 u16 a = mineralrandom.next() % 16;
2852 u16 amount = coal_amount * a*a*a / 1000;
2853 for(s16 i=0; i<amount; i++)
2855 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2856 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2857 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2858 for(u16 i=0; i<27; i++)
2860 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2861 u32 vi = vmanip.m_area.index(p);
2862 if(vmanip.m_data[vi].getContent() == c_stone)
2863 if(mineralrandom.next()%8 == 0)
2864 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2871 u16 iron_amount = 8;
2872 u16 iron_rareness = 60 / iron_amount;
2873 if(iron_rareness == 0)
2875 if(mineralrandom.next()%iron_rareness == 0)
2877 u16 a = mineralrandom.next() % 16;
2878 u16 amount = iron_amount * a*a*a / 1000;
2879 for(s16 i=0; i<amount; i++)
2881 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2882 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2883 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2884 for(u16 i=0; i<27; i++)
2886 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2887 u32 vi = vmanip.m_area.index(p);
2888 if(vmanip.m_data[vi].getContent() == c_stone)
2889 if(mineralrandom.next()%8 == 0)
2890 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2901 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2903 //VoxelArea a(node_min, node_max);
2904 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2905 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2906 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2907 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2908 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2909 for(int i=0; i<2; i++)
2911 enum LightBank bank = banks[i];
2913 core::map<v3s16, bool> light_sources;
2914 core::map<v3s16, u8> unlight_from;
2916 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2917 light_sources, unlight_from);
2919 bool inexistent_top_provides_sunlight = !block_is_underground;
2920 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2921 vmanip, a, inexistent_top_provides_sunlight,
2922 light_sources, ndef);
2923 // TODO: Do stuff according to bottom_sunlight_valid
2925 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2927 vmanip.spreadLight(bank, light_sources, ndef);
2932 BlockMakeData::BlockMakeData():
2939 BlockMakeData::~BlockMakeData()
2944 }; // namespace mapgen