3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
37 Some helper functions for the map generator
41 // Returns Y one under area minimum if not found
42 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
43 INodeDefManager *ndef)
45 v3s16 em = vmanip.m_area.getExtent();
46 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
47 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
48 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
50 for(y=y_nodes_max; y>=y_nodes_min; y--)
52 MapNode &n = vmanip.m_data[i];
53 if(ndef->get(n).walkable)
56 vmanip.m_area.add_y(em, i, -1);
61 return y_nodes_min - 1;
64 // Returns Y one under area minimum if not found
65 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
66 INodeDefManager *ndef)
68 v3s16 em = vmanip.m_area.getExtent();
69 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
70 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
71 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
73 for(y=y_nodes_max; y>=y_nodes_min; y--)
75 MapNode &n = vmanip.m_data[i];
76 if(ndef->get(n).walkable
77 // TODO: Cache LEGN values
78 && n.getContent() != LEGN(ndef, "CONTENT_TREE")
79 && n.getContent() != LEGN(ndef, "CONTENT_LEAVES"))
82 vmanip.m_area.add_y(em, i, -1);
87 return y_nodes_min - 1;
90 // Returns Y one under area minimum if not found
91 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
92 INodeDefManager *ndef)
94 v3s16 em = vmanip.m_area.getExtent();
95 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
96 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
97 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
99 content_t c_stone = LEGN(ndef, "CONTENT_STONE");
100 for(y=y_nodes_max; y>=y_nodes_min; y--)
102 MapNode &n = vmanip.m_data[i];
103 if(n.getContent() == c_stone)
106 vmanip.m_area.add_y(em, i, -1);
111 return y_nodes_min - 1;
115 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
116 bool is_apple_tree, INodeDefManager *ndef)
118 MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
119 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
120 MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
122 s16 trunk_h = myrand_range(4, 5);
124 for(s16 ii=0; ii<trunk_h; ii++)
126 if(vmanip.m_area.contains(p1))
127 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
131 // p1 is now the last piece of the trunk
134 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
135 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
136 Buffer<u8> leaves_d(leaves_a.getVolume());
137 for(s32 i=0; i<leaves_a.getVolume(); i++)
140 // Force leaves at near the end of the trunk
143 for(s16 z=-d; z<=d; z++)
144 for(s16 y=-d; y<=d; y++)
145 for(s16 x=-d; x<=d; x++)
147 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
151 // Add leaves randomly
152 for(u32 iii=0; iii<7; iii++)
157 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
158 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
159 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
162 for(s16 z=0; z<=d; z++)
163 for(s16 y=0; y<=d; y++)
164 for(s16 x=0; x<=d; x++)
166 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
170 // Blit leaves to vmanip
171 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
172 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
173 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
177 if(vmanip.m_area.contains(p) == false)
179 u32 vi = vmanip.m_area.index(p);
180 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
181 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
183 u32 i = leaves_a.index(x,y,z);
184 if(leaves_d[i] == 1) {
185 bool is_apple = myrand_range(0,99) < 10;
186 if(is_apple_tree && is_apple) {
187 vmanip.m_data[vi] = applenode;
189 vmanip.m_data[vi] = leavesnode;
195 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
196 INodeDefManager *ndef)
198 MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
199 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
201 for(s16 x=-1; x<=1; x++)
202 for(s16 z=-1; z<=1; z++)
204 if(myrand_range(0, 2) == 0)
206 v3s16 p1 = p0 + v3s16(x,0,z);
207 v3s16 p2 = p0 + v3s16(x,-1,z);
208 if(vmanip.m_area.contains(p2)
209 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
210 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
211 else if(vmanip.m_area.contains(p1))
212 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
215 s16 trunk_h = myrand_range(8, 12);
217 for(s16 ii=0; ii<trunk_h; ii++)
219 if(vmanip.m_area.contains(p1))
220 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
224 // p1 is now the last piece of the trunk
227 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
228 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
229 Buffer<u8> leaves_d(leaves_a.getVolume());
230 for(s32 i=0; i<leaves_a.getVolume(); i++)
233 // Force leaves at near the end of the trunk
236 for(s16 z=-d; z<=d; z++)
237 for(s16 y=-d; y<=d; y++)
238 for(s16 x=-d; x<=d; x++)
240 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
244 // Add leaves randomly
245 for(u32 iii=0; iii<30; iii++)
250 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
251 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
252 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
255 for(s16 z=0; z<=d; z++)
256 for(s16 y=0; y<=d; y++)
257 for(s16 x=0; x<=d; x++)
259 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
263 // Blit leaves to vmanip
264 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
265 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
266 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
270 if(vmanip.m_area.contains(p) == false)
272 u32 vi = vmanip.m_area.index(p);
273 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
274 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
276 u32 i = leaves_a.index(x,y,z);
278 vmanip.m_data[vi] = leavesnode;
282 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
283 INodeDefManager *ndef)
285 MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
287 s16 trunk_h = myrand_range(2, 3);
289 for(s16 ii=0; ii<trunk_h; ii++)
291 if(vmanip.m_area.contains(p1))
292 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
297 void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
298 INodeDefManager *ndef)
300 MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
304 for(s16 ii=0; ii<trunk_h; ii++)
306 if(vmanip.m_area.contains(p1))
307 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
313 Dungeon making routines
316 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
317 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
318 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
319 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
321 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
322 INodeDefManager *ndef)
325 for(s16 z=0; z<roomsize.Z; z++)
326 for(s16 y=0; y<roomsize.Y; y++)
329 v3s16 p = roomplace + v3s16(0,y,z);
330 if(vmanip.m_area.contains(p) == false)
332 u32 vi = vmanip.m_area.index(p);
333 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
335 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
338 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
339 if(vmanip.m_area.contains(p) == false)
341 u32 vi = vmanip.m_area.index(p);
342 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
344 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
349 for(s16 x=0; x<roomsize.X; x++)
350 for(s16 y=0; y<roomsize.Y; y++)
353 v3s16 p = roomplace + v3s16(x,y,0);
354 if(vmanip.m_area.contains(p) == false)
356 u32 vi = vmanip.m_area.index(p);
357 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
359 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
362 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
363 if(vmanip.m_area.contains(p) == false)
365 u32 vi = vmanip.m_area.index(p);
366 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
368 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
372 // Make +-Y walls (floor and ceiling)
373 for(s16 z=0; z<roomsize.Z; z++)
374 for(s16 x=0; x<roomsize.X; x++)
377 v3s16 p = roomplace + v3s16(x,0,z);
378 if(vmanip.m_area.contains(p) == false)
380 u32 vi = vmanip.m_area.index(p);
381 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
383 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
386 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
387 if(vmanip.m_area.contains(p) == false)
389 u32 vi = vmanip.m_area.index(p);
390 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
392 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
397 for(s16 z=1; z<roomsize.Z-1; z++)
398 for(s16 y=1; y<roomsize.Y-1; y++)
399 for(s16 x=1; x<roomsize.X-1; x++)
401 v3s16 p = roomplace + v3s16(x,y,z);
402 if(vmanip.m_area.contains(p) == false)
404 u32 vi = vmanip.m_area.index(p);
405 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
406 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
410 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
411 u8 avoid_flags, MapNode n, u8 or_flags)
413 for(s16 z=0; z<size.Z; z++)
414 for(s16 y=0; y<size.Y; y++)
415 for(s16 x=0; x<size.X; x++)
417 v3s16 p = place + v3s16(x,y,z);
418 if(vmanip.m_area.contains(p) == false)
420 u32 vi = vmanip.m_area.index(p);
421 if(vmanip.m_flags[vi] & avoid_flags)
423 vmanip.m_flags[vi] |= or_flags;
424 vmanip.m_data[vi] = n;
428 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
429 INodeDefManager *ndef)
431 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
432 VMANIP_FLAG_DUNGEON_INSIDE);
435 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
436 INodeDefManager *ndef)
438 make_hole1(vmanip, doorplace, ndef);
439 // Place torch (for testing)
440 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
443 static v3s16 rand_ortho_dir(PseudoRandom &random)
445 if(random.next()%2==0)
446 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
448 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
451 static v3s16 turn_xz(v3s16 olddir, int t)
471 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
473 int turn = random.range(0,2);
482 dir = turn_xz(olddir, 0);
485 dir = turn_xz(olddir, 1);
489 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
490 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
491 PseudoRandom &random, INodeDefManager *ndef)
493 make_hole1(vmanip, doorplace, ndef);
494 v3s16 p0 = doorplace;
498 length = random.range(1,13);
500 length = random.range(1,6);
501 length = random.range(1,13);
502 u32 partlength = random.range(1,13);
505 if(random.next()%2 == 0 && partlength >= 3)
506 make_stairs = random.next()%2 ? 1 : -1;
507 for(u32 i=0; i<length; i++)
513 /*// If already empty
514 if(vmanip.getNodeNoExNoEmerge(p).getContent()
516 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
521 if(vmanip.m_area.contains(p) == true
522 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
526 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
527 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
528 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
529 VMANIP_FLAG_DUNGEON_INSIDE);
530 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
531 VMANIP_FLAG_DUNGEON_INSIDE);
535 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
536 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
537 make_hole1(vmanip, p, ndef);
538 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
539 VMANIP_FLAG_DUNGEON_INSIDE);*/
546 // Can't go here, turn away
547 dir = turn_xz(dir, random.range(0,1));
548 make_stairs = -make_stairs;
550 partlength = random.range(1,length);
555 if(partcount >= partlength)
559 dir = random_turn(random, dir);
561 partlength = random.range(1,length);
564 if(random.next()%2 == 0 && partlength >= 3)
565 make_stairs = random.next()%2 ? 1 : -1;
576 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
577 INodeDefManager *ndef):
588 m_dir = rand_ortho_dir(m_random);
591 void setPos(v3s16 pos)
596 void setDir(v3s16 dir)
601 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
603 for(u32 i=0; i<100; i++)
605 v3s16 p = m_pos + m_dir;
606 v3s16 p1 = p + v3s16(0,1,0);
607 if(vmanip.m_area.contains(p) == false
608 || vmanip.m_area.contains(p1) == false
614 if(vmanip.getNodeNoExNoEmerge(p).getContent()
615 == LEGN(m_ndef, "CONTENT_COBBLE")
616 && vmanip.getNodeNoExNoEmerge(p1).getContent()
617 == LEGN(m_ndef, "CONTENT_COBBLE"))
619 // Found wall, this is a good place!
622 // Randomize next direction
627 Determine where to move next
629 // Jump one up if the actual space is there
630 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
631 == LEGN(m_ndef, "CONTENT_COBBLE")
632 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
633 == LEGN(m_ndef, "CONTENT_AIR")
634 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
635 == LEGN(m_ndef, "CONTENT_AIR"))
637 // Jump one down if the actual space is there
638 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
639 == LEGN(m_ndef, "CONTENT_COBBLE")
640 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
641 == LEGN(m_ndef, "CONTENT_AIR")
642 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
643 == LEGN(m_ndef, "CONTENT_AIR"))
645 // Check if walking is now possible
646 if(vmanip.getNodeNoExNoEmerge(p).getContent()
647 != LEGN(m_ndef, "CONTENT_AIR")
648 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
649 != LEGN(m_ndef, "CONTENT_AIR"))
651 // Cannot continue walking here
661 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
662 v3s16 &result_doordir, v3s16 &result_roomplace)
664 for(s16 trycount=0; trycount<30; trycount++)
668 bool r = findPlaceForDoor(doorplace, doordir);
672 // X east, Z north, Y up
674 if(doordir == v3s16(1,0,0)) // X+
675 roomplace = doorplace +
676 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
677 if(doordir == v3s16(-1,0,0)) // X-
678 roomplace = doorplace +
679 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
680 if(doordir == v3s16(0,0,1)) // Z+
681 roomplace = doorplace +
682 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
683 if(doordir == v3s16(0,0,-1)) // Z-
684 roomplace = doorplace +
685 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
688 if(doordir == v3s16(1,0,0)) // X+
689 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
690 if(doordir == v3s16(-1,0,0)) // X-
691 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
692 if(doordir == v3s16(0,0,1)) // Z+
693 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
694 if(doordir == v3s16(0,0,-1)) // Z-
695 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
700 for(s16 z=1; z<roomsize.Z-1; z++)
701 for(s16 y=1; y<roomsize.Y-1; y++)
702 for(s16 x=1; x<roomsize.X-1; x++)
704 v3s16 p = roomplace + v3s16(x,y,z);
705 if(vmanip.m_area.contains(p) == false)
710 if(vmanip.m_flags[vmanip.m_area.index(p)]
711 & VMANIP_FLAG_DUNGEON_INSIDE)
722 result_doorplace = doorplace;
723 result_doordir = doordir;
724 result_roomplace = roomplace;
731 VoxelManipulator &vmanip;
734 PseudoRandom &m_random;
735 INodeDefManager *m_ndef;
738 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
739 INodeDefManager *ndef)
741 v3s16 areasize = vmanip.m_area.getExtent();
746 Find place for first room
749 for(u32 i=0; i<100; i++)
751 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
752 roomplace = vmanip.m_area.MinEdge + v3s16(
753 random.range(0,areasize.X-roomsize.X-1),
754 random.range(0,areasize.Y-roomsize.Y-1),
755 random.range(0,areasize.Z-roomsize.Z-1));
757 Check that we're not putting the room to an unknown place,
758 otherwise it might end up floating in the air
761 for(s16 z=1; z<roomsize.Z-1; z++)
762 for(s16 y=1; y<roomsize.Y-1; y++)
763 for(s16 x=1; x<roomsize.X-1; x++)
765 v3s16 p = roomplace + v3s16(x,y,z);
766 u32 vi = vmanip.m_area.index(p);
767 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
772 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
786 Stores the center position of the last room made, so that
787 a new corridor can be started from the last room instead of
788 the new room, if chosen so.
790 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
792 u32 room_count = random.range(2,7);
793 for(u32 i=0; i<room_count; i++)
795 // Make a room to the determined place
796 make_room1(vmanip, roomsize, roomplace, ndef);
798 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
800 // Place torch at room center (for testing)
801 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
804 if(i == room_count-1)
807 // Determine walker start position
809 bool start_in_last_room = (random.range(0,2)!=0);
810 //bool start_in_last_room = true;
812 v3s16 walker_start_place;
814 if(start_in_last_room)
816 walker_start_place = last_room_center;
820 walker_start_place = room_center;
821 // Store center of current room as the last one
822 last_room_center = room_center;
825 // Create walker and find a place for a door
826 RoomWalker walker(vmanip, walker_start_place, random, ndef);
829 bool r = walker.findPlaceForDoor(doorplace, doordir);
833 if(random.range(0,1)==0)
835 make_door1(vmanip, doorplace, doordir, ndef);
837 // Don't actually make a door
838 doorplace -= doordir;
840 // Make a random corridor starting from the door
842 v3s16 corridor_end_dir;
843 make_corridor(vmanip, doorplace, doordir, corridor_end,
844 corridor_end_dir, random, ndef);
846 // Find a place for a random sized room
847 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
848 walker.setPos(corridor_end);
849 walker.setDir(corridor_end_dir);
850 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
854 if(random.range(0,1)==0)
856 make_door1(vmanip, doorplace, doordir, ndef);
858 // Don't actually make a door
859 roomplace -= doordir;
864 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
865 INodeDefManager *ndef)
869 s32 r = random.range(0, 3);
871 dir = v3s16( 1, 0, 0);
875 dir = v3s16(-1, 0, 0);
879 dir = v3s16( 0, 0, 1);
883 dir = v3s16( 0, 0,-1);
886 v3s16 p = vmanip.m_area.MinEdge + v3s16(
887 16+random.range(0,15),
888 16+random.range(0,15),
889 16+random.range(0,15));
890 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC"), facedir_i);
891 u32 length = random.range(3,15);
892 for(u32 j=0; j<length; j++)
895 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
900 Noise functions. Make sure seed is mangled differently in each one.
905 Scaling the output of the noise function affects the overdrive of the
906 contour function, which affects the shape of the output considerably.
908 #define CAVE_NOISE_SCALE 12.0
909 //#define CAVE_NOISE_SCALE 10.0
910 //#define CAVE_NOISE_SCALE 7.5
911 //#define CAVE_NOISE_SCALE 5.0
912 //#define CAVE_NOISE_SCALE 1.0
914 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
915 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
917 NoiseParams get_cave_noise1_params(u64 seed)
919 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
920 200, CAVE_NOISE_SCALE);*/
921 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
922 100, CAVE_NOISE_SCALE);*/
923 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
924 100, CAVE_NOISE_SCALE);*/
925 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
926 100, CAVE_NOISE_SCALE);*/
927 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
928 50, CAVE_NOISE_SCALE);
929 //return NoiseParams(NOISE_CONSTANT_ONE);
932 NoiseParams get_cave_noise2_params(u64 seed)
934 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
935 200, CAVE_NOISE_SCALE);*/
936 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
937 100, CAVE_NOISE_SCALE);*/
938 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
939 100, CAVE_NOISE_SCALE);*/
940 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
941 50, CAVE_NOISE_SCALE);
942 //return NoiseParams(NOISE_CONSTANT_ONE);
945 NoiseParams get_ground_noise1_params(u64 seed)
947 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
951 NoiseParams get_ground_crumbleness_params(u64 seed)
953 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
957 NoiseParams get_ground_wetness_params(u64 seed)
959 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
963 bool is_cave(u64 seed, v3s16 p)
965 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
966 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
967 return d1*d2 > CAVE_NOISE_THRESHOLD;
971 Ground density noise shall be interpreted by using this.
973 TODO: No perlin noises here, they should be outsourced
975 NOTE: The speed of these actually isn't terrible
977 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
979 //return ((double)p.Y < ground_noise1_val);
981 double f = 0.55 + noise2d_perlin(
982 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
983 seed+920381, 3, 0.45);
988 double h = WATER_LEVEL + 10 * noise2d_perlin(
989 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
993 return ((double)p.Y - h < ground_noise1_val * f);
997 Queries whether a position is ground or not.
999 bool is_ground(u64 seed, v3s16 p)
1001 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1002 return val_is_ground(val1, p, seed);
1006 // Amount of trees per area in nodes
1007 double tree_amount_2d(u64 seed, v2s16 p)
1009 /*double noise = noise2d_perlin(
1010 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1012 double noise = noise2d_perlin(
1013 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1015 double zeroval = -0.39;
1019 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1023 double surface_humidity_2d(u64 seed, v2s16 p)
1025 double noise = noise2d_perlin(
1026 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1027 seed+72384, 4, 0.66);
1028 noise = (noise + 1.0)/2.0;
1037 Incrementally find ground level from 3d noise
1039 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1041 // Start a bit fuzzy to make averaging lower precision values
1043 s16 level = myrand_range(-precision/2, precision/2);
1044 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1046 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1048 // First find non-ground by going upwards
1049 // Don't stop in caves.
1051 s16 max = level+dec[i-1]*2;
1052 v3s16 p(p2d.X, level, p2d.Y);
1053 for(; p.Y < max; p.Y += dec[i])
1055 if(!is_ground(seed, p))
1062 // Then find ground by going downwards from there.
1063 // Go in caves, too, when precision is 1.
1065 s16 min = level-dec[i-1]*2;
1066 v3s16 p(p2d.X, level, p2d.Y);
1067 for(; p.Y>min; p.Y-=dec[i])
1069 bool ground = is_ground(seed, p);
1070 /*if(dec[i] == 1 && is_cave(seed, p))
1081 // This is more like the actual ground level
1082 level += dec[i-1]/2;
1087 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1089 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1091 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1092 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1094 a += find_ground_level_from_noise(seed,
1095 v2s16(node_min.X, node_min.Y), p);
1096 a += find_ground_level_from_noise(seed,
1097 v2s16(node_min.X, node_max.Y), p);
1098 a += find_ground_level_from_noise(seed,
1099 v2s16(node_max.X, node_max.Y), p);
1100 a += find_ground_level_from_noise(seed,
1101 v2s16(node_max.X, node_min.Y), p);
1102 a += find_ground_level_from_noise(seed,
1103 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1108 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1110 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1112 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1113 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1116 a = MYMAX(a, find_ground_level_from_noise(seed,
1117 v2s16(node_min.X, node_min.Y), p));
1118 a = MYMAX(a, find_ground_level_from_noise(seed,
1119 v2s16(node_min.X, node_max.Y), p));
1120 a = MYMAX(a, find_ground_level_from_noise(seed,
1121 v2s16(node_max.X, node_max.Y), p));
1122 a = MYMAX(a, find_ground_level_from_noise(seed,
1123 v2s16(node_min.X, node_min.Y), p));
1125 a = MYMAX(a, find_ground_level_from_noise(seed,
1126 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1127 // Side middle points
1128 a = MYMAX(a, find_ground_level_from_noise(seed,
1129 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1130 a = MYMAX(a, find_ground_level_from_noise(seed,
1131 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1132 a = MYMAX(a, find_ground_level_from_noise(seed,
1133 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1134 a = MYMAX(a, find_ground_level_from_noise(seed,
1135 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1139 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1141 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1143 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1144 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1147 a = MYMIN(a, find_ground_level_from_noise(seed,
1148 v2s16(node_min.X, node_min.Y), p));
1149 a = MYMIN(a, find_ground_level_from_noise(seed,
1150 v2s16(node_min.X, node_max.Y), p));
1151 a = MYMIN(a, find_ground_level_from_noise(seed,
1152 v2s16(node_max.X, node_max.Y), p));
1153 a = MYMIN(a, find_ground_level_from_noise(seed,
1154 v2s16(node_min.X, node_min.Y), p));
1156 a = MYMIN(a, find_ground_level_from_noise(seed,
1157 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1158 // Side middle points
1159 a = MYMIN(a, find_ground_level_from_noise(seed,
1160 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1161 a = MYMIN(a, find_ground_level_from_noise(seed,
1162 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1163 a = MYMIN(a, find_ground_level_from_noise(seed,
1164 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1165 a = MYMIN(a, find_ground_level_from_noise(seed,
1166 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1171 // Required by mapgen.h
1172 bool block_is_underground(u64 seed, v3s16 blockpos)
1174 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1175 seed, v2s16(blockpos.X, blockpos.Z));*/
1176 // Nah, this is just a heuristic, just return something
1177 s16 minimum_groundlevel = WATER_LEVEL;
1179 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1185 #define AVERAGE_MUD_AMOUNT 4
1187 double base_rock_level_2d(u64 seed, v2s16 p)
1189 // The base ground level
1190 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1191 + 20. * noise2d_perlin(
1192 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1193 seed+82341, 5, 0.6);
1195 /*// A bit hillier one
1196 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1197 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1198 seed+93413, 6, 0.69);
1202 // Higher ground level
1203 double higher = (double)WATER_LEVEL + 20. + 10. * noise2d_perlin(
1204 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1205 seed+85039, 4, 0.6);
1206 //higher = 30; // For debugging
1208 // Limit higher to at least base
1212 // Steepness factor of cliffs
1213 double b = 0.85 + 0.5 * noise2d_perlin(
1214 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1216 b = rangelim(b, 0.0, 1000.0);
1219 b = rangelim(b, 3.0, 1000.0);
1220 //dstream<<"b="<<b<<std::endl;
1223 // Offset to more low
1224 double a_off = -0.20;
1225 // High/low selector
1226 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1227 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1228 seed+4213, 6, 0.7));*/
1229 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1230 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1231 seed+4213, 5, 0.69));
1233 a = rangelim(a, 0.0, 1.0);
1235 //dstream<<"a="<<a<<std::endl;
1237 double h = base*(1.0-a) + higher*a;
1244 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1246 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1249 double get_mud_add_amount(u64 seed, v2s16 p)
1251 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1252 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1253 seed+91013, 3, 0.55));
1256 bool get_have_sand(u64 seed, v2s16 p2d)
1258 // Determine whether to have sand here
1259 double sandnoise = noise2d_perlin(
1260 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1261 seed+59420, 3, 0.50);
1263 return (sandnoise > -0.15);
1266 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1268 void make_block(BlockMakeData *data)
1272 //dstream<<"makeBlock: no-op"<<std::endl;
1276 assert(data->vmanip);
1277 assert(data->nodedef);
1278 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1279 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1280 data->blockpos_requested.Z >= data->blockpos_min.Z);
1281 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1282 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1283 data->blockpos_requested.Z <= data->blockpos_max.Z);
1285 INodeDefManager *ndef = data->nodedef;
1287 // Hack: use minimum block coordinates for old code that assumes
1289 v3s16 blockpos = data->blockpos_requested;
1291 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1292 <<blockpos.Z<<")"<<std::endl;*/
1294 v3s16 blockpos_min = data->blockpos_min;
1295 v3s16 blockpos_max = data->blockpos_max;
1296 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1297 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1299 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1300 // Area of central chunk
1301 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1302 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1303 // Full allocated area
1304 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1305 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1307 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1309 const s16 max_spread_amount = MAP_BLOCKSIZE;
1311 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1312 * (blockpos_max.Y - blockpos_min.Y + 1)
1313 * (blockpos_max.Z - blockpos_max.Z + 1);
1315 int volume_nodes = volume_blocks *
1316 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1318 // Generated surface area
1319 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1321 // Horribly wrong heuristic, but better than nothing
1322 bool block_is_underground = (WATER_LEVEL /* local minimum ground level */ >
1323 MAP_BLOCKSIZE * (data->blockpos_max.X
1324 - data->blockpos_min.X + 1) / 2);
1327 Create a block-specific seed
1329 /*u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1330 + full_node_min.Y*42123 + full_node_min.X*23;*/
1333 Cache some ground type values for speed
1336 // Creates variables c_name=id and n_name=node
1337 #define CONTENT_VARIABLE(ndef, name)\
1338 content_t c_##name = ndef->getId(#name);\
1339 MapNode n_##name(c_##name);
1341 CONTENT_VARIABLE(ndef, stone);
1342 CONTENT_VARIABLE(ndef, air);
1343 CONTENT_VARIABLE(ndef, water_source);
1344 CONTENT_VARIABLE(ndef, dirt);
1345 CONTENT_VARIABLE(ndef, sand);
1346 CONTENT_VARIABLE(ndef, gravel);
1347 CONTENT_VARIABLE(ndef, clay);
1348 CONTENT_VARIABLE(ndef, lava_source);
1349 CONTENT_VARIABLE(ndef, cobble);
1350 CONTENT_VARIABLE(ndef, mossycobble);
1351 CONTENT_VARIABLE(ndef, dirt_with_grass);
1352 CONTENT_VARIABLE(ndef, junglegrass);
1353 CONTENT_VARIABLE(ndef, stone_with_coal);
1354 CONTENT_VARIABLE(ndef, stone_with_iron);
1355 CONTENT_VARIABLE(ndef, mese);
1357 // Maximum height of the stone surface and obstacles.
1358 // This is used to guide the cave generation
1359 s16 stone_surface_max_y = 0;
1362 Generate general ground level to full area
1366 TimeTaker timer1("Generating ground level");
1368 for(s16 x=node_min.X; x<=node_max.X; x++)
1369 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1372 v2s16 p2d = v2s16(x,z);
1375 Skip of already generated
1378 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1379 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1383 // Ground height at this point
1384 float surface_y_f = 0.0;
1386 // Use perlin noise for ground height
1387 surface_y_f = base_rock_level_2d(data->seed, p2d);
1389 /*// Experimental stuff
1391 float a = highlands_level_2d(data->seed, p2d);
1396 // Convert to integer
1397 s16 surface_y = (s16)surface_y_f;
1400 if(surface_y > stone_surface_max_y)
1401 stone_surface_max_y = surface_y;
1404 Fill ground with stone
1407 // Use fast index incrementing
1408 v3s16 em = vmanip.m_area.getExtent();
1409 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1410 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1413 vmanip.m_data[i] = MapNode(c_stone);
1414 else if(y <= WATER_LEVEL)
1415 vmanip.m_data[i] = MapNode(c_water_source);
1417 vmanip.m_data[i] = MapNode(c_air);
1419 vmanip.m_area.add_y(em, i, 1);
1427 // Limit dirt flow area by 1 because mud is flown into neighbors.
1428 assert(central_area_size.X == central_area_size.Z);
1429 s16 mudflow_minpos = 0-max_spread_amount+1;
1430 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1433 Loop this part, it will make stuff look older and newer nicely
1436 const u32 age_loops = 2;
1437 for(u32 i_age=0; i_age<age_loops; i_age++)
1439 /******************************
1440 BEGINNING OF AGING LOOP
1441 ******************************/
1446 //TimeTaker timer1("caves");
1449 Make caves (this code is relatively horrible)
1451 u32 caves_count = volume_nodes / 100000 + 1;
1452 u32 bruises_count = volume_nodes * stone_surface_max_y / 40000000;
1453 if(stone_surface_max_y < WATER_LEVEL - 20)
1455 /*u32 caves_count = 0;
1456 u32 bruises_count = 0;*/
1457 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1459 s16 min_tunnel_diameter = 2;
1460 s16 max_tunnel_diameter = 5;
1461 u16 tunnel_routepoints = 20;
1463 v3f main_direction(0,0,0);
1465 bool bruise_surface = (jj > caves_count);
1469 min_tunnel_diameter = 5;
1470 max_tunnel_diameter = myrand_range(10, myrand_range(30,50));
1471 /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
1472 max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
1474 /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(data->seed+42,
1475 data->sectorpos_base.X, data->sectorpos_base.Y)), 0, 15);*/
1477 tunnel_routepoints = 5;
1483 // Allowed route area size in nodes
1484 v3s16 ar = central_area_size;
1486 // Area starting point in nodes
1487 v3s16 of = node_min;
1490 //(this should be more than the maximum radius of the tunnel)
1491 //s16 insure = 5; // Didn't work with max_d = 20
1493 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1494 ar += v3s16(1,0,1) * more * 2;
1495 of -= v3s16(1,0,1) * more;
1497 s16 route_y_min = 0;
1498 // Allow half a diameter + 7 over stone surface
1499 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1501 /*// If caves, don't go through surface too often
1502 if(bruise_surface == false)
1503 route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
1505 // Limit maximum to area
1506 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1510 /*// Minimum is at y=0
1511 route_y_min = -of.Y - 0;*/
1512 // Minimum is at y=max_tunnel_diameter/4
1513 //route_y_min = -of.Y + max_tunnel_diameter/4;
1514 //s16 min = -of.Y + max_tunnel_diameter/4;
1515 s16 min = -of.Y + 0;
1516 route_y_min = myrand_range(min, min + max_tunnel_diameter);
1517 route_y_min = rangelim(route_y_min, 0, route_y_max);
1520 /*dstream<<"route_y_min = "<<route_y_min
1521 <<", route_y_max = "<<route_y_max<<std::endl;*/
1523 s16 route_start_y_min = route_y_min;
1524 s16 route_start_y_max = route_y_max;
1526 // Start every 4th cave from surface when applicable
1527 bool coming_from_surface = false;
1528 if(node_min.Y <= 0 && node_max.Y >= 0){
1529 coming_from_surface = (jj % 4 == 0 && bruise_surface == false);
1530 if(coming_from_surface)
1531 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1534 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1535 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1537 // Randomize starting position
1539 (float)(myrand()%ar.X)+0.5,
1540 (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
1541 (float)(myrand()%ar.Z)+0.5
1544 MapNode airnode(CONTENT_AIR);
1547 Generate some tunnel starting from orp
1550 for(u16 j=0; j<tunnel_routepoints; j++)
1552 if(j%7==0 && bruise_surface == false)
1554 main_direction = v3f(
1555 ((float)(myrand()%20)-(float)10)/10,
1556 ((float)(myrand()%20)-(float)10)/30,
1557 ((float)(myrand()%20)-(float)10)/10
1559 main_direction *= (float)myrand_range(1, 3);
1563 s16 min_d = min_tunnel_diameter;
1564 s16 max_d = max_tunnel_diameter;
1565 s16 rs = myrand_range(min_d, max_d);
1570 maxlen = v3s16(rs*7,rs*7,rs*7);
1574 maxlen = v3s16(rs*4, myrand_range(1, rs*3), rs*4);
1579 if(coming_from_surface && j < 3)
1582 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
1583 (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
1584 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
1590 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
1591 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
1592 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
1596 vec += main_direction;
1601 else if(rp.X >= ar.X)
1603 if(rp.Y < route_y_min)
1605 else if(rp.Y >= route_y_max)
1606 rp.Y = route_y_max-1;
1609 else if(rp.Z >= ar.Z)
1613 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1615 v3f fp = orp + vec * f;
1616 v3s16 cp(fp.X, fp.Y, fp.Z);
1619 s16 d1 = d0 + rs - 1;
1620 for(s16 z0=d0; z0<=d1; z0++)
1622 //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
1623 s16 si = rs - MYMAX(0, abs(z0)-rs/7);
1624 for(s16 x0=-si; x0<=si-1; x0++)
1626 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1627 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
1628 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
1629 //s16 si2 = rs - abs(x0);
1630 for(s16 y0=-si2; y0<=si2-1; y0++)
1632 // Make better floors
1633 if(y0 < -rs + 1 && abs(x0)<=1 && abs(z0)<=1)
1640 /*if(isInArea(p, ar) == false)
1642 // Check only height
1643 if(y < 0 || y >= ar.Y)
1647 //assert(vmanip.m_area.contains(p));
1648 if(vmanip.m_area.contains(p) == false)
1650 dstream<<"WARNING: "<<__FUNCTION_NAME
1651 <<":"<<__LINE__<<": "
1652 <<"point not in area"
1657 // Just set it to air, it will be changed to
1659 u32 i = vmanip.m_area.index(p);
1660 vmanip.m_data[i] = airnode;
1662 if(bruise_surface == false)
1665 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1683 TimeTaker timer1("add mud");
1686 Add mud to the central chunk
1689 for(s16 x=node_min.X; x<=node_max.X; x++)
1690 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1692 // Node position in 2d
1693 v2s16 p2d = v2s16(x,z);
1695 // Randomize mud amount
1696 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0;
1698 // Find ground level
1699 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1700 // Handle area not found
1701 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1705 If topmost node is grass, change it to mud.
1706 It might be if it was flown to there from a neighboring
1707 chunk and then converted.
1710 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1711 MapNode *n = &vmanip.m_data[i];
1712 if(n->getContent() == c_dirt_with_grass)
1713 *n = MapNode(c_dirt);
1721 v3s16 em = vmanip.m_area.getExtent();
1722 s16 y_start = surface_y+1;
1723 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1724 for(s16 y=y_start; y<=node_max.Y; y++)
1726 if(mudcount >= mud_add_amount)
1729 MapNode &n = vmanip.m_data[i];
1730 n = MapNode(c_dirt);
1733 vmanip.m_area.add_y(em, i, 1);
1745 TimeTaker timer1("flow mud");
1748 Flow mud away from steep edges
1751 // Iterate a few times
1752 for(s16 k=0; k<3; k++)
1755 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1756 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1758 // Invert coordinates every 2nd iteration
1761 x = mudflow_maxpos - (x-mudflow_minpos);
1762 z = mudflow_maxpos - (z-mudflow_minpos);
1765 // Node position in 2d
1766 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1768 v3s16 em = vmanip.m_area.getExtent();
1769 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1776 for(; y>=node_min.Y; y--)
1778 n = &vmanip.m_data[i];
1779 //if(content_walkable(n->d))
1781 if(n->getContent() == c_dirt ||
1782 n->getContent() == c_dirt_with_grass)
1785 vmanip.m_area.add_y(em, i, -1);
1788 // Stop if out of area
1789 //if(vmanip.m_area.contains(i) == false)
1793 /*// If not mud, do nothing to it
1794 MapNode *n = &vmanip.m_data[i];
1795 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1799 Don't flow it if the stuff under it is not mud
1803 vmanip.m_area.add_y(em, i2, -1);
1804 // Cancel if out of area
1805 if(vmanip.m_area.contains(i2) == false)
1807 MapNode *n2 = &vmanip.m_data[i2];
1808 if(n2->getContent() != c_dirt &&
1809 n2->getContent() != c_dirt_with_grass)
1813 // Make it exactly mud
1814 n->setContent(c_dirt);
1816 /*s16 recurse_count = 0;
1820 v3s16(0,0,1), // back
1821 v3s16(1,0,0), // right
1822 v3s16(0,0,-1), // front
1823 v3s16(-1,0,0), // left
1826 // Theck that upper is air or doesn't exist.
1827 // Cancel dropping if upper keeps it in place
1829 vmanip.m_area.add_y(em, i3, 1);
1830 if(vmanip.m_area.contains(i3) == true
1831 && ndef->get(vmanip.m_data[i3]).walkable)
1838 for(u32 di=0; di<4; di++)
1840 v3s16 dirp = dirs4[di];
1843 vmanip.m_area.add_p(em, i2, dirp);
1844 // Fail if out of area
1845 if(vmanip.m_area.contains(i2) == false)
1847 // Check that side is air
1848 MapNode *n2 = &vmanip.m_data[i2];
1849 if(ndef->get(*n2).walkable)
1851 // Check that under side is air
1852 vmanip.m_area.add_y(em, i2, -1);
1853 if(vmanip.m_area.contains(i2) == false)
1855 n2 = &vmanip.m_data[i2];
1856 if(ndef->get(*n2).walkable)
1858 /*// Check that under that is air (need a drop of 2)
1859 vmanip.m_area.add_y(em, i2, -1);
1860 if(vmanip.m_area.contains(i2) == false)
1862 n2 = &vmanip.m_data[i2];
1863 if(content_walkable(n2->d))
1865 // Loop further down until not air
1866 bool dropped_to_unknown = false;
1868 vmanip.m_area.add_y(em, i2, -1);
1869 n2 = &vmanip.m_data[i2];
1870 // if out of known area
1871 if(vmanip.m_area.contains(i2) == false
1872 || n2->getContent() == CONTENT_IGNORE){
1873 dropped_to_unknown = true;
1876 }while(ndef->get(*n2).walkable == false);
1877 // Loop one up so that we're in air
1878 vmanip.m_area.add_y(em, i2, 1);
1879 n2 = &vmanip.m_data[i2];
1881 bool old_is_water = (n->getContent() == c_water_source);
1882 // Move mud to new place
1883 if(!dropped_to_unknown)
1885 // Set old place to be air (or water)
1887 *n = MapNode(c_water_source);
1889 *n = MapNode(CONTENT_AIR);
1903 /***********************
1905 ************************/
1908 Add top and bottom side of water to transforming_liquid queue
1911 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1912 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1917 bool water_found = false;
1918 // Use fast index incrementing
1919 v3s16 em = vmanip.m_area.getExtent();
1920 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1921 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1923 if(water_found == false)
1925 if(vmanip.m_data[i].getContent() == c_water_source)
1927 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1928 data->transforming_liquid.push_back(p);
1934 // This can be done because water_found can only
1935 // turn to true and end up here after going through
1937 if(vmanip.m_data[i+1].getContent() != c_water_source)
1939 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1940 data->transforming_liquid.push_back(p);
1941 water_found = false;
1945 vmanip.m_area.add_y(em, i, -1);
1954 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1955 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1957 // Node position in 2d
1958 v2s16 p2d = v2s16(x,z);
1961 Find the lowest surface to which enough light ends up
1964 Basically just wait until not air and not leaves.
1968 v3s16 em = vmanip.m_area.getExtent();
1969 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1971 // Go to ground level
1972 for(y=node_max.Y; y>=full_node_min.Y; y--)
1974 MapNode &n = vmanip.m_data[i];
1975 if(ndef->get(n).param_type != CPT_LIGHT
1976 || ndef->get(n).liquid_type != LIQUID_NONE)
1978 vmanip.m_area.add_y(em, i, -1);
1980 if(y >= full_node_min.Y)
1983 surface_y = full_node_min.Y;
1986 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
1987 MapNode *n = &vmanip.m_data[i];
1988 if(n->getContent() == c_dirt)
1989 n->setContent(c_dirt_with_grass);
1995 assert(central_area_size.X == central_area_size.Z);
1997 // Divide area into parts
1999 s16 sidelen = central_area_size.X / div;
2000 double area = sidelen * sidelen;
2001 for(s16 x0=0; x0<div; x0++)
2002 for(s16 z0=0; z0<div; z0++)
2004 // Center position of part of division
2006 node_min.X + sidelen/2 + sidelen*x0,
2007 node_min.Z + sidelen/2 + sidelen*z0
2009 // Minimum edge of part of division
2011 node_min.X + sidelen*x0,
2012 node_min.Z + sidelen*z0
2014 // Maximum edge of part of division
2016 node_min.X + sidelen + sidelen*x0 - 1,
2017 node_min.Z + sidelen + sidelen*z0 - 1
2020 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2021 // Put trees in random places on part of division
2022 for(u32 i=0; i<tree_count; i++)
2024 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2025 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2026 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2027 // Don't make a tree under water level
2030 // Don't make a tree so high that it doesn't fit
2031 if(y > node_max.Y - 6)
2035 Trees grow only on mud and grass
2038 u32 i = vmanip.m_area.index(v3s16(p));
2039 MapNode *n = &vmanip.m_data[i];
2040 if(n->getContent() != c_dirt
2041 && n->getContent() != c_dirt_with_grass)
2046 make_tree(vmanip, p, false, ndef);
2053 Make base ground level
2056 for(s16 x=node_min.X; x<=node_max.X; x++)
2057 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2062 // Use fast index incrementing
2063 v3s16 em = vmanip.m_area.getExtent();
2064 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2065 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2067 // Only modify places that have no content
2068 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2070 // First priority: make air and water.
2071 // This avoids caves inside water.
2072 if(all_is_ground_except_caves == false
2073 && val_is_ground(noisebuf_ground.get(x,y,z),
2074 v3s16(x,y,z), data->seed) == false)
2076 if(y <= WATER_LEVEL)
2077 vmanip.m_data[i] = n_water_source;
2079 vmanip.m_data[i] = n_air;
2081 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2082 vmanip.m_data[i] = n_air;
2084 vmanip.m_data[i] = n_stone;
2087 vmanip->m_area.add_y(em, i, 1);
2093 Add mud and sand and others underground (in place of stone)
2096 for(s16 x=node_min.X; x<=node_max.X; x++)
2097 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2102 // Use fast index incrementing
2103 v3s16 em = vmanip.m_area.getExtent();
2104 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2105 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2107 if(vmanip.m_data[i].getContent() == c_stone)
2109 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2111 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2112 vmanip.m_data[i] = n_dirt;
2114 vmanip.m_data[i] = n_sand;
2116 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2118 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2119 vmanip.m_data[i] = n_gravel;
2121 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2122 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2124 vmanip.m_data[i] = n_lava_source;
2125 for(s16 x1=-1; x1<=1; x1++)
2126 for(s16 y1=-1; y1<=1; y1++)
2127 for(s16 z1=-1; z1<=1; z1++)
2128 data->transforming_liquid.push_back(
2129 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2133 vmanip->m_area.add_y(em, i, -1);
2142 //if(node_min.Y < approx_groundlevel)
2143 //if(myrand() % 3 == 0)
2144 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2145 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2146 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2147 float dungeon_rarity = 0.02;
2148 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2150 && node_min.Y < approx_groundlevel)
2152 // Dungeon generator doesn't modify places which have this set
2153 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2154 | VMANIP_FLAG_DUNGEON_PRESERVE);
2156 // Set all air and water to be untouchable to make dungeons open
2157 // to caves and open air
2158 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2159 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2164 // Use fast index incrementing
2165 v3s16 em = vmanip.m_area.getExtent();
2166 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2167 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2169 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2170 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2171 else if(vmanip.m_data[i].getContent() == c_water_source)
2172 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2173 vmanip->m_area.add_y(em, i, -1);
2178 PseudoRandom random(blockseed+2);
2181 make_dungeon1(vmanip, random, ndef);
2183 // Convert some cobble to mossy cobble
2184 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2185 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2190 // Use fast index incrementing
2191 v3s16 em = vmanip.m_area.getExtent();
2192 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2193 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2195 // (noisebuf not used because it doesn't contain the
2197 double wetness = noise3d_param(
2198 get_ground_wetness_params(data->seed), x,y,z);
2199 double d = noise3d_perlin((float)x/2.5,
2200 (float)y/2.5,(float)z/2.5,
2202 if(vmanip.m_data[i].getContent() == c_cobble)
2206 vmanip.m_data[i].setContent(c_mossycobble);
2209 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2212 vmanip.m_data[i].setContent(c_dirt);
2214 vmanip->m_area.add_y(em, i, -1);
2224 PseudoRandom ncrandom(blockseed+9324342);
2225 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2227 make_nc(vmanip, ncrandom, ndef);
2232 Add top and bottom side of water to transforming_liquid queue
2235 for(s16 x=node_min.X; x<=node_max.X; x++)
2236 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2241 bool water_found = false;
2242 // Use fast index incrementing
2243 v3s16 em = vmanip.m_area.getExtent();
2244 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2245 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2247 if(water_found == false)
2249 if(vmanip.m_data[i].getContent() == c_water_source)
2251 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2252 data->transforming_liquid.push_back(p);
2258 // This can be done because water_found can only
2259 // turn to true and end up here after going through
2261 if(vmanip.m_data[i+1].getContent() != c_water_source)
2263 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2264 data->transforming_liquid.push_back(p);
2265 water_found = false;
2269 vmanip->m_area.add_y(em, i, -1);
2275 If close to ground level
2278 //if(abs(approx_ground_depth) < 30)
2279 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2285 for(s16 x=node_min.X; x<=node_max.X; x++)
2286 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2291 bool possibly_have_sand = get_have_sand(data->seed, p2d);
2292 bool have_sand = false;
2293 u32 current_depth = 0;
2294 bool air_detected = false;
2295 bool water_detected = false;
2296 bool have_clay = false;
2298 // Use fast index incrementing
2299 s16 start_y = node_max.Y+2;
2300 v3s16 em = vmanip.m_area.getExtent();
2301 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2302 for(s16 y=start_y; y>=node_min.Y-3; y--)
2304 if(vmanip.m_data[i].getContent() == c_water_source)
2305 water_detected = true;
2306 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2307 air_detected = true;
2309 if((vmanip.m_data[i].getContent() == c_stone
2310 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2311 || vmanip.m_data[i].getContent() == c_dirt
2312 || vmanip.m_data[i].getContent() == c_sand
2313 || vmanip.m_data[i].getContent() == c_gravel
2314 ) && (air_detected || water_detected))
2316 if(current_depth == 0 && y <= WATER_LEVEL+2
2317 && possibly_have_sand)
2320 if(current_depth < 4)
2324 // Determine whether to have clay in the sand here
2325 double claynoise = noise2d_perlin(
2326 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2327 data->seed+4321, 6, 0.95) + 0.5;
2329 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2330 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2331 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2334 vmanip.m_data[i] = MapNode(c_clay);
2336 vmanip.m_data[i] = MapNode(c_sand);
2339 else if(current_depth==0 && !water_detected
2340 && y >= WATER_LEVEL && air_detected)
2341 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2344 vmanip.m_data[i] = MapNode(c_dirt);
2348 if(vmanip.m_data[i].getContent() == c_dirt
2349 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2350 vmanip.m_data[i] = MapNode(c_stone);
2355 if(current_depth >= 8)
2358 else if(current_depth != 0)
2361 vmanip->m_area.add_y(em, i, -1);
2367 Calculate some stuff
2370 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2371 bool is_jungle = surface_humidity > 0.75;
2373 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2380 PseudoRandom treerandom(blockseed);
2381 // Put trees in random places on part of division
2382 for(u32 i=0; i<tree_count; i++)
2384 s16 x = treerandom.range(node_min.X, node_max.X);
2385 s16 z = treerandom.range(node_min.Z, node_max.Z);
2386 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2387 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2388 // Don't make a tree under water level
2391 // Make sure tree fits (only trees whose starting point is
2392 // at this block are added)
2393 if(y < node_min.Y || y > node_max.Y)
2396 Find exact ground level
2400 for(; p.Y >= y-6; p.Y--)
2402 u32 i = vmanip->m_area.index(p);
2403 MapNode *n = &vmanip->m_data[i];
2404 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2410 // If not found, handle next one
2415 u32 i = vmanip->m_area.index(p);
2416 MapNode *n = &vmanip->m_data[i];
2418 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2421 // Papyrus grows only on mud and in water
2422 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2425 make_papyrus(vmanip, p, ndef);
2427 // Trees grow only on mud and grass, on land
2428 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2431 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2432 if(is_jungle == false)
2435 if(myrand_range(0,4) != 0)
2436 is_apple_tree = false;
2438 is_apple_tree = noise2d_perlin(
2439 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2440 data->seed+342902, 3, 0.45) > 0.2;
2441 make_tree(vmanip, p, is_apple_tree, ndef);
2444 make_jungletree(vmanip, p, ndef);
2446 // Cactii grow only on sand, on land
2447 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2450 make_cactus(vmanip, p, ndef);
2460 PseudoRandom grassrandom(blockseed);
2461 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2463 s16 x = grassrandom.range(node_min.X, node_max.X);
2464 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2465 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2468 if(y < node_min.Y || y > node_max.Y)
2471 Find exact ground level
2475 for(; p.Y >= y-6; p.Y--)
2477 u32 i = vmanip->m_area.index(p);
2478 MapNode *n = &vmanip->m_data[i];
2479 if(data->nodedef->get(*n).is_ground_content)
2485 // If not found, handle next one
2489 if(vmanip.m_area.contains(p) == false)
2491 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2494 if(vmanip.m_area.contains(p))
2495 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2497 if(vmanip.m_area.contains(p))
2498 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2504 Add some kind of random stones
2507 u32 random_stone_count = gen_area_nodes *
2508 randomstone_amount_2d(data->seed, p2d_center);
2509 // Put in random places on part of division
2510 for(u32 i=0; i<random_stone_count; i++)
2512 s16 x = myrand_range(node_min.X, node_max.X);
2513 s16 z = myrand_range(node_min.Z, node_max.Z);
2514 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2515 // Don't add under water level
2516 /*if(y < WATER_LEVEL)
2518 // Don't add if doesn't belong to this block
2519 if(y < node_min.Y || y > node_max.Y)
2524 u32 i = vmanip->m_area.index(v3s16(p));
2525 MapNode *n = &vmanip->m_data[i];
2526 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2529 // Will be placed one higher
2532 make_randomstone(vmanip, p);
2541 u32 large_stone_count = gen_area_nodes *
2542 largestone_amount_2d(data->seed, p2d_center);
2543 //u32 large_stone_count = 1;
2544 // Put in random places on part of division
2545 for(u32 i=0; i<large_stone_count; i++)
2547 s16 x = myrand_range(node_min.X, node_max.X);
2548 s16 z = myrand_range(node_min.Z, node_max.Z);
2549 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2550 // Don't add under water level
2551 /*if(y < WATER_LEVEL)
2553 // Don't add if doesn't belong to this block
2554 if(y < node_min.Y || y > node_max.Y)
2559 u32 i = vmanip->m_area.index(v3s16(p));
2560 MapNode *n = &vmanip->m_data[i];
2561 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2564 // Will be placed one lower
2567 make_largestone(vmanip, p);
2577 PseudoRandom mineralrandom(blockseed);
2582 for(s16 i=0; i<approx_ground_depth/4; i++)
2584 if(mineralrandom.next()%50 == 0)
2586 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2587 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2588 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2589 for(u16 i=0; i<27; i++)
2591 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2592 u32 vi = vmanip.m_area.index(p);
2593 if(vmanip.m_data[vi].getContent() == c_stone)
2594 if(mineralrandom.next()%8 == 0)
2595 vmanip.m_data[vi] = MapNode(c_mese);
2604 u16 a = mineralrandom.range(0,15);
2606 u16 amount = 20 * a/1000;
2607 for(s16 i=0; i<amount; i++)
2609 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2610 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2611 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2613 u8 base_content = c_stone;
2614 MapNode new_content(CONTENT_IGNORE);
2617 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2619 new_content = MapNode(c_stone_with_coal);
2623 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2624 new_content = MapNode(c_stone_with_iron);
2625 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2626 vmanip.m_data[i] = MapNode(c_dirt);
2628 vmanip.m_data[i] = MapNode(c_sand);*/
2630 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2634 if(new_content.getContent() != CONTENT_IGNORE)
2636 for(u16 i=0; i<27; i++)
2638 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2639 u32 vi = vmanip.m_area.index(p);
2640 if(vmanip.m_data[vi].getContent() == base_content)
2642 if(mineralrandom.next()%sparseness == 0)
2643 vmanip.m_data[vi] = new_content;
2652 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2653 //for(s16 i=0; i<50; i++)
2654 u16 coal_amount = 30;
2655 u16 coal_rareness = 60 / coal_amount;
2656 if(coal_rareness == 0)
2658 if(mineralrandom.next()%coal_rareness == 0)
2660 u16 a = mineralrandom.next() % 16;
2661 u16 amount = coal_amount * a*a*a / 1000;
2662 for(s16 i=0; i<amount; i++)
2664 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2665 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2666 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2667 for(u16 i=0; i<27; i++)
2669 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2670 u32 vi = vmanip.m_area.index(p);
2671 if(vmanip.m_data[vi].getContent() == c_stone)
2672 if(mineralrandom.next()%8 == 0)
2673 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2680 u16 iron_amount = 8;
2681 u16 iron_rareness = 60 / iron_amount;
2682 if(iron_rareness == 0)
2684 if(mineralrandom.next()%iron_rareness == 0)
2686 u16 a = mineralrandom.next() % 16;
2687 u16 amount = iron_amount * a*a*a / 1000;
2688 for(s16 i=0; i<amount; i++)
2690 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2691 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2692 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2693 for(u16 i=0; i<27; i++)
2695 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2696 u32 vi = vmanip.m_area.index(p);
2697 if(vmanip.m_data[vi].getContent() == c_stone)
2698 if(mineralrandom.next()%8 == 0)
2699 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2710 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2712 //VoxelArea a(node_min, node_max);
2713 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2714 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2715 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2716 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2717 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2718 for(int i=0; i<2; i++)
2720 enum LightBank bank = banks[i];
2722 core::map<v3s16, bool> light_sources;
2723 core::map<v3s16, u8> unlight_from;
2725 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2726 light_sources, unlight_from);
2728 bool inexistent_top_provides_sunlight = !block_is_underground;
2729 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2730 vmanip, a, inexistent_top_provides_sunlight,
2731 light_sources, ndef);
2732 // TODO: Do stuff according to bottom_sunlight_valid
2734 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2736 vmanip.spreadLight(bank, light_sources, ndef);
2741 BlockMakeData::BlockMakeData():
2748 BlockMakeData::~BlockMakeData()
2753 }; // namespace mapgen