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.
22 #include "content_mapnode.h"
27 //#include "serverobject.h"
28 #include "content_sao.h"
34 Some helper functions for the map generator
38 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
40 v3s16 em = vmanip.m_area.getExtent();
41 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
42 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
43 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
45 for(y=y_nodes_max; y>=y_nodes_min; y--)
47 MapNode &n = vmanip.m_data[i];
48 if(content_walkable(n.d))
51 vmanip.m_area.add_y(em, i, -1);
59 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
61 v3s16 em = vmanip.m_area.getExtent();
62 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
63 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
64 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
66 for(y=y_nodes_max; y>=y_nodes_min; y--)
68 MapNode &n = vmanip.m_data[i];
69 if(content_walkable(n.d)
70 && n.d != CONTENT_TREE
71 && n.d != CONTENT_LEAVES)
74 vmanip.m_area.add_y(em, i, -1);
83 static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
85 MapNode treenode(CONTENT_TREE);
86 MapNode leavesnode(CONTENT_LEAVES);
88 s16 trunk_h = myrand_range(3, 6);
90 for(s16 ii=0; ii<trunk_h; ii++)
92 if(vmanip.m_area.contains(p1))
93 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
97 // p1 is now the last piece of the trunk
100 VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
101 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
102 Buffer<u8> leaves_d(leaves_a.getVolume());
103 for(s32 i=0; i<leaves_a.getVolume(); i++)
106 // Force leaves at near the end of the trunk
109 for(s16 z=-d; z<=d; z++)
110 for(s16 y=-d; y<=d; y++)
111 for(s16 x=-d; x<=d; x++)
113 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
117 // Add leaves randomly
118 for(u32 iii=0; iii<7; iii++)
123 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
124 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
125 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
128 for(s16 z=0; z<=d; z++)
129 for(s16 y=0; y<=d; y++)
130 for(s16 x=0; x<=d; x++)
132 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
136 // Blit leaves to vmanip
137 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
138 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
139 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
143 if(vmanip.m_area.contains(p) == false)
145 u32 vi = vmanip.m_area.index(p);
146 if(vmanip.m_data[vi].d != CONTENT_AIR
147 && vmanip.m_data[vi].d != CONTENT_IGNORE)
149 u32 i = leaves_a.index(x,y,z);
151 vmanip.m_data[vi] = leavesnode;
156 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
158 MapNode stonenode(CONTENT_STONE);
160 s16 size = myrand_range(3, 6);
162 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
163 Buffer<u8> stone_d(stone_a.getVolume());
164 for(s32 i=0; i<stone_a.getVolume(); i++)
167 // Force stone at bottom to make it usually touch the ground
169 for(s16 z=0; z<=0; z++)
170 for(s16 y=0; y<=0; y++)
171 for(s16 x=0; x<=0; x++)
173 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
177 // Generate from perlin noise
178 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
179 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
180 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
182 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
183 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
184 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
186 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
188 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
192 u32 vi = stone_a.index(v3s16(x,y,z));
197 /*// Add stone randomly
198 for(u32 iii=0; iii<7; iii++)
203 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
204 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
205 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
208 for(s16 z=0; z<=d; z++)
209 for(s16 y=0; y<=d; y++)
210 for(s16 x=0; x<=d; x++)
212 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
216 // Blit stone to vmanip
217 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
218 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
219 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
223 if(vmanip.m_area.contains(p) == false)
225 u32 vi = vmanip.m_area.index(p);
226 if(vmanip.m_data[vi].d != CONTENT_AIR
227 && vmanip.m_data[vi].d != CONTENT_IGNORE)
229 u32 i = stone_a.index(x,y,z);
231 vmanip.m_data[vi] = stonenode;
237 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
239 MapNode stonenode(CONTENT_STONE);
241 s16 size = myrand_range(8, 16);
243 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
244 Buffer<u8> stone_d(stone_a.getVolume());
245 for(s32 i=0; i<stone_a.getVolume(); i++)
248 // Force stone at bottom to make it usually touch the ground
250 for(s16 z=0; z<=0; z++)
251 for(s16 y=0; y<=0; y++)
252 for(s16 x=0; x<=0; x++)
254 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
258 // Generate from perlin noise
259 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
260 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
261 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
264 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
265 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
266 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
267 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
268 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
269 double dz = (double)z-mid_z;
270 double dx = (double)x-mid_x;
271 double dy = MYMAX(0, (double)y-mid_y);
272 double r = sqrt(dz*dz+dx*dx+dy*dy);
273 d /= (2*r/size)*2 + 0.01;
276 u32 vi = stone_a.index(v3s16(x,y,z));
281 /*// Add stone randomly
282 for(u32 iii=0; iii<7; iii++)
287 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
288 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
289 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
292 for(s16 z=0; z<=d; z++)
293 for(s16 y=0; y<=d; y++)
294 for(s16 x=0; x<=d; x++)
296 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
300 // Blit stone to vmanip
301 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
302 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
303 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
307 if(vmanip.m_area.contains(p) == false)
309 u32 vi = vmanip.m_area.index(p);
310 /*if(vmanip.m_data[vi].d != CONTENT_AIR
311 && vmanip.m_data[vi].d != CONTENT_IGNORE)
313 u32 i = stone_a.index(x,y,z);
315 vmanip.m_data[vi] = stonenode;
321 Dungeon making routines
324 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
325 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
326 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
327 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
329 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
332 for(s16 z=0; z<roomsize.Z; z++)
333 for(s16 y=0; y<roomsize.Y; y++)
336 v3s16 p = roomplace + v3s16(0,y,z);
337 if(vmanip.m_area.contains(p) == false)
339 u32 vi = vmanip.m_area.index(p);
340 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
342 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
345 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
346 if(vmanip.m_area.contains(p) == false)
348 u32 vi = vmanip.m_area.index(p);
349 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
351 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
356 for(s16 x=0; x<roomsize.X; x++)
357 for(s16 y=0; y<roomsize.Y; y++)
360 v3s16 p = roomplace + v3s16(x,y,0);
361 if(vmanip.m_area.contains(p) == false)
363 u32 vi = vmanip.m_area.index(p);
364 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
366 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
369 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
370 if(vmanip.m_area.contains(p) == false)
372 u32 vi = vmanip.m_area.index(p);
373 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
375 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
379 // Make +-Y walls (floor and ceiling)
380 for(s16 z=0; z<roomsize.Z; z++)
381 for(s16 x=0; x<roomsize.X; x++)
384 v3s16 p = roomplace + v3s16(x,0,z);
385 if(vmanip.m_area.contains(p) == false)
387 u32 vi = vmanip.m_area.index(p);
388 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
390 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
393 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
394 if(vmanip.m_area.contains(p) == false)
396 u32 vi = vmanip.m_area.index(p);
397 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
399 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
404 for(s16 z=1; z<roomsize.Z-1; z++)
405 for(s16 y=1; y<roomsize.Y-1; y++)
406 for(s16 x=1; x<roomsize.X-1; x++)
408 v3s16 p = roomplace + v3s16(x,y,z);
409 if(vmanip.m_area.contains(p) == false)
411 u32 vi = vmanip.m_area.index(p);
412 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
413 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
417 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
418 u8 avoid_flags, MapNode n, u8 or_flags)
420 for(s16 z=0; z<size.Z; z++)
421 for(s16 y=0; y<size.Y; y++)
422 for(s16 x=0; x<size.X; x++)
424 v3s16 p = place + v3s16(x,y,z);
425 if(vmanip.m_area.contains(p) == false)
427 u32 vi = vmanip.m_area.index(p);
428 if(vmanip.m_flags[vi] & avoid_flags)
430 vmanip.m_flags[vi] |= or_flags;
431 vmanip.m_data[vi] = n;
435 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
437 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
438 VMANIP_FLAG_DUNGEON_INSIDE);
441 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
443 make_hole1(vmanip, doorplace);
444 // Place torch (for testing)
445 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
448 static v3s16 rand_ortho_dir(PseudoRandom &random)
450 if(random.next()%2==0)
451 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
453 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
456 static v3s16 turn_xz(v3s16 olddir, int t)
476 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
478 int turn = random.range(0,2);
487 dir = turn_xz(olddir, 0);
490 dir = turn_xz(olddir, 1);
494 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
495 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
496 PseudoRandom &random)
498 make_hole1(vmanip, doorplace);
499 v3s16 p0 = doorplace;
503 length = random.range(1,13);
505 length = random.range(1,6);
506 length = random.range(1,13);
507 u32 partlength = random.range(1,13);
510 if(random.next()%2 == 0 && partlength >= 3)
511 make_stairs = random.next()%2 ? 1 : -1;
512 for(u32 i=0; i<length; i++)
518 /*// If already empty
519 if(vmanip.getNodeNoExNoEmerge(p).d
521 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
526 if(vmanip.m_area.contains(p) == true
527 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
531 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
532 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
533 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
534 VMANIP_FLAG_DUNGEON_INSIDE);
535 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
536 VMANIP_FLAG_DUNGEON_INSIDE);
540 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
541 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
542 make_hole1(vmanip, p);
543 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
544 VMANIP_FLAG_DUNGEON_INSIDE);*/
551 // Can't go here, turn away
552 dir = turn_xz(dir, random.range(0,1));
553 make_stairs = -make_stairs;
555 partlength = random.range(1,length);
560 if(partcount >= partlength)
564 dir = random_turn(random, dir);
566 partlength = random.range(1,length);
569 if(random.next()%2 == 0 && partlength >= 3)
570 make_stairs = random.next()%2 ? 1 : -1;
581 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
591 m_dir = rand_ortho_dir(m_random);
594 void setPos(v3s16 pos)
599 void setDir(v3s16 dir)
604 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
606 for(u32 i=0; i<100; i++)
608 v3s16 p = m_pos + m_dir;
609 v3s16 p1 = p + v3s16(0,1,0);
610 if(vmanip.m_area.contains(p) == false
611 || vmanip.m_area.contains(p1) == false
617 if(vmanip.getNodeNoExNoEmerge(p).d
619 && vmanip.getNodeNoExNoEmerge(p1).d
622 // Found wall, this is a good place!
625 // Randomize next direction
630 Determine where to move next
632 // Jump one up if the actual space is there
633 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
635 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
637 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d
640 // Jump one down if the actual space is there
641 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
643 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
645 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d
648 // Check if walking is now possible
649 if(vmanip.getNodeNoExNoEmerge(p).d
651 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
654 // Cannot continue walking here
664 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
665 v3s16 &result_doordir, v3s16 &result_roomplace)
667 for(s16 trycount=0; trycount<30; trycount++)
671 bool r = findPlaceForDoor(doorplace, doordir);
675 // X east, Z north, Y up
677 if(doordir == v3s16(1,0,0)) // X+
678 roomplace = doorplace +
679 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
680 if(doordir == v3s16(-1,0,0)) // X-
681 roomplace = doorplace +
682 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
683 if(doordir == v3s16(0,0,1)) // Z+
684 roomplace = doorplace +
685 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
686 if(doordir == v3s16(0,0,-1)) // Z-
687 roomplace = doorplace +
688 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
691 if(doordir == v3s16(1,0,0)) // X+
692 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
693 if(doordir == v3s16(-1,0,0)) // X-
694 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
695 if(doordir == v3s16(0,0,1)) // Z+
696 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
697 if(doordir == v3s16(0,0,-1)) // Z-
698 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
703 for(s16 z=1; z<roomsize.Z-1; z++)
704 for(s16 y=1; y<roomsize.Y-1; y++)
705 for(s16 x=1; x<roomsize.X-1; x++)
707 v3s16 p = roomplace + v3s16(x,y,z);
708 if(vmanip.m_area.contains(p) == false)
713 if(vmanip.m_flags[vmanip.m_area.index(p)]
714 & VMANIP_FLAG_DUNGEON_INSIDE)
725 result_doorplace = doorplace;
726 result_doordir = doordir;
727 result_roomplace = roomplace;
734 VoxelManipulator &vmanip;
737 PseudoRandom &m_random;
740 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
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].d == 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);
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(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);
830 bool r = walker.findPlaceForDoor(doorplace, doordir);
834 if(random.range(0,1)==0)
836 make_door1(vmanip, doorplace, doordir);
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);
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);
859 // Don't actually make a door
860 roomplace -= doordir;
866 Noise functions. Make sure seed is mangled differently in each one.
870 Scaling the output of the noise function affects the overdrive of the
871 contour function, which affects the shape of the output considerably.
873 #define CAVE_NOISE_SCALE 12.0
874 //#define CAVE_NOISE_SCALE 10.0
875 //#define CAVE_NOISE_SCALE 7.5
876 //#define CAVE_NOISE_SCALE 5.0
877 //#define CAVE_NOISE_SCALE 1.0
879 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
880 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
882 NoiseParams get_cave_noise1_params(u64 seed)
884 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
885 200, CAVE_NOISE_SCALE);*/
886 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
887 100, CAVE_NOISE_SCALE);*/
888 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
889 100, CAVE_NOISE_SCALE);*/
890 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
891 100, CAVE_NOISE_SCALE);*/
892 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
893 50, CAVE_NOISE_SCALE);
894 //return NoiseParams(NOISE_CONSTANT_ONE);
897 NoiseParams get_cave_noise2_params(u64 seed)
899 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
900 200, CAVE_NOISE_SCALE);*/
901 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
902 100, CAVE_NOISE_SCALE);*/
903 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
904 100, CAVE_NOISE_SCALE);*/
905 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
906 50, CAVE_NOISE_SCALE);
907 //return NoiseParams(NOISE_CONSTANT_ONE);
910 NoiseParams get_ground_noise1_params(u64 seed)
912 return NoiseParams(NOISE_PERLIN, seed+983240, 5,
916 NoiseParams get_ground_crumbleness_params(u64 seed)
918 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
922 NoiseParams get_ground_wetness_params(u64 seed)
924 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
928 bool is_cave(u64 seed, v3s16 p)
930 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
931 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
932 return d1*d2 > CAVE_NOISE_THRESHOLD;
936 Ground density noise shall be interpreted by using this.
938 TODO: No perlin noises here, they should be outsourced
940 NOTE: The speed of these actually isn't terrible
942 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
944 //return ((double)p.Y < ground_noise1_val);
946 double f = 0.55 + noise2d_perlin(
947 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
948 seed+920381, 3, 0.5);
953 double h = WATER_LEVEL + 10 * noise2d_perlin(
954 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
958 return ((double)p.Y - h < ground_noise1_val * f);
962 Queries whether a position is ground or not.
964 bool is_ground(u64 seed, v3s16 p)
966 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
967 return val_is_ground(val1, p, seed);
970 // Amount of trees per area in nodes
971 double tree_amount_2d(u64 seed, v2s16 p)
973 /*double noise = noise2d_perlin(
974 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
976 double noise = noise2d_perlin(
977 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
979 double zeroval = -0.35;
983 return 0.04 * (noise-zeroval) / (1.0-zeroval);
987 double randomstone_amount_2d(u64 seed, v2s16 p)
989 double noise = noise2d_perlin(
990 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
991 seed+3829434, 5, 0.66);
992 double zeroval = 0.1;
996 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1000 double largestone_amount_2d(u64 seed, v2s16 p)
1002 double noise = noise2d_perlin(
1003 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1004 seed+14143242, 5, 0.66);
1005 double zeroval = 0.3;
1009 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1013 Incrementally find ground level from 3d noise
1015 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1017 // Start a bit fuzzy to make averaging lower precision values
1019 s16 level = myrand_range(-precision/2, precision/2);
1020 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1022 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1024 // First find non-ground by going upwards
1025 // Don't stop in caves.
1027 s16 max = level+dec[i-1]*2;
1028 v3s16 p(p2d.X, level, p2d.Y);
1029 for(; p.Y < max; p.Y += dec[i])
1031 if(!is_ground(seed, p))
1038 // Then find ground by going downwards from there.
1039 // Go in caves, too, when precision is 1.
1041 s16 min = level-dec[i-1]*2;
1042 v3s16 p(p2d.X, level, p2d.Y);
1043 for(; p.Y>min; p.Y-=dec[i])
1045 bool ground = is_ground(seed, p);
1046 /*if(dec[i] == 1 && is_cave(seed, p))
1057 // This is more like the actual ground level
1058 level += dec[i-1]/2;
1063 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1065 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1067 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1068 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1070 a += find_ground_level_from_noise(seed,
1071 v2s16(node_min.X, node_min.Y), p);
1072 a += find_ground_level_from_noise(seed,
1073 v2s16(node_min.X, node_max.Y), p);
1074 a += find_ground_level_from_noise(seed,
1075 v2s16(node_max.X, node_max.Y), p);
1076 a += find_ground_level_from_noise(seed,
1077 v2s16(node_max.X, node_min.Y), p);
1078 a += find_ground_level_from_noise(seed,
1079 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1084 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1086 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1088 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1089 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1092 a = MYMAX(a, find_ground_level_from_noise(seed,
1093 v2s16(node_min.X, node_min.Y), p));
1094 a = MYMAX(a, find_ground_level_from_noise(seed,
1095 v2s16(node_min.X, node_max.Y), p));
1096 a = MYMAX(a, find_ground_level_from_noise(seed,
1097 v2s16(node_max.X, node_max.Y), p));
1098 a = MYMAX(a, find_ground_level_from_noise(seed,
1099 v2s16(node_min.X, node_min.Y), p));
1101 a = MYMAX(a, find_ground_level_from_noise(seed,
1102 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1103 // Side middle points
1104 a = MYMAX(a, find_ground_level_from_noise(seed,
1105 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1106 a = MYMAX(a, find_ground_level_from_noise(seed,
1107 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1108 a = MYMAX(a, find_ground_level_from_noise(seed,
1109 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1110 a = MYMAX(a, find_ground_level_from_noise(seed,
1111 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1115 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1117 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1119 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1120 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1123 a = MYMIN(a, find_ground_level_from_noise(seed,
1124 v2s16(node_min.X, node_min.Y), p));
1125 a = MYMIN(a, find_ground_level_from_noise(seed,
1126 v2s16(node_min.X, node_max.Y), p));
1127 a = MYMIN(a, find_ground_level_from_noise(seed,
1128 v2s16(node_max.X, node_max.Y), p));
1129 a = MYMIN(a, find_ground_level_from_noise(seed,
1130 v2s16(node_min.X, node_min.Y), p));
1132 a = MYMIN(a, find_ground_level_from_noise(seed,
1133 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1134 // Side middle points
1135 a = MYMIN(a, find_ground_level_from_noise(seed,
1136 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1137 a = MYMIN(a, find_ground_level_from_noise(seed,
1138 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1139 a = MYMIN(a, find_ground_level_from_noise(seed,
1140 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1141 a = MYMIN(a, find_ground_level_from_noise(seed,
1142 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1146 bool block_is_underground(u64 seed, v3s16 blockpos)
1148 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1149 seed, v2s16(blockpos.X, blockpos.Z));
1151 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1158 #define AVERAGE_MUD_AMOUNT 4
1160 double base_rock_level_2d(u64 seed, v2s16 p)
1162 // The base ground level
1163 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1164 + 20. * noise2d_perlin(
1165 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1166 (seed>>32)+654879876, 6, 0.6);
1168 /*// A bit hillier one
1169 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1170 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1171 (seed>>27)+90340, 6, 0.69);
1175 // Higher ground level
1176 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1177 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1178 seed+85039, 5, 0.69);
1179 //higher = 30; // For debugging
1181 // Limit higher to at least base
1185 // Steepness factor of cliffs
1186 double b = 1.0 + 1.0 * noise2d_perlin(
1187 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1189 b = rangelim(b, 0.0, 1000.0);
1192 b = rangelim(b, 3.0, 1000.0);
1193 //dstream<<"b="<<b<<std::endl;
1196 // Offset to more low
1197 double a_off = -0.2;
1198 // High/low selector
1199 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1200 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1201 seed-359, 6, 0.7));*/
1202 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1203 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1204 seed-359, 5, 0.60));
1206 a = rangelim(a, 0.0, 1.0);
1208 //dstream<<"a="<<a<<std::endl;
1210 double h = base*(1.0-a) + higher*a;
1217 double get_mud_add_amount(u64 seed, v2s16 p)
1219 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1220 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1221 seed+91013, 3, 0.55));
1225 bool get_have_sand(u64 seed, v2s16 p2d)
1227 // Determine whether to have sand here
1228 double sandnoise = noise2d_perlin(
1229 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1230 seed+59420, 3, 0.50);
1232 return (sandnoise > -0.15);
1236 Adds random objects to block, depending on the content of the block
1238 void add_random_objects(MapBlock *block)
1240 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1241 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1243 bool last_node_walkable = false;
1244 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1247 MapNode n = block->getNodeNoEx(p);
1248 if(n.d == CONTENT_IGNORE)
1250 if(content_features(n.d).liquid_type != LIQUID_NONE)
1252 if(content_features(n.d).walkable)
1254 last_node_walkable = true;
1257 if(last_node_walkable)
1259 // If block contains light information
1260 if(content_features(n.d).param_type == CPT_LIGHT)
1262 if(n.getLight(LIGHTBANK_DAY) <= 3)
1264 if(myrand() % 300 == 0)
1266 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1268 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1269 std::string data = obj->getStaticData();
1270 StaticObject s_obj(obj->getType(),
1271 obj->getBasePosition(), data);
1273 block->m_static_objects.insert(0, s_obj);
1274 block->m_static_objects.insert(0, s_obj);
1275 block->m_static_objects.insert(0, s_obj);
1276 block->m_static_objects.insert(0, s_obj);
1277 block->m_static_objects.insert(0, s_obj);
1278 block->m_static_objects.insert(0, s_obj);
1281 if(myrand() % 1000 == 0)
1283 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1285 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1286 std::string data = obj->getStaticData();
1287 StaticObject s_obj(obj->getType(),
1288 obj->getBasePosition(), data);
1290 block->m_static_objects.insert(0, s_obj);
1296 last_node_walkable = false;
1299 block->setChangedFlag();
1302 void make_block(BlockMakeData *data)
1306 dstream<<"makeBlock: no-op"<<std::endl;
1310 v3s16 blockpos = data->blockpos;
1312 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1313 <<blockpos.Z<<")"<<std::endl;*/
1315 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1316 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1317 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1318 // Area of center block
1319 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1320 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1321 // Full allocated area
1322 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1323 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1325 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1327 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1330 Get average ground level from noise
1333 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1334 data->seed, v2s16(blockpos.X, blockpos.Z));
1335 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1337 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1339 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1340 data->seed, v2s16(blockpos.X, blockpos.Z));
1341 // Minimum amount of ground above the top of the central block
1342 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1344 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1345 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1346 // Maximum amount of ground above the bottom of the central block
1347 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1350 Special case for high air or water: Just fill with air and water.
1352 if(maximum_ground_depth < -20)
1354 for(s16 x=node_min.X; x<=node_max.X; x++)
1355 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1360 // Use fast index incrementing
1361 v3s16 em = vmanip.m_area.getExtent();
1362 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1363 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1365 // Only modify places that have no content
1366 if(vmanip.m_data[i].d == CONTENT_IGNORE)
1368 if(y <= WATER_LEVEL)
1369 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1371 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1374 data->vmanip->m_area.add_y(em, i, 1);
1384 If block is deep underground, this is set to true and ground
1385 density noise is not generated, for speed optimization.
1387 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1390 Create a block-specific seed
1392 u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234
1393 + full_node_min.Y*42123 + full_node_min.X*23;
1399 //NoiseBuffer noisebuf1;
1400 //NoiseBuffer noisebuf2;
1401 NoiseBuffer noisebuf_cave;
1402 NoiseBuffer noisebuf_ground;
1403 NoiseBuffer noisebuf_ground_crumbleness;
1404 NoiseBuffer noisebuf_ground_wetness;
1406 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1407 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1409 //TimeTaker timer("noisebuf.create");
1415 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1416 minpos_f.X, minpos_f.Y, minpos_f.Z,
1417 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1419 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1427 v3f sl = v3f(4.0, 4.0, 4.0);
1432 if(all_is_ground_except_caves == false)
1433 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1434 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1435 minpos_f.X, minpos_f.Y, minpos_f.Z,
1436 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1440 Ground property noise
1442 sl = v3f(2.5, 2.5, 2.5);
1443 noisebuf_ground_crumbleness.create(
1444 get_ground_crumbleness_params(data->seed),
1445 minpos_f.X, minpos_f.Y, minpos_f.Z,
1446 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1448 noisebuf_ground_wetness.create(
1449 get_ground_wetness_params(data->seed),
1450 minpos_f.X, minpos_f.Y, minpos_f.Z,
1451 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1456 Make base ground level
1459 for(s16 x=node_min.X; x<=node_max.X; x++)
1460 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1465 // Use fast index incrementing
1466 v3s16 em = vmanip.m_area.getExtent();
1467 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1468 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1470 // Only modify places that have no content
1471 if(vmanip.m_data[i].d == CONTENT_IGNORE)
1473 // First priority: make air and water.
1474 // This avoids caves inside water.
1475 if(all_is_ground_except_caves == false
1476 && val_is_ground(noisebuf_ground.get(x,y,z),
1477 v3s16(x,y,z), data->seed) == false)
1479 if(y <= WATER_LEVEL)
1480 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1482 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1484 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1485 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1487 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1490 data->vmanip->m_area.add_y(em, i, 1);
1500 PseudoRandom mineralrandom(blockseed);
1505 for(s16 i=0; i<approx_ground_depth/4; i++)
1507 if(mineralrandom.next()%50 == 0)
1509 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1510 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1511 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1512 for(u16 i=0; i<27; i++)
1514 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1515 u32 vi = vmanip.m_area.index(p);
1516 if(vmanip.m_data[vi].d == CONTENT_STONE)
1517 if(mineralrandom.next()%8 == 0)
1518 vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1527 u16 a = mineralrandom.range(0,15);
1529 u16 amount = 20 * a/1000;
1530 for(s16 i=0; i<amount; i++)
1532 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1533 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1534 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1536 u8 base_content = CONTENT_STONE;
1537 MapNode new_content(CONTENT_IGNORE);
1540 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1542 new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1546 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1547 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1548 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1549 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1551 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1553 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1557 if(new_content.d != CONTENT_IGNORE)
1559 for(u16 i=0; i<27; i++)
1561 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1562 u32 vi = vmanip.m_area.index(p);
1563 if(vmanip.m_data[vi].d == base_content)
1565 if(mineralrandom.next()%sparseness == 0)
1566 vmanip.m_data[vi] = new_content;
1575 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1576 //for(s16 i=0; i<50; i++)
1577 u16 coal_amount = 30;
1578 u16 coal_rareness = 60 / coal_amount;
1579 if(coal_rareness == 0)
1581 if(mineralrandom.next()%coal_rareness == 0)
1583 u16 a = mineralrandom.next() % 16;
1584 u16 amount = coal_amount * a*a*a / 1000;
1585 for(s16 i=0; i<amount; i++)
1587 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1588 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1589 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1590 for(u16 i=0; i<27; i++)
1592 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1593 u32 vi = vmanip.m_area.index(p);
1594 if(vmanip.m_data[vi].d == CONTENT_STONE)
1595 if(mineralrandom.next()%8 == 0)
1596 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1603 u16 iron_amount = 8;
1604 u16 iron_rareness = 60 / iron_amount;
1605 if(iron_rareness == 0)
1607 if(mineralrandom.next()%iron_rareness == 0)
1609 u16 a = mineralrandom.next() % 16;
1610 u16 amount = iron_amount * a*a*a / 1000;
1611 for(s16 i=0; i<amount; i++)
1613 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1614 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1615 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1616 for(u16 i=0; i<27; i++)
1618 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1619 u32 vi = vmanip.m_area.index(p);
1620 if(vmanip.m_data[vi].d == CONTENT_STONE)
1621 if(mineralrandom.next()%8 == 0)
1622 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1629 Add mud and sand and others underground (in place of stone)
1632 for(s16 x=node_min.X; x<=node_max.X; x++)
1633 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1638 // Use fast index incrementing
1639 v3s16 em = vmanip.m_area.getExtent();
1640 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1641 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1643 if(vmanip.m_data[i].d == CONTENT_STONE)
1645 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1647 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1648 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1650 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1652 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1654 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1655 vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1659 data->vmanip->m_area.add_y(em, i, -1);
1668 //if(node_min.Y < approx_groundlevel)
1669 //if(myrand() % 3 == 0)
1670 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1671 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1672 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1673 float dungeon_rarity = 0.02;
1674 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1676 && node_min.Y < approx_groundlevel)
1678 // Dungeon generator doesn't modify places which have this set
1679 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1680 | VMANIP_FLAG_DUNGEON_PRESERVE);
1682 // Set all air and water to be untouchable to make dungeons open
1683 // to caves and open air
1684 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1685 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1690 // Use fast index incrementing
1691 v3s16 em = vmanip.m_area.getExtent();
1692 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1693 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1695 if(vmanip.m_data[i].d == CONTENT_AIR)
1696 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1697 else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1698 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1699 data->vmanip->m_area.add_y(em, i, -1);
1704 PseudoRandom random(blockseed+2);
1707 make_dungeon1(vmanip, random);
1709 // Convert some cobble to mossy cobble
1710 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1711 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1716 // Use fast index incrementing
1717 v3s16 em = vmanip.m_area.getExtent();
1718 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1719 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1721 // (noisebuf not used because it doesn't contain the
1723 double wetness = noise3d_param(
1724 get_ground_wetness_params(data->seed), x,y,z);
1725 double d = noise3d_perlin((float)x/2.5,
1726 (float)y/2.5,(float)z/2.5,
1728 if(vmanip.m_data[i].d == CONTENT_COBBLE)
1732 vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE;
1735 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1738 vmanip.m_data[i].d = CONTENT_MUD;
1740 data->vmanip->m_area.add_y(em, i, -1);
1747 Add top and bottom side of water to transforming_liquid queue
1750 for(s16 x=node_min.X; x<=node_max.X; x++)
1751 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1756 bool water_found = false;
1757 // Use fast index incrementing
1758 v3s16 em = vmanip.m_area.getExtent();
1759 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1760 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1762 if(water_found == false)
1764 if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1766 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1767 data->transforming_liquid.push_back(p);
1773 // This can be done because water_found can only
1774 // turn to true and end up here after going through
1776 if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE)
1778 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1779 data->transforming_liquid.push_back(p);
1780 water_found = false;
1784 data->vmanip->m_area.add_y(em, i, -1);
1790 If close to ground level
1793 //if(abs(approx_ground_depth) < 30)
1794 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1800 for(s16 x=node_min.X; x<=node_max.X; x++)
1801 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1806 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1807 bool have_sand = false;
1808 u32 current_depth = 0;
1809 bool air_detected = false;
1810 bool water_detected = false;
1811 // Use fast index incrementing
1812 s16 start_y = node_max.Y+2;
1813 v3s16 em = vmanip.m_area.getExtent();
1814 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1815 for(s16 y=start_y; y>=node_min.Y-3; y--)
1817 if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1818 water_detected = true;
1819 if(vmanip.m_data[i].d == CONTENT_AIR)
1820 air_detected = true;
1822 if((vmanip.m_data[i].d == CONTENT_STONE
1823 || vmanip.m_data[i].d == CONTENT_GRASS
1824 || vmanip.m_data[i].d == CONTENT_MUD
1825 || vmanip.m_data[i].d == CONTENT_SAND
1826 || vmanip.m_data[i].d == CONTENT_GRAVEL
1827 ) && (air_detected || water_detected))
1829 if(current_depth == 0 && y <= WATER_LEVEL+2
1830 && possibly_have_sand)
1833 if(current_depth < 4)
1837 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1840 else if(current_depth==0 && !water_detected
1841 && y >= WATER_LEVEL && air_detected)
1842 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
1845 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1849 if(vmanip.m_data[i].d == CONTENT_MUD
1850 || vmanip.m_data[i].d == CONTENT_GRASS)
1851 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1856 if(current_depth >= 8)
1859 else if(current_depth != 0)
1862 data->vmanip->m_area.add_y(em, i, -1);
1872 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
1873 PseudoRandom treerandom(blockseed);
1874 // Put trees in random places on part of division
1875 for(u32 i=0; i<tree_count; i++)
1877 s16 x = treerandom.range(node_min.X, node_max.X);
1878 s16 z = treerandom.range(node_min.Z, node_max.Z);
1879 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
1880 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
1881 // Don't make a tree under water level
1884 // Make sure tree fits (only trees whose starting point is
1885 // at this block are added)
1886 if(y < node_min.Y || y > node_max.Y)
1889 Find exact ground level
1893 for(; p.Y >= y-6; p.Y--)
1895 u32 i = data->vmanip->m_area.index(p);
1896 MapNode *n = &data->vmanip->m_data[i];
1897 if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE)
1903 // If not found, handle next one
1907 Trees grow only on mud and grass
1910 u32 i = data->vmanip->m_area.index(p);
1911 MapNode *n = &data->vmanip->m_data[i];
1912 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1915 // Tree will be placed one higher
1918 make_tree(vmanip, p);
1923 Add some kind of random stones
1926 u32 random_stone_count = block_area_nodes *
1927 randomstone_amount_2d(data->seed, p2d_center);
1928 // Put in random places on part of division
1929 for(u32 i=0; i<random_stone_count; i++)
1931 s16 x = myrand_range(node_min.X, node_max.X);
1932 s16 z = myrand_range(node_min.Z, node_max.Z);
1933 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
1934 // Don't add under water level
1935 /*if(y < WATER_LEVEL)
1937 // Don't add if doesn't belong to this block
1938 if(y < node_min.Y || y > node_max.Y)
1943 u32 i = data->vmanip->m_area.index(v3s16(p));
1944 MapNode *n = &data->vmanip->m_data[i];
1945 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1948 // Will be placed one higher
1951 make_randomstone(data->vmanip, p);
1960 u32 large_stone_count = block_area_nodes *
1961 largestone_amount_2d(data->seed, p2d_center);
1962 //u32 large_stone_count = 1;
1963 // Put in random places on part of division
1964 for(u32 i=0; i<large_stone_count; i++)
1966 s16 x = myrand_range(node_min.X, node_max.X);
1967 s16 z = myrand_range(node_min.Z, node_max.Z);
1968 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
1969 // Don't add under water level
1970 /*if(y < WATER_LEVEL)
1972 // Don't add if doesn't belong to this block
1973 if(y < node_min.Y || y > node_max.Y)
1978 u32 i = data->vmanip->m_area.index(v3s16(p));
1979 MapNode *n = &data->vmanip->m_data[i];
1980 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1983 // Will be placed one lower
1986 make_largestone(data->vmanip, p);
1993 BlockMakeData::BlockMakeData():
1999 BlockMakeData::~BlockMakeData()
2004 }; // namespace mapgen