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 for(y=y_nodes_max; y>=y_nodes_min; y--)
107 MapNode &n = vmanip.m_data[i];
108 if(n.getContent() == c_stone)
111 vmanip.m_area.add_y(em, i, -1);
116 return y_nodes_min - 1;
120 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
121 bool is_apple_tree, INodeDefManager *ndef)
123 MapNode treenode(ndef->getId("mapgen_tree"));
124 MapNode leavesnode(ndef->getId("mapgen_leaves"));
125 MapNode applenode(ndef->getId("mapgen_apple"));
127 s16 trunk_h = myrand_range(4, 5);
129 for(s16 ii=0; ii<trunk_h; ii++)
131 if(vmanip.m_area.contains(p1))
132 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
136 // p1 is now the last piece of the trunk
139 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
140 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
141 Buffer<u8> leaves_d(leaves_a.getVolume());
142 for(s32 i=0; i<leaves_a.getVolume(); i++)
145 // Force leaves at near the end of the trunk
148 for(s16 z=-d; z<=d; z++)
149 for(s16 y=-d; y<=d; y++)
150 for(s16 x=-d; x<=d; x++)
152 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
156 // Add leaves randomly
157 for(u32 iii=0; iii<7; iii++)
162 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
163 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
164 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
167 for(s16 z=0; z<=d; z++)
168 for(s16 y=0; y<=d; y++)
169 for(s16 x=0; x<=d; x++)
171 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
175 // Blit leaves to vmanip
176 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
177 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
178 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
182 if(vmanip.m_area.contains(p) == false)
184 u32 vi = vmanip.m_area.index(p);
185 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
186 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
188 u32 i = leaves_a.index(x,y,z);
189 if(leaves_d[i] == 1) {
190 bool is_apple = myrand_range(0,99) < 10;
191 if(is_apple_tree && is_apple) {
192 vmanip.m_data[vi] = applenode;
194 vmanip.m_data[vi] = leavesnode;
201 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
202 INodeDefManager *ndef)
204 MapNode treenode(ndef->getId("mapgen_jungletree"));
205 MapNode leavesnode(ndef->getId("mapgen_leaves"));
207 for(s16 x=-1; x<=1; x++)
208 for(s16 z=-1; z<=1; z++)
210 if(myrand_range(0, 2) == 0)
212 v3s16 p1 = p0 + v3s16(x,0,z);
213 v3s16 p2 = p0 + v3s16(x,-1,z);
214 if(vmanip.m_area.contains(p2)
215 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
216 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
217 else if(vmanip.m_area.contains(p1))
218 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
221 s16 trunk_h = myrand_range(8, 12);
223 for(s16 ii=0; ii<trunk_h; ii++)
225 if(vmanip.m_area.contains(p1))
226 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
230 // p1 is now the last piece of the trunk
233 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
234 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
235 Buffer<u8> leaves_d(leaves_a.getVolume());
236 for(s32 i=0; i<leaves_a.getVolume(); i++)
239 // Force leaves at near the end of the trunk
242 for(s16 z=-d; z<=d; z++)
243 for(s16 y=-d; y<=d; y++)
244 for(s16 x=-d; x<=d; x++)
246 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
250 // Add leaves randomly
251 for(u32 iii=0; iii<30; iii++)
256 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
257 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
258 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
261 for(s16 z=0; z<=d; z++)
262 for(s16 y=0; y<=d; y++)
263 for(s16 x=0; x<=d; x++)
265 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
269 // Blit leaves to vmanip
270 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
271 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
272 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
276 if(vmanip.m_area.contains(p) == false)
278 u32 vi = vmanip.m_area.index(p);
279 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
280 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
282 u32 i = leaves_a.index(x,y,z);
284 vmanip.m_data[vi] = leavesnode;
288 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
289 INodeDefManager *ndef)
291 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
293 s16 trunk_h = myrand_range(2, 3);
295 for(s16 ii=0; ii<trunk_h; ii++)
297 if(vmanip.m_area.contains(p1))
298 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
303 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
304 INodeDefManager *ndef)
306 MapNode cactusnode(ndef->getId("mapgen_cactus"));
310 for(s16 ii=0; ii<trunk_h; ii++)
312 if(vmanip.m_area.contains(p1))
313 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
321 Dungeon making routines
324 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
325 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
326 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
327 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
329 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
330 INodeDefManager *ndef)
333 for(s16 z=0; z<roomsize.Z; z++)
334 for(s16 y=0; y<roomsize.Y; y++)
337 v3s16 p = roomplace + v3s16(0,y,z);
338 if(vmanip.m_area.contains(p) == false)
340 u32 vi = vmanip.m_area.index(p);
341 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
343 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
346 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
347 if(vmanip.m_area.contains(p) == false)
349 u32 vi = vmanip.m_area.index(p);
350 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
352 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
357 for(s16 x=0; x<roomsize.X; x++)
358 for(s16 y=0; y<roomsize.Y; y++)
361 v3s16 p = roomplace + v3s16(x,y,0);
362 if(vmanip.m_area.contains(p) == false)
364 u32 vi = vmanip.m_area.index(p);
365 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
367 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
370 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
371 if(vmanip.m_area.contains(p) == false)
373 u32 vi = vmanip.m_area.index(p);
374 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
376 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
380 // Make +-Y walls (floor and ceiling)
381 for(s16 z=0; z<roomsize.Z; z++)
382 for(s16 x=0; x<roomsize.X; x++)
385 v3s16 p = roomplace + v3s16(x,0,z);
386 if(vmanip.m_area.contains(p) == false)
388 u32 vi = vmanip.m_area.index(p);
389 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
391 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
394 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
395 if(vmanip.m_area.contains(p) == false)
397 u32 vi = vmanip.m_area.index(p);
398 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
400 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
405 for(s16 z=1; z<roomsize.Z-1; z++)
406 for(s16 y=1; y<roomsize.Y-1; y++)
407 for(s16 x=1; x<roomsize.X-1; x++)
409 v3s16 p = roomplace + v3s16(x,y,z);
410 if(vmanip.m_area.contains(p) == false)
412 u32 vi = vmanip.m_area.index(p);
413 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
414 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
418 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
419 u8 avoid_flags, MapNode n, u8 or_flags)
421 for(s16 z=0; z<size.Z; z++)
422 for(s16 y=0; y<size.Y; y++)
423 for(s16 x=0; x<size.X; x++)
425 v3s16 p = place + v3s16(x,y,z);
426 if(vmanip.m_area.contains(p) == false)
428 u32 vi = vmanip.m_area.index(p);
429 if(vmanip.m_flags[vi] & avoid_flags)
431 vmanip.m_flags[vi] |= or_flags;
432 vmanip.m_data[vi] = n;
436 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
437 INodeDefManager *ndef)
439 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
440 VMANIP_FLAG_DUNGEON_INSIDE);
443 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
444 INodeDefManager *ndef)
446 make_hole1(vmanip, doorplace, ndef);
447 // Place torch (for testing)
448 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
451 static v3s16 rand_ortho_dir(PseudoRandom &random)
453 if(random.next()%2==0)
454 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
456 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
459 static v3s16 turn_xz(v3s16 olddir, int t)
479 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
481 int turn = random.range(0,2);
490 dir = turn_xz(olddir, 0);
493 dir = turn_xz(olddir, 1);
497 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
498 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
499 PseudoRandom &random, INodeDefManager *ndef)
501 make_hole1(vmanip, doorplace, ndef);
502 v3s16 p0 = doorplace;
506 length = random.range(1,13);
508 length = random.range(1,6);
509 length = random.range(1,13);
510 u32 partlength = random.range(1,13);
513 if(random.next()%2 == 0 && partlength >= 3)
514 make_stairs = random.next()%2 ? 1 : -1;
515 for(u32 i=0; i<length; i++)
521 /*// If already empty
522 if(vmanip.getNodeNoExNoEmerge(p).getContent()
524 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
529 if(vmanip.m_area.contains(p) == true
530 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
534 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
535 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
536 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
537 VMANIP_FLAG_DUNGEON_INSIDE);
538 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
539 VMANIP_FLAG_DUNGEON_INSIDE);
543 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
544 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
545 make_hole1(vmanip, p, ndef);
546 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
547 VMANIP_FLAG_DUNGEON_INSIDE);*/
554 // Can't go here, turn away
555 dir = turn_xz(dir, random.range(0,1));
556 make_stairs = -make_stairs;
558 partlength = random.range(1,length);
563 if(partcount >= partlength)
567 dir = random_turn(random, dir);
569 partlength = random.range(1,length);
572 if(random.next()%2 == 0 && partlength >= 3)
573 make_stairs = random.next()%2 ? 1 : -1;
584 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
585 INodeDefManager *ndef):
596 m_dir = rand_ortho_dir(m_random);
599 void setPos(v3s16 pos)
604 void setDir(v3s16 dir)
609 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
611 for(u32 i=0; i<100; i++)
613 v3s16 p = m_pos + m_dir;
614 v3s16 p1 = p + v3s16(0,1,0);
615 if(vmanip.m_area.contains(p) == false
616 || vmanip.m_area.contains(p1) == false
622 if(vmanip.getNodeNoExNoEmerge(p).getContent()
623 == m_ndef->getId("mapgen_cobble")
624 && vmanip.getNodeNoExNoEmerge(p1).getContent()
625 == m_ndef->getId("mapgen_cobble"))
627 // Found wall, this is a good place!
630 // Randomize next direction
635 Determine where to move next
637 // Jump one up if the actual space is there
638 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
639 == m_ndef->getId("mapgen_cobble")
640 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
642 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
645 // Jump one down if the actual space is there
646 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
647 == m_ndef->getId("mapgen_cobble")
648 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
650 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
653 // Check if walking is now possible
654 if(vmanip.getNodeNoExNoEmerge(p).getContent()
656 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
659 // Cannot continue walking here
669 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
670 v3s16 &result_doordir, v3s16 &result_roomplace)
672 for(s16 trycount=0; trycount<30; trycount++)
676 bool r = findPlaceForDoor(doorplace, doordir);
680 // X east, Z north, Y up
682 if(doordir == v3s16(1,0,0)) // X+
683 roomplace = doorplace +
684 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
685 if(doordir == v3s16(-1,0,0)) // X-
686 roomplace = doorplace +
687 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
688 if(doordir == v3s16(0,0,1)) // Z+
689 roomplace = doorplace +
690 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
691 if(doordir == v3s16(0,0,-1)) // Z-
692 roomplace = doorplace +
693 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
696 if(doordir == v3s16(1,0,0)) // X+
697 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
698 if(doordir == v3s16(-1,0,0)) // X-
699 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
700 if(doordir == v3s16(0,0,1)) // Z+
701 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
702 if(doordir == v3s16(0,0,-1)) // Z-
703 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
708 for(s16 z=1; z<roomsize.Z-1; z++)
709 for(s16 y=1; y<roomsize.Y-1; y++)
710 for(s16 x=1; x<roomsize.X-1; x++)
712 v3s16 p = roomplace + v3s16(x,y,z);
713 if(vmanip.m_area.contains(p) == false)
718 if(vmanip.m_flags[vmanip.m_area.index(p)]
719 & VMANIP_FLAG_DUNGEON_INSIDE)
730 result_doorplace = doorplace;
731 result_doordir = doordir;
732 result_roomplace = roomplace;
739 VoxelManipulator &vmanip;
742 PseudoRandom &m_random;
743 INodeDefManager *m_ndef;
746 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
747 INodeDefManager *ndef)
749 v3s16 areasize = vmanip.m_area.getExtent();
754 Find place for first room
757 for(u32 i=0; i<100; i++)
759 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
760 roomplace = vmanip.m_area.MinEdge + v3s16(
761 random.range(0,areasize.X-roomsize.X-1),
762 random.range(0,areasize.Y-roomsize.Y-1),
763 random.range(0,areasize.Z-roomsize.Z-1));
765 Check that we're not putting the room to an unknown place,
766 otherwise it might end up floating in the air
769 for(s16 z=1; z<roomsize.Z-1; z++)
770 for(s16 y=1; y<roomsize.Y-1; y++)
771 for(s16 x=1; x<roomsize.X-1; x++)
773 v3s16 p = roomplace + v3s16(x,y,z);
774 u32 vi = vmanip.m_area.index(p);
775 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
780 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
794 Stores the center position of the last room made, so that
795 a new corridor can be started from the last room instead of
796 the new room, if chosen so.
798 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
800 u32 room_count = random.range(2,7);
801 for(u32 i=0; i<room_count; i++)
803 // Make a room to the determined place
804 make_room1(vmanip, roomsize, roomplace, ndef);
806 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
808 // Place torch at room center (for testing)
809 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
812 if(i == room_count-1)
815 // Determine walker start position
817 bool start_in_last_room = (random.range(0,2)!=0);
818 //bool start_in_last_room = true;
820 v3s16 walker_start_place;
822 if(start_in_last_room)
824 walker_start_place = last_room_center;
828 walker_start_place = room_center;
829 // Store center of current room as the last one
830 last_room_center = room_center;
833 // Create walker and find a place for a door
834 RoomWalker walker(vmanip, walker_start_place, random, ndef);
837 bool r = walker.findPlaceForDoor(doorplace, doordir);
841 if(random.range(0,1)==0)
843 make_door1(vmanip, doorplace, doordir, ndef);
845 // Don't actually make a door
846 doorplace -= doordir;
848 // Make a random corridor starting from the door
850 v3s16 corridor_end_dir;
851 make_corridor(vmanip, doorplace, doordir, corridor_end,
852 corridor_end_dir, random, ndef);
854 // Find a place for a random sized room
855 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
856 walker.setPos(corridor_end);
857 walker.setDir(corridor_end_dir);
858 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
862 if(random.range(0,1)==0)
864 make_door1(vmanip, doorplace, doordir, ndef);
866 // Don't actually make a door
867 roomplace -= doordir;
874 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
875 INodeDefManager *ndef)
879 s32 r = random.range(0, 3);
881 dir = v3s16( 1, 0, 0);
885 dir = v3s16(-1, 0, 0);
889 dir = v3s16( 0, 0, 1);
893 dir = v3s16( 0, 0,-1);
896 v3s16 p = vmanip.m_area.MinEdge + v3s16(
897 16+random.range(0,15),
898 16+random.range(0,15),
899 16+random.range(0,15));
900 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
901 u32 length = random.range(3,15);
902 for(u32 j=0; j<length; j++)
905 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
911 Noise functions. Make sure seed is mangled differently in each one.
916 Scaling the output of the noise function affects the overdrive of the
917 contour function, which affects the shape of the output considerably.
919 #define CAVE_NOISE_SCALE 12.0
920 //#define CAVE_NOISE_SCALE 10.0
921 //#define CAVE_NOISE_SCALE 7.5
922 //#define CAVE_NOISE_SCALE 5.0
923 //#define CAVE_NOISE_SCALE 1.0
925 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
926 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
928 NoiseParams get_cave_noise1_params(u64 seed)
930 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
931 200, CAVE_NOISE_SCALE);*/
932 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
933 100, CAVE_NOISE_SCALE);*/
934 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
935 100, CAVE_NOISE_SCALE);*/
936 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
937 100, CAVE_NOISE_SCALE);*/
938 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
939 50, CAVE_NOISE_SCALE);
940 //return NoiseParams(NOISE_CONSTANT_ONE);
943 NoiseParams get_cave_noise2_params(u64 seed)
945 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
946 200, CAVE_NOISE_SCALE);*/
947 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
948 100, CAVE_NOISE_SCALE);*/
949 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
950 100, CAVE_NOISE_SCALE);*/
951 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
952 50, CAVE_NOISE_SCALE);
953 //return NoiseParams(NOISE_CONSTANT_ONE);
956 NoiseParams get_ground_noise1_params(u64 seed)
958 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
962 NoiseParams get_ground_crumbleness_params(u64 seed)
964 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
968 NoiseParams get_ground_wetness_params(u64 seed)
970 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
974 bool is_cave(u64 seed, v3s16 p)
976 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
977 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
978 return d1*d2 > CAVE_NOISE_THRESHOLD;
982 Ground density noise shall be interpreted by using this.
984 TODO: No perlin noises here, they should be outsourced
986 NOTE: The speed of these actually isn't terrible
988 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
990 //return ((double)p.Y < ground_noise1_val);
992 double f = 0.55 + noise2d_perlin(
993 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
994 seed+920381, 3, 0.45);
999 double h = WATER_LEVEL + 10 * noise2d_perlin(
1000 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1001 seed+84174, 4, 0.5);
1004 return ((double)p.Y - h < ground_noise1_val * f);
1008 Queries whether a position is ground or not.
1010 bool is_ground(u64 seed, v3s16 p)
1012 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1013 return val_is_ground(val1, p, seed);
1017 // Amount of trees per area in nodes
1018 double tree_amount_2d(u64 seed, v2s16 p)
1020 /*double noise = noise2d_perlin(
1021 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1023 double noise = noise2d_perlin(
1024 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1026 double zeroval = -0.39;
1030 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1034 double surface_humidity_2d(u64 seed, v2s16 p)
1036 double noise = noise2d_perlin(
1037 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1038 seed+72384, 4, 0.66);
1039 noise = (noise + 1.0)/2.0;
1048 Incrementally find ground level from 3d noise
1050 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1052 // Start a bit fuzzy to make averaging lower precision values
1054 s16 level = myrand_range(-precision/2, precision/2);
1055 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1057 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1059 // First find non-ground by going upwards
1060 // Don't stop in caves.
1062 s16 max = level+dec[i-1]*2;
1063 v3s16 p(p2d.X, level, p2d.Y);
1064 for(; p.Y < max; p.Y += dec[i])
1066 if(!is_ground(seed, p))
1073 // Then find ground by going downwards from there.
1074 // Go in caves, too, when precision is 1.
1076 s16 min = level-dec[i-1]*2;
1077 v3s16 p(p2d.X, level, p2d.Y);
1078 for(; p.Y>min; p.Y-=dec[i])
1080 bool ground = is_ground(seed, p);
1081 /*if(dec[i] == 1 && is_cave(seed, p))
1092 // This is more like the actual ground level
1093 level += dec[i-1]/2;
1098 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1100 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1102 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1103 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1105 a += find_ground_level_from_noise(seed,
1106 v2s16(node_min.X, node_min.Y), p);
1107 a += find_ground_level_from_noise(seed,
1108 v2s16(node_min.X, node_max.Y), p);
1109 a += find_ground_level_from_noise(seed,
1110 v2s16(node_max.X, node_max.Y), p);
1111 a += find_ground_level_from_noise(seed,
1112 v2s16(node_max.X, node_min.Y), p);
1113 a += find_ground_level_from_noise(seed,
1114 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1119 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1121 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1123 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1124 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1127 a = MYMAX(a, find_ground_level_from_noise(seed,
1128 v2s16(node_min.X, node_min.Y), p));
1129 a = MYMAX(a, find_ground_level_from_noise(seed,
1130 v2s16(node_min.X, node_max.Y), p));
1131 a = MYMAX(a, find_ground_level_from_noise(seed,
1132 v2s16(node_max.X, node_max.Y), p));
1133 a = MYMAX(a, find_ground_level_from_noise(seed,
1134 v2s16(node_min.X, node_min.Y), p));
1136 a = MYMAX(a, find_ground_level_from_noise(seed,
1137 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1138 // Side middle points
1139 a = MYMAX(a, find_ground_level_from_noise(seed,
1140 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1141 a = MYMAX(a, find_ground_level_from_noise(seed,
1142 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1143 a = MYMAX(a, find_ground_level_from_noise(seed,
1144 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1145 a = MYMAX(a, find_ground_level_from_noise(seed,
1146 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1150 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1152 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1154 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1155 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1158 a = MYMIN(a, find_ground_level_from_noise(seed,
1159 v2s16(node_min.X, node_min.Y), p));
1160 a = MYMIN(a, find_ground_level_from_noise(seed,
1161 v2s16(node_min.X, node_max.Y), p));
1162 a = MYMIN(a, find_ground_level_from_noise(seed,
1163 v2s16(node_max.X, node_max.Y), p));
1164 a = MYMIN(a, find_ground_level_from_noise(seed,
1165 v2s16(node_min.X, node_min.Y), p));
1167 a = MYMIN(a, find_ground_level_from_noise(seed,
1168 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1169 // Side middle points
1170 a = MYMIN(a, find_ground_level_from_noise(seed,
1171 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1172 a = MYMIN(a, find_ground_level_from_noise(seed,
1173 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1174 a = MYMIN(a, find_ground_level_from_noise(seed,
1175 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1176 a = MYMIN(a, find_ground_level_from_noise(seed,
1177 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1182 // Required by mapgen.h
1183 bool block_is_underground(u64 seed, v3s16 blockpos)
1185 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1186 seed, v2s16(blockpos.X, blockpos.Z));*/
1187 // Nah, this is just a heuristic, just return something
1188 s16 minimum_groundlevel = WATER_LEVEL;
1190 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1196 #define AVERAGE_MUD_AMOUNT 4
1198 double base_rock_level_2d(u64 seed, v2s16 p)
1200 // The base ground level
1201 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1202 + 20. * noise2d_perlin(
1203 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1204 seed+82341, 5, 0.6);
1206 /*// A bit hillier one
1207 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1208 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1209 seed+93413, 6, 0.69);
1213 // Higher ground level
1214 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1215 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1216 seed+85039, 5, 0.6);
1217 //higher = 30; // For debugging
1219 // Limit higher to at least base
1223 // Steepness factor of cliffs
1224 double b = 0.85 + 0.5 * noise2d_perlin(
1225 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1227 b = rangelim(b, 0.0, 1000.0);
1230 b = rangelim(b, 0.5, 1000.0);
1231 // Values 1.5...100 give quite horrible looking slopes
1232 if(b > 1.5 && b < 100.0){
1238 //dstream<<"b="<<b<<std::endl;
1242 // Offset to more low
1243 double a_off = -0.20;
1244 // High/low selector
1245 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1246 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1247 seed+4213, 6, 0.7));*/
1248 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1249 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1250 seed+4213, 5, 0.69));
1252 a = rangelim(a, 0.0, 1.0);
1254 //dstream<<"a="<<a<<std::endl;
1256 double h = base*(1.0-a) + higher*a;
1263 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1265 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1268 double get_mud_add_amount(u64 seed, v2s16 p)
1270 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1271 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1272 seed+91013, 3, 0.55));
1275 bool get_have_beach(u64 seed, v2s16 p2d)
1277 // Determine whether to have sand here
1278 double sandnoise = noise2d_perlin(
1279 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1280 seed+59420, 3, 0.50);
1282 return (sandnoise > 0.15);
1285 u32 get_blockseed(u64 seed, v3s16 p)
1287 s32 x=p.X, y=p.Y, z=p.Z;
1288 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1291 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1293 void make_block(BlockMakeData *data)
1297 //dstream<<"makeBlock: no-op"<<std::endl;
1301 assert(data->vmanip);
1302 assert(data->nodedef);
1303 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1304 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1305 data->blockpos_requested.Z >= data->blockpos_min.Z);
1306 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1307 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1308 data->blockpos_requested.Z <= data->blockpos_max.Z);
1310 INodeDefManager *ndef = data->nodedef;
1312 // Hack: use minimum block coordinates for old code that assumes
1314 v3s16 blockpos = data->blockpos_requested;
1316 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1317 <<blockpos.Z<<")"<<std::endl;*/
1319 v3s16 blockpos_min = data->blockpos_min;
1320 v3s16 blockpos_max = data->blockpos_max;
1321 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1322 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1324 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1325 // Area of central chunk
1326 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1327 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1328 // Full allocated area
1329 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1330 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1332 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1334 const s16 max_spread_amount = MAP_BLOCKSIZE;
1336 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1337 * (blockpos_max.Y - blockpos_min.Y + 1)
1338 * (blockpos_max.Z - blockpos_max.Z + 1);
1340 int volume_nodes = volume_blocks *
1341 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1343 // Generated surface area
1344 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1346 // Horribly wrong heuristic, but better than nothing
1347 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1350 Create a block-specific seed
1352 u32 blockseed = get_blockseed(data->seed, full_node_min);
1355 Cache some ground type values for speed
1358 // Creates variables c_name=id and n_name=node
1359 #define CONTENT_VARIABLE(ndef, name)\
1360 content_t c_##name = ndef->getId("mapgen_" #name);\
1361 MapNode n_##name(c_##name);
1363 CONTENT_VARIABLE(ndef, stone);
1364 CONTENT_VARIABLE(ndef, air);
1365 CONTENT_VARIABLE(ndef, water_source);
1366 CONTENT_VARIABLE(ndef, dirt);
1367 CONTENT_VARIABLE(ndef, sand);
1368 CONTENT_VARIABLE(ndef, gravel);
1369 CONTENT_VARIABLE(ndef, clay);
1370 CONTENT_VARIABLE(ndef, lava_source);
1371 CONTENT_VARIABLE(ndef, cobble);
1372 CONTENT_VARIABLE(ndef, mossycobble);
1373 CONTENT_VARIABLE(ndef, dirt_with_grass);
1374 CONTENT_VARIABLE(ndef, junglegrass);
1375 CONTENT_VARIABLE(ndef, stone_with_coal);
1376 CONTENT_VARIABLE(ndef, stone_with_iron);
1377 CONTENT_VARIABLE(ndef, mese);
1379 // Maximum height of the stone surface and obstacles.
1380 // This is used to guide the cave generation
1381 s16 stone_surface_max_y = 0;
1384 Generate general ground level to full area
1388 TimeTaker timer1("Generating ground level");
1390 for(s16 x=node_min.X; x<=node_max.X; x++)
1391 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1394 v2s16 p2d = v2s16(x,z);
1397 Skip of already generated
1400 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1401 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1405 // Ground height at this point
1406 float surface_y_f = 0.0;
1408 // Use perlin noise for ground height
1409 surface_y_f = base_rock_level_2d(data->seed, p2d);
1411 /*// Experimental stuff
1413 float a = highlands_level_2d(data->seed, p2d);
1418 // Convert to integer
1419 s16 surface_y = (s16)surface_y_f;
1422 if(surface_y > stone_surface_max_y)
1423 stone_surface_max_y = surface_y;
1426 Fill ground with stone
1429 // Use fast index incrementing
1430 v3s16 em = vmanip.m_area.getExtent();
1431 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1432 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1435 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1436 vmanip.m_data[i] = MapNode(c_stone);
1437 } else if(y <= WATER_LEVEL){
1438 vmanip.m_data[i] = MapNode(c_water_source);
1440 vmanip.m_data[i] = MapNode(c_air);
1443 vmanip.m_area.add_y(em, i, 1);
1451 // Limit dirt flow area by 1 because mud is flown into neighbors.
1452 assert(central_area_size.X == central_area_size.Z);
1453 s16 mudflow_minpos = 0-max_spread_amount+1;
1454 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1457 Loop this part, it will make stuff look older and newer nicely
1460 const u32 age_loops = 2;
1461 for(u32 i_age=0; i_age<age_loops; i_age++)
1463 /******************************
1464 BEGINNING OF AGING LOOP
1465 ******************************/
1470 //TimeTaker timer1("caves");
1473 Make caves (this code is relatively horrible)
1475 double cave_amount = noise2d_perlin(
1476 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1477 data->seed+34329, 3, 0.50);
1478 cave_amount = MYMAX(0.0, 4.0*cave_amount+2.0);
1479 u32 caves_count = cave_amount * volume_nodes / 100000;
1480 u32 bruises_count = cave_amount * volume_nodes / 400000;
1481 bruises_count *= MYMAX(1, -node_max.Y/100);
1482 if(stone_surface_max_y < WATER_LEVEL - 20)
1484 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1486 s16 min_tunnel_diameter = 2;
1487 s16 max_tunnel_diameter = myrand_range(3,5);
1488 u16 tunnel_routepoints = myrand_range(5,25);
1489 int dswitchint = myrand_range(1,14);
1490 int part_max_length_rs = myrand_range(2,11);
1492 v3f main_direction(0,0,0);
1494 bool bruise_surface = (jj > caves_count);
1498 min_tunnel_diameter = 5;
1499 max_tunnel_diameter = myrand_range(10, myrand_range(20,40));
1500 /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
1501 max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
1503 /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(data->seed+42,
1504 data->sectorpos_base.X, data->sectorpos_base.Y)), 0, 15);*/
1506 tunnel_routepoints = 5;
1512 // Allowed route area size in nodes
1513 v3s16 ar = central_area_size;
1515 // Area starting point in nodes
1516 v3s16 of = node_min;
1519 //(this should be more than the maximum radius of the tunnel)
1520 //s16 insure = 5; // Didn't work with max_d = 20
1522 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1523 ar += v3s16(1,0,1) * more * 2;
1524 of -= v3s16(1,0,1) * more;
1526 s16 route_y_min = 0;
1527 // Allow half a diameter + 7 over stone surface
1528 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1530 /*// If caves, don't go through surface too often
1531 if(bruise_surface == false)
1532 route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
1534 // Limit maximum to area
1535 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1539 /*// Minimum is at y=0
1540 route_y_min = -of.Y - 0;*/
1541 // Minimum is at y=max_tunnel_diameter/4
1542 //route_y_min = -of.Y + max_tunnel_diameter/4;
1543 //s16 min = -of.Y + max_tunnel_diameter/4;
1544 //s16 min = -of.Y + 0;
1546 route_y_min = myrand_range(min, min + max_tunnel_diameter);
1547 route_y_min = rangelim(route_y_min, 0, route_y_max);
1550 /*dstream<<"route_y_min = "<<route_y_min
1551 <<", route_y_max = "<<route_y_max<<std::endl;*/
1553 s16 route_start_y_min = route_y_min;
1554 s16 route_start_y_max = route_y_max;
1556 // Start every 4th cave from surface when applicable
1557 /*bool coming_from_surface = false;
1558 if(node_min.Y <= 0 && node_max.Y >= 0){
1559 coming_from_surface = (jj % 4 == 0 && bruise_surface == false);
1560 if(coming_from_surface)
1561 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1564 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1565 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1567 // Randomize starting position
1569 (float)(myrand()%ar.X)+0.5,
1570 (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
1571 (float)(myrand()%ar.Z)+0.5
1574 v3s16 startp(orp.X, orp.Y, orp.Z);
1577 MapNode airnode(CONTENT_AIR);
1578 MapNode waternode(c_water_source);
1579 MapNode lavanode(c_lava_source);
1582 Generate some tunnel starting from orp
1585 for(u16 j=0; j<tunnel_routepoints; j++)
1587 if(j%dswitchint==0 && bruise_surface == false)
1589 main_direction = v3f(
1590 ((float)(myrand()%20)-(float)10)/10,
1591 ((float)(myrand()%20)-(float)10)/30,
1592 ((float)(myrand()%20)-(float)10)/10
1594 main_direction *= (float)myrand_range(0, 10)/10;
1598 s16 min_d = min_tunnel_diameter;
1599 s16 max_d = max_tunnel_diameter;
1600 s16 rs = myrand_range(min_d, max_d);
1605 maxlen = v3s16(rs*part_max_length_rs,rs*part_max_length_rs/3,rs*part_max_length_rs);
1609 maxlen = v3s16(rs*part_max_length_rs, myrand_range(1, rs*part_max_length_rs), rs*part_max_length_rs);
1615 (float)(myrand()%(maxlen.X*1))-(float)maxlen.X/2,
1616 (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y/2,
1617 (float)(myrand()%(maxlen.Z*1))-(float)maxlen.Z/2
1620 // Jump downward sometimes
1621 if(!bruise_surface && myrand_range(0,12) == 0)
1624 (float)(myrand()%(maxlen.X*1))-(float)maxlen.X/2,
1625 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1626 (float)(myrand()%(maxlen.Z*1))-(float)maxlen.Z/2
1630 /*if(bruise_surface){
1632 s16 h = find_ground_level_clever(vmanip,
1633 v2s16(p.X, p.Z), ndef);
1634 route_y_min = h - rs/3;
1635 route_y_max = h + rs;
1638 vec += main_direction;
1643 else if(rp.X >= ar.X)
1645 if(rp.Y < route_y_min)
1647 else if(rp.Y >= route_y_max)
1648 rp.Y = route_y_max-1;
1651 else if(rp.Z >= ar.Z)
1655 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1657 v3f fp = orp + vec * f;
1658 fp.X += 0.1*myrand_range(-10,10);
1659 fp.Z += 0.1*myrand_range(-10,10);
1660 v3s16 cp(fp.X, fp.Y, fp.Z);
1663 s16 d1 = d0 + rs - 1;
1664 for(s16 z0=d0; z0<=d1; z0++)
1666 s16 si = rs - MYMAX(0, abs(z0)-rs/7);
1667 //s16 si = rs - MYMAX(0, abs(z0)-rs/7);
1668 for(s16 x0=-si; x0<=si-1; x0++)
1670 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1671 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
1672 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
1673 //s16 si2 = rs - abs(x0);
1674 for(s16 y0=-si2; y0<=si2-1; y0++)
1676 // Make better floors in small caves
1677 if(y0 < -rs + 1 && si<=7)
1679 bool is_bottomish = (y0 <= -si2 + 1);
1685 /*if(isInArea(p, ar) == false)
1687 // Check only height
1688 if(y < 0 || y >= ar.Y)
1692 if(vmanip.m_area.contains(p) == false)
1695 // Just set it to air, it will be changed to
1697 u32 i = vmanip.m_area.index(p);
1701 if(full_node_min.Y < WATER_LEVEL &&
1702 full_node_max.Y > WATER_LEVEL){
1703 if(p.Y <= WATER_LEVEL)
1704 vmanip.m_data[i] = waternode;
1706 vmanip.m_data[i] = airnode;
1707 } else if(full_node_max.Y < WATER_LEVEL){
1709 vmanip.m_data[i] = MapNode(c_stone);
1710 else if(p.Y < startp.Y - 2)
1711 vmanip.m_data[i] = lavanode;
1713 vmanip.m_data[i] = airnode;
1715 vmanip.m_data[i] = airnode;
1718 // Don't replace air or water or lava
1719 if(vmanip.m_data[i].getContent() == CONTENT_AIR ||
1720 vmanip.m_data[i].getContent() == c_water_source ||
1721 vmanip.m_data[i].getContent() == c_lava_source)
1723 vmanip.m_data[i] = airnode;
1726 if(bruise_surface == false)
1729 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1747 TimeTaker timer1("add mud");
1750 Add mud to the central chunk
1753 for(s16 x=node_min.X; x<=node_max.X; x++)
1754 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1756 // Node position in 2d
1757 v2s16 p2d = v2s16(x,z);
1759 MapNode addnode(c_dirt);
1761 // Randomize mud amount
1762 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0;
1764 // Find ground level
1765 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1766 // Handle area not found
1767 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1770 if(mud_add_amount <= 0){
1771 mud_add_amount = 1 - mud_add_amount;
1772 addnode = MapNode(c_gravel);
1773 } else if(get_have_beach(data->seed, p2d) &&
1774 surface_y + mud_add_amount <= WATER_LEVEL+2){
1775 addnode = MapNode(c_sand);
1779 If topmost node is grass, change it to mud.
1780 It might be if it was flown to there from a neighboring
1781 chunk and then converted.
1784 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1785 MapNode *n = &vmanip.m_data[i];
1786 if(n->getContent() == c_dirt_with_grass)
1787 *n = MapNode(c_dirt);
1795 v3s16 em = vmanip.m_area.getExtent();
1796 s16 y_start = surface_y+1;
1797 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1798 for(s16 y=y_start; y<=node_max.Y; y++)
1800 if(mudcount >= mud_add_amount)
1803 MapNode &n = vmanip.m_data[i];
1807 vmanip.m_area.add_y(em, i, 1);
1817 Add blobs of dirt and gravel underground
1820 PseudoRandom pr(blockseed+983);
1821 for(int i=0; i<volume_nodes/10/10/10; i++)
1823 bool only_fill_cave = (myrand_range(0,1) != 0);
1830 pr.range(node_min.X, node_max.X)-size.X/2,
1831 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1832 pr.range(node_min.Z, node_max.Z)-size.Z/2
1835 if(p0.Y > -32 && pr.range(0,1) == 0)
1836 n1 = MapNode(c_dirt);
1838 n1 = MapNode(c_gravel);
1839 for(int x1=0; x1<size.X; x1++)
1840 for(int y1=0; y1<size.Y; y1++)
1841 for(int z1=0; z1<size.Z; z1++)
1843 v3s16 p = p0 + v3s16(x1,y1,z1);
1844 u32 i = vmanip.m_area.index(p);
1845 if(!vmanip.m_area.contains(i))
1847 // Cancel if not stone and not cave air
1848 if(vmanip.m_data[i].getContent() != c_stone &&
1849 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1851 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1853 vmanip.m_data[i] = n1;
1861 TimeTaker timer1("flow mud");
1864 Flow mud away from steep edges
1867 // Iterate a few times
1868 for(s16 k=0; k<3; k++)
1871 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1872 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1874 // Invert coordinates every 2nd iteration
1877 x = mudflow_maxpos - (x-mudflow_minpos);
1878 z = mudflow_maxpos - (z-mudflow_minpos);
1881 // Node position in 2d
1882 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1884 v3s16 em = vmanip.m_area.getExtent();
1885 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1892 for(; y>=node_min.Y; y--)
1894 n = &vmanip.m_data[i];
1895 //if(content_walkable(n->d))
1897 if(n->getContent() == c_dirt ||
1898 n->getContent() == c_dirt_with_grass ||
1899 n->getContent() == c_gravel)
1902 vmanip.m_area.add_y(em, i, -1);
1905 // Stop if out of area
1906 //if(vmanip.m_area.contains(i) == false)
1910 /*// If not mud, do nothing to it
1911 MapNode *n = &vmanip.m_data[i];
1912 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1915 if(n->getContent() == c_dirt ||
1916 n->getContent() == c_dirt_with_grass)
1918 // Make it exactly mud
1919 n->setContent(c_dirt);
1922 Don't flow it if the stuff under it is not mud
1926 vmanip.m_area.add_y(em, i2, -1);
1927 // Cancel if out of area
1928 if(vmanip.m_area.contains(i2) == false)
1930 MapNode *n2 = &vmanip.m_data[i2];
1931 if(n2->getContent() != c_dirt &&
1932 n2->getContent() != c_dirt_with_grass)
1937 /*s16 recurse_count = 0;
1941 v3s16(0,0,1), // back
1942 v3s16(1,0,0), // right
1943 v3s16(0,0,-1), // front
1944 v3s16(-1,0,0), // left
1947 // Theck that upper is air or doesn't exist.
1948 // Cancel dropping if upper keeps it in place
1950 vmanip.m_area.add_y(em, i3, 1);
1951 if(vmanip.m_area.contains(i3) == true
1952 && ndef->get(vmanip.m_data[i3]).walkable)
1959 for(u32 di=0; di<4; di++)
1961 v3s16 dirp = dirs4[di];
1964 vmanip.m_area.add_p(em, i2, dirp);
1965 // Fail if out of area
1966 if(vmanip.m_area.contains(i2) == false)
1968 // Check that side is air
1969 MapNode *n2 = &vmanip.m_data[i2];
1970 if(ndef->get(*n2).walkable)
1972 // Check that under side is air
1973 vmanip.m_area.add_y(em, i2, -1);
1974 if(vmanip.m_area.contains(i2) == false)
1976 n2 = &vmanip.m_data[i2];
1977 if(ndef->get(*n2).walkable)
1979 /*// Check that under that is air (need a drop of 2)
1980 vmanip.m_area.add_y(em, i2, -1);
1981 if(vmanip.m_area.contains(i2) == false)
1983 n2 = &vmanip.m_data[i2];
1984 if(content_walkable(n2->d))
1986 // Loop further down until not air
1987 bool dropped_to_unknown = false;
1989 vmanip.m_area.add_y(em, i2, -1);
1990 n2 = &vmanip.m_data[i2];
1991 // if out of known area
1992 if(vmanip.m_area.contains(i2) == false
1993 || n2->getContent() == CONTENT_IGNORE){
1994 dropped_to_unknown = true;
1997 }while(ndef->get(*n2).walkable == false);
1998 // Loop one up so that we're in air
1999 vmanip.m_area.add_y(em, i2, 1);
2000 n2 = &vmanip.m_data[i2];
2002 bool old_is_water = (n->getContent() == c_water_source);
2003 // Move mud to new place
2004 if(!dropped_to_unknown)
2006 // Set old place to be air (or water)
2008 *n = MapNode(c_water_source);
2010 *n = MapNode(CONTENT_AIR);
2024 /***********************
2026 ************************/
2029 Add top and bottom side of water to transforming_liquid queue
2032 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2033 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2038 bool water_found = false;
2039 // Use fast index incrementing
2040 v3s16 em = vmanip.m_area.getExtent();
2041 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2042 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2044 if(y == full_node_max.Y){
2046 (vmanip.m_data[i].getContent() == c_water_source ||
2047 vmanip.m_data[i].getContent() == c_lava_source);
2049 else if(water_found == false)
2051 if(vmanip.m_data[i].getContent() == c_water_source ||
2052 vmanip.m_data[i].getContent() == c_lava_source)
2054 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2055 data->transforming_liquid.push_back(p);
2061 // This can be done because water_found can only
2062 // turn to true and end up here after going through
2064 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2065 vmanip.m_data[i+1].getContent() != c_lava_source)
2067 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2068 data->transforming_liquid.push_back(p);
2069 water_found = false;
2073 vmanip.m_area.add_y(em, i, -1);
2082 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2083 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2085 // Node position in 2d
2086 v2s16 p2d = v2s16(x,z);
2089 Find the lowest surface to which enough light ends up
2092 Basically just wait until not air and not leaves.
2096 v3s16 em = vmanip.m_area.getExtent();
2097 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2099 // Go to ground level
2100 for(y=node_max.Y; y>=full_node_min.Y; y--)
2102 MapNode &n = vmanip.m_data[i];
2103 if(ndef->get(n).param_type != CPT_LIGHT
2104 || ndef->get(n).liquid_type != LIQUID_NONE)
2106 vmanip.m_area.add_y(em, i, -1);
2108 if(y >= full_node_min.Y)
2111 surface_y = full_node_min.Y;
2114 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2115 MapNode *n = &vmanip.m_data[i];
2116 if(n->getContent() == c_dirt){
2117 // Well yeah, this can't be overground...
2118 if(surface_y < WATER_LEVEL - 20)
2120 n->setContent(c_dirt_with_grass);
2127 assert(central_area_size.X == central_area_size.Z);
2129 // Divide area into parts
2131 s16 sidelen = central_area_size.X / div;
2132 double area = sidelen * sidelen;
2133 for(s16 x0=0; x0<div; x0++)
2134 for(s16 z0=0; z0<div; z0++)
2136 // Center position of part of division
2138 node_min.X + sidelen/2 + sidelen*x0,
2139 node_min.Z + sidelen/2 + sidelen*z0
2141 // Minimum edge of part of division
2143 node_min.X + sidelen*x0,
2144 node_min.Z + sidelen*z0
2146 // Maximum edge of part of division
2148 node_min.X + sidelen + sidelen*x0 - 1,
2149 node_min.Z + sidelen + sidelen*z0 - 1
2152 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2153 // Put trees in random places on part of division
2154 for(u32 i=0; i<tree_count; i++)
2156 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2157 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2158 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2159 // Don't make a tree under water level
2162 // Don't make a tree so high that it doesn't fit
2163 if(y > node_max.Y - 6)
2167 Trees grow only on mud and grass
2170 u32 i = vmanip.m_area.index(v3s16(p));
2171 MapNode *n = &vmanip.m_data[i];
2172 if(n->getContent() != c_dirt
2173 && n->getContent() != c_dirt_with_grass)
2178 make_tree(vmanip, p, false, ndef);
2185 Make base ground level
2188 for(s16 x=node_min.X; x<=node_max.X; x++)
2189 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2194 // Use fast index incrementing
2195 v3s16 em = vmanip.m_area.getExtent();
2196 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2197 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2199 // Only modify places that have no content
2200 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2202 // First priority: make air and water.
2203 // This avoids caves inside water.
2204 if(all_is_ground_except_caves == false
2205 && val_is_ground(noisebuf_ground.get(x,y,z),
2206 v3s16(x,y,z), data->seed) == false)
2208 if(y <= WATER_LEVEL)
2209 vmanip.m_data[i] = n_water_source;
2211 vmanip.m_data[i] = n_air;
2213 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2214 vmanip.m_data[i] = n_air;
2216 vmanip.m_data[i] = n_stone;
2219 vmanip->m_area.add_y(em, i, 1);
2225 Add mud and sand and others underground (in place of stone)
2228 for(s16 x=node_min.X; x<=node_max.X; x++)
2229 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2234 // Use fast index incrementing
2235 v3s16 em = vmanip.m_area.getExtent();
2236 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2237 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2239 if(vmanip.m_data[i].getContent() == c_stone)
2241 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2243 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2244 vmanip.m_data[i] = n_dirt;
2246 vmanip.m_data[i] = n_sand;
2248 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2250 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2251 vmanip.m_data[i] = n_gravel;
2253 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2254 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2256 vmanip.m_data[i] = n_lava_source;
2257 for(s16 x1=-1; x1<=1; x1++)
2258 for(s16 y1=-1; y1<=1; y1++)
2259 for(s16 z1=-1; z1<=1; z1++)
2260 data->transforming_liquid.push_back(
2261 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2265 vmanip->m_area.add_y(em, i, -1);
2274 //if(node_min.Y < approx_groundlevel)
2275 //if(myrand() % 3 == 0)
2276 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2277 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2278 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2279 float dungeon_rarity = 0.02;
2280 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2282 && node_min.Y < approx_groundlevel)
2284 // Dungeon generator doesn't modify places which have this set
2285 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2286 | VMANIP_FLAG_DUNGEON_PRESERVE);
2288 // Set all air and water to be untouchable to make dungeons open
2289 // to caves and open air
2290 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2291 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2296 // Use fast index incrementing
2297 v3s16 em = vmanip.m_area.getExtent();
2298 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2299 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2301 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2302 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2303 else if(vmanip.m_data[i].getContent() == c_water_source)
2304 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2305 vmanip->m_area.add_y(em, i, -1);
2310 PseudoRandom random(blockseed+2);
2313 make_dungeon1(vmanip, random, ndef);
2315 // Convert some cobble to mossy cobble
2316 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2317 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2322 // Use fast index incrementing
2323 v3s16 em = vmanip.m_area.getExtent();
2324 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2325 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2327 // (noisebuf not used because it doesn't contain the
2329 double wetness = noise3d_param(
2330 get_ground_wetness_params(data->seed), x,y,z);
2331 double d = noise3d_perlin((float)x/2.5,
2332 (float)y/2.5,(float)z/2.5,
2334 if(vmanip.m_data[i].getContent() == c_cobble)
2338 vmanip.m_data[i].setContent(c_mossycobble);
2341 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2344 vmanip.m_data[i].setContent(c_dirt);
2346 vmanip->m_area.add_y(em, i, -1);
2356 PseudoRandom ncrandom(blockseed+9324342);
2357 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2359 make_nc(vmanip, ncrandom, ndef);
2364 Add top and bottom side of water to transforming_liquid queue
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 water_found = false;
2374 // Use fast index incrementing
2375 v3s16 em = vmanip.m_area.getExtent();
2376 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2377 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2379 if(water_found == false)
2381 if(vmanip.m_data[i].getContent() == c_water_source)
2383 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2384 data->transforming_liquid.push_back(p);
2390 // This can be done because water_found can only
2391 // turn to true and end up here after going through
2393 if(vmanip.m_data[i+1].getContent() != c_water_source)
2395 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2396 data->transforming_liquid.push_back(p);
2397 water_found = false;
2401 vmanip->m_area.add_y(em, i, -1);
2407 If close to ground level
2410 //if(abs(approx_ground_depth) < 30)
2411 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2417 for(s16 x=node_min.X; x<=node_max.X; x++)
2418 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2423 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2424 bool have_sand = false;
2425 u32 current_depth = 0;
2426 bool air_detected = false;
2427 bool water_detected = false;
2428 bool have_clay = false;
2430 // Use fast index incrementing
2431 s16 start_y = node_max.Y+2;
2432 v3s16 em = vmanip.m_area.getExtent();
2433 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2434 for(s16 y=start_y; y>=node_min.Y-3; y--)
2436 if(vmanip.m_data[i].getContent() == c_water_source)
2437 water_detected = true;
2438 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2439 air_detected = true;
2441 if((vmanip.m_data[i].getContent() == c_stone
2442 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2443 || vmanip.m_data[i].getContent() == c_dirt
2444 || vmanip.m_data[i].getContent() == c_sand
2445 || vmanip.m_data[i].getContent() == c_gravel
2446 ) && (air_detected || water_detected))
2448 if(current_depth == 0 && y <= WATER_LEVEL+2
2449 && possibly_have_sand)
2452 if(current_depth < 4)
2456 // Determine whether to have clay in the sand here
2457 double claynoise = noise2d_perlin(
2458 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2459 data->seed+4321, 6, 0.95) + 0.5;
2461 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2462 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2463 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2466 vmanip.m_data[i] = MapNode(c_clay);
2468 vmanip.m_data[i] = MapNode(c_sand);
2471 else if(current_depth==0 && !water_detected
2472 && y >= WATER_LEVEL && air_detected)
2473 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2476 vmanip.m_data[i] = MapNode(c_dirt);
2480 if(vmanip.m_data[i].getContent() == c_dirt
2481 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2482 vmanip.m_data[i] = MapNode(c_stone);
2487 if(current_depth >= 8)
2490 else if(current_depth != 0)
2493 vmanip->m_area.add_y(em, i, -1);
2499 Calculate some stuff
2502 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2503 bool is_jungle = surface_humidity > 0.75;
2505 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2512 PseudoRandom treerandom(blockseed);
2513 // Put trees in random places on part of division
2514 for(u32 i=0; i<tree_count; i++)
2516 s16 x = treerandom.range(node_min.X, node_max.X);
2517 s16 z = treerandom.range(node_min.Z, node_max.Z);
2518 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2519 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2520 // Don't make a tree under water level
2523 // Make sure tree fits (only trees whose starting point is
2524 // at this block are added)
2525 if(y < node_min.Y || y > node_max.Y)
2528 Find exact ground level
2532 for(; p.Y >= y-6; p.Y--)
2534 u32 i = vmanip->m_area.index(p);
2535 MapNode *n = &vmanip->m_data[i];
2536 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2542 // If not found, handle next one
2547 u32 i = vmanip->m_area.index(p);
2548 MapNode *n = &vmanip->m_data[i];
2550 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2553 // Papyrus grows only on mud and in water
2554 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2557 make_papyrus(vmanip, p, ndef);
2559 // Trees grow only on mud and grass, on land
2560 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2563 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2564 if(is_jungle == false)
2567 if(myrand_range(0,4) != 0)
2568 is_apple_tree = false;
2570 is_apple_tree = noise2d_perlin(
2571 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2572 data->seed+342902, 3, 0.45) > 0.2;
2573 make_tree(vmanip, p, is_apple_tree, ndef);
2576 make_jungletree(vmanip, p, ndef);
2578 // Cactii grow only on sand, on land
2579 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2582 make_cactus(vmanip, p, ndef);
2592 PseudoRandom grassrandom(blockseed);
2593 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2595 s16 x = grassrandom.range(node_min.X, node_max.X);
2596 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2597 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2600 if(y < node_min.Y || y > node_max.Y)
2603 Find exact ground level
2607 for(; p.Y >= y-6; p.Y--)
2609 u32 i = vmanip->m_area.index(p);
2610 MapNode *n = &vmanip->m_data[i];
2611 if(data->nodedef->get(*n).is_ground_content)
2617 // If not found, handle next one
2621 if(vmanip.m_area.contains(p) == false)
2623 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2626 if(vmanip.m_area.contains(p))
2627 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2629 if(vmanip.m_area.contains(p))
2630 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2636 Add some kind of random stones
2639 u32 random_stone_count = gen_area_nodes *
2640 randomstone_amount_2d(data->seed, p2d_center);
2641 // Put in random places on part of division
2642 for(u32 i=0; i<random_stone_count; i++)
2644 s16 x = myrand_range(node_min.X, node_max.X);
2645 s16 z = myrand_range(node_min.Z, node_max.Z);
2646 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2647 // Don't add under water level
2648 /*if(y < WATER_LEVEL)
2650 // Don't add if doesn't belong to this block
2651 if(y < node_min.Y || y > node_max.Y)
2656 u32 i = vmanip->m_area.index(v3s16(p));
2657 MapNode *n = &vmanip->m_data[i];
2658 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2661 // Will be placed one higher
2664 make_randomstone(vmanip, p);
2673 u32 large_stone_count = gen_area_nodes *
2674 largestone_amount_2d(data->seed, p2d_center);
2675 //u32 large_stone_count = 1;
2676 // Put in random places on part of division
2677 for(u32 i=0; i<large_stone_count; i++)
2679 s16 x = myrand_range(node_min.X, node_max.X);
2680 s16 z = myrand_range(node_min.Z, node_max.Z);
2681 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2682 // Don't add under water level
2683 /*if(y < WATER_LEVEL)
2685 // Don't add if doesn't belong to this block
2686 if(y < node_min.Y || y > node_max.Y)
2691 u32 i = vmanip->m_area.index(v3s16(p));
2692 MapNode *n = &vmanip->m_data[i];
2693 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2696 // Will be placed one lower
2699 make_largestone(vmanip, p);
2709 PseudoRandom mineralrandom(blockseed);
2714 for(s16 i=0; i<approx_ground_depth/4; i++)
2716 if(mineralrandom.next()%50 == 0)
2718 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2719 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2720 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2721 for(u16 i=0; i<27; i++)
2723 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2724 u32 vi = vmanip.m_area.index(p);
2725 if(vmanip.m_data[vi].getContent() == c_stone)
2726 if(mineralrandom.next()%8 == 0)
2727 vmanip.m_data[vi] = MapNode(c_mese);
2736 u16 a = mineralrandom.range(0,15);
2738 u16 amount = 20 * a/1000;
2739 for(s16 i=0; i<amount; i++)
2741 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2742 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2743 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2745 u8 base_content = c_stone;
2746 MapNode new_content(CONTENT_IGNORE);
2749 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2751 new_content = MapNode(c_stone_with_coal);
2755 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2756 new_content = MapNode(c_stone_with_iron);
2757 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2758 vmanip.m_data[i] = MapNode(c_dirt);
2760 vmanip.m_data[i] = MapNode(c_sand);*/
2762 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2766 if(new_content.getContent() != CONTENT_IGNORE)
2768 for(u16 i=0; i<27; i++)
2770 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2771 u32 vi = vmanip.m_area.index(p);
2772 if(vmanip.m_data[vi].getContent() == base_content)
2774 if(mineralrandom.next()%sparseness == 0)
2775 vmanip.m_data[vi] = new_content;
2784 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2785 //for(s16 i=0; i<50; i++)
2786 u16 coal_amount = 30;
2787 u16 coal_rareness = 60 / coal_amount;
2788 if(coal_rareness == 0)
2790 if(mineralrandom.next()%coal_rareness == 0)
2792 u16 a = mineralrandom.next() % 16;
2793 u16 amount = coal_amount * a*a*a / 1000;
2794 for(s16 i=0; i<amount; i++)
2796 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2797 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2798 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2799 for(u16 i=0; i<27; i++)
2801 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2802 u32 vi = vmanip.m_area.index(p);
2803 if(vmanip.m_data[vi].getContent() == c_stone)
2804 if(mineralrandom.next()%8 == 0)
2805 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2812 u16 iron_amount = 8;
2813 u16 iron_rareness = 60 / iron_amount;
2814 if(iron_rareness == 0)
2816 if(mineralrandom.next()%iron_rareness == 0)
2818 u16 a = mineralrandom.next() % 16;
2819 u16 amount = iron_amount * a*a*a / 1000;
2820 for(s16 i=0; i<amount; i++)
2822 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2823 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2824 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2825 for(u16 i=0; i<27; i++)
2827 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2828 u32 vi = vmanip.m_area.index(p);
2829 if(vmanip.m_data[vi].getContent() == c_stone)
2830 if(mineralrandom.next()%8 == 0)
2831 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2842 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2844 //VoxelArea a(node_min, node_max);
2845 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2846 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2847 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2848 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2849 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2850 for(int i=0; i<2; i++)
2852 enum LightBank bank = banks[i];
2854 core::map<v3s16, bool> light_sources;
2855 core::map<v3s16, u8> unlight_from;
2857 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2858 light_sources, unlight_from);
2860 bool inexistent_top_provides_sunlight = !block_is_underground;
2861 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2862 vmanip, a, inexistent_top_provides_sunlight,
2863 light_sources, ndef);
2864 // TODO: Do stuff according to bottom_sunlight_valid
2866 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2868 vmanip.spreadLight(bank, light_sources, ndef);
2873 BlockMakeData::BlockMakeData():
2880 BlockMakeData::~BlockMakeData()
2885 }; // namespace mapgen