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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
37 Some helper functions for the map generator
41 // Returns Y one under area minimum if not found
42 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
43 INodeDefManager *ndef)
45 v3s16 em = vmanip.m_area.getExtent();
46 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
47 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
48 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
50 for(y=y_nodes_max; y>=y_nodes_min; y--)
52 MapNode &n = vmanip.m_data[i];
53 if(ndef->get(n).walkable)
56 vmanip.m_area.add_y(em, i, -1);
61 return y_nodes_min - 1;
65 // Returns Y one under area minimum if not found
66 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
67 INodeDefManager *ndef)
69 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
70 return vmanip.m_area.MinEdge.Y-1;
71 v3s16 em = vmanip.m_area.getExtent();
72 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
73 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
74 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
76 content_t c_tree = ndef->getId("mapgen_tree");
77 content_t c_leaves = ndef->getId("mapgen_leaves");
78 for(y=y_nodes_max; y>=y_nodes_min; y--)
80 MapNode &n = vmanip.m_data[i];
81 if(ndef->get(n).walkable
82 && n.getContent() != c_tree
83 && n.getContent() != c_leaves)
86 vmanip.m_area.add_y(em, i, -1);
91 return y_nodes_min - 1;
95 // Returns Y one under area minimum if not found
96 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
97 INodeDefManager *ndef)
99 v3s16 em = vmanip.m_area.getExtent();
100 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
101 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
102 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
104 content_t c_stone = ndef->getId("mapgen_stone");
105 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
106 for(y=y_nodes_max; y>=y_nodes_min; y--)
108 MapNode &n = vmanip.m_data[i];
109 content_t c = n.getContent();
110 if(c != CONTENT_IGNORE && (
111 c == c_stone || c == c_desert_stone))
114 vmanip.m_area.add_y(em, i, -1);
119 return y_nodes_min - 1;
123 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
124 bool is_apple_tree, INodeDefManager *ndef)
126 MapNode treenode(ndef->getId("mapgen_tree"));
127 MapNode leavesnode(ndef->getId("mapgen_leaves"));
128 MapNode applenode(ndef->getId("mapgen_apple"));
130 s16 trunk_h = myrand_range(4, 5);
132 for(s16 ii=0; ii<trunk_h; ii++)
134 if(vmanip.m_area.contains(p1))
135 if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
136 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
140 // p1 is now the last piece of the trunk
143 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
144 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
145 Buffer<u8> leaves_d(leaves_a.getVolume());
146 for(s32 i=0; i<leaves_a.getVolume(); i++)
149 // Force leaves at near the end of the trunk
152 for(s16 z=-d; z<=d; z++)
153 for(s16 y=-d; y<=d; y++)
154 for(s16 x=-d; x<=d; x++)
156 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
160 // Add leaves randomly
161 for(u32 iii=0; iii<7; iii++)
166 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
167 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
168 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
171 for(s16 z=0; z<=d; z++)
172 for(s16 y=0; y<=d; y++)
173 for(s16 x=0; x<=d; x++)
175 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
179 // Blit leaves to vmanip
180 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
181 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
182 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
186 if(vmanip.m_area.contains(p) == false)
188 u32 vi = vmanip.m_area.index(p);
189 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
190 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
192 u32 i = leaves_a.index(x,y,z);
193 if(leaves_d[i] == 1) {
194 bool is_apple = myrand_range(0,99) < 10;
195 if(is_apple_tree && is_apple) {
196 vmanip.m_data[vi] = applenode;
198 vmanip.m_data[vi] = leavesnode;
205 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
206 INodeDefManager *ndef)
208 MapNode treenode(ndef->getId("mapgen_jungletree"));
209 MapNode leavesnode(ndef->getId("mapgen_leaves"));
211 for(s16 x=-1; x<=1; x++)
212 for(s16 z=-1; z<=1; z++)
214 if(myrand_range(0, 2) == 0)
216 v3s16 p1 = p0 + v3s16(x,0,z);
217 v3s16 p2 = p0 + v3s16(x,-1,z);
218 if(vmanip.m_area.contains(p2)
219 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
220 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
221 else if(vmanip.m_area.contains(p1))
222 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
225 s16 trunk_h = myrand_range(8, 12);
227 for(s16 ii=0; ii<trunk_h; ii++)
229 if(vmanip.m_area.contains(p1))
230 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
234 // p1 is now the last piece of the trunk
237 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
238 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
239 Buffer<u8> leaves_d(leaves_a.getVolume());
240 for(s32 i=0; i<leaves_a.getVolume(); i++)
243 // Force leaves at near the end of the trunk
246 for(s16 z=-d; z<=d; z++)
247 for(s16 y=-d; y<=d; y++)
248 for(s16 x=-d; x<=d; x++)
250 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
254 // Add leaves randomly
255 for(u32 iii=0; iii<30; iii++)
260 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
261 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
262 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
265 for(s16 z=0; z<=d; z++)
266 for(s16 y=0; y<=d; y++)
267 for(s16 x=0; x<=d; x++)
269 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
273 // Blit leaves to vmanip
274 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
275 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
276 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
280 if(vmanip.m_area.contains(p) == false)
282 u32 vi = vmanip.m_area.index(p);
283 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
284 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
286 u32 i = leaves_a.index(x,y,z);
288 vmanip.m_data[vi] = leavesnode;
292 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
293 INodeDefManager *ndef)
295 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
297 s16 trunk_h = myrand_range(2, 3);
299 for(s16 ii=0; ii<trunk_h; ii++)
301 if(vmanip.m_area.contains(p1))
302 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
307 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
308 INodeDefManager *ndef)
310 MapNode cactusnode(ndef->getId("mapgen_cactus"));
314 for(s16 ii=0; ii<trunk_h; ii++)
316 if(vmanip.m_area.contains(p1))
317 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
325 Dungeon making routines
328 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
329 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
330 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
331 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
333 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
334 INodeDefManager *ndef)
337 for(s16 z=0; z<roomsize.Z; z++)
338 for(s16 y=0; y<roomsize.Y; y++)
341 v3s16 p = roomplace + v3s16(0,y,z);
342 if(vmanip.m_area.contains(p) == false)
344 u32 vi = vmanip.m_area.index(p);
345 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
347 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
350 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
351 if(vmanip.m_area.contains(p) == false)
353 u32 vi = vmanip.m_area.index(p);
354 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
356 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
361 for(s16 x=0; x<roomsize.X; x++)
362 for(s16 y=0; y<roomsize.Y; y++)
365 v3s16 p = roomplace + v3s16(x,y,0);
366 if(vmanip.m_area.contains(p) == false)
368 u32 vi = vmanip.m_area.index(p);
369 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
371 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
374 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
375 if(vmanip.m_area.contains(p) == false)
377 u32 vi = vmanip.m_area.index(p);
378 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
380 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
384 // Make +-Y walls (floor and ceiling)
385 for(s16 z=0; z<roomsize.Z; z++)
386 for(s16 x=0; x<roomsize.X; x++)
389 v3s16 p = roomplace + v3s16(x,0,z);
390 if(vmanip.m_area.contains(p) == false)
392 u32 vi = vmanip.m_area.index(p);
393 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
395 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
398 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
399 if(vmanip.m_area.contains(p) == false)
401 u32 vi = vmanip.m_area.index(p);
402 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
404 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
409 for(s16 z=1; z<roomsize.Z-1; z++)
410 for(s16 y=1; y<roomsize.Y-1; y++)
411 for(s16 x=1; x<roomsize.X-1; x++)
413 v3s16 p = roomplace + v3s16(x,y,z);
414 if(vmanip.m_area.contains(p) == false)
416 u32 vi = vmanip.m_area.index(p);
417 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
418 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
422 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
423 u8 avoid_flags, MapNode n, u8 or_flags)
425 for(s16 z=0; z<size.Z; z++)
426 for(s16 y=0; y<size.Y; y++)
427 for(s16 x=0; x<size.X; x++)
429 v3s16 p = place + v3s16(x,y,z);
430 if(vmanip.m_area.contains(p) == false)
432 u32 vi = vmanip.m_area.index(p);
433 if(vmanip.m_flags[vi] & avoid_flags)
435 vmanip.m_flags[vi] |= or_flags;
436 vmanip.m_data[vi] = n;
440 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
441 INodeDefManager *ndef)
443 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
444 VMANIP_FLAG_DUNGEON_INSIDE);
447 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
448 INodeDefManager *ndef)
450 make_hole1(vmanip, doorplace, ndef);
451 // Place torch (for testing)
452 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
455 static v3s16 rand_ortho_dir(PseudoRandom &random)
457 if(random.next()%2==0)
458 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
460 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
463 static v3s16 turn_xz(v3s16 olddir, int t)
483 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
485 int turn = random.range(0,2);
494 dir = turn_xz(olddir, 0);
497 dir = turn_xz(olddir, 1);
501 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
502 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
503 PseudoRandom &random, INodeDefManager *ndef)
505 make_hole1(vmanip, doorplace, ndef);
506 v3s16 p0 = doorplace;
510 length = random.range(1,13);
512 length = random.range(1,6);
513 length = random.range(1,13);
514 u32 partlength = random.range(1,13);
517 if(random.next()%2 == 0 && partlength >= 3)
518 make_stairs = random.next()%2 ? 1 : -1;
519 for(u32 i=0; i<length; i++)
525 /*// If already empty
526 if(vmanip.getNodeNoExNoEmerge(p).getContent()
528 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
533 if(vmanip.m_area.contains(p) == true
534 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
538 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
539 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
540 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
541 VMANIP_FLAG_DUNGEON_INSIDE);
542 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
543 VMANIP_FLAG_DUNGEON_INSIDE);
547 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
548 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
549 make_hole1(vmanip, p, ndef);
550 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
551 VMANIP_FLAG_DUNGEON_INSIDE);*/
558 // Can't go here, turn away
559 dir = turn_xz(dir, random.range(0,1));
560 make_stairs = -make_stairs;
562 partlength = random.range(1,length);
567 if(partcount >= partlength)
571 dir = random_turn(random, dir);
573 partlength = random.range(1,length);
576 if(random.next()%2 == 0 && partlength >= 3)
577 make_stairs = random.next()%2 ? 1 : -1;
588 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
589 INodeDefManager *ndef):
600 m_dir = rand_ortho_dir(m_random);
603 void setPos(v3s16 pos)
608 void setDir(v3s16 dir)
613 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
615 for(u32 i=0; i<100; i++)
617 v3s16 p = m_pos + m_dir;
618 v3s16 p1 = p + v3s16(0,1,0);
619 if(vmanip.m_area.contains(p) == false
620 || vmanip.m_area.contains(p1) == false
626 if(vmanip.getNodeNoExNoEmerge(p).getContent()
627 == m_ndef->getId("mapgen_cobble")
628 && vmanip.getNodeNoExNoEmerge(p1).getContent()
629 == m_ndef->getId("mapgen_cobble"))
631 // Found wall, this is a good place!
634 // Randomize next direction
639 Determine where to move next
641 // Jump one up if the actual space is there
642 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
643 == m_ndef->getId("mapgen_cobble")
644 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
646 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
649 // Jump one down if the actual space is there
650 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
651 == m_ndef->getId("mapgen_cobble")
652 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
654 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
657 // Check if walking is now possible
658 if(vmanip.getNodeNoExNoEmerge(p).getContent()
660 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
663 // Cannot continue walking here
673 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
674 v3s16 &result_doordir, v3s16 &result_roomplace)
676 for(s16 trycount=0; trycount<30; trycount++)
680 bool r = findPlaceForDoor(doorplace, doordir);
684 // X east, Z north, Y up
686 if(doordir == v3s16(1,0,0)) // X+
687 roomplace = doorplace +
688 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
689 if(doordir == v3s16(-1,0,0)) // X-
690 roomplace = doorplace +
691 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
692 if(doordir == v3s16(0,0,1)) // Z+
693 roomplace = doorplace +
694 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
695 if(doordir == v3s16(0,0,-1)) // Z-
696 roomplace = doorplace +
697 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
700 if(doordir == v3s16(1,0,0)) // X+
701 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
702 if(doordir == v3s16(-1,0,0)) // X-
703 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
704 if(doordir == v3s16(0,0,1)) // Z+
705 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
706 if(doordir == v3s16(0,0,-1)) // Z-
707 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
712 for(s16 z=1; z<roomsize.Z-1; z++)
713 for(s16 y=1; y<roomsize.Y-1; y++)
714 for(s16 x=1; x<roomsize.X-1; x++)
716 v3s16 p = roomplace + v3s16(x,y,z);
717 if(vmanip.m_area.contains(p) == false)
722 if(vmanip.m_flags[vmanip.m_area.index(p)]
723 & VMANIP_FLAG_DUNGEON_INSIDE)
734 result_doorplace = doorplace;
735 result_doordir = doordir;
736 result_roomplace = roomplace;
743 VoxelManipulator &vmanip;
746 PseudoRandom &m_random;
747 INodeDefManager *m_ndef;
750 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
751 INodeDefManager *ndef)
753 v3s16 areasize = vmanip.m_area.getExtent();
758 Find place for first room
761 for(u32 i=0; i<100; i++)
763 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
764 roomplace = vmanip.m_area.MinEdge + v3s16(
765 random.range(0,areasize.X-roomsize.X-1),
766 random.range(0,areasize.Y-roomsize.Y-1),
767 random.range(0,areasize.Z-roomsize.Z-1));
769 Check that we're not putting the room to an unknown place,
770 otherwise it might end up floating in the air
773 for(s16 z=1; z<roomsize.Z-1; z++)
774 for(s16 y=1; y<roomsize.Y-1; y++)
775 for(s16 x=1; x<roomsize.X-1; x++)
777 v3s16 p = roomplace + v3s16(x,y,z);
778 u32 vi = vmanip.m_area.index(p);
779 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
784 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
798 Stores the center position of the last room made, so that
799 a new corridor can be started from the last room instead of
800 the new room, if chosen so.
802 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
804 u32 room_count = random.range(2,7);
805 for(u32 i=0; i<room_count; i++)
807 // Make a room to the determined place
808 make_room1(vmanip, roomsize, roomplace, ndef);
810 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
812 // Place torch at room center (for testing)
813 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
816 if(i == room_count-1)
819 // Determine walker start position
821 bool start_in_last_room = (random.range(0,2)!=0);
822 //bool start_in_last_room = true;
824 v3s16 walker_start_place;
826 if(start_in_last_room)
828 walker_start_place = last_room_center;
832 walker_start_place = room_center;
833 // Store center of current room as the last one
834 last_room_center = room_center;
837 // Create walker and find a place for a door
838 RoomWalker walker(vmanip, walker_start_place, random, ndef);
841 bool r = walker.findPlaceForDoor(doorplace, doordir);
845 if(random.range(0,1)==0)
847 make_door1(vmanip, doorplace, doordir, ndef);
849 // Don't actually make a door
850 doorplace -= doordir;
852 // Make a random corridor starting from the door
854 v3s16 corridor_end_dir;
855 make_corridor(vmanip, doorplace, doordir, corridor_end,
856 corridor_end_dir, random, ndef);
858 // Find a place for a random sized room
859 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
860 walker.setPos(corridor_end);
861 walker.setDir(corridor_end_dir);
862 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
866 if(random.range(0,1)==0)
868 make_door1(vmanip, doorplace, doordir, ndef);
870 // Don't actually make a door
871 roomplace -= doordir;
878 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
879 INodeDefManager *ndef)
883 s32 r = random.range(0, 3);
885 dir = v3s16( 1, 0, 0);
889 dir = v3s16(-1, 0, 0);
893 dir = v3s16( 0, 0, 1);
897 dir = v3s16( 0, 0,-1);
900 v3s16 p = vmanip.m_area.MinEdge + v3s16(
901 16+random.range(0,15),
902 16+random.range(0,15),
903 16+random.range(0,15));
904 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
905 u32 length = random.range(3,15);
906 for(u32 j=0; j<length; j++)
909 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
915 Noise functions. Make sure seed is mangled differently in each one.
920 Scaling the output of the noise function affects the overdrive of the
921 contour function, which affects the shape of the output considerably.
923 #define CAVE_NOISE_SCALE 12.0
924 //#define CAVE_NOISE_SCALE 10.0
925 //#define CAVE_NOISE_SCALE 7.5
926 //#define CAVE_NOISE_SCALE 5.0
927 //#define CAVE_NOISE_SCALE 1.0
929 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
930 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
932 NoiseParams get_cave_noise1_params(u64 seed)
934 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
935 200, CAVE_NOISE_SCALE);*/
936 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
937 100, CAVE_NOISE_SCALE);*/
938 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
939 100, CAVE_NOISE_SCALE);*/
940 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
941 100, CAVE_NOISE_SCALE);*/
942 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
943 50, CAVE_NOISE_SCALE);
944 //return NoiseParams(NOISE_CONSTANT_ONE);
947 NoiseParams get_cave_noise2_params(u64 seed)
949 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
950 200, CAVE_NOISE_SCALE);*/
951 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
952 100, CAVE_NOISE_SCALE);*/
953 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
954 100, CAVE_NOISE_SCALE);*/
955 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
956 50, CAVE_NOISE_SCALE);
957 //return NoiseParams(NOISE_CONSTANT_ONE);
960 NoiseParams get_ground_noise1_params(u64 seed)
962 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
966 NoiseParams get_ground_crumbleness_params(u64 seed)
968 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
972 NoiseParams get_ground_wetness_params(u64 seed)
974 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
978 bool is_cave(u64 seed, v3s16 p)
980 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
981 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
982 return d1*d2 > CAVE_NOISE_THRESHOLD;
986 Ground density noise shall be interpreted by using this.
988 TODO: No perlin noises here, they should be outsourced
990 NOTE: The speed of these actually isn't terrible
992 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
994 //return ((double)p.Y < ground_noise1_val);
996 double f = 0.55 + noise2d_perlin(
997 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
998 seed+920381, 3, 0.45);
1003 double h = WATER_LEVEL + 10 * noise2d_perlin(
1004 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1005 seed+84174, 4, 0.5);
1008 return ((double)p.Y - h < ground_noise1_val * f);
1012 Queries whether a position is ground or not.
1014 bool is_ground(u64 seed, v3s16 p)
1016 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1017 return val_is_ground(val1, p, seed);
1021 // Amount of trees per area in nodes
1022 double tree_amount_2d(u64 seed, v2s16 p)
1024 /*double noise = noise2d_perlin(
1025 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1027 double noise = noise2d_perlin(
1028 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1030 double zeroval = -0.39;
1034 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1038 double surface_humidity_2d(u64 seed, v2s16 p)
1040 double noise = noise2d_perlin(
1041 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1042 seed+72384, 4, 0.66);
1043 noise = (noise + 1.0)/2.0;
1052 Incrementally find ground level from 3d noise
1054 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1056 // Start a bit fuzzy to make averaging lower precision values
1058 s16 level = myrand_range(-precision/2, precision/2);
1059 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1061 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1063 // First find non-ground by going upwards
1064 // Don't stop in caves.
1066 s16 max = level+dec[i-1]*2;
1067 v3s16 p(p2d.X, level, p2d.Y);
1068 for(; p.Y < max; p.Y += dec[i])
1070 if(!is_ground(seed, p))
1077 // Then find ground by going downwards from there.
1078 // Go in caves, too, when precision is 1.
1080 s16 min = level-dec[i-1]*2;
1081 v3s16 p(p2d.X, level, p2d.Y);
1082 for(; p.Y>min; p.Y-=dec[i])
1084 bool ground = is_ground(seed, p);
1085 /*if(dec[i] == 1 && is_cave(seed, p))
1096 // This is more like the actual ground level
1097 level += dec[i-1]/2;
1102 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1104 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1106 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1107 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1109 a += find_ground_level_from_noise(seed,
1110 v2s16(node_min.X, node_min.Y), p);
1111 a += find_ground_level_from_noise(seed,
1112 v2s16(node_min.X, node_max.Y), p);
1113 a += find_ground_level_from_noise(seed,
1114 v2s16(node_max.X, node_max.Y), p);
1115 a += find_ground_level_from_noise(seed,
1116 v2s16(node_max.X, node_min.Y), p);
1117 a += find_ground_level_from_noise(seed,
1118 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1123 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1125 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1127 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1128 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1131 a = MYMAX(a, find_ground_level_from_noise(seed,
1132 v2s16(node_min.X, node_min.Y), p));
1133 a = MYMAX(a, find_ground_level_from_noise(seed,
1134 v2s16(node_min.X, node_max.Y), p));
1135 a = MYMAX(a, find_ground_level_from_noise(seed,
1136 v2s16(node_max.X, node_max.Y), p));
1137 a = MYMAX(a, find_ground_level_from_noise(seed,
1138 v2s16(node_min.X, node_min.Y), p));
1140 a = MYMAX(a, find_ground_level_from_noise(seed,
1141 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1142 // Side middle points
1143 a = MYMAX(a, find_ground_level_from_noise(seed,
1144 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1145 a = MYMAX(a, find_ground_level_from_noise(seed,
1146 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1147 a = MYMAX(a, find_ground_level_from_noise(seed,
1148 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1149 a = MYMAX(a, find_ground_level_from_noise(seed,
1150 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1154 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1156 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1158 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1159 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1162 a = MYMIN(a, find_ground_level_from_noise(seed,
1163 v2s16(node_min.X, node_min.Y), p));
1164 a = MYMIN(a, find_ground_level_from_noise(seed,
1165 v2s16(node_min.X, node_max.Y), p));
1166 a = MYMIN(a, find_ground_level_from_noise(seed,
1167 v2s16(node_max.X, node_max.Y), p));
1168 a = MYMIN(a, find_ground_level_from_noise(seed,
1169 v2s16(node_min.X, node_min.Y), p));
1171 a = MYMIN(a, find_ground_level_from_noise(seed,
1172 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1173 // Side middle points
1174 a = MYMIN(a, find_ground_level_from_noise(seed,
1175 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1176 a = MYMIN(a, find_ground_level_from_noise(seed,
1177 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1178 a = MYMIN(a, find_ground_level_from_noise(seed,
1179 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1180 a = MYMIN(a, find_ground_level_from_noise(seed,
1181 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1186 // Required by mapgen.h
1187 bool block_is_underground(u64 seed, v3s16 blockpos)
1189 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1190 seed, v2s16(blockpos.X, blockpos.Z));*/
1191 // Nah, this is just a heuristic, just return something
1192 s16 minimum_groundlevel = WATER_LEVEL;
1194 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1200 #define AVERAGE_MUD_AMOUNT 4
1202 double base_rock_level_2d(u64 seed, v2s16 p)
1204 // The base ground level
1205 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1206 + 20. * noise2d_perlin(
1207 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1208 seed+82341, 5, 0.6);
1210 /*// A bit hillier one
1211 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1212 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1213 seed+93413, 6, 0.69);
1217 // Higher ground level
1218 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1219 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1220 seed+85039, 5, 0.6);
1221 //higher = 30; // For debugging
1223 // Limit higher to at least base
1227 // Steepness factor of cliffs
1228 double b = 0.85 + 0.5 * noise2d_perlin(
1229 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1231 b = rangelim(b, 0.0, 1000.0);
1234 b = rangelim(b, 0.5, 1000.0);
1235 // Values 1.5...100 give quite horrible looking slopes
1236 if(b > 1.5 && b < 100.0){
1242 //dstream<<"b="<<b<<std::endl;
1246 // Offset to more low
1247 double a_off = -0.20;
1248 // High/low selector
1249 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1250 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1251 seed+4213, 6, 0.7));*/
1252 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1253 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1254 seed+4213, 5, 0.69));
1256 a = rangelim(a, 0.0, 1.0);
1258 //dstream<<"a="<<a<<std::endl;
1260 double h = base*(1.0-a) + higher*a;
1267 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1269 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1272 double get_mud_add_amount(u64 seed, v2s16 p)
1274 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1275 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1276 seed+91013, 3, 0.55));
1279 bool get_have_beach(u64 seed, v2s16 p2d)
1281 // Determine whether to have sand here
1282 double sandnoise = noise2d_perlin(
1283 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1284 seed+59420, 3, 0.50);
1286 return (sandnoise > 0.15);
1295 BiomeType get_biome(u64 seed, v2s16 p2d)
1297 // Just do something very simple as for now
1298 double d = noise2d_perlin(
1299 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1300 seed+9130, 3, 0.50);
1303 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1308 u32 get_blockseed(u64 seed, v3s16 p)
1310 s32 x=p.X, y=p.Y, z=p.Z;
1311 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1314 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1316 void make_block(BlockMakeData *data)
1320 //dstream<<"makeBlock: no-op"<<std::endl;
1324 assert(data->vmanip);
1325 assert(data->nodedef);
1326 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1327 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1328 data->blockpos_requested.Z >= data->blockpos_min.Z);
1329 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1330 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1331 data->blockpos_requested.Z <= data->blockpos_max.Z);
1333 INodeDefManager *ndef = data->nodedef;
1335 // Hack: use minimum block coordinates for old code that assumes
1337 v3s16 blockpos = data->blockpos_requested;
1339 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1340 <<blockpos.Z<<")"<<std::endl;*/
1342 v3s16 blockpos_min = data->blockpos_min;
1343 v3s16 blockpos_max = data->blockpos_max;
1344 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1345 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1347 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1348 // Area of central chunk
1349 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1350 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1351 // Full allocated area
1352 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1353 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1355 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1357 const s16 max_spread_amount = MAP_BLOCKSIZE;
1359 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1360 * (blockpos_max.Y - blockpos_min.Y + 1)
1361 * (blockpos_max.Z - blockpos_max.Z + 1);
1363 int volume_nodes = volume_blocks *
1364 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1366 // Generated surface area
1367 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1369 // Horribly wrong heuristic, but better than nothing
1370 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1373 Create a block-specific seed
1375 u32 blockseed = get_blockseed(data->seed, full_node_min);
1378 Cache some ground type values for speed
1381 // Creates variables c_name=id and n_name=node
1382 #define CONTENT_VARIABLE(ndef, name)\
1383 content_t c_##name = ndef->getId("mapgen_" #name);\
1384 MapNode n_##name(c_##name);
1385 // Default to something else if was CONTENT_IGNORE
1386 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1387 if(c_##name == CONTENT_IGNORE){\
1388 c_##name = c_##dname;\
1389 n_##name = n_##dname;\
1392 CONTENT_VARIABLE(ndef, stone);
1393 CONTENT_VARIABLE(ndef, air);
1394 CONTENT_VARIABLE(ndef, water_source);
1395 CONTENT_VARIABLE(ndef, dirt);
1396 CONTENT_VARIABLE(ndef, sand);
1397 CONTENT_VARIABLE(ndef, gravel);
1398 CONTENT_VARIABLE(ndef, clay);
1399 CONTENT_VARIABLE(ndef, lava_source);
1400 CONTENT_VARIABLE(ndef, cobble);
1401 CONTENT_VARIABLE(ndef, mossycobble);
1402 CONTENT_VARIABLE(ndef, dirt_with_grass);
1403 CONTENT_VARIABLE(ndef, junglegrass);
1404 CONTENT_VARIABLE(ndef, stone_with_coal);
1405 CONTENT_VARIABLE(ndef, stone_with_iron);
1406 CONTENT_VARIABLE(ndef, mese);
1407 CONTENT_VARIABLE(ndef, desert_sand);
1408 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1409 CONTENT_VARIABLE(ndef, desert_stone);
1410 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1412 // Maximum height of the stone surface and obstacles.
1413 // This is used to guide the cave generation
1414 s16 stone_surface_max_y = 0;
1417 Generate general ground level to full area
1421 TimeTaker timer1("Generating ground level");
1423 for(s16 x=node_min.X; x<=node_max.X; x++)
1424 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1427 v2s16 p2d = v2s16(x,z);
1430 Skip of already generated
1433 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1434 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1438 // Ground height at this point
1439 float surface_y_f = 0.0;
1441 // Use perlin noise for ground height
1442 surface_y_f = base_rock_level_2d(data->seed, p2d);
1444 /*// Experimental stuff
1446 float a = highlands_level_2d(data->seed, p2d);
1451 // Convert to integer
1452 s16 surface_y = (s16)surface_y_f;
1455 if(surface_y > stone_surface_max_y)
1456 stone_surface_max_y = surface_y;
1458 BiomeType bt = get_biome(data->seed, p2d);
1460 Fill ground with stone
1463 // Use fast index incrementing
1464 v3s16 em = vmanip.m_area.getExtent();
1465 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1466 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1468 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1470 if(y > WATER_LEVEL && bt == BT_DESERT)
1471 vmanip.m_data[i] = n_desert_stone;
1473 vmanip.m_data[i] = n_stone;
1474 } else if(y <= WATER_LEVEL){
1475 vmanip.m_data[i] = MapNode(c_water_source);
1477 vmanip.m_data[i] = MapNode(c_air);
1480 vmanip.m_area.add_y(em, i, 1);
1488 // Limit dirt flow area by 1 because mud is flown into neighbors.
1489 assert(central_area_size.X == central_area_size.Z);
1490 s16 mudflow_minpos = 0-max_spread_amount+1;
1491 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1494 Loop this part, it will make stuff look older and newer nicely
1497 const u32 age_loops = 2;
1498 for(u32 i_age=0; i_age<age_loops; i_age++)
1500 /******************************
1501 BEGINNING OF AGING LOOP
1502 ******************************/
1507 //TimeTaker timer1("caves");
1510 Make caves (this code is relatively horrible)
1512 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1513 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1514 data->seed+34329, 3, 0.50);
1515 cave_amount = MYMAX(0.0, cave_amount);
1516 u32 caves_count = cave_amount * volume_nodes / 50000;
1517 u32 bruises_count = 1;
1518 PseudoRandom ps(blockseed+21343);
1519 PseudoRandom ps2(blockseed+1032);
1520 if(ps.range(1, 6) == 1)
1521 bruises_count = ps.range(0, ps.range(0, 2));
1522 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1526 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1528 bool large_cave = (jj >= caves_count);
1529 s16 min_tunnel_diameter = 2;
1530 s16 max_tunnel_diameter = ps.range(2,6);
1531 int dswitchint = ps.range(1,14);
1532 u16 tunnel_routepoints = 0;
1533 int part_max_length_rs = 0;
1535 part_max_length_rs = ps.range(2,4);
1536 tunnel_routepoints = ps.range(5, ps.range(15,30));
1537 min_tunnel_diameter = 5;
1538 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1540 part_max_length_rs = ps.range(2,9);
1541 tunnel_routepoints = ps.range(10, ps.range(15,30));
1543 bool large_cave_is_flat = (ps.range(0,1) == 0);
1545 v3f main_direction(0,0,0);
1547 // Allowed route area size in nodes
1548 v3s16 ar = central_area_size;
1550 // Area starting point in nodes
1551 v3s16 of = node_min;
1554 //(this should be more than the maximum radius of the tunnel)
1555 //s16 insure = 5; // Didn't work with max_d = 20
1557 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1558 ar += v3s16(1,0,1) * more * 2;
1559 of -= v3s16(1,0,1) * more;
1561 s16 route_y_min = 0;
1562 // Allow half a diameter + 7 over stone surface
1563 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1565 /*// If caves, don't go through surface too often
1566 if(large_cave == false)
1567 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1569 // Limit maximum to area
1570 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1574 /*// Minimum is at y=0
1575 route_y_min = -of.Y - 0;*/
1576 // Minimum is at y=max_tunnel_diameter/4
1577 //route_y_min = -of.Y + max_tunnel_diameter/4;
1578 //s16 min = -of.Y + max_tunnel_diameter/4;
1579 //s16 min = -of.Y + 0;
1581 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1583 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1584 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1586 route_y_min = ps.range(min, min + max_tunnel_diameter);
1587 route_y_min = rangelim(route_y_min, 0, route_y_max);
1590 /*dstream<<"route_y_min = "<<route_y_min
1591 <<", route_y_max = "<<route_y_max<<std::endl;*/
1593 s16 route_start_y_min = route_y_min;
1594 s16 route_start_y_max = route_y_max;
1596 // Start every 4th cave from surface when applicable
1597 /*bool coming_from_surface = false;
1598 if(node_min.Y <= 0 && node_max.Y >= 0){
1599 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1600 if(coming_from_surface)
1601 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1604 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1605 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1607 // Randomize starting position
1609 (float)(ps.next()%ar.X)+0.5,
1610 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1611 (float)(ps.next()%ar.Z)+0.5
1614 v3s16 startp(orp.X, orp.Y, orp.Z);
1617 MapNode airnode(CONTENT_AIR);
1618 MapNode waternode(c_water_source);
1619 MapNode lavanode(c_lava_source);
1622 Generate some tunnel starting from orp
1625 for(u16 j=0; j<tunnel_routepoints; j++)
1627 if(j%dswitchint==0 && large_cave == false)
1629 main_direction = v3f(
1630 ((float)(ps.next()%20)-(float)10)/10,
1631 ((float)(ps.next()%20)-(float)10)/30,
1632 ((float)(ps.next()%20)-(float)10)/10
1634 main_direction *= (float)ps.range(0, 10)/10;
1638 s16 min_d = min_tunnel_diameter;
1639 s16 max_d = max_tunnel_diameter;
1640 s16 rs = ps.range(min_d, max_d);
1642 // Every second section is rough
1643 bool randomize_xz = (ps2.range(1,2) == 1);
1649 rs*part_max_length_rs,
1650 rs*part_max_length_rs/2,
1651 rs*part_max_length_rs
1657 rs*part_max_length_rs,
1658 ps.range(1, rs*part_max_length_rs),
1659 rs*part_max_length_rs
1666 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1667 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1668 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1671 // Jump downward sometimes
1672 if(!large_cave && ps.range(0,12) == 0)
1675 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1676 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1677 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1683 s16 h = find_ground_level_clever(vmanip,
1684 v2s16(p.X, p.Z), ndef);
1685 route_y_min = h - rs/3;
1686 route_y_max = h + rs;
1689 vec += main_direction;
1694 else if(rp.X >= ar.X)
1696 if(rp.Y < route_y_min)
1698 else if(rp.Y >= route_y_max)
1699 rp.Y = route_y_max-1;
1702 else if(rp.Z >= ar.Z)
1706 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1708 v3f fp = orp + vec * f;
1709 fp.X += 0.1*ps.range(-10,10);
1710 fp.Z += 0.1*ps.range(-10,10);
1711 v3s16 cp(fp.X, fp.Y, fp.Z);
1716 d0 += ps.range(-1,1);
1717 d1 += ps.range(-1,1);
1719 for(s16 z0=d0; z0<=d1; z0++)
1721 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1722 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1724 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1725 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1726 for(s16 y0=-si2; y0<=si2; y0++)
1728 /*// Make better floors in small caves
1729 if(y0 <= -rs/2 && rs<=7)
1731 if(large_cave_is_flat){
1732 // Make large caves not so tall
1733 if(rs > 7 && abs(y0) >= rs/3)
1743 if(vmanip.m_area.contains(p) == false)
1746 u32 i = vmanip.m_area.index(p);
1750 if(full_node_min.Y < WATER_LEVEL &&
1751 full_node_max.Y > WATER_LEVEL){
1752 if(p.Y <= WATER_LEVEL)
1753 vmanip.m_data[i] = waternode;
1755 vmanip.m_data[i] = airnode;
1756 } else if(full_node_max.Y < WATER_LEVEL){
1757 if(p.Y < startp.Y - 2)
1758 vmanip.m_data[i] = lavanode;
1760 vmanip.m_data[i] = airnode;
1762 vmanip.m_data[i] = airnode;
1765 // Don't replace air or water or lava or ignore
1766 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1767 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1768 vmanip.m_data[i].getContent() == c_water_source ||
1769 vmanip.m_data[i].getContent() == c_lava_source)
1772 vmanip.m_data[i] = airnode;
1775 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1793 TimeTaker timer1("add mud");
1796 Add mud to the central chunk
1799 for(s16 x=node_min.X; x<=node_max.X; x++)
1800 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1802 // Node position in 2d
1803 v2s16 p2d = v2s16(x,z);
1805 // Randomize mud amount
1806 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1808 // Find ground level
1809 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1810 // Handle area not found
1811 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1814 MapNode addnode(c_dirt);
1815 BiomeType bt = get_biome(data->seed, p2d);
1818 addnode = MapNode(c_desert_sand);
1820 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1821 addnode = MapNode(c_sand);
1822 } else if(mud_add_amount <= 0){
1823 mud_add_amount = 1 - mud_add_amount;
1824 addnode = MapNode(c_gravel);
1825 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1826 surface_y + mud_add_amount <= WATER_LEVEL+2){
1827 addnode = MapNode(c_sand);
1830 if(bt == BT_DESERT){
1832 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1837 If topmost node is grass, change it to mud.
1838 It might be if it was flown to there from a neighboring
1839 chunk and then converted.
1842 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1843 MapNode *n = &vmanip.m_data[i];
1844 if(n->getContent() == c_dirt_with_grass)
1845 *n = MapNode(c_dirt);
1853 v3s16 em = vmanip.m_area.getExtent();
1854 s16 y_start = surface_y+1;
1855 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1856 for(s16 y=y_start; y<=node_max.Y; y++)
1858 if(mudcount >= mud_add_amount)
1861 MapNode &n = vmanip.m_data[i];
1865 vmanip.m_area.add_y(em, i, 1);
1875 Add blobs of dirt and gravel underground
1877 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1879 PseudoRandom pr(blockseed+983);
1880 for(int i=0; i<volume_nodes/10/10/10; i++)
1882 bool only_fill_cave = (myrand_range(0,1) != 0);
1889 pr.range(node_min.X, node_max.X)-size.X/2,
1890 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1891 pr.range(node_min.Z, node_max.Z)-size.Z/2
1894 if(p0.Y > -32 && pr.range(0,1) == 0)
1895 n1 = MapNode(c_dirt);
1897 n1 = MapNode(c_gravel);
1898 for(int x1=0; x1<size.X; x1++)
1899 for(int y1=0; y1<size.Y; y1++)
1900 for(int z1=0; z1<size.Z; z1++)
1902 v3s16 p = p0 + v3s16(x1,y1,z1);
1903 u32 i = vmanip.m_area.index(p);
1904 if(!vmanip.m_area.contains(i))
1906 // Cancel if not stone and not cave air
1907 if(vmanip.m_data[i].getContent() != c_stone &&
1908 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1910 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1912 vmanip.m_data[i] = n1;
1920 TimeTaker timer1("flow mud");
1923 Flow mud away from steep edges
1926 // Iterate a few times
1927 for(s16 k=0; k<3; k++)
1930 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1931 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1933 // Invert coordinates every 2nd iteration
1936 x = mudflow_maxpos - (x-mudflow_minpos);
1937 z = mudflow_maxpos - (z-mudflow_minpos);
1940 // Node position in 2d
1941 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1943 v3s16 em = vmanip.m_area.getExtent();
1944 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1947 while(y >= node_min.Y)
1954 for(; y>=node_min.Y; y--)
1956 n = &vmanip.m_data[i];
1957 //if(content_walkable(n->d))
1959 if(n->getContent() == c_dirt ||
1960 n->getContent() == c_dirt_with_grass ||
1961 n->getContent() == c_gravel)
1964 vmanip.m_area.add_y(em, i, -1);
1967 // Stop if out of area
1968 //if(vmanip.m_area.contains(i) == false)
1972 /*// If not mud, do nothing to it
1973 MapNode *n = &vmanip.m_data[i];
1974 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1977 if(n->getContent() == c_dirt ||
1978 n->getContent() == c_dirt_with_grass)
1980 // Make it exactly mud
1981 n->setContent(c_dirt);
1984 Don't flow it if the stuff under it is not mud
1988 vmanip.m_area.add_y(em, i2, -1);
1989 // Cancel if out of area
1990 if(vmanip.m_area.contains(i2) == false)
1992 MapNode *n2 = &vmanip.m_data[i2];
1993 if(n2->getContent() != c_dirt &&
1994 n2->getContent() != c_dirt_with_grass)
1999 /*s16 recurse_count = 0;
2003 v3s16(0,0,1), // back
2004 v3s16(1,0,0), // right
2005 v3s16(0,0,-1), // front
2006 v3s16(-1,0,0), // left
2009 // Theck that upper is air or doesn't exist.
2010 // Cancel dropping if upper keeps it in place
2012 vmanip.m_area.add_y(em, i3, 1);
2013 if(vmanip.m_area.contains(i3) == true
2014 && ndef->get(vmanip.m_data[i3]).walkable)
2021 for(u32 di=0; di<4; di++)
2023 v3s16 dirp = dirs4[di];
2026 vmanip.m_area.add_p(em, i2, dirp);
2027 // Fail if out of area
2028 if(vmanip.m_area.contains(i2) == false)
2030 // Check that side is air
2031 MapNode *n2 = &vmanip.m_data[i2];
2032 if(ndef->get(*n2).walkable)
2034 // Check that under side is air
2035 vmanip.m_area.add_y(em, i2, -1);
2036 if(vmanip.m_area.contains(i2) == false)
2038 n2 = &vmanip.m_data[i2];
2039 if(ndef->get(*n2).walkable)
2041 /*// Check that under that is air (need a drop of 2)
2042 vmanip.m_area.add_y(em, i2, -1);
2043 if(vmanip.m_area.contains(i2) == false)
2045 n2 = &vmanip.m_data[i2];
2046 if(content_walkable(n2->d))
2048 // Loop further down until not air
2049 bool dropped_to_unknown = false;
2051 vmanip.m_area.add_y(em, i2, -1);
2052 n2 = &vmanip.m_data[i2];
2053 // if out of known area
2054 if(vmanip.m_area.contains(i2) == false
2055 || n2->getContent() == CONTENT_IGNORE){
2056 dropped_to_unknown = true;
2059 }while(ndef->get(*n2).walkable == false);
2060 // Loop one up so that we're in air
2061 vmanip.m_area.add_y(em, i2, 1);
2062 n2 = &vmanip.m_data[i2];
2064 bool old_is_water = (n->getContent() == c_water_source);
2065 // Move mud to new place
2066 if(!dropped_to_unknown) {
2068 // Set old place to be air (or water)
2070 *n = MapNode(c_water_source);
2072 *n = MapNode(CONTENT_AIR);
2088 /***********************
2090 ************************/
2093 Add top and bottom side of water to transforming_liquid queue
2096 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2097 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2102 bool water_found = false;
2103 // Use fast index incrementing
2104 v3s16 em = vmanip.m_area.getExtent();
2105 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2106 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2108 if(y == full_node_max.Y){
2110 (vmanip.m_data[i].getContent() == c_water_source ||
2111 vmanip.m_data[i].getContent() == c_lava_source);
2113 else if(water_found == false)
2115 if(vmanip.m_data[i].getContent() == c_water_source ||
2116 vmanip.m_data[i].getContent() == c_lava_source)
2118 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2119 data->transforming_liquid.push_back(p);
2125 // This can be done because water_found can only
2126 // turn to true and end up here after going through
2128 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2129 vmanip.m_data[i+1].getContent() != c_lava_source)
2131 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2132 data->transforming_liquid.push_back(p);
2133 water_found = false;
2137 vmanip.m_area.add_y(em, i, -1);
2146 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2147 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2149 // Node position in 2d
2150 v2s16 p2d = v2s16(x,z);
2153 Find the lowest surface to which enough light ends up
2156 Basically just wait until not air and not leaves.
2160 v3s16 em = vmanip.m_area.getExtent();
2161 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2163 // Go to ground level
2164 for(y=node_max.Y; y>=full_node_min.Y; y--)
2166 MapNode &n = vmanip.m_data[i];
2167 if(ndef->get(n).param_type != CPT_LIGHT
2168 || ndef->get(n).liquid_type != LIQUID_NONE)
2170 vmanip.m_area.add_y(em, i, -1);
2172 if(y >= full_node_min.Y)
2175 surface_y = full_node_min.Y;
2178 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2179 MapNode *n = &vmanip.m_data[i];
2180 if(n->getContent() == c_dirt){
2181 // Well yeah, this can't be overground...
2182 if(surface_y < WATER_LEVEL - 20)
2184 n->setContent(c_dirt_with_grass);
2191 assert(central_area_size.X == central_area_size.Z);
2193 // Divide area into parts
2195 s16 sidelen = central_area_size.X / div;
2196 double area = sidelen * sidelen;
2197 for(s16 x0=0; x0<div; x0++)
2198 for(s16 z0=0; z0<div; z0++)
2200 // Center position of part of division
2202 node_min.X + sidelen/2 + sidelen*x0,
2203 node_min.Z + sidelen/2 + sidelen*z0
2205 // Minimum edge of part of division
2207 node_min.X + sidelen*x0,
2208 node_min.Z + sidelen*z0
2210 // Maximum edge of part of division
2212 node_min.X + sidelen + sidelen*x0 - 1,
2213 node_min.Z + sidelen + sidelen*z0 - 1
2216 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2217 // Put trees in random places on part of division
2218 for(u32 i=0; i<tree_count; i++)
2220 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2221 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2222 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2223 // Don't make a tree under water level
2226 // Don't make a tree so high that it doesn't fit
2227 if(y > node_max.Y - 6)
2231 Trees grow only on mud and grass
2234 u32 i = vmanip.m_area.index(v3s16(p));
2235 MapNode *n = &vmanip.m_data[i];
2236 if(n->getContent() != c_dirt
2237 && n->getContent() != c_dirt_with_grass)
2242 make_tree(vmanip, p, false, ndef);
2249 Make base ground level
2252 for(s16 x=node_min.X; x<=node_max.X; x++)
2253 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2258 // Use fast index incrementing
2259 v3s16 em = vmanip.m_area.getExtent();
2260 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2261 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2263 // Only modify places that have no content
2264 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2266 // First priority: make air and water.
2267 // This avoids caves inside water.
2268 if(all_is_ground_except_caves == false
2269 && val_is_ground(noisebuf_ground.get(x,y,z),
2270 v3s16(x,y,z), data->seed) == false)
2272 if(y <= WATER_LEVEL)
2273 vmanip.m_data[i] = n_water_source;
2275 vmanip.m_data[i] = n_air;
2277 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2278 vmanip.m_data[i] = n_air;
2280 vmanip.m_data[i] = n_stone;
2283 vmanip->m_area.add_y(em, i, 1);
2289 Add mud and sand and others underground (in place of stone)
2292 for(s16 x=node_min.X; x<=node_max.X; x++)
2293 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2298 // Use fast index incrementing
2299 v3s16 em = vmanip.m_area.getExtent();
2300 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2301 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2303 if(vmanip.m_data[i].getContent() == c_stone)
2305 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2307 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2308 vmanip.m_data[i] = n_dirt;
2310 vmanip.m_data[i] = n_sand;
2312 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2314 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2315 vmanip.m_data[i] = n_gravel;
2317 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2318 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2320 vmanip.m_data[i] = n_lava_source;
2321 for(s16 x1=-1; x1<=1; x1++)
2322 for(s16 y1=-1; y1<=1; y1++)
2323 for(s16 z1=-1; z1<=1; z1++)
2324 data->transforming_liquid.push_back(
2325 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2329 vmanip->m_area.add_y(em, i, -1);
2338 //if(node_min.Y < approx_groundlevel)
2339 //if(myrand() % 3 == 0)
2340 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2341 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2342 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2343 float dungeon_rarity = 0.02;
2344 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2346 && node_min.Y < approx_groundlevel)
2348 // Dungeon generator doesn't modify places which have this set
2349 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2350 | VMANIP_FLAG_DUNGEON_PRESERVE);
2352 // Set all air and water to be untouchable to make dungeons open
2353 // to caves and open air
2354 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2355 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2360 // Use fast index incrementing
2361 v3s16 em = vmanip.m_area.getExtent();
2362 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2363 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2365 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2366 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2367 else if(vmanip.m_data[i].getContent() == c_water_source)
2368 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2369 vmanip->m_area.add_y(em, i, -1);
2374 PseudoRandom random(blockseed+2);
2377 make_dungeon1(vmanip, random, ndef);
2379 // Convert some cobble to mossy cobble
2380 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2381 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2386 // Use fast index incrementing
2387 v3s16 em = vmanip.m_area.getExtent();
2388 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2389 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2391 // (noisebuf not used because it doesn't contain the
2393 double wetness = noise3d_param(
2394 get_ground_wetness_params(data->seed), x,y,z);
2395 double d = noise3d_perlin((float)x/2.5,
2396 (float)y/2.5,(float)z/2.5,
2398 if(vmanip.m_data[i].getContent() == c_cobble)
2402 vmanip.m_data[i].setContent(c_mossycobble);
2405 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2408 vmanip.m_data[i].setContent(c_dirt);
2410 vmanip->m_area.add_y(em, i, -1);
2420 PseudoRandom ncrandom(blockseed+9324342);
2421 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2423 make_nc(vmanip, ncrandom, ndef);
2428 Add top and bottom side of water to transforming_liquid queue
2431 for(s16 x=node_min.X; x<=node_max.X; x++)
2432 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2437 bool water_found = false;
2438 // Use fast index incrementing
2439 v3s16 em = vmanip.m_area.getExtent();
2440 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2441 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2443 if(water_found == false)
2445 if(vmanip.m_data[i].getContent() == c_water_source)
2447 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2448 data->transforming_liquid.push_back(p);
2454 // This can be done because water_found can only
2455 // turn to true and end up here after going through
2457 if(vmanip.m_data[i+1].getContent() != c_water_source)
2459 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2460 data->transforming_liquid.push_back(p);
2461 water_found = false;
2465 vmanip->m_area.add_y(em, i, -1);
2471 If close to ground level
2474 //if(abs(approx_ground_depth) < 30)
2475 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2481 for(s16 x=node_min.X; x<=node_max.X; x++)
2482 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2487 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2488 bool have_sand = false;
2489 u32 current_depth = 0;
2490 bool air_detected = false;
2491 bool water_detected = false;
2492 bool have_clay = false;
2494 // Use fast index incrementing
2495 s16 start_y = node_max.Y+2;
2496 v3s16 em = vmanip.m_area.getExtent();
2497 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2498 for(s16 y=start_y; y>=node_min.Y-3; y--)
2500 if(vmanip.m_data[i].getContent() == c_water_source)
2501 water_detected = true;
2502 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2503 air_detected = true;
2505 if((vmanip.m_data[i].getContent() == c_stone
2506 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2507 || vmanip.m_data[i].getContent() == c_dirt
2508 || vmanip.m_data[i].getContent() == c_sand
2509 || vmanip.m_data[i].getContent() == c_gravel
2510 ) && (air_detected || water_detected))
2512 if(current_depth == 0 && y <= WATER_LEVEL+2
2513 && possibly_have_sand)
2516 if(current_depth < 4)
2520 vmanip.m_data[i] = MapNode(c_sand);
2523 else if(current_depth==0 && !water_detected
2524 && y >= WATER_LEVEL && air_detected)
2525 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2528 vmanip.m_data[i] = MapNode(c_dirt);
2532 if(vmanip.m_data[i].getContent() == c_dirt
2533 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2534 vmanip.m_data[i] = MapNode(c_stone);
2539 if(current_depth >= 8)
2542 else if(current_depth != 0)
2545 vmanip->m_area.add_y(em, i, -1);
2551 Calculate some stuff
2554 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2555 bool is_jungle = surface_humidity > 0.75;
2557 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2564 PseudoRandom treerandom(blockseed);
2565 // Put trees in random places on part of division
2566 for(u32 i=0; i<tree_count; i++)
2568 s16 x = treerandom.range(node_min.X, node_max.X);
2569 s16 z = treerandom.range(node_min.Z, node_max.Z);
2570 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2571 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2572 // Don't make a tree under water level
2575 // Make sure tree fits (only trees whose starting point is
2576 // at this block are added)
2577 if(y < node_min.Y || y > node_max.Y)
2580 Find exact ground level
2584 for(; p.Y >= y-6; p.Y--)
2586 u32 i = vmanip->m_area.index(p);
2587 MapNode *n = &vmanip->m_data[i];
2588 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2594 // If not found, handle next one
2599 u32 i = vmanip->m_area.index(p);
2600 MapNode *n = &vmanip->m_data[i];
2602 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2605 // Papyrus grows only on mud and in water
2606 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2609 make_papyrus(vmanip, p, ndef);
2611 // Trees grow only on mud and grass, on land
2612 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2615 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2616 if(is_jungle == false)
2619 if(myrand_range(0,4) != 0)
2620 is_apple_tree = false;
2622 is_apple_tree = noise2d_perlin(
2623 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2624 data->seed+342902, 3, 0.45) > 0.2;
2625 make_tree(vmanip, p, is_apple_tree, ndef);
2628 make_jungletree(vmanip, p, ndef);
2630 // Cactii grow only on sand, on land
2631 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2634 make_cactus(vmanip, p, ndef);
2644 PseudoRandom grassrandom(blockseed);
2645 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2647 s16 x = grassrandom.range(node_min.X, node_max.X);
2648 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2649 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2652 if(y < node_min.Y || y > node_max.Y)
2655 Find exact ground level
2659 for(; p.Y >= y-6; p.Y--)
2661 u32 i = vmanip->m_area.index(p);
2662 MapNode *n = &vmanip->m_data[i];
2663 if(data->nodedef->get(*n).is_ground_content)
2669 // If not found, handle next one
2673 if(vmanip.m_area.contains(p) == false)
2675 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2678 if(vmanip.m_area.contains(p))
2679 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2681 if(vmanip.m_area.contains(p))
2682 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2688 Add some kind of random stones
2691 u32 random_stone_count = gen_area_nodes *
2692 randomstone_amount_2d(data->seed, p2d_center);
2693 // Put in random places on part of division
2694 for(u32 i=0; i<random_stone_count; i++)
2696 s16 x = myrand_range(node_min.X, node_max.X);
2697 s16 z = myrand_range(node_min.Z, node_max.Z);
2698 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2699 // Don't add under water level
2700 /*if(y < WATER_LEVEL)
2702 // Don't add if doesn't belong to this block
2703 if(y < node_min.Y || y > node_max.Y)
2708 u32 i = vmanip->m_area.index(v3s16(p));
2709 MapNode *n = &vmanip->m_data[i];
2710 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2713 // Will be placed one higher
2716 make_randomstone(vmanip, p);
2725 u32 large_stone_count = gen_area_nodes *
2726 largestone_amount_2d(data->seed, p2d_center);
2727 //u32 large_stone_count = 1;
2728 // Put in random places on part of division
2729 for(u32 i=0; i<large_stone_count; i++)
2731 s16 x = myrand_range(node_min.X, node_max.X);
2732 s16 z = myrand_range(node_min.Z, node_max.Z);
2733 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2734 // Don't add under water level
2735 /*if(y < WATER_LEVEL)
2737 // Don't add if doesn't belong to this block
2738 if(y < node_min.Y || y > node_max.Y)
2743 u32 i = vmanip->m_area.index(v3s16(p));
2744 MapNode *n = &vmanip->m_data[i];
2745 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2748 // Will be placed one lower
2751 make_largestone(vmanip, p);
2761 PseudoRandom mineralrandom(blockseed);
2766 for(s16 i=0; i<approx_ground_depth/4; i++)
2768 if(mineralrandom.next()%50 == 0)
2770 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2771 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2772 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2773 for(u16 i=0; i<27; i++)
2775 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2776 u32 vi = vmanip.m_area.index(p);
2777 if(vmanip.m_data[vi].getContent() == c_stone)
2778 if(mineralrandom.next()%8 == 0)
2779 vmanip.m_data[vi] = MapNode(c_mese);
2788 u16 a = mineralrandom.range(0,15);
2790 u16 amount = 20 * a/1000;
2791 for(s16 i=0; i<amount; i++)
2793 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2794 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2795 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2797 u8 base_content = c_stone;
2798 MapNode new_content(CONTENT_IGNORE);
2801 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2803 new_content = MapNode(c_stone_with_coal);
2807 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2808 new_content = MapNode(c_stone_with_iron);
2809 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2810 vmanip.m_data[i] = MapNode(c_dirt);
2812 vmanip.m_data[i] = MapNode(c_sand);*/
2814 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2818 if(new_content.getContent() != CONTENT_IGNORE)
2820 for(u16 i=0; i<27; i++)
2822 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2823 u32 vi = vmanip.m_area.index(p);
2824 if(vmanip.m_data[vi].getContent() == base_content)
2826 if(mineralrandom.next()%sparseness == 0)
2827 vmanip.m_data[vi] = new_content;
2836 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2837 //for(s16 i=0; i<50; i++)
2838 u16 coal_amount = 30;
2839 u16 coal_rareness = 60 / coal_amount;
2840 if(coal_rareness == 0)
2842 if(mineralrandom.next()%coal_rareness == 0)
2844 u16 a = mineralrandom.next() % 16;
2845 u16 amount = coal_amount * a*a*a / 1000;
2846 for(s16 i=0; i<amount; i++)
2848 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2849 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2850 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2851 for(u16 i=0; i<27; i++)
2853 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2854 u32 vi = vmanip.m_area.index(p);
2855 if(vmanip.m_data[vi].getContent() == c_stone)
2856 if(mineralrandom.next()%8 == 0)
2857 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2864 u16 iron_amount = 8;
2865 u16 iron_rareness = 60 / iron_amount;
2866 if(iron_rareness == 0)
2868 if(mineralrandom.next()%iron_rareness == 0)
2870 u16 a = mineralrandom.next() % 16;
2871 u16 amount = iron_amount * a*a*a / 1000;
2872 for(s16 i=0; i<amount; i++)
2874 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2875 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2876 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2877 for(u16 i=0; i<27; i++)
2879 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2880 u32 vi = vmanip.m_area.index(p);
2881 if(vmanip.m_data[vi].getContent() == c_stone)
2882 if(mineralrandom.next()%8 == 0)
2883 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2894 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2896 //VoxelArea a(node_min, node_max);
2897 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2898 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2899 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2900 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2901 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2902 for(int i=0; i<2; i++)
2904 enum LightBank bank = banks[i];
2906 core::map<v3s16, bool> light_sources;
2907 core::map<v3s16, u8> unlight_from;
2909 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2910 light_sources, unlight_from);
2912 bool inexistent_top_provides_sunlight = !block_is_underground;
2913 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2914 vmanip, a, inexistent_top_provides_sunlight,
2915 light_sources, ndef);
2916 // TODO: Do stuff according to bottom_sunlight_valid
2918 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2920 vmanip.spreadLight(bank, light_sources, ndef);
2925 BlockMakeData::BlockMakeData():
2932 BlockMakeData::~BlockMakeData()
2937 }; // namespace mapgen