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;
64 // Returns Y one under area minimum if not found
65 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
66 INodeDefManager *ndef)
68 v3s16 em = vmanip.m_area.getExtent();
69 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
70 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
71 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
73 content_t c_tree = ndef->getId("mapgen_tree");
74 content_t c_leaves = ndef->getId("mapgen_leaves");
75 for(y=y_nodes_max; y>=y_nodes_min; y--)
77 MapNode &n = vmanip.m_data[i];
78 if(ndef->get(n).walkable
79 && n.getContent() != c_tree
80 && n.getContent() != c_leaves)
83 vmanip.m_area.add_y(em, i, -1);
88 return y_nodes_min - 1;
91 // Returns Y one under area minimum if not found
92 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
93 INodeDefManager *ndef)
95 v3s16 em = vmanip.m_area.getExtent();
96 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
97 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
98 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
100 content_t c_stone = ndef->getId("mapgen_stone");
101 for(y=y_nodes_max; y>=y_nodes_min; y--)
103 MapNode &n = vmanip.m_data[i];
104 if(n.getContent() == c_stone)
107 vmanip.m_area.add_y(em, i, -1);
112 return y_nodes_min - 1;
116 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
117 bool is_apple_tree, INodeDefManager *ndef)
119 MapNode treenode(ndef->getId("mapgen_tree"));
120 MapNode leavesnode(ndef->getId("mapgen_leaves"));
121 MapNode applenode(ndef->getId("mapgen_apple"));
123 s16 trunk_h = myrand_range(4, 5);
125 for(s16 ii=0; ii<trunk_h; ii++)
127 if(vmanip.m_area.contains(p1))
128 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
132 // p1 is now the last piece of the trunk
135 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
136 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
137 Buffer<u8> leaves_d(leaves_a.getVolume());
138 for(s32 i=0; i<leaves_a.getVolume(); i++)
141 // Force leaves at near the end of the trunk
144 for(s16 z=-d; z<=d; z++)
145 for(s16 y=-d; y<=d; y++)
146 for(s16 x=-d; x<=d; x++)
148 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
152 // Add leaves randomly
153 for(u32 iii=0; iii<7; iii++)
158 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
159 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
160 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
163 for(s16 z=0; z<=d; z++)
164 for(s16 y=0; y<=d; y++)
165 for(s16 x=0; x<=d; x++)
167 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
171 // Blit leaves to vmanip
172 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
173 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
174 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
178 if(vmanip.m_area.contains(p) == false)
180 u32 vi = vmanip.m_area.index(p);
181 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
182 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
184 u32 i = leaves_a.index(x,y,z);
185 if(leaves_d[i] == 1) {
186 bool is_apple = myrand_range(0,99) < 10;
187 if(is_apple_tree && is_apple) {
188 vmanip.m_data[vi] = applenode;
190 vmanip.m_data[vi] = leavesnode;
197 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
198 INodeDefManager *ndef)
200 MapNode treenode(ndef->getId("mapgen_jungletree"));
201 MapNode leavesnode(ndef->getId("mapgen_leaves"));
203 for(s16 x=-1; x<=1; x++)
204 for(s16 z=-1; z<=1; z++)
206 if(myrand_range(0, 2) == 0)
208 v3s16 p1 = p0 + v3s16(x,0,z);
209 v3s16 p2 = p0 + v3s16(x,-1,z);
210 if(vmanip.m_area.contains(p2)
211 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
212 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
213 else if(vmanip.m_area.contains(p1))
214 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
217 s16 trunk_h = myrand_range(8, 12);
219 for(s16 ii=0; ii<trunk_h; ii++)
221 if(vmanip.m_area.contains(p1))
222 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
226 // p1 is now the last piece of the trunk
229 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
230 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
231 Buffer<u8> leaves_d(leaves_a.getVolume());
232 for(s32 i=0; i<leaves_a.getVolume(); i++)
235 // Force leaves at near the end of the trunk
238 for(s16 z=-d; z<=d; z++)
239 for(s16 y=-d; y<=d; y++)
240 for(s16 x=-d; x<=d; x++)
242 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
246 // Add leaves randomly
247 for(u32 iii=0; iii<30; iii++)
252 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
253 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
254 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
257 for(s16 z=0; z<=d; z++)
258 for(s16 y=0; y<=d; y++)
259 for(s16 x=0; x<=d; x++)
261 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
265 // Blit leaves to vmanip
266 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
267 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
268 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
272 if(vmanip.m_area.contains(p) == false)
274 u32 vi = vmanip.m_area.index(p);
275 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
276 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
278 u32 i = leaves_a.index(x,y,z);
280 vmanip.m_data[vi] = leavesnode;
284 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
285 INodeDefManager *ndef)
287 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
289 s16 trunk_h = myrand_range(2, 3);
291 for(s16 ii=0; ii<trunk_h; ii++)
293 if(vmanip.m_area.contains(p1))
294 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
299 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
300 INodeDefManager *ndef)
302 MapNode cactusnode(ndef->getId("mapgen_cactus"));
306 for(s16 ii=0; ii<trunk_h; ii++)
308 if(vmanip.m_area.contains(p1))
309 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
317 Dungeon making routines
320 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
321 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
322 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
323 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
325 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
326 INodeDefManager *ndef)
329 for(s16 z=0; z<roomsize.Z; z++)
330 for(s16 y=0; y<roomsize.Y; y++)
333 v3s16 p = roomplace + v3s16(0,y,z);
334 if(vmanip.m_area.contains(p) == false)
336 u32 vi = vmanip.m_area.index(p);
337 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
339 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
342 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
343 if(vmanip.m_area.contains(p) == false)
345 u32 vi = vmanip.m_area.index(p);
346 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
348 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
353 for(s16 x=0; x<roomsize.X; x++)
354 for(s16 y=0; y<roomsize.Y; y++)
357 v3s16 p = roomplace + v3s16(x,y,0);
358 if(vmanip.m_area.contains(p) == false)
360 u32 vi = vmanip.m_area.index(p);
361 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
363 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
366 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
367 if(vmanip.m_area.contains(p) == false)
369 u32 vi = vmanip.m_area.index(p);
370 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
372 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
376 // Make +-Y walls (floor and ceiling)
377 for(s16 z=0; z<roomsize.Z; z++)
378 for(s16 x=0; x<roomsize.X; x++)
381 v3s16 p = roomplace + v3s16(x,0,z);
382 if(vmanip.m_area.contains(p) == false)
384 u32 vi = vmanip.m_area.index(p);
385 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
387 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
390 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
391 if(vmanip.m_area.contains(p) == false)
393 u32 vi = vmanip.m_area.index(p);
394 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
396 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
401 for(s16 z=1; z<roomsize.Z-1; z++)
402 for(s16 y=1; y<roomsize.Y-1; y++)
403 for(s16 x=1; x<roomsize.X-1; x++)
405 v3s16 p = roomplace + v3s16(x,y,z);
406 if(vmanip.m_area.contains(p) == false)
408 u32 vi = vmanip.m_area.index(p);
409 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
410 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
414 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
415 u8 avoid_flags, MapNode n, u8 or_flags)
417 for(s16 z=0; z<size.Z; z++)
418 for(s16 y=0; y<size.Y; y++)
419 for(s16 x=0; x<size.X; x++)
421 v3s16 p = place + v3s16(x,y,z);
422 if(vmanip.m_area.contains(p) == false)
424 u32 vi = vmanip.m_area.index(p);
425 if(vmanip.m_flags[vi] & avoid_flags)
427 vmanip.m_flags[vi] |= or_flags;
428 vmanip.m_data[vi] = n;
432 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
433 INodeDefManager *ndef)
435 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
436 VMANIP_FLAG_DUNGEON_INSIDE);
439 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
440 INodeDefManager *ndef)
442 make_hole1(vmanip, doorplace, ndef);
443 // Place torch (for testing)
444 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
447 static v3s16 rand_ortho_dir(PseudoRandom &random)
449 if(random.next()%2==0)
450 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
452 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
455 static v3s16 turn_xz(v3s16 olddir, int t)
475 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
477 int turn = random.range(0,2);
486 dir = turn_xz(olddir, 0);
489 dir = turn_xz(olddir, 1);
493 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
494 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
495 PseudoRandom &random, INodeDefManager *ndef)
497 make_hole1(vmanip, doorplace, ndef);
498 v3s16 p0 = doorplace;
502 length = random.range(1,13);
504 length = random.range(1,6);
505 length = random.range(1,13);
506 u32 partlength = random.range(1,13);
509 if(random.next()%2 == 0 && partlength >= 3)
510 make_stairs = random.next()%2 ? 1 : -1;
511 for(u32 i=0; i<length; i++)
517 /*// If already empty
518 if(vmanip.getNodeNoExNoEmerge(p).getContent()
520 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
525 if(vmanip.m_area.contains(p) == true
526 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
530 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
531 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
532 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
533 VMANIP_FLAG_DUNGEON_INSIDE);
534 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
535 VMANIP_FLAG_DUNGEON_INSIDE);
539 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
540 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
541 make_hole1(vmanip, p, ndef);
542 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
543 VMANIP_FLAG_DUNGEON_INSIDE);*/
550 // Can't go here, turn away
551 dir = turn_xz(dir, random.range(0,1));
552 make_stairs = -make_stairs;
554 partlength = random.range(1,length);
559 if(partcount >= partlength)
563 dir = random_turn(random, dir);
565 partlength = random.range(1,length);
568 if(random.next()%2 == 0 && partlength >= 3)
569 make_stairs = random.next()%2 ? 1 : -1;
580 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
581 INodeDefManager *ndef):
592 m_dir = rand_ortho_dir(m_random);
595 void setPos(v3s16 pos)
600 void setDir(v3s16 dir)
605 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
607 for(u32 i=0; i<100; i++)
609 v3s16 p = m_pos + m_dir;
610 v3s16 p1 = p + v3s16(0,1,0);
611 if(vmanip.m_area.contains(p) == false
612 || vmanip.m_area.contains(p1) == false
618 if(vmanip.getNodeNoExNoEmerge(p).getContent()
619 == m_ndef->getId("mapgen_cobble")
620 && vmanip.getNodeNoExNoEmerge(p1).getContent()
621 == m_ndef->getId("mapgen_cobble"))
623 // Found wall, this is a good place!
626 // Randomize next direction
631 Determine where to move next
633 // Jump one up if the actual space is there
634 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
635 == m_ndef->getId("mapgen_cobble")
636 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
638 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
641 // Jump one down if the actual space is there
642 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
643 == m_ndef->getId("mapgen_cobble")
644 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
646 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
649 // Check if walking is now possible
650 if(vmanip.getNodeNoExNoEmerge(p).getContent()
652 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
655 // Cannot continue walking here
665 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
666 v3s16 &result_doordir, v3s16 &result_roomplace)
668 for(s16 trycount=0; trycount<30; trycount++)
672 bool r = findPlaceForDoor(doorplace, doordir);
676 // X east, Z north, Y up
678 if(doordir == v3s16(1,0,0)) // X+
679 roomplace = doorplace +
680 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
681 if(doordir == v3s16(-1,0,0)) // X-
682 roomplace = doorplace +
683 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
684 if(doordir == v3s16(0,0,1)) // Z+
685 roomplace = doorplace +
686 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
687 if(doordir == v3s16(0,0,-1)) // Z-
688 roomplace = doorplace +
689 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
692 if(doordir == v3s16(1,0,0)) // X+
693 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
694 if(doordir == v3s16(-1,0,0)) // X-
695 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
696 if(doordir == v3s16(0,0,1)) // Z+
697 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
698 if(doordir == v3s16(0,0,-1)) // Z-
699 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
704 for(s16 z=1; z<roomsize.Z-1; z++)
705 for(s16 y=1; y<roomsize.Y-1; y++)
706 for(s16 x=1; x<roomsize.X-1; x++)
708 v3s16 p = roomplace + v3s16(x,y,z);
709 if(vmanip.m_area.contains(p) == false)
714 if(vmanip.m_flags[vmanip.m_area.index(p)]
715 & VMANIP_FLAG_DUNGEON_INSIDE)
726 result_doorplace = doorplace;
727 result_doordir = doordir;
728 result_roomplace = roomplace;
735 VoxelManipulator &vmanip;
738 PseudoRandom &m_random;
739 INodeDefManager *m_ndef;
742 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
743 INodeDefManager *ndef)
745 v3s16 areasize = vmanip.m_area.getExtent();
750 Find place for first room
753 for(u32 i=0; i<100; i++)
755 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
756 roomplace = vmanip.m_area.MinEdge + v3s16(
757 random.range(0,areasize.X-roomsize.X-1),
758 random.range(0,areasize.Y-roomsize.Y-1),
759 random.range(0,areasize.Z-roomsize.Z-1));
761 Check that we're not putting the room to an unknown place,
762 otherwise it might end up floating in the air
765 for(s16 z=1; z<roomsize.Z-1; z++)
766 for(s16 y=1; y<roomsize.Y-1; y++)
767 for(s16 x=1; x<roomsize.X-1; x++)
769 v3s16 p = roomplace + v3s16(x,y,z);
770 u32 vi = vmanip.m_area.index(p);
771 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
776 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
790 Stores the center position of the last room made, so that
791 a new corridor can be started from the last room instead of
792 the new room, if chosen so.
794 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
796 u32 room_count = random.range(2,7);
797 for(u32 i=0; i<room_count; i++)
799 // Make a room to the determined place
800 make_room1(vmanip, roomsize, roomplace, ndef);
802 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
804 // Place torch at room center (for testing)
805 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
808 if(i == room_count-1)
811 // Determine walker start position
813 bool start_in_last_room = (random.range(0,2)!=0);
814 //bool start_in_last_room = true;
816 v3s16 walker_start_place;
818 if(start_in_last_room)
820 walker_start_place = last_room_center;
824 walker_start_place = room_center;
825 // Store center of current room as the last one
826 last_room_center = room_center;
829 // Create walker and find a place for a door
830 RoomWalker walker(vmanip, walker_start_place, random, ndef);
833 bool r = walker.findPlaceForDoor(doorplace, doordir);
837 if(random.range(0,1)==0)
839 make_door1(vmanip, doorplace, doordir, ndef);
841 // Don't actually make a door
842 doorplace -= doordir;
844 // Make a random corridor starting from the door
846 v3s16 corridor_end_dir;
847 make_corridor(vmanip, doorplace, doordir, corridor_end,
848 corridor_end_dir, random, ndef);
850 // Find a place for a random sized room
851 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
852 walker.setPos(corridor_end);
853 walker.setDir(corridor_end_dir);
854 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
858 if(random.range(0,1)==0)
860 make_door1(vmanip, doorplace, doordir, ndef);
862 // Don't actually make a door
863 roomplace -= doordir;
870 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
871 INodeDefManager *ndef)
875 s32 r = random.range(0, 3);
877 dir = v3s16( 1, 0, 0);
881 dir = v3s16(-1, 0, 0);
885 dir = v3s16( 0, 0, 1);
889 dir = v3s16( 0, 0,-1);
892 v3s16 p = vmanip.m_area.MinEdge + v3s16(
893 16+random.range(0,15),
894 16+random.range(0,15),
895 16+random.range(0,15));
896 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
897 u32 length = random.range(3,15);
898 for(u32 j=0; j<length; j++)
901 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
907 Noise functions. Make sure seed is mangled differently in each one.
912 Scaling the output of the noise function affects the overdrive of the
913 contour function, which affects the shape of the output considerably.
915 #define CAVE_NOISE_SCALE 12.0
916 //#define CAVE_NOISE_SCALE 10.0
917 //#define CAVE_NOISE_SCALE 7.5
918 //#define CAVE_NOISE_SCALE 5.0
919 //#define CAVE_NOISE_SCALE 1.0
921 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
922 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
924 NoiseParams get_cave_noise1_params(u64 seed)
926 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
927 200, CAVE_NOISE_SCALE);*/
928 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
929 100, CAVE_NOISE_SCALE);*/
930 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
931 100, CAVE_NOISE_SCALE);*/
932 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
933 100, CAVE_NOISE_SCALE);*/
934 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
935 50, CAVE_NOISE_SCALE);
936 //return NoiseParams(NOISE_CONSTANT_ONE);
939 NoiseParams get_cave_noise2_params(u64 seed)
941 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
942 200, CAVE_NOISE_SCALE);*/
943 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
944 100, CAVE_NOISE_SCALE);*/
945 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
946 100, CAVE_NOISE_SCALE);*/
947 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
948 50, CAVE_NOISE_SCALE);
949 //return NoiseParams(NOISE_CONSTANT_ONE);
952 NoiseParams get_ground_noise1_params(u64 seed)
954 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
958 NoiseParams get_ground_crumbleness_params(u64 seed)
960 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
964 NoiseParams get_ground_wetness_params(u64 seed)
966 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
970 bool is_cave(u64 seed, v3s16 p)
972 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
973 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
974 return d1*d2 > CAVE_NOISE_THRESHOLD;
978 Ground density noise shall be interpreted by using this.
980 TODO: No perlin noises here, they should be outsourced
982 NOTE: The speed of these actually isn't terrible
984 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
986 //return ((double)p.Y < ground_noise1_val);
988 double f = 0.55 + noise2d_perlin(
989 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
990 seed+920381, 3, 0.45);
995 double h = WATER_LEVEL + 10 * noise2d_perlin(
996 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1000 return ((double)p.Y - h < ground_noise1_val * f);
1004 Queries whether a position is ground or not.
1006 bool is_ground(u64 seed, v3s16 p)
1008 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1009 return val_is_ground(val1, p, seed);
1013 // Amount of trees per area in nodes
1014 double tree_amount_2d(u64 seed, v2s16 p)
1016 /*double noise = noise2d_perlin(
1017 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1019 double noise = noise2d_perlin(
1020 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1022 double zeroval = -0.39;
1026 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1030 double surface_humidity_2d(u64 seed, v2s16 p)
1032 double noise = noise2d_perlin(
1033 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1034 seed+72384, 4, 0.66);
1035 noise = (noise + 1.0)/2.0;
1044 Incrementally find ground level from 3d noise
1046 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1048 // Start a bit fuzzy to make averaging lower precision values
1050 s16 level = myrand_range(-precision/2, precision/2);
1051 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1053 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1055 // First find non-ground by going upwards
1056 // Don't stop in caves.
1058 s16 max = level+dec[i-1]*2;
1059 v3s16 p(p2d.X, level, p2d.Y);
1060 for(; p.Y < max; p.Y += dec[i])
1062 if(!is_ground(seed, p))
1069 // Then find ground by going downwards from there.
1070 // Go in caves, too, when precision is 1.
1072 s16 min = level-dec[i-1]*2;
1073 v3s16 p(p2d.X, level, p2d.Y);
1074 for(; p.Y>min; p.Y-=dec[i])
1076 bool ground = is_ground(seed, p);
1077 /*if(dec[i] == 1 && is_cave(seed, p))
1088 // This is more like the actual ground level
1089 level += dec[i-1]/2;
1094 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1096 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1098 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1099 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1101 a += find_ground_level_from_noise(seed,
1102 v2s16(node_min.X, node_min.Y), p);
1103 a += find_ground_level_from_noise(seed,
1104 v2s16(node_min.X, node_max.Y), p);
1105 a += find_ground_level_from_noise(seed,
1106 v2s16(node_max.X, node_max.Y), p);
1107 a += find_ground_level_from_noise(seed,
1108 v2s16(node_max.X, node_min.Y), p);
1109 a += find_ground_level_from_noise(seed,
1110 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1115 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1117 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1119 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1120 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1123 a = MYMAX(a, find_ground_level_from_noise(seed,
1124 v2s16(node_min.X, node_min.Y), p));
1125 a = MYMAX(a, find_ground_level_from_noise(seed,
1126 v2s16(node_min.X, node_max.Y), p));
1127 a = MYMAX(a, find_ground_level_from_noise(seed,
1128 v2s16(node_max.X, node_max.Y), p));
1129 a = MYMAX(a, find_ground_level_from_noise(seed,
1130 v2s16(node_min.X, node_min.Y), p));
1132 a = MYMAX(a, find_ground_level_from_noise(seed,
1133 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1134 // Side middle points
1135 a = MYMAX(a, find_ground_level_from_noise(seed,
1136 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1137 a = MYMAX(a, find_ground_level_from_noise(seed,
1138 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1139 a = MYMAX(a, find_ground_level_from_noise(seed,
1140 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1141 a = MYMAX(a, find_ground_level_from_noise(seed,
1142 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1146 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1148 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1150 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1151 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1154 a = MYMIN(a, find_ground_level_from_noise(seed,
1155 v2s16(node_min.X, node_min.Y), p));
1156 a = MYMIN(a, find_ground_level_from_noise(seed,
1157 v2s16(node_min.X, node_max.Y), p));
1158 a = MYMIN(a, find_ground_level_from_noise(seed,
1159 v2s16(node_max.X, node_max.Y), p));
1160 a = MYMIN(a, find_ground_level_from_noise(seed,
1161 v2s16(node_min.X, node_min.Y), p));
1163 a = MYMIN(a, find_ground_level_from_noise(seed,
1164 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1165 // Side middle points
1166 a = MYMIN(a, find_ground_level_from_noise(seed,
1167 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1168 a = MYMIN(a, find_ground_level_from_noise(seed,
1169 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1170 a = MYMIN(a, find_ground_level_from_noise(seed,
1171 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1172 a = MYMIN(a, find_ground_level_from_noise(seed,
1173 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1178 // Required by mapgen.h
1179 bool block_is_underground(u64 seed, v3s16 blockpos)
1181 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1182 seed, v2s16(blockpos.X, blockpos.Z));*/
1183 // Nah, this is just a heuristic, just return something
1184 s16 minimum_groundlevel = WATER_LEVEL;
1186 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1192 #define AVERAGE_MUD_AMOUNT 4
1194 double base_rock_level_2d(u64 seed, v2s16 p)
1196 // The base ground level
1197 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1198 + 20. * noise2d_perlin(
1199 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1200 seed+82341, 5, 0.6);
1202 /*// A bit hillier one
1203 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1204 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1205 seed+93413, 6, 0.69);
1209 // Higher ground level
1210 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1211 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1212 seed+85039, 5, 0.6);
1213 //higher = 30; // For debugging
1215 // Limit higher to at least base
1219 // Steepness factor of cliffs
1220 double b = 0.85 + 0.5 * noise2d_perlin(
1221 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1223 b = rangelim(b, 0.0, 1000.0);
1226 b = rangelim(b, 0.5, 1000.0);
1227 // Values 1.5...100 give quite horrible looking slopes
1228 if(b > 1.5 && b < 100.0){
1234 //dstream<<"b="<<b<<std::endl;
1238 // Offset to more low
1239 double a_off = -0.20;
1240 // High/low selector
1241 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1242 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1243 seed+4213, 6, 0.7));*/
1244 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1245 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1246 seed+4213, 5, 0.69));
1248 a = rangelim(a, 0.0, 1.0);
1250 //dstream<<"a="<<a<<std::endl;
1252 double h = base*(1.0-a) + higher*a;
1259 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1261 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1264 double get_mud_add_amount(u64 seed, v2s16 p)
1266 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1267 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1268 seed+91013, 3, 0.55));
1271 bool get_have_beach(u64 seed, v2s16 p2d)
1273 // Determine whether to have sand here
1274 double sandnoise = noise2d_perlin(
1275 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1276 seed+59420, 3, 0.50);
1278 return (sandnoise > 0.15);
1281 u32 get_blockseed(u64 seed, v3s16 p)
1283 s32 x=p.X, y=p.Y, z=p.Z;
1284 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1287 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1289 void make_block(BlockMakeData *data)
1293 //dstream<<"makeBlock: no-op"<<std::endl;
1297 assert(data->vmanip);
1298 assert(data->nodedef);
1299 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1300 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1301 data->blockpos_requested.Z >= data->blockpos_min.Z);
1302 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1303 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1304 data->blockpos_requested.Z <= data->blockpos_max.Z);
1306 INodeDefManager *ndef = data->nodedef;
1308 // Hack: use minimum block coordinates for old code that assumes
1310 v3s16 blockpos = data->blockpos_requested;
1312 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1313 <<blockpos.Z<<")"<<std::endl;*/
1315 v3s16 blockpos_min = data->blockpos_min;
1316 v3s16 blockpos_max = data->blockpos_max;
1317 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1318 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1320 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1321 // Area of central chunk
1322 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1323 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1324 // Full allocated area
1325 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1326 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1328 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1330 const s16 max_spread_amount = MAP_BLOCKSIZE;
1332 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1333 * (blockpos_max.Y - blockpos_min.Y + 1)
1334 * (blockpos_max.Z - blockpos_max.Z + 1);
1336 int volume_nodes = volume_blocks *
1337 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1339 // Generated surface area
1340 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1342 // Horribly wrong heuristic, but better than nothing
1343 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1346 Create a block-specific seed
1348 u32 blockseed = get_blockseed(data->seed, full_node_min);
1351 Cache some ground type values for speed
1354 // Creates variables c_name=id and n_name=node
1355 #define CONTENT_VARIABLE(ndef, name)\
1356 content_t c_##name = ndef->getId("mapgen_" #name);\
1357 MapNode n_##name(c_##name);
1359 CONTENT_VARIABLE(ndef, stone);
1360 CONTENT_VARIABLE(ndef, air);
1361 CONTENT_VARIABLE(ndef, water_source);
1362 CONTENT_VARIABLE(ndef, dirt);
1363 CONTENT_VARIABLE(ndef, sand);
1364 CONTENT_VARIABLE(ndef, gravel);
1365 CONTENT_VARIABLE(ndef, clay);
1366 CONTENT_VARIABLE(ndef, lava_source);
1367 CONTENT_VARIABLE(ndef, cobble);
1368 CONTENT_VARIABLE(ndef, mossycobble);
1369 CONTENT_VARIABLE(ndef, dirt_with_grass);
1370 CONTENT_VARIABLE(ndef, junglegrass);
1371 CONTENT_VARIABLE(ndef, stone_with_coal);
1372 CONTENT_VARIABLE(ndef, stone_with_iron);
1373 CONTENT_VARIABLE(ndef, mese);
1375 // Maximum height of the stone surface and obstacles.
1376 // This is used to guide the cave generation
1377 s16 stone_surface_max_y = 0;
1380 Generate general ground level to full area
1384 TimeTaker timer1("Generating ground level");
1386 for(s16 x=node_min.X; x<=node_max.X; x++)
1387 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1390 v2s16 p2d = v2s16(x,z);
1393 Skip of already generated
1396 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1397 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1401 // Ground height at this point
1402 float surface_y_f = 0.0;
1404 // Use perlin noise for ground height
1405 surface_y_f = base_rock_level_2d(data->seed, p2d);
1407 /*// Experimental stuff
1409 float a = highlands_level_2d(data->seed, p2d);
1414 // Convert to integer
1415 s16 surface_y = (s16)surface_y_f;
1418 if(surface_y > stone_surface_max_y)
1419 stone_surface_max_y = surface_y;
1422 Fill ground with stone
1425 // Use fast index incrementing
1426 v3s16 em = vmanip.m_area.getExtent();
1427 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1428 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1431 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1432 vmanip.m_data[i] = MapNode(c_stone);
1433 } else if(y <= WATER_LEVEL){
1434 vmanip.m_data[i] = MapNode(c_water_source);
1436 vmanip.m_data[i] = MapNode(c_air);
1439 vmanip.m_area.add_y(em, i, 1);
1448 Add blobs of dirt and gravel underground
1451 PseudoRandom pr(blockseed+983);
1452 for(int i=0; i<volume_nodes/12/12/12; i++){
1459 pr.range(node_min.X, node_max.X)-size.X/2,
1460 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1461 pr.range(node_min.Z, node_max.Z)-size.Z/2
1464 if(p0.Y > -32 && pr.range(0,1) == 0)
1465 n1 = MapNode(c_dirt);
1467 n1 = MapNode(c_gravel);
1468 for(int x1=0; x1<size.X; x1++)
1469 for(int y1=0; y1<size.Y; y1++)
1470 for(int z1=0; z1<size.Z; z1++)
1472 v3s16 p = p0 + v3s16(x1,y1,z1);
1473 u32 i = vmanip.m_area.index(p);
1474 if(!vmanip.m_area.contains(i))
1476 if(vmanip.m_data[i].getContent() != c_stone)
1478 vmanip.m_data[i] = n1;
1483 // Limit dirt flow area by 1 because mud is flown into neighbors.
1484 assert(central_area_size.X == central_area_size.Z);
1485 s16 mudflow_minpos = 0-max_spread_amount+1;
1486 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1489 Loop this part, it will make stuff look older and newer nicely
1492 const u32 age_loops = 2;
1493 for(u32 i_age=0; i_age<age_loops; i_age++)
1495 /******************************
1496 BEGINNING OF AGING LOOP
1497 ******************************/
1502 //TimeTaker timer1("caves");
1505 Make caves (this code is relatively horrible)
1507 u32 caves_count = volume_nodes / 100000 + 1;
1508 u32 bruises_count = volume_nodes * stone_surface_max_y / 40000000;
1509 if(stone_surface_max_y < WATER_LEVEL - 20)
1511 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1513 s16 min_tunnel_diameter = 2;
1514 s16 max_tunnel_diameter = myrand_range(4,5);
1515 u16 tunnel_routepoints = 20;
1517 v3f main_direction(0,0,0);
1519 bool bruise_surface = (jj > caves_count);
1523 min_tunnel_diameter = 5;
1524 max_tunnel_diameter = myrand_range(10, myrand_range(30,50));
1525 /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
1526 max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
1528 /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(data->seed+42,
1529 data->sectorpos_base.X, data->sectorpos_base.Y)), 0, 15);*/
1531 tunnel_routepoints = 5;
1537 // Allowed route area size in nodes
1538 v3s16 ar = central_area_size;
1540 // Area starting point in nodes
1541 v3s16 of = node_min;
1544 //(this should be more than the maximum radius of the tunnel)
1545 //s16 insure = 5; // Didn't work with max_d = 20
1547 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1548 ar += v3s16(1,0,1) * more * 2;
1549 of -= v3s16(1,0,1) * more;
1551 s16 route_y_min = 0;
1552 // Allow half a diameter + 7 over stone surface
1553 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1555 /*// If caves, don't go through surface too often
1556 if(bruise_surface == false)
1557 route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
1559 // Limit maximum to area
1560 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1564 /*// Minimum is at y=0
1565 route_y_min = -of.Y - 0;*/
1566 // Minimum is at y=max_tunnel_diameter/4
1567 //route_y_min = -of.Y + max_tunnel_diameter/4;
1568 //s16 min = -of.Y + max_tunnel_diameter/4;
1569 s16 min = -of.Y + 0;
1570 route_y_min = myrand_range(min, min + max_tunnel_diameter);
1571 route_y_min = rangelim(route_y_min, 0, route_y_max);
1574 /*dstream<<"route_y_min = "<<route_y_min
1575 <<", route_y_max = "<<route_y_max<<std::endl;*/
1577 s16 route_start_y_min = route_y_min;
1578 s16 route_start_y_max = route_y_max;
1580 // Start every 4th cave from surface when applicable
1581 bool coming_from_surface = false;
1582 if(node_min.Y <= 0 && node_max.Y >= 0){
1583 coming_from_surface = (jj % 4 == 0 && bruise_surface == false);
1584 if(coming_from_surface)
1585 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1588 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1589 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1591 // Randomize starting position
1593 (float)(myrand()%ar.X)+0.5,
1594 (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
1595 (float)(myrand()%ar.Z)+0.5
1598 MapNode airnode(CONTENT_AIR);
1599 MapNode waternode(c_water_source);
1602 Generate some tunnel starting from orp
1605 for(u16 j=0; j<tunnel_routepoints; j++)
1607 if(j%7==0 && bruise_surface == false)
1609 main_direction = v3f(
1610 ((float)(myrand()%20)-(float)10)/10,
1611 ((float)(myrand()%20)-(float)10)/30,
1612 ((float)(myrand()%20)-(float)10)/10
1614 main_direction *= (float)myrand_range(1, 3);
1618 s16 min_d = min_tunnel_diameter;
1619 s16 max_d = max_tunnel_diameter;
1620 s16 rs = myrand_range(min_d, max_d);
1625 maxlen = v3s16(rs*7,rs*2,rs*7);
1629 maxlen = v3s16(rs*4, myrand_range(1, rs*3), rs*4);
1634 if(coming_from_surface && j < 3)
1637 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
1638 (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
1639 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
1645 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
1646 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
1647 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
1653 s16 h = find_ground_level_clever(vmanip,
1654 v2s16(p.X, p.Z), ndef);
1655 route_y_min = h - rs/3;
1656 route_y_max = h + rs;
1659 vec += main_direction;
1664 else if(rp.X >= ar.X)
1666 if(rp.Y < route_y_min)
1668 else if(rp.Y >= route_y_max)
1669 rp.Y = route_y_max-1;
1672 else if(rp.Z >= ar.Z)
1676 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1678 v3f fp = orp + vec * f;
1679 fp.X += 0.1*myrand_range(-10,10);
1680 fp.Z += 0.1*myrand_range(-10,10);
1681 v3s16 cp(fp.X, fp.Y, fp.Z);
1684 s16 d1 = d0 + rs - 1;
1685 for(s16 z0=d0; z0<=d1; z0++)
1687 s16 si = rs - MYMAX(0, abs(z0)-rs/4);
1688 //s16 si = rs - MYMAX(0, abs(z0)-rs/7);
1689 for(s16 x0=-si; x0<=si-1; x0++)
1691 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1692 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
1693 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
1694 //s16 si2 = rs - abs(x0);
1695 for(s16 y0=-si2; y0<=si2-1; y0++)
1697 // Make better floors
1698 if(y0 < -rs + 1 && abs(x0)<=1 && abs(z0)<=1)
1705 /*if(isInArea(p, ar) == false)
1707 // Check only height
1708 if(y < 0 || y >= ar.Y)
1712 //assert(vmanip.m_area.contains(p));
1713 if(vmanip.m_area.contains(p) == false)
1715 dstream<<"WARNING: "<<__FUNCTION_NAME
1716 <<":"<<__LINE__<<": "
1717 <<"point not in area"
1722 // Just set it to air, it will be changed to
1724 u32 i = vmanip.m_area.index(p);
1726 if(p.Y <= WATER_LEVEL)
1727 vmanip.m_data[i] = waternode;
1729 vmanip.m_data[i] = airnode;
1731 vmanip.m_data[i] = airnode;
1734 if(bruise_surface == false)
1737 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1755 TimeTaker timer1("add mud");
1758 Add mud to the central chunk
1761 for(s16 x=node_min.X; x<=node_max.X; x++)
1762 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1764 // Node position in 2d
1765 v2s16 p2d = v2s16(x,z);
1767 MapNode addnode(c_dirt);
1769 // Randomize mud amount
1770 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0;
1772 // Find ground level
1773 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1774 // Handle area not found
1775 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1778 if(mud_add_amount <= 0){
1779 mud_add_amount = 1 - mud_add_amount;
1780 addnode = MapNode(c_gravel);
1781 } else if(get_have_beach(data->seed, p2d) &&
1782 surface_y + mud_add_amount <= WATER_LEVEL+2){
1783 addnode = MapNode(c_sand);
1787 If topmost node is grass, change it to mud.
1788 It might be if it was flown to there from a neighboring
1789 chunk and then converted.
1792 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1793 MapNode *n = &vmanip.m_data[i];
1794 if(n->getContent() == c_dirt_with_grass)
1795 *n = MapNode(c_dirt);
1803 v3s16 em = vmanip.m_area.getExtent();
1804 s16 y_start = surface_y+1;
1805 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1806 for(s16 y=y_start; y<=node_max.Y; y++)
1808 if(mudcount >= mud_add_amount)
1811 MapNode &n = vmanip.m_data[i];
1815 vmanip.m_area.add_y(em, i, 1);
1827 TimeTaker timer1("flow mud");
1830 Flow mud away from steep edges
1833 // Iterate a few times
1834 for(s16 k=0; k<3; k++)
1837 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1838 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1840 // Invert coordinates every 2nd iteration
1843 x = mudflow_maxpos - (x-mudflow_minpos);
1844 z = mudflow_maxpos - (z-mudflow_minpos);
1847 // Node position in 2d
1848 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1850 v3s16 em = vmanip.m_area.getExtent();
1851 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1858 for(; y>=node_min.Y; y--)
1860 n = &vmanip.m_data[i];
1861 //if(content_walkable(n->d))
1863 if(n->getContent() == c_dirt ||
1864 n->getContent() == c_dirt_with_grass)
1867 vmanip.m_area.add_y(em, i, -1);
1870 // Stop if out of area
1871 //if(vmanip.m_area.contains(i) == false)
1875 /*// If not mud, do nothing to it
1876 MapNode *n = &vmanip.m_data[i];
1877 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1881 Don't flow it if the stuff under it is not mud
1885 vmanip.m_area.add_y(em, i2, -1);
1886 // Cancel if out of area
1887 if(vmanip.m_area.contains(i2) == false)
1889 MapNode *n2 = &vmanip.m_data[i2];
1890 if(n2->getContent() != c_dirt &&
1891 n2->getContent() != c_dirt_with_grass)
1895 // Make it exactly mud
1896 n->setContent(c_dirt);
1898 /*s16 recurse_count = 0;
1902 v3s16(0,0,1), // back
1903 v3s16(1,0,0), // right
1904 v3s16(0,0,-1), // front
1905 v3s16(-1,0,0), // left
1908 // Theck that upper is air or doesn't exist.
1909 // Cancel dropping if upper keeps it in place
1911 vmanip.m_area.add_y(em, i3, 1);
1912 if(vmanip.m_area.contains(i3) == true
1913 && ndef->get(vmanip.m_data[i3]).walkable)
1920 for(u32 di=0; di<4; di++)
1922 v3s16 dirp = dirs4[di];
1925 vmanip.m_area.add_p(em, i2, dirp);
1926 // Fail if out of area
1927 if(vmanip.m_area.contains(i2) == false)
1929 // Check that side is air
1930 MapNode *n2 = &vmanip.m_data[i2];
1931 if(ndef->get(*n2).walkable)
1933 // Check that under side is air
1934 vmanip.m_area.add_y(em, i2, -1);
1935 if(vmanip.m_area.contains(i2) == false)
1937 n2 = &vmanip.m_data[i2];
1938 if(ndef->get(*n2).walkable)
1940 /*// Check that under that is air (need a drop of 2)
1941 vmanip.m_area.add_y(em, i2, -1);
1942 if(vmanip.m_area.contains(i2) == false)
1944 n2 = &vmanip.m_data[i2];
1945 if(content_walkable(n2->d))
1947 // Loop further down until not air
1948 bool dropped_to_unknown = false;
1950 vmanip.m_area.add_y(em, i2, -1);
1951 n2 = &vmanip.m_data[i2];
1952 // if out of known area
1953 if(vmanip.m_area.contains(i2) == false
1954 || n2->getContent() == CONTENT_IGNORE){
1955 dropped_to_unknown = true;
1958 }while(ndef->get(*n2).walkable == false);
1959 // Loop one up so that we're in air
1960 vmanip.m_area.add_y(em, i2, 1);
1961 n2 = &vmanip.m_data[i2];
1963 bool old_is_water = (n->getContent() == c_water_source);
1964 // Move mud to new place
1965 if(!dropped_to_unknown)
1967 // Set old place to be air (or water)
1969 *n = MapNode(c_water_source);
1971 *n = MapNode(CONTENT_AIR);
1985 /***********************
1987 ************************/
1990 Add top and bottom side of water to transforming_liquid queue
1993 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1994 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1999 bool water_found = false;
2000 // Use fast index incrementing
2001 v3s16 em = vmanip.m_area.getExtent();
2002 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2003 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2005 if(water_found == false)
2007 if(vmanip.m_data[i].getContent() == c_water_source)
2009 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2010 data->transforming_liquid.push_back(p);
2016 // This can be done because water_found can only
2017 // turn to true and end up here after going through
2019 if(vmanip.m_data[i+1].getContent() != c_water_source)
2021 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2022 data->transforming_liquid.push_back(p);
2023 water_found = false;
2027 vmanip.m_area.add_y(em, i, -1);
2036 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2037 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2039 // Node position in 2d
2040 v2s16 p2d = v2s16(x,z);
2043 Find the lowest surface to which enough light ends up
2046 Basically just wait until not air and not leaves.
2050 v3s16 em = vmanip.m_area.getExtent();
2051 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2053 // Go to ground level
2054 for(y=node_max.Y; y>=full_node_min.Y; y--)
2056 MapNode &n = vmanip.m_data[i];
2057 if(ndef->get(n).param_type != CPT_LIGHT
2058 || ndef->get(n).liquid_type != LIQUID_NONE)
2060 vmanip.m_area.add_y(em, i, -1);
2062 if(y >= full_node_min.Y)
2065 surface_y = full_node_min.Y;
2068 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2069 MapNode *n = &vmanip.m_data[i];
2070 if(n->getContent() == c_dirt)
2071 n->setContent(c_dirt_with_grass);
2077 assert(central_area_size.X == central_area_size.Z);
2079 // Divide area into parts
2081 s16 sidelen = central_area_size.X / div;
2082 double area = sidelen * sidelen;
2083 for(s16 x0=0; x0<div; x0++)
2084 for(s16 z0=0; z0<div; z0++)
2086 // Center position of part of division
2088 node_min.X + sidelen/2 + sidelen*x0,
2089 node_min.Z + sidelen/2 + sidelen*z0
2091 // Minimum edge of part of division
2093 node_min.X + sidelen*x0,
2094 node_min.Z + sidelen*z0
2096 // Maximum edge of part of division
2098 node_min.X + sidelen + sidelen*x0 - 1,
2099 node_min.Z + sidelen + sidelen*z0 - 1
2102 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2103 // Put trees in random places on part of division
2104 for(u32 i=0; i<tree_count; i++)
2106 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2107 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2108 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2109 // Don't make a tree under water level
2112 // Don't make a tree so high that it doesn't fit
2113 if(y > node_max.Y - 6)
2117 Trees grow only on mud and grass
2120 u32 i = vmanip.m_area.index(v3s16(p));
2121 MapNode *n = &vmanip.m_data[i];
2122 if(n->getContent() != c_dirt
2123 && n->getContent() != c_dirt_with_grass)
2128 make_tree(vmanip, p, false, ndef);
2135 Make base ground level
2138 for(s16 x=node_min.X; x<=node_max.X; x++)
2139 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2144 // Use fast index incrementing
2145 v3s16 em = vmanip.m_area.getExtent();
2146 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2147 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2149 // Only modify places that have no content
2150 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2152 // First priority: make air and water.
2153 // This avoids caves inside water.
2154 if(all_is_ground_except_caves == false
2155 && val_is_ground(noisebuf_ground.get(x,y,z),
2156 v3s16(x,y,z), data->seed) == false)
2158 if(y <= WATER_LEVEL)
2159 vmanip.m_data[i] = n_water_source;
2161 vmanip.m_data[i] = n_air;
2163 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2164 vmanip.m_data[i] = n_air;
2166 vmanip.m_data[i] = n_stone;
2169 vmanip->m_area.add_y(em, i, 1);
2175 Add mud and sand and others underground (in place of stone)
2178 for(s16 x=node_min.X; x<=node_max.X; x++)
2179 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2184 // Use fast index incrementing
2185 v3s16 em = vmanip.m_area.getExtent();
2186 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2187 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2189 if(vmanip.m_data[i].getContent() == c_stone)
2191 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2193 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2194 vmanip.m_data[i] = n_dirt;
2196 vmanip.m_data[i] = n_sand;
2198 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2200 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2201 vmanip.m_data[i] = n_gravel;
2203 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2204 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2206 vmanip.m_data[i] = n_lava_source;
2207 for(s16 x1=-1; x1<=1; x1++)
2208 for(s16 y1=-1; y1<=1; y1++)
2209 for(s16 z1=-1; z1<=1; z1++)
2210 data->transforming_liquid.push_back(
2211 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2215 vmanip->m_area.add_y(em, i, -1);
2224 //if(node_min.Y < approx_groundlevel)
2225 //if(myrand() % 3 == 0)
2226 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2227 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2228 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2229 float dungeon_rarity = 0.02;
2230 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2232 && node_min.Y < approx_groundlevel)
2234 // Dungeon generator doesn't modify places which have this set
2235 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2236 | VMANIP_FLAG_DUNGEON_PRESERVE);
2238 // Set all air and water to be untouchable to make dungeons open
2239 // to caves and open air
2240 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2241 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2246 // Use fast index incrementing
2247 v3s16 em = vmanip.m_area.getExtent();
2248 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2249 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2251 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2252 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2253 else if(vmanip.m_data[i].getContent() == c_water_source)
2254 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2255 vmanip->m_area.add_y(em, i, -1);
2260 PseudoRandom random(blockseed+2);
2263 make_dungeon1(vmanip, random, ndef);
2265 // Convert some cobble to mossy cobble
2266 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2267 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2272 // Use fast index incrementing
2273 v3s16 em = vmanip.m_area.getExtent();
2274 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2275 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2277 // (noisebuf not used because it doesn't contain the
2279 double wetness = noise3d_param(
2280 get_ground_wetness_params(data->seed), x,y,z);
2281 double d = noise3d_perlin((float)x/2.5,
2282 (float)y/2.5,(float)z/2.5,
2284 if(vmanip.m_data[i].getContent() == c_cobble)
2288 vmanip.m_data[i].setContent(c_mossycobble);
2291 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2294 vmanip.m_data[i].setContent(c_dirt);
2296 vmanip->m_area.add_y(em, i, -1);
2306 PseudoRandom ncrandom(blockseed+9324342);
2307 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2309 make_nc(vmanip, ncrandom, ndef);
2314 Add top and bottom side of water to transforming_liquid queue
2317 for(s16 x=node_min.X; x<=node_max.X; x++)
2318 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2323 bool water_found = false;
2324 // Use fast index incrementing
2325 v3s16 em = vmanip.m_area.getExtent();
2326 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2327 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2329 if(water_found == false)
2331 if(vmanip.m_data[i].getContent() == c_water_source)
2333 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2334 data->transforming_liquid.push_back(p);
2340 // This can be done because water_found can only
2341 // turn to true and end up here after going through
2343 if(vmanip.m_data[i+1].getContent() != c_water_source)
2345 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2346 data->transforming_liquid.push_back(p);
2347 water_found = false;
2351 vmanip->m_area.add_y(em, i, -1);
2357 If close to ground level
2360 //if(abs(approx_ground_depth) < 30)
2361 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2367 for(s16 x=node_min.X; x<=node_max.X; x++)
2368 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2373 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2374 bool have_sand = false;
2375 u32 current_depth = 0;
2376 bool air_detected = false;
2377 bool water_detected = false;
2378 bool have_clay = false;
2380 // Use fast index incrementing
2381 s16 start_y = node_max.Y+2;
2382 v3s16 em = vmanip.m_area.getExtent();
2383 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2384 for(s16 y=start_y; y>=node_min.Y-3; y--)
2386 if(vmanip.m_data[i].getContent() == c_water_source)
2387 water_detected = true;
2388 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2389 air_detected = true;
2391 if((vmanip.m_data[i].getContent() == c_stone
2392 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2393 || vmanip.m_data[i].getContent() == c_dirt
2394 || vmanip.m_data[i].getContent() == c_sand
2395 || vmanip.m_data[i].getContent() == c_gravel
2396 ) && (air_detected || water_detected))
2398 if(current_depth == 0 && y <= WATER_LEVEL+2
2399 && possibly_have_sand)
2402 if(current_depth < 4)
2406 // Determine whether to have clay in the sand here
2407 double claynoise = noise2d_perlin(
2408 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2409 data->seed+4321, 6, 0.95) + 0.5;
2411 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2412 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2413 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2416 vmanip.m_data[i] = MapNode(c_clay);
2418 vmanip.m_data[i] = MapNode(c_sand);
2421 else if(current_depth==0 && !water_detected
2422 && y >= WATER_LEVEL && air_detected)
2423 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2426 vmanip.m_data[i] = MapNode(c_dirt);
2430 if(vmanip.m_data[i].getContent() == c_dirt
2431 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2432 vmanip.m_data[i] = MapNode(c_stone);
2437 if(current_depth >= 8)
2440 else if(current_depth != 0)
2443 vmanip->m_area.add_y(em, i, -1);
2449 Calculate some stuff
2452 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2453 bool is_jungle = surface_humidity > 0.75;
2455 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2462 PseudoRandom treerandom(blockseed);
2463 // Put trees in random places on part of division
2464 for(u32 i=0; i<tree_count; i++)
2466 s16 x = treerandom.range(node_min.X, node_max.X);
2467 s16 z = treerandom.range(node_min.Z, node_max.Z);
2468 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2469 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2470 // Don't make a tree under water level
2473 // Make sure tree fits (only trees whose starting point is
2474 // at this block are added)
2475 if(y < node_min.Y || y > node_max.Y)
2478 Find exact ground level
2482 for(; p.Y >= y-6; p.Y--)
2484 u32 i = vmanip->m_area.index(p);
2485 MapNode *n = &vmanip->m_data[i];
2486 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2492 // If not found, handle next one
2497 u32 i = vmanip->m_area.index(p);
2498 MapNode *n = &vmanip->m_data[i];
2500 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2503 // Papyrus grows only on mud and in water
2504 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2507 make_papyrus(vmanip, p, ndef);
2509 // Trees grow only on mud and grass, on land
2510 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2513 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2514 if(is_jungle == false)
2517 if(myrand_range(0,4) != 0)
2518 is_apple_tree = false;
2520 is_apple_tree = noise2d_perlin(
2521 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2522 data->seed+342902, 3, 0.45) > 0.2;
2523 make_tree(vmanip, p, is_apple_tree, ndef);
2526 make_jungletree(vmanip, p, ndef);
2528 // Cactii grow only on sand, on land
2529 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2532 make_cactus(vmanip, p, ndef);
2542 PseudoRandom grassrandom(blockseed);
2543 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2545 s16 x = grassrandom.range(node_min.X, node_max.X);
2546 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2547 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2550 if(y < node_min.Y || y > node_max.Y)
2553 Find exact ground level
2557 for(; p.Y >= y-6; p.Y--)
2559 u32 i = vmanip->m_area.index(p);
2560 MapNode *n = &vmanip->m_data[i];
2561 if(data->nodedef->get(*n).is_ground_content)
2567 // If not found, handle next one
2571 if(vmanip.m_area.contains(p) == false)
2573 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2576 if(vmanip.m_area.contains(p))
2577 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2579 if(vmanip.m_area.contains(p))
2580 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2586 Add some kind of random stones
2589 u32 random_stone_count = gen_area_nodes *
2590 randomstone_amount_2d(data->seed, p2d_center);
2591 // Put in random places on part of division
2592 for(u32 i=0; i<random_stone_count; i++)
2594 s16 x = myrand_range(node_min.X, node_max.X);
2595 s16 z = myrand_range(node_min.Z, node_max.Z);
2596 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2597 // Don't add under water level
2598 /*if(y < WATER_LEVEL)
2600 // Don't add if doesn't belong to this block
2601 if(y < node_min.Y || y > node_max.Y)
2606 u32 i = vmanip->m_area.index(v3s16(p));
2607 MapNode *n = &vmanip->m_data[i];
2608 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2611 // Will be placed one higher
2614 make_randomstone(vmanip, p);
2623 u32 large_stone_count = gen_area_nodes *
2624 largestone_amount_2d(data->seed, p2d_center);
2625 //u32 large_stone_count = 1;
2626 // Put in random places on part of division
2627 for(u32 i=0; i<large_stone_count; i++)
2629 s16 x = myrand_range(node_min.X, node_max.X);
2630 s16 z = myrand_range(node_min.Z, node_max.Z);
2631 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2632 // Don't add under water level
2633 /*if(y < WATER_LEVEL)
2635 // Don't add if doesn't belong to this block
2636 if(y < node_min.Y || y > node_max.Y)
2641 u32 i = vmanip->m_area.index(v3s16(p));
2642 MapNode *n = &vmanip->m_data[i];
2643 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2646 // Will be placed one lower
2649 make_largestone(vmanip, p);
2659 PseudoRandom mineralrandom(blockseed);
2664 for(s16 i=0; i<approx_ground_depth/4; i++)
2666 if(mineralrandom.next()%50 == 0)
2668 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2669 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2670 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2671 for(u16 i=0; i<27; i++)
2673 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2674 u32 vi = vmanip.m_area.index(p);
2675 if(vmanip.m_data[vi].getContent() == c_stone)
2676 if(mineralrandom.next()%8 == 0)
2677 vmanip.m_data[vi] = MapNode(c_mese);
2686 u16 a = mineralrandom.range(0,15);
2688 u16 amount = 20 * a/1000;
2689 for(s16 i=0; i<amount; i++)
2691 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2692 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2693 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2695 u8 base_content = c_stone;
2696 MapNode new_content(CONTENT_IGNORE);
2699 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2701 new_content = MapNode(c_stone_with_coal);
2705 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2706 new_content = MapNode(c_stone_with_iron);
2707 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2708 vmanip.m_data[i] = MapNode(c_dirt);
2710 vmanip.m_data[i] = MapNode(c_sand);*/
2712 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2716 if(new_content.getContent() != CONTENT_IGNORE)
2718 for(u16 i=0; i<27; i++)
2720 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2721 u32 vi = vmanip.m_area.index(p);
2722 if(vmanip.m_data[vi].getContent() == base_content)
2724 if(mineralrandom.next()%sparseness == 0)
2725 vmanip.m_data[vi] = new_content;
2734 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2735 //for(s16 i=0; i<50; i++)
2736 u16 coal_amount = 30;
2737 u16 coal_rareness = 60 / coal_amount;
2738 if(coal_rareness == 0)
2740 if(mineralrandom.next()%coal_rareness == 0)
2742 u16 a = mineralrandom.next() % 16;
2743 u16 amount = coal_amount * a*a*a / 1000;
2744 for(s16 i=0; i<amount; i++)
2746 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2747 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2748 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2749 for(u16 i=0; i<27; i++)
2751 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2752 u32 vi = vmanip.m_area.index(p);
2753 if(vmanip.m_data[vi].getContent() == c_stone)
2754 if(mineralrandom.next()%8 == 0)
2755 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2762 u16 iron_amount = 8;
2763 u16 iron_rareness = 60 / iron_amount;
2764 if(iron_rareness == 0)
2766 if(mineralrandom.next()%iron_rareness == 0)
2768 u16 a = mineralrandom.next() % 16;
2769 u16 amount = iron_amount * a*a*a / 1000;
2770 for(s16 i=0; i<amount; i++)
2772 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2773 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2774 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2775 for(u16 i=0; i<27; i++)
2777 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2778 u32 vi = vmanip.m_area.index(p);
2779 if(vmanip.m_data[vi].getContent() == c_stone)
2780 if(mineralrandom.next()%8 == 0)
2781 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2792 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2794 //VoxelArea a(node_min, node_max);
2795 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2796 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2797 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2798 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2799 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2800 for(int i=0; i<2; i++)
2802 enum LightBank bank = banks[i];
2804 core::map<v3s16, bool> light_sources;
2805 core::map<v3s16, u8> unlight_from;
2807 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2808 light_sources, unlight_from);
2810 bool inexistent_top_provides_sunlight = !block_is_underground;
2811 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2812 vmanip, a, inexistent_top_provides_sunlight,
2813 light_sources, ndef);
2814 // TODO: Do stuff according to bottom_sunlight_valid
2816 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2818 vmanip.spreadLight(bank, light_sources, ndef);
2823 BlockMakeData::BlockMakeData():
2830 BlockMakeData::~BlockMakeData()
2835 }; // namespace mapgen