3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
37 Some helper functions for the map generator
41 // Returns Y one under area minimum if not found
42 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
43 INodeDefManager *ndef)
45 v3s16 em = vmanip.m_area.getExtent();
46 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
47 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
48 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
50 for(y=y_nodes_max; y>=y_nodes_min; y--)
52 MapNode &n = vmanip.m_data[i];
53 if(ndef->get(n).walkable)
56 vmanip.m_area.add_y(em, i, -1);
61 return y_nodes_min - 1;
64 // Returns Y one under area minimum if not found
65 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
66 INodeDefManager *ndef)
68 v3s16 em = vmanip.m_area.getExtent();
69 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
70 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
71 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
73 content_t c_tree = LEGN(ndef, "CONTENT_TREE");
74 content_t c_leaves = LEGN(ndef, "CONTENT_LEAVES");
75 for(y=y_nodes_max; y>=y_nodes_min; y--)
77 MapNode &n = vmanip.m_data[i];
78 if(ndef->get(n).walkable
79 && n.getContent() != c_tree
80 && n.getContent() != c_leaves)
83 vmanip.m_area.add_y(em, i, -1);
88 return y_nodes_min - 1;
91 // Returns Y one under area minimum if not found
92 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
93 INodeDefManager *ndef)
95 v3s16 em = vmanip.m_area.getExtent();
96 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
97 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
98 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
100 content_t c_stone = LEGN(ndef, "CONTENT_STONE");
101 for(y=y_nodes_max; y>=y_nodes_min; y--)
103 MapNode &n = vmanip.m_data[i];
104 if(n.getContent() == c_stone)
107 vmanip.m_area.add_y(em, i, -1);
112 return y_nodes_min - 1;
116 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
117 bool is_apple_tree, INodeDefManager *ndef)
119 MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
120 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
121 MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
123 s16 trunk_h = myrand_range(4, 5);
125 for(s16 ii=0; ii<trunk_h; ii++)
127 if(vmanip.m_area.contains(p1))
128 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
132 // p1 is now the last piece of the trunk
135 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
136 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
137 Buffer<u8> leaves_d(leaves_a.getVolume());
138 for(s32 i=0; i<leaves_a.getVolume(); i++)
141 // Force leaves at near the end of the trunk
144 for(s16 z=-d; z<=d; z++)
145 for(s16 y=-d; y<=d; y++)
146 for(s16 x=-d; x<=d; x++)
148 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
152 // Add leaves randomly
153 for(u32 iii=0; iii<7; iii++)
158 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
159 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
160 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
163 for(s16 z=0; z<=d; z++)
164 for(s16 y=0; y<=d; y++)
165 for(s16 x=0; x<=d; x++)
167 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
171 // Blit leaves to vmanip
172 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
173 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
174 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
178 if(vmanip.m_area.contains(p) == false)
180 u32 vi = vmanip.m_area.index(p);
181 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
182 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
184 u32 i = leaves_a.index(x,y,z);
185 if(leaves_d[i] == 1) {
186 bool is_apple = myrand_range(0,99) < 10;
187 if(is_apple_tree && is_apple) {
188 vmanip.m_data[vi] = applenode;
190 vmanip.m_data[vi] = leavesnode;
196 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
197 INodeDefManager *ndef)
199 MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
200 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
202 for(s16 x=-1; x<=1; x++)
203 for(s16 z=-1; z<=1; z++)
205 if(myrand_range(0, 2) == 0)
207 v3s16 p1 = p0 + v3s16(x,0,z);
208 v3s16 p2 = p0 + v3s16(x,-1,z);
209 if(vmanip.m_area.contains(p2)
210 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
211 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
212 else if(vmanip.m_area.contains(p1))
213 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
216 s16 trunk_h = myrand_range(8, 12);
218 for(s16 ii=0; ii<trunk_h; ii++)
220 if(vmanip.m_area.contains(p1))
221 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
225 // p1 is now the last piece of the trunk
228 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
229 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
230 Buffer<u8> leaves_d(leaves_a.getVolume());
231 for(s32 i=0; i<leaves_a.getVolume(); i++)
234 // Force leaves at near the end of the trunk
237 for(s16 z=-d; z<=d; z++)
238 for(s16 y=-d; y<=d; y++)
239 for(s16 x=-d; x<=d; x++)
241 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
245 // Add leaves randomly
246 for(u32 iii=0; iii<30; iii++)
251 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
252 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
253 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
256 for(s16 z=0; z<=d; z++)
257 for(s16 y=0; y<=d; y++)
258 for(s16 x=0; x<=d; x++)
260 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
264 // Blit leaves to vmanip
265 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
266 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
267 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
271 if(vmanip.m_area.contains(p) == false)
273 u32 vi = vmanip.m_area.index(p);
274 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
275 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
277 u32 i = leaves_a.index(x,y,z);
279 vmanip.m_data[vi] = leavesnode;
283 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
284 INodeDefManager *ndef)
286 MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
288 s16 trunk_h = myrand_range(2, 3);
290 for(s16 ii=0; ii<trunk_h; ii++)
292 if(vmanip.m_area.contains(p1))
293 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
298 void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
299 INodeDefManager *ndef)
301 MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
305 for(s16 ii=0; ii<trunk_h; ii++)
307 if(vmanip.m_area.contains(p1))
308 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
314 Dungeon making routines
317 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
318 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
319 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
320 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
322 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
323 INodeDefManager *ndef)
326 for(s16 z=0; z<roomsize.Z; z++)
327 for(s16 y=0; y<roomsize.Y; y++)
330 v3s16 p = roomplace + v3s16(0,y,z);
331 if(vmanip.m_area.contains(p) == false)
333 u32 vi = vmanip.m_area.index(p);
334 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
336 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
339 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
340 if(vmanip.m_area.contains(p) == false)
342 u32 vi = vmanip.m_area.index(p);
343 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
345 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
350 for(s16 x=0; x<roomsize.X; x++)
351 for(s16 y=0; y<roomsize.Y; y++)
354 v3s16 p = roomplace + v3s16(x,y,0);
355 if(vmanip.m_area.contains(p) == false)
357 u32 vi = vmanip.m_area.index(p);
358 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
360 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
363 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
364 if(vmanip.m_area.contains(p) == false)
366 u32 vi = vmanip.m_area.index(p);
367 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
369 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
373 // Make +-Y walls (floor and ceiling)
374 for(s16 z=0; z<roomsize.Z; z++)
375 for(s16 x=0; x<roomsize.X; x++)
378 v3s16 p = roomplace + v3s16(x,0,z);
379 if(vmanip.m_area.contains(p) == false)
381 u32 vi = vmanip.m_area.index(p);
382 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
384 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
387 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
388 if(vmanip.m_area.contains(p) == false)
390 u32 vi = vmanip.m_area.index(p);
391 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
393 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
398 for(s16 z=1; z<roomsize.Z-1; z++)
399 for(s16 y=1; y<roomsize.Y-1; y++)
400 for(s16 x=1; x<roomsize.X-1; x++)
402 v3s16 p = roomplace + v3s16(x,y,z);
403 if(vmanip.m_area.contains(p) == false)
405 u32 vi = vmanip.m_area.index(p);
406 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
407 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
411 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
412 u8 avoid_flags, MapNode n, u8 or_flags)
414 for(s16 z=0; z<size.Z; z++)
415 for(s16 y=0; y<size.Y; y++)
416 for(s16 x=0; x<size.X; x++)
418 v3s16 p = place + v3s16(x,y,z);
419 if(vmanip.m_area.contains(p) == false)
421 u32 vi = vmanip.m_area.index(p);
422 if(vmanip.m_flags[vi] & avoid_flags)
424 vmanip.m_flags[vi] |= or_flags;
425 vmanip.m_data[vi] = n;
429 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
430 INodeDefManager *ndef)
432 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
433 VMANIP_FLAG_DUNGEON_INSIDE);
436 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
437 INodeDefManager *ndef)
439 make_hole1(vmanip, doorplace, ndef);
440 // Place torch (for testing)
441 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
444 static v3s16 rand_ortho_dir(PseudoRandom &random)
446 if(random.next()%2==0)
447 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
449 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
452 static v3s16 turn_xz(v3s16 olddir, int t)
472 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
474 int turn = random.range(0,2);
483 dir = turn_xz(olddir, 0);
486 dir = turn_xz(olddir, 1);
490 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
491 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
492 PseudoRandom &random, INodeDefManager *ndef)
494 make_hole1(vmanip, doorplace, ndef);
495 v3s16 p0 = doorplace;
499 length = random.range(1,13);
501 length = random.range(1,6);
502 length = random.range(1,13);
503 u32 partlength = random.range(1,13);
506 if(random.next()%2 == 0 && partlength >= 3)
507 make_stairs = random.next()%2 ? 1 : -1;
508 for(u32 i=0; i<length; i++)
514 /*// If already empty
515 if(vmanip.getNodeNoExNoEmerge(p).getContent()
517 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
522 if(vmanip.m_area.contains(p) == true
523 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
527 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
528 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
529 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
530 VMANIP_FLAG_DUNGEON_INSIDE);
531 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
532 VMANIP_FLAG_DUNGEON_INSIDE);
536 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
537 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
538 make_hole1(vmanip, p, ndef);
539 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
540 VMANIP_FLAG_DUNGEON_INSIDE);*/
547 // Can't go here, turn away
548 dir = turn_xz(dir, random.range(0,1));
549 make_stairs = -make_stairs;
551 partlength = random.range(1,length);
556 if(partcount >= partlength)
560 dir = random_turn(random, dir);
562 partlength = random.range(1,length);
565 if(random.next()%2 == 0 && partlength >= 3)
566 make_stairs = random.next()%2 ? 1 : -1;
577 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
578 INodeDefManager *ndef):
589 m_dir = rand_ortho_dir(m_random);
592 void setPos(v3s16 pos)
597 void setDir(v3s16 dir)
602 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
604 for(u32 i=0; i<100; i++)
606 v3s16 p = m_pos + m_dir;
607 v3s16 p1 = p + v3s16(0,1,0);
608 if(vmanip.m_area.contains(p) == false
609 || vmanip.m_area.contains(p1) == false
615 if(vmanip.getNodeNoExNoEmerge(p).getContent()
616 == LEGN(m_ndef, "CONTENT_COBBLE")
617 && vmanip.getNodeNoExNoEmerge(p1).getContent()
618 == LEGN(m_ndef, "CONTENT_COBBLE"))
620 // Found wall, this is a good place!
623 // Randomize next direction
628 Determine where to move next
630 // Jump one up if the actual space is there
631 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
632 == LEGN(m_ndef, "CONTENT_COBBLE")
633 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
634 == LEGN(m_ndef, "CONTENT_AIR")
635 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
636 == LEGN(m_ndef, "CONTENT_AIR"))
638 // Jump one down if the actual space is there
639 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
640 == LEGN(m_ndef, "CONTENT_COBBLE")
641 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
642 == LEGN(m_ndef, "CONTENT_AIR")
643 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
644 == LEGN(m_ndef, "CONTENT_AIR"))
646 // Check if walking is now possible
647 if(vmanip.getNodeNoExNoEmerge(p).getContent()
648 != LEGN(m_ndef, "CONTENT_AIR")
649 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
650 != LEGN(m_ndef, "CONTENT_AIR"))
652 // Cannot continue walking here
662 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
663 v3s16 &result_doordir, v3s16 &result_roomplace)
665 for(s16 trycount=0; trycount<30; trycount++)
669 bool r = findPlaceForDoor(doorplace, doordir);
673 // X east, Z north, Y up
675 if(doordir == v3s16(1,0,0)) // X+
676 roomplace = doorplace +
677 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
678 if(doordir == v3s16(-1,0,0)) // X-
679 roomplace = doorplace +
680 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
681 if(doordir == v3s16(0,0,1)) // Z+
682 roomplace = doorplace +
683 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
684 if(doordir == v3s16(0,0,-1)) // Z-
685 roomplace = doorplace +
686 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
689 if(doordir == v3s16(1,0,0)) // X+
690 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
691 if(doordir == v3s16(-1,0,0)) // X-
692 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
693 if(doordir == v3s16(0,0,1)) // Z+
694 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
695 if(doordir == v3s16(0,0,-1)) // Z-
696 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
701 for(s16 z=1; z<roomsize.Z-1; z++)
702 for(s16 y=1; y<roomsize.Y-1; y++)
703 for(s16 x=1; x<roomsize.X-1; x++)
705 v3s16 p = roomplace + v3s16(x,y,z);
706 if(vmanip.m_area.contains(p) == false)
711 if(vmanip.m_flags[vmanip.m_area.index(p)]
712 & VMANIP_FLAG_DUNGEON_INSIDE)
723 result_doorplace = doorplace;
724 result_doordir = doordir;
725 result_roomplace = roomplace;
732 VoxelManipulator &vmanip;
735 PseudoRandom &m_random;
736 INodeDefManager *m_ndef;
739 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
740 INodeDefManager *ndef)
742 v3s16 areasize = vmanip.m_area.getExtent();
747 Find place for first room
750 for(u32 i=0; i<100; i++)
752 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
753 roomplace = vmanip.m_area.MinEdge + v3s16(
754 random.range(0,areasize.X-roomsize.X-1),
755 random.range(0,areasize.Y-roomsize.Y-1),
756 random.range(0,areasize.Z-roomsize.Z-1));
758 Check that we're not putting the room to an unknown place,
759 otherwise it might end up floating in the air
762 for(s16 z=1; z<roomsize.Z-1; z++)
763 for(s16 y=1; y<roomsize.Y-1; y++)
764 for(s16 x=1; x<roomsize.X-1; x++)
766 v3s16 p = roomplace + v3s16(x,y,z);
767 u32 vi = vmanip.m_area.index(p);
768 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
773 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
787 Stores the center position of the last room made, so that
788 a new corridor can be started from the last room instead of
789 the new room, if chosen so.
791 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
793 u32 room_count = random.range(2,7);
794 for(u32 i=0; i<room_count; i++)
796 // Make a room to the determined place
797 make_room1(vmanip, roomsize, roomplace, ndef);
799 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
801 // Place torch at room center (for testing)
802 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
805 if(i == room_count-1)
808 // Determine walker start position
810 bool start_in_last_room = (random.range(0,2)!=0);
811 //bool start_in_last_room = true;
813 v3s16 walker_start_place;
815 if(start_in_last_room)
817 walker_start_place = last_room_center;
821 walker_start_place = room_center;
822 // Store center of current room as the last one
823 last_room_center = room_center;
826 // Create walker and find a place for a door
827 RoomWalker walker(vmanip, walker_start_place, random, ndef);
830 bool r = walker.findPlaceForDoor(doorplace, doordir);
834 if(random.range(0,1)==0)
836 make_door1(vmanip, doorplace, doordir, ndef);
838 // Don't actually make a door
839 doorplace -= doordir;
841 // Make a random corridor starting from the door
843 v3s16 corridor_end_dir;
844 make_corridor(vmanip, doorplace, doordir, corridor_end,
845 corridor_end_dir, random, ndef);
847 // Find a place for a random sized room
848 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
849 walker.setPos(corridor_end);
850 walker.setDir(corridor_end_dir);
851 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
855 if(random.range(0,1)==0)
857 make_door1(vmanip, doorplace, doordir, ndef);
859 // Don't actually make a door
860 roomplace -= doordir;
865 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
866 INodeDefManager *ndef)
870 s32 r = random.range(0, 3);
872 dir = v3s16( 1, 0, 0);
876 dir = v3s16(-1, 0, 0);
880 dir = v3s16( 0, 0, 1);
884 dir = v3s16( 0, 0,-1);
887 v3s16 p = vmanip.m_area.MinEdge + v3s16(
888 16+random.range(0,15),
889 16+random.range(0,15),
890 16+random.range(0,15));
891 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC"), facedir_i);
892 u32 length = random.range(3,15);
893 for(u32 j=0; j<length; j++)
896 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
901 Noise functions. Make sure seed is mangled differently in each one.
906 Scaling the output of the noise function affects the overdrive of the
907 contour function, which affects the shape of the output considerably.
909 #define CAVE_NOISE_SCALE 12.0
910 //#define CAVE_NOISE_SCALE 10.0
911 //#define CAVE_NOISE_SCALE 7.5
912 //#define CAVE_NOISE_SCALE 5.0
913 //#define CAVE_NOISE_SCALE 1.0
915 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
916 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
918 NoiseParams get_cave_noise1_params(u64 seed)
920 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
921 200, CAVE_NOISE_SCALE);*/
922 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
923 100, CAVE_NOISE_SCALE);*/
924 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
925 100, CAVE_NOISE_SCALE);*/
926 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
927 100, CAVE_NOISE_SCALE);*/
928 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
929 50, CAVE_NOISE_SCALE);
930 //return NoiseParams(NOISE_CONSTANT_ONE);
933 NoiseParams get_cave_noise2_params(u64 seed)
935 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
936 200, CAVE_NOISE_SCALE);*/
937 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
938 100, CAVE_NOISE_SCALE);*/
939 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
940 100, CAVE_NOISE_SCALE);*/
941 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
942 50, CAVE_NOISE_SCALE);
943 //return NoiseParams(NOISE_CONSTANT_ONE);
946 NoiseParams get_ground_noise1_params(u64 seed)
948 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
952 NoiseParams get_ground_crumbleness_params(u64 seed)
954 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
958 NoiseParams get_ground_wetness_params(u64 seed)
960 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
964 bool is_cave(u64 seed, v3s16 p)
966 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
967 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
968 return d1*d2 > CAVE_NOISE_THRESHOLD;
972 Ground density noise shall be interpreted by using this.
974 TODO: No perlin noises here, they should be outsourced
976 NOTE: The speed of these actually isn't terrible
978 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
980 //return ((double)p.Y < ground_noise1_val);
982 double f = 0.55 + noise2d_perlin(
983 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
984 seed+920381, 3, 0.45);
989 double h = WATER_LEVEL + 10 * noise2d_perlin(
990 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
994 return ((double)p.Y - h < ground_noise1_val * f);
998 Queries whether a position is ground or not.
1000 bool is_ground(u64 seed, v3s16 p)
1002 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1003 return val_is_ground(val1, p, seed);
1007 // Amount of trees per area in nodes
1008 double tree_amount_2d(u64 seed, v2s16 p)
1010 /*double noise = noise2d_perlin(
1011 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1013 double noise = noise2d_perlin(
1014 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1016 double zeroval = -0.39;
1020 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1024 double surface_humidity_2d(u64 seed, v2s16 p)
1026 double noise = noise2d_perlin(
1027 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1028 seed+72384, 4, 0.66);
1029 noise = (noise + 1.0)/2.0;
1038 Incrementally find ground level from 3d noise
1040 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1042 // Start a bit fuzzy to make averaging lower precision values
1044 s16 level = myrand_range(-precision/2, precision/2);
1045 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1047 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1049 // First find non-ground by going upwards
1050 // Don't stop in caves.
1052 s16 max = level+dec[i-1]*2;
1053 v3s16 p(p2d.X, level, p2d.Y);
1054 for(; p.Y < max; p.Y += dec[i])
1056 if(!is_ground(seed, p))
1063 // Then find ground by going downwards from there.
1064 // Go in caves, too, when precision is 1.
1066 s16 min = level-dec[i-1]*2;
1067 v3s16 p(p2d.X, level, p2d.Y);
1068 for(; p.Y>min; p.Y-=dec[i])
1070 bool ground = is_ground(seed, p);
1071 /*if(dec[i] == 1 && is_cave(seed, p))
1082 // This is more like the actual ground level
1083 level += dec[i-1]/2;
1088 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1090 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1092 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1093 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1095 a += find_ground_level_from_noise(seed,
1096 v2s16(node_min.X, node_min.Y), p);
1097 a += find_ground_level_from_noise(seed,
1098 v2s16(node_min.X, node_max.Y), p);
1099 a += find_ground_level_from_noise(seed,
1100 v2s16(node_max.X, node_max.Y), p);
1101 a += find_ground_level_from_noise(seed,
1102 v2s16(node_max.X, node_min.Y), p);
1103 a += find_ground_level_from_noise(seed,
1104 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1109 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1111 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1113 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1114 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1117 a = MYMAX(a, find_ground_level_from_noise(seed,
1118 v2s16(node_min.X, node_min.Y), p));
1119 a = MYMAX(a, find_ground_level_from_noise(seed,
1120 v2s16(node_min.X, node_max.Y), p));
1121 a = MYMAX(a, find_ground_level_from_noise(seed,
1122 v2s16(node_max.X, node_max.Y), p));
1123 a = MYMAX(a, find_ground_level_from_noise(seed,
1124 v2s16(node_min.X, node_min.Y), p));
1126 a = MYMAX(a, find_ground_level_from_noise(seed,
1127 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1128 // Side middle points
1129 a = MYMAX(a, find_ground_level_from_noise(seed,
1130 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1131 a = MYMAX(a, find_ground_level_from_noise(seed,
1132 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1133 a = MYMAX(a, find_ground_level_from_noise(seed,
1134 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1135 a = MYMAX(a, find_ground_level_from_noise(seed,
1136 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1140 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1142 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1144 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1145 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1148 a = MYMIN(a, find_ground_level_from_noise(seed,
1149 v2s16(node_min.X, node_min.Y), p));
1150 a = MYMIN(a, find_ground_level_from_noise(seed,
1151 v2s16(node_min.X, node_max.Y), p));
1152 a = MYMIN(a, find_ground_level_from_noise(seed,
1153 v2s16(node_max.X, node_max.Y), p));
1154 a = MYMIN(a, find_ground_level_from_noise(seed,
1155 v2s16(node_min.X, node_min.Y), p));
1157 a = MYMIN(a, find_ground_level_from_noise(seed,
1158 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1159 // Side middle points
1160 a = MYMIN(a, find_ground_level_from_noise(seed,
1161 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1162 a = MYMIN(a, find_ground_level_from_noise(seed,
1163 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1164 a = MYMIN(a, find_ground_level_from_noise(seed,
1165 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1166 a = MYMIN(a, find_ground_level_from_noise(seed,
1167 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1172 // Required by mapgen.h
1173 bool block_is_underground(u64 seed, v3s16 blockpos)
1175 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1176 seed, v2s16(blockpos.X, blockpos.Z));*/
1177 // Nah, this is just a heuristic, just return something
1178 s16 minimum_groundlevel = WATER_LEVEL;
1180 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1186 #define AVERAGE_MUD_AMOUNT 4
1188 double base_rock_level_2d(u64 seed, v2s16 p)
1190 // The base ground level
1191 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1192 + 20. * noise2d_perlin(
1193 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1194 seed+82341, 5, 0.6);
1196 /*// A bit hillier one
1197 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1198 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1199 seed+93413, 6, 0.69);
1203 // Higher ground level
1204 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1205 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1206 seed+85039, 5, 0.6);
1207 //higher = 30; // For debugging
1209 // Limit higher to at least base
1213 // Steepness factor of cliffs
1214 double b = 0.85 + 0.5 * noise2d_perlin(
1215 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1217 b = rangelim(b, 0.0, 1000.0);
1220 b = rangelim(b, 0.5, 1000.0);
1221 // Values 1.5...100 give quite horrible looking slopes
1222 if(b > 1.5 && b < 100.0){
1228 //dstream<<"b="<<b<<std::endl;
1232 // Offset to more low
1233 double a_off = -0.20;
1234 // High/low selector
1235 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1236 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1237 seed+4213, 6, 0.7));*/
1238 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1239 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1240 seed+4213, 5, 0.69));
1242 a = rangelim(a, 0.0, 1.0);
1244 //dstream<<"a="<<a<<std::endl;
1246 double h = base*(1.0-a) + higher*a;
1253 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1255 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1258 double get_mud_add_amount(u64 seed, v2s16 p)
1260 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1261 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1262 seed+91013, 3, 0.55));
1265 bool get_have_sand(u64 seed, v2s16 p2d)
1267 // Determine whether to have sand here
1268 double sandnoise = noise2d_perlin(
1269 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1270 seed+59420, 3, 0.50);
1272 return (sandnoise > -0.15);
1275 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1277 void make_block(BlockMakeData *data)
1281 //dstream<<"makeBlock: no-op"<<std::endl;
1285 assert(data->vmanip);
1286 assert(data->nodedef);
1287 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1288 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1289 data->blockpos_requested.Z >= data->blockpos_min.Z);
1290 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1291 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1292 data->blockpos_requested.Z <= data->blockpos_max.Z);
1294 INodeDefManager *ndef = data->nodedef;
1296 // Hack: use minimum block coordinates for old code that assumes
1298 v3s16 blockpos = data->blockpos_requested;
1300 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1301 <<blockpos.Z<<")"<<std::endl;*/
1303 v3s16 blockpos_min = data->blockpos_min;
1304 v3s16 blockpos_max = data->blockpos_max;
1305 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1306 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1308 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1309 // Area of central chunk
1310 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1311 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1312 // Full allocated area
1313 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1314 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1316 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1318 const s16 max_spread_amount = MAP_BLOCKSIZE;
1320 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1321 * (blockpos_max.Y - blockpos_min.Y + 1)
1322 * (blockpos_max.Z - blockpos_max.Z + 1);
1324 int volume_nodes = volume_blocks *
1325 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1327 // Generated surface area
1328 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1330 // Horribly wrong heuristic, but better than nothing
1331 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1334 Create a block-specific seed
1336 /*u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1337 + full_node_min.Y*42123 + full_node_min.X*23;*/
1340 Cache some ground type values for speed
1343 // Creates variables c_name=id and n_name=node
1344 #define CONTENT_VARIABLE(ndef, name)\
1345 content_t c_##name = ndef->getId(#name);\
1346 MapNode n_##name(c_##name);
1348 CONTENT_VARIABLE(ndef, stone);
1349 CONTENT_VARIABLE(ndef, air);
1350 CONTENT_VARIABLE(ndef, water_source);
1351 CONTENT_VARIABLE(ndef, dirt);
1352 CONTENT_VARIABLE(ndef, sand);
1353 CONTENT_VARIABLE(ndef, gravel);
1354 CONTENT_VARIABLE(ndef, clay);
1355 CONTENT_VARIABLE(ndef, lava_source);
1356 CONTENT_VARIABLE(ndef, cobble);
1357 CONTENT_VARIABLE(ndef, mossycobble);
1358 CONTENT_VARIABLE(ndef, dirt_with_grass);
1359 CONTENT_VARIABLE(ndef, junglegrass);
1360 CONTENT_VARIABLE(ndef, stone_with_coal);
1361 CONTENT_VARIABLE(ndef, stone_with_iron);
1362 CONTENT_VARIABLE(ndef, mese);
1364 // Maximum height of the stone surface and obstacles.
1365 // This is used to guide the cave generation
1366 s16 stone_surface_max_y = 0;
1369 Generate general ground level to full area
1373 TimeTaker timer1("Generating ground level");
1375 for(s16 x=node_min.X; x<=node_max.X; x++)
1376 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1379 v2s16 p2d = v2s16(x,z);
1382 Skip of already generated
1385 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1386 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1390 // Ground height at this point
1391 float surface_y_f = 0.0;
1393 // Use perlin noise for ground height
1394 surface_y_f = base_rock_level_2d(data->seed, p2d);
1396 /*// Experimental stuff
1398 float a = highlands_level_2d(data->seed, p2d);
1403 // Convert to integer
1404 s16 surface_y = (s16)surface_y_f;
1407 if(surface_y > stone_surface_max_y)
1408 stone_surface_max_y = surface_y;
1411 Fill ground with stone
1414 // Use fast index incrementing
1415 v3s16 em = vmanip.m_area.getExtent();
1416 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1417 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1420 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1421 vmanip.m_data[i] = MapNode(c_stone);
1422 } else if(y <= WATER_LEVEL){
1423 vmanip.m_data[i] = MapNode(c_water_source);
1425 vmanip.m_data[i] = MapNode(c_air);
1428 vmanip.m_area.add_y(em, i, 1);
1436 // Limit dirt flow area by 1 because mud is flown into neighbors.
1437 assert(central_area_size.X == central_area_size.Z);
1438 s16 mudflow_minpos = 0-max_spread_amount+1;
1439 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1442 Loop this part, it will make stuff look older and newer nicely
1445 const u32 age_loops = 2;
1446 for(u32 i_age=0; i_age<age_loops; i_age++)
1448 /******************************
1449 BEGINNING OF AGING LOOP
1450 ******************************/
1455 //TimeTaker timer1("caves");
1458 Make caves (this code is relatively horrible)
1460 u32 caves_count = volume_nodes / 100000 + 1;
1461 u32 bruises_count = volume_nodes * stone_surface_max_y / 40000000;
1462 if(stone_surface_max_y < WATER_LEVEL - 20)
1464 /*u32 caves_count = 0;
1465 u32 bruises_count = 0;*/
1466 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1468 s16 min_tunnel_diameter = 2;
1469 s16 max_tunnel_diameter = 5;
1470 u16 tunnel_routepoints = 20;
1472 v3f main_direction(0,0,0);
1474 bool bruise_surface = (jj > caves_count);
1478 min_tunnel_diameter = 5;
1479 max_tunnel_diameter = myrand_range(10, myrand_range(30,50));
1480 /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
1481 max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
1483 /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(data->seed+42,
1484 data->sectorpos_base.X, data->sectorpos_base.Y)), 0, 15);*/
1486 tunnel_routepoints = 5;
1492 // Allowed route area size in nodes
1493 v3s16 ar = central_area_size;
1495 // Area starting point in nodes
1496 v3s16 of = node_min;
1499 //(this should be more than the maximum radius of the tunnel)
1500 //s16 insure = 5; // Didn't work with max_d = 20
1502 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1503 ar += v3s16(1,0,1) * more * 2;
1504 of -= v3s16(1,0,1) * more;
1506 s16 route_y_min = 0;
1507 // Allow half a diameter + 7 over stone surface
1508 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1510 /*// If caves, don't go through surface too often
1511 if(bruise_surface == false)
1512 route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
1514 // Limit maximum to area
1515 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1519 /*// Minimum is at y=0
1520 route_y_min = -of.Y - 0;*/
1521 // Minimum is at y=max_tunnel_diameter/4
1522 //route_y_min = -of.Y + max_tunnel_diameter/4;
1523 //s16 min = -of.Y + max_tunnel_diameter/4;
1524 s16 min = -of.Y + 0;
1525 route_y_min = myrand_range(min, min + max_tunnel_diameter);
1526 route_y_min = rangelim(route_y_min, 0, route_y_max);
1529 /*dstream<<"route_y_min = "<<route_y_min
1530 <<", route_y_max = "<<route_y_max<<std::endl;*/
1532 s16 route_start_y_min = route_y_min;
1533 s16 route_start_y_max = route_y_max;
1535 // Start every 4th cave from surface when applicable
1536 bool coming_from_surface = false;
1537 if(node_min.Y <= 0 && node_max.Y >= 0){
1538 coming_from_surface = (jj % 4 == 0 && bruise_surface == false);
1539 if(coming_from_surface)
1540 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1543 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1544 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1546 // Randomize starting position
1548 (float)(myrand()%ar.X)+0.5,
1549 (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
1550 (float)(myrand()%ar.Z)+0.5
1553 MapNode airnode(CONTENT_AIR);
1554 MapNode waternode(c_water_source);
1557 Generate some tunnel starting from orp
1560 for(u16 j=0; j<tunnel_routepoints; j++)
1562 if(j%7==0 && bruise_surface == false)
1564 main_direction = v3f(
1565 ((float)(myrand()%20)-(float)10)/10,
1566 ((float)(myrand()%20)-(float)10)/30,
1567 ((float)(myrand()%20)-(float)10)/10
1569 main_direction *= (float)myrand_range(1, 3);
1573 s16 min_d = min_tunnel_diameter;
1574 s16 max_d = max_tunnel_diameter;
1575 s16 rs = myrand_range(min_d, max_d);
1580 maxlen = v3s16(rs*7,rs*2,rs*7);
1584 maxlen = v3s16(rs*4, myrand_range(1, rs*3), rs*4);
1589 if(coming_from_surface && j < 3)
1592 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
1593 (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
1594 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
1600 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
1601 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
1602 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
1608 s16 h = find_ground_level_clever(vmanip,
1609 v2s16(p.X, p.Z), ndef);
1610 route_y_min = h - rs/3;
1611 route_y_max = h + rs;
1614 vec += main_direction;
1619 else if(rp.X >= ar.X)
1621 if(rp.Y < route_y_min)
1623 else if(rp.Y >= route_y_max)
1624 rp.Y = route_y_max-1;
1627 else if(rp.Z >= ar.Z)
1631 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1633 v3f fp = orp + vec * f;
1634 fp.X += 0.1*myrand_range(-10,10);
1635 fp.Z += 0.1*myrand_range(-10,10);
1636 v3s16 cp(fp.X, fp.Y, fp.Z);
1639 s16 d1 = d0 + rs - 1;
1640 for(s16 z0=d0; z0<=d1; z0++)
1642 s16 si = rs - MYMAX(0, abs(z0)-rs/4);
1643 //s16 si = rs - MYMAX(0, abs(z0)-rs/7);
1644 for(s16 x0=-si; x0<=si-1; x0++)
1646 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1647 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
1648 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
1649 //s16 si2 = rs - abs(x0);
1650 for(s16 y0=-si2; y0<=si2-1; y0++)
1652 // Make better floors
1653 if(y0 < -rs + 1 && abs(x0)<=1 && abs(z0)<=1)
1660 /*if(isInArea(p, ar) == false)
1662 // Check only height
1663 if(y < 0 || y >= ar.Y)
1667 //assert(vmanip.m_area.contains(p));
1668 if(vmanip.m_area.contains(p) == false)
1670 dstream<<"WARNING: "<<__FUNCTION_NAME
1671 <<":"<<__LINE__<<": "
1672 <<"point not in area"
1677 // Just set it to air, it will be changed to
1679 u32 i = vmanip.m_area.index(p);
1681 if(p.Y <= WATER_LEVEL)
1682 vmanip.m_data[i] = waternode;
1684 vmanip.m_data[i] = airnode;
1686 vmanip.m_data[i] = airnode;
1689 if(bruise_surface == false)
1692 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1710 TimeTaker timer1("add mud");
1713 Add mud to the central chunk
1716 for(s16 x=node_min.X; x<=node_max.X; x++)
1717 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1719 // Node position in 2d
1720 v2s16 p2d = v2s16(x,z);
1722 MapNode addnode(c_dirt);
1724 // Randomize mud amount
1725 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0;
1727 if(mud_add_amount <= 0){
1728 mud_add_amount = 1 - mud_add_amount;
1729 addnode = MapNode(c_gravel);
1732 // Find ground level
1733 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1734 // Handle area not found
1735 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1739 If topmost node is grass, change it to mud.
1740 It might be if it was flown to there from a neighboring
1741 chunk and then converted.
1744 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1745 MapNode *n = &vmanip.m_data[i];
1746 if(n->getContent() == c_dirt_with_grass)
1747 *n = MapNode(c_dirt);
1755 v3s16 em = vmanip.m_area.getExtent();
1756 s16 y_start = surface_y+1;
1757 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1758 for(s16 y=y_start; y<=node_max.Y; y++)
1760 if(mudcount >= mud_add_amount)
1763 MapNode &n = vmanip.m_data[i];
1767 vmanip.m_area.add_y(em, i, 1);
1779 TimeTaker timer1("flow mud");
1782 Flow mud away from steep edges
1785 // Iterate a few times
1786 for(s16 k=0; k<3; k++)
1789 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1790 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1792 // Invert coordinates every 2nd iteration
1795 x = mudflow_maxpos - (x-mudflow_minpos);
1796 z = mudflow_maxpos - (z-mudflow_minpos);
1799 // Node position in 2d
1800 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1802 v3s16 em = vmanip.m_area.getExtent();
1803 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1810 for(; y>=node_min.Y; y--)
1812 n = &vmanip.m_data[i];
1813 //if(content_walkable(n->d))
1815 if(n->getContent() == c_dirt ||
1816 n->getContent() == c_dirt_with_grass)
1819 vmanip.m_area.add_y(em, i, -1);
1822 // Stop if out of area
1823 //if(vmanip.m_area.contains(i) == false)
1827 /*// If not mud, do nothing to it
1828 MapNode *n = &vmanip.m_data[i];
1829 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1833 Don't flow it if the stuff under it is not mud
1837 vmanip.m_area.add_y(em, i2, -1);
1838 // Cancel if out of area
1839 if(vmanip.m_area.contains(i2) == false)
1841 MapNode *n2 = &vmanip.m_data[i2];
1842 if(n2->getContent() != c_dirt &&
1843 n2->getContent() != c_dirt_with_grass)
1847 // Make it exactly mud
1848 n->setContent(c_dirt);
1850 /*s16 recurse_count = 0;
1854 v3s16(0,0,1), // back
1855 v3s16(1,0,0), // right
1856 v3s16(0,0,-1), // front
1857 v3s16(-1,0,0), // left
1860 // Theck that upper is air or doesn't exist.
1861 // Cancel dropping if upper keeps it in place
1863 vmanip.m_area.add_y(em, i3, 1);
1864 if(vmanip.m_area.contains(i3) == true
1865 && ndef->get(vmanip.m_data[i3]).walkable)
1872 for(u32 di=0; di<4; di++)
1874 v3s16 dirp = dirs4[di];
1877 vmanip.m_area.add_p(em, i2, dirp);
1878 // Fail if out of area
1879 if(vmanip.m_area.contains(i2) == false)
1881 // Check that side is air
1882 MapNode *n2 = &vmanip.m_data[i2];
1883 if(ndef->get(*n2).walkable)
1885 // Check that under side is air
1886 vmanip.m_area.add_y(em, i2, -1);
1887 if(vmanip.m_area.contains(i2) == false)
1889 n2 = &vmanip.m_data[i2];
1890 if(ndef->get(*n2).walkable)
1892 /*// Check that under that is air (need a drop of 2)
1893 vmanip.m_area.add_y(em, i2, -1);
1894 if(vmanip.m_area.contains(i2) == false)
1896 n2 = &vmanip.m_data[i2];
1897 if(content_walkable(n2->d))
1899 // Loop further down until not air
1900 bool dropped_to_unknown = false;
1902 vmanip.m_area.add_y(em, i2, -1);
1903 n2 = &vmanip.m_data[i2];
1904 // if out of known area
1905 if(vmanip.m_area.contains(i2) == false
1906 || n2->getContent() == CONTENT_IGNORE){
1907 dropped_to_unknown = true;
1910 }while(ndef->get(*n2).walkable == false);
1911 // Loop one up so that we're in air
1912 vmanip.m_area.add_y(em, i2, 1);
1913 n2 = &vmanip.m_data[i2];
1915 bool old_is_water = (n->getContent() == c_water_source);
1916 // Move mud to new place
1917 if(!dropped_to_unknown)
1919 // Set old place to be air (or water)
1921 *n = MapNode(c_water_source);
1923 *n = MapNode(CONTENT_AIR);
1937 /***********************
1939 ************************/
1942 Add top and bottom side of water to transforming_liquid queue
1945 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1946 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1951 bool water_found = false;
1952 // Use fast index incrementing
1953 v3s16 em = vmanip.m_area.getExtent();
1954 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1955 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1957 if(water_found == false)
1959 if(vmanip.m_data[i].getContent() == c_water_source)
1961 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1962 data->transforming_liquid.push_back(p);
1968 // This can be done because water_found can only
1969 // turn to true and end up here after going through
1971 if(vmanip.m_data[i+1].getContent() != c_water_source)
1973 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1974 data->transforming_liquid.push_back(p);
1975 water_found = false;
1979 vmanip.m_area.add_y(em, i, -1);
1988 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1989 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1991 // Node position in 2d
1992 v2s16 p2d = v2s16(x,z);
1995 Find the lowest surface to which enough light ends up
1998 Basically just wait until not air and not leaves.
2002 v3s16 em = vmanip.m_area.getExtent();
2003 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2005 // Go to ground level
2006 for(y=node_max.Y; y>=full_node_min.Y; y--)
2008 MapNode &n = vmanip.m_data[i];
2009 if(ndef->get(n).param_type != CPT_LIGHT
2010 || ndef->get(n).liquid_type != LIQUID_NONE)
2012 vmanip.m_area.add_y(em, i, -1);
2014 if(y >= full_node_min.Y)
2017 surface_y = full_node_min.Y;
2020 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2021 MapNode *n = &vmanip.m_data[i];
2022 if(n->getContent() == c_dirt)
2023 n->setContent(c_dirt_with_grass);
2029 assert(central_area_size.X == central_area_size.Z);
2031 // Divide area into parts
2033 s16 sidelen = central_area_size.X / div;
2034 double area = sidelen * sidelen;
2035 for(s16 x0=0; x0<div; x0++)
2036 for(s16 z0=0; z0<div; z0++)
2038 // Center position of part of division
2040 node_min.X + sidelen/2 + sidelen*x0,
2041 node_min.Z + sidelen/2 + sidelen*z0
2043 // Minimum edge of part of division
2045 node_min.X + sidelen*x0,
2046 node_min.Z + sidelen*z0
2048 // Maximum edge of part of division
2050 node_min.X + sidelen + sidelen*x0 - 1,
2051 node_min.Z + sidelen + sidelen*z0 - 1
2054 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2055 // Put trees in random places on part of division
2056 for(u32 i=0; i<tree_count; i++)
2058 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2059 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2060 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2061 // Don't make a tree under water level
2064 // Don't make a tree so high that it doesn't fit
2065 if(y > node_max.Y - 6)
2069 Trees grow only on mud and grass
2072 u32 i = vmanip.m_area.index(v3s16(p));
2073 MapNode *n = &vmanip.m_data[i];
2074 if(n->getContent() != c_dirt
2075 && n->getContent() != c_dirt_with_grass)
2080 make_tree(vmanip, p, false, ndef);
2087 Make base ground level
2090 for(s16 x=node_min.X; x<=node_max.X; x++)
2091 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2096 // Use fast index incrementing
2097 v3s16 em = vmanip.m_area.getExtent();
2098 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2099 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2101 // Only modify places that have no content
2102 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2104 // First priority: make air and water.
2105 // This avoids caves inside water.
2106 if(all_is_ground_except_caves == false
2107 && val_is_ground(noisebuf_ground.get(x,y,z),
2108 v3s16(x,y,z), data->seed) == false)
2110 if(y <= WATER_LEVEL)
2111 vmanip.m_data[i] = n_water_source;
2113 vmanip.m_data[i] = n_air;
2115 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2116 vmanip.m_data[i] = n_air;
2118 vmanip.m_data[i] = n_stone;
2121 vmanip->m_area.add_y(em, i, 1);
2127 Add mud and sand and others underground (in place of stone)
2130 for(s16 x=node_min.X; x<=node_max.X; x++)
2131 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2136 // Use fast index incrementing
2137 v3s16 em = vmanip.m_area.getExtent();
2138 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2139 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2141 if(vmanip.m_data[i].getContent() == c_stone)
2143 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2145 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2146 vmanip.m_data[i] = n_dirt;
2148 vmanip.m_data[i] = n_sand;
2150 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2152 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2153 vmanip.m_data[i] = n_gravel;
2155 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2156 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2158 vmanip.m_data[i] = n_lava_source;
2159 for(s16 x1=-1; x1<=1; x1++)
2160 for(s16 y1=-1; y1<=1; y1++)
2161 for(s16 z1=-1; z1<=1; z1++)
2162 data->transforming_liquid.push_back(
2163 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2167 vmanip->m_area.add_y(em, i, -1);
2176 //if(node_min.Y < approx_groundlevel)
2177 //if(myrand() % 3 == 0)
2178 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2179 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2180 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2181 float dungeon_rarity = 0.02;
2182 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2184 && node_min.Y < approx_groundlevel)
2186 // Dungeon generator doesn't modify places which have this set
2187 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2188 | VMANIP_FLAG_DUNGEON_PRESERVE);
2190 // Set all air and water to be untouchable to make dungeons open
2191 // to caves and open air
2192 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2193 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2198 // Use fast index incrementing
2199 v3s16 em = vmanip.m_area.getExtent();
2200 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2201 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2203 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2204 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2205 else if(vmanip.m_data[i].getContent() == c_water_source)
2206 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2207 vmanip->m_area.add_y(em, i, -1);
2212 PseudoRandom random(blockseed+2);
2215 make_dungeon1(vmanip, random, ndef);
2217 // Convert some cobble to mossy cobble
2218 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2219 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2224 // Use fast index incrementing
2225 v3s16 em = vmanip.m_area.getExtent();
2226 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2227 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2229 // (noisebuf not used because it doesn't contain the
2231 double wetness = noise3d_param(
2232 get_ground_wetness_params(data->seed), x,y,z);
2233 double d = noise3d_perlin((float)x/2.5,
2234 (float)y/2.5,(float)z/2.5,
2236 if(vmanip.m_data[i].getContent() == c_cobble)
2240 vmanip.m_data[i].setContent(c_mossycobble);
2243 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2246 vmanip.m_data[i].setContent(c_dirt);
2248 vmanip->m_area.add_y(em, i, -1);
2258 PseudoRandom ncrandom(blockseed+9324342);
2259 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2261 make_nc(vmanip, ncrandom, ndef);
2266 Add top and bottom side of water to transforming_liquid queue
2269 for(s16 x=node_min.X; x<=node_max.X; x++)
2270 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2275 bool water_found = false;
2276 // Use fast index incrementing
2277 v3s16 em = vmanip.m_area.getExtent();
2278 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2279 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2281 if(water_found == false)
2283 if(vmanip.m_data[i].getContent() == c_water_source)
2285 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2286 data->transforming_liquid.push_back(p);
2292 // This can be done because water_found can only
2293 // turn to true and end up here after going through
2295 if(vmanip.m_data[i+1].getContent() != c_water_source)
2297 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2298 data->transforming_liquid.push_back(p);
2299 water_found = false;
2303 vmanip->m_area.add_y(em, i, -1);
2309 If close to ground level
2312 //if(abs(approx_ground_depth) < 30)
2313 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2319 for(s16 x=node_min.X; x<=node_max.X; x++)
2320 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2325 bool possibly_have_sand = get_have_sand(data->seed, p2d);
2326 bool have_sand = false;
2327 u32 current_depth = 0;
2328 bool air_detected = false;
2329 bool water_detected = false;
2330 bool have_clay = false;
2332 // Use fast index incrementing
2333 s16 start_y = node_max.Y+2;
2334 v3s16 em = vmanip.m_area.getExtent();
2335 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2336 for(s16 y=start_y; y>=node_min.Y-3; y--)
2338 if(vmanip.m_data[i].getContent() == c_water_source)
2339 water_detected = true;
2340 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2341 air_detected = true;
2343 if((vmanip.m_data[i].getContent() == c_stone
2344 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2345 || vmanip.m_data[i].getContent() == c_dirt
2346 || vmanip.m_data[i].getContent() == c_sand
2347 || vmanip.m_data[i].getContent() == c_gravel
2348 ) && (air_detected || water_detected))
2350 if(current_depth == 0 && y <= WATER_LEVEL+2
2351 && possibly_have_sand)
2354 if(current_depth < 4)
2358 // Determine whether to have clay in the sand here
2359 double claynoise = noise2d_perlin(
2360 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2361 data->seed+4321, 6, 0.95) + 0.5;
2363 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2364 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2365 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2368 vmanip.m_data[i] = MapNode(c_clay);
2370 vmanip.m_data[i] = MapNode(c_sand);
2373 else if(current_depth==0 && !water_detected
2374 && y >= WATER_LEVEL && air_detected)
2375 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2378 vmanip.m_data[i] = MapNode(c_dirt);
2382 if(vmanip.m_data[i].getContent() == c_dirt
2383 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2384 vmanip.m_data[i] = MapNode(c_stone);
2389 if(current_depth >= 8)
2392 else if(current_depth != 0)
2395 vmanip->m_area.add_y(em, i, -1);
2401 Calculate some stuff
2404 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2405 bool is_jungle = surface_humidity > 0.75;
2407 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2414 PseudoRandom treerandom(blockseed);
2415 // Put trees in random places on part of division
2416 for(u32 i=0; i<tree_count; i++)
2418 s16 x = treerandom.range(node_min.X, node_max.X);
2419 s16 z = treerandom.range(node_min.Z, node_max.Z);
2420 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2421 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2422 // Don't make a tree under water level
2425 // Make sure tree fits (only trees whose starting point is
2426 // at this block are added)
2427 if(y < node_min.Y || y > node_max.Y)
2430 Find exact ground level
2434 for(; p.Y >= y-6; p.Y--)
2436 u32 i = vmanip->m_area.index(p);
2437 MapNode *n = &vmanip->m_data[i];
2438 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2444 // If not found, handle next one
2449 u32 i = vmanip->m_area.index(p);
2450 MapNode *n = &vmanip->m_data[i];
2452 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2455 // Papyrus grows only on mud and in water
2456 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2459 make_papyrus(vmanip, p, ndef);
2461 // Trees grow only on mud and grass, on land
2462 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2465 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2466 if(is_jungle == false)
2469 if(myrand_range(0,4) != 0)
2470 is_apple_tree = false;
2472 is_apple_tree = noise2d_perlin(
2473 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2474 data->seed+342902, 3, 0.45) > 0.2;
2475 make_tree(vmanip, p, is_apple_tree, ndef);
2478 make_jungletree(vmanip, p, ndef);
2480 // Cactii grow only on sand, on land
2481 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2484 make_cactus(vmanip, p, ndef);
2494 PseudoRandom grassrandom(blockseed);
2495 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2497 s16 x = grassrandom.range(node_min.X, node_max.X);
2498 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2499 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2502 if(y < node_min.Y || y > node_max.Y)
2505 Find exact ground level
2509 for(; p.Y >= y-6; p.Y--)
2511 u32 i = vmanip->m_area.index(p);
2512 MapNode *n = &vmanip->m_data[i];
2513 if(data->nodedef->get(*n).is_ground_content)
2519 // If not found, handle next one
2523 if(vmanip.m_area.contains(p) == false)
2525 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2528 if(vmanip.m_area.contains(p))
2529 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2531 if(vmanip.m_area.contains(p))
2532 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2538 Add some kind of random stones
2541 u32 random_stone_count = gen_area_nodes *
2542 randomstone_amount_2d(data->seed, p2d_center);
2543 // Put in random places on part of division
2544 for(u32 i=0; i<random_stone_count; i++)
2546 s16 x = myrand_range(node_min.X, node_max.X);
2547 s16 z = myrand_range(node_min.Z, node_max.Z);
2548 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2549 // Don't add under water level
2550 /*if(y < WATER_LEVEL)
2552 // Don't add if doesn't belong to this block
2553 if(y < node_min.Y || y > node_max.Y)
2558 u32 i = vmanip->m_area.index(v3s16(p));
2559 MapNode *n = &vmanip->m_data[i];
2560 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2563 // Will be placed one higher
2566 make_randomstone(vmanip, p);
2575 u32 large_stone_count = gen_area_nodes *
2576 largestone_amount_2d(data->seed, p2d_center);
2577 //u32 large_stone_count = 1;
2578 // Put in random places on part of division
2579 for(u32 i=0; i<large_stone_count; i++)
2581 s16 x = myrand_range(node_min.X, node_max.X);
2582 s16 z = myrand_range(node_min.Z, node_max.Z);
2583 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2584 // Don't add under water level
2585 /*if(y < WATER_LEVEL)
2587 // Don't add if doesn't belong to this block
2588 if(y < node_min.Y || y > node_max.Y)
2593 u32 i = vmanip->m_area.index(v3s16(p));
2594 MapNode *n = &vmanip->m_data[i];
2595 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2598 // Will be placed one lower
2601 make_largestone(vmanip, p);
2611 PseudoRandom mineralrandom(blockseed);
2616 for(s16 i=0; i<approx_ground_depth/4; i++)
2618 if(mineralrandom.next()%50 == 0)
2620 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2621 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2622 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2623 for(u16 i=0; i<27; i++)
2625 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2626 u32 vi = vmanip.m_area.index(p);
2627 if(vmanip.m_data[vi].getContent() == c_stone)
2628 if(mineralrandom.next()%8 == 0)
2629 vmanip.m_data[vi] = MapNode(c_mese);
2638 u16 a = mineralrandom.range(0,15);
2640 u16 amount = 20 * a/1000;
2641 for(s16 i=0; i<amount; i++)
2643 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2644 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2645 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2647 u8 base_content = c_stone;
2648 MapNode new_content(CONTENT_IGNORE);
2651 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2653 new_content = MapNode(c_stone_with_coal);
2657 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2658 new_content = MapNode(c_stone_with_iron);
2659 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2660 vmanip.m_data[i] = MapNode(c_dirt);
2662 vmanip.m_data[i] = MapNode(c_sand);*/
2664 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2668 if(new_content.getContent() != CONTENT_IGNORE)
2670 for(u16 i=0; i<27; i++)
2672 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2673 u32 vi = vmanip.m_area.index(p);
2674 if(vmanip.m_data[vi].getContent() == base_content)
2676 if(mineralrandom.next()%sparseness == 0)
2677 vmanip.m_data[vi] = new_content;
2686 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2687 //for(s16 i=0; i<50; i++)
2688 u16 coal_amount = 30;
2689 u16 coal_rareness = 60 / coal_amount;
2690 if(coal_rareness == 0)
2692 if(mineralrandom.next()%coal_rareness == 0)
2694 u16 a = mineralrandom.next() % 16;
2695 u16 amount = coal_amount * a*a*a / 1000;
2696 for(s16 i=0; i<amount; i++)
2698 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2699 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2700 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2701 for(u16 i=0; i<27; i++)
2703 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2704 u32 vi = vmanip.m_area.index(p);
2705 if(vmanip.m_data[vi].getContent() == c_stone)
2706 if(mineralrandom.next()%8 == 0)
2707 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2714 u16 iron_amount = 8;
2715 u16 iron_rareness = 60 / iron_amount;
2716 if(iron_rareness == 0)
2718 if(mineralrandom.next()%iron_rareness == 0)
2720 u16 a = mineralrandom.next() % 16;
2721 u16 amount = iron_amount * a*a*a / 1000;
2722 for(s16 i=0; i<amount; i++)
2724 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2725 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2726 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2727 for(u16 i=0; i<27; i++)
2729 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2730 u32 vi = vmanip.m_area.index(p);
2731 if(vmanip.m_data[vi].getContent() == c_stone)
2732 if(mineralrandom.next()%8 == 0)
2733 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2744 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2746 //VoxelArea a(node_min, node_max);
2747 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2748 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2749 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2750 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2751 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2752 for(int i=0; i<2; i++)
2754 enum LightBank bank = banks[i];
2756 core::map<v3s16, bool> light_sources;
2757 core::map<v3s16, u8> unlight_from;
2759 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2760 light_sources, unlight_from);
2762 bool inexistent_top_provides_sunlight = !block_is_underground;
2763 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2764 vmanip, a, inexistent_top_provides_sunlight,
2765 light_sources, ndef);
2766 // TODO: Do stuff according to bottom_sunlight_valid
2768 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2770 vmanip.spreadLight(bank, light_sources, ndef);
2775 BlockMakeData::BlockMakeData():
2782 BlockMakeData::~BlockMakeData()
2787 }; // namespace mapgen