3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
38 Some helper functions for the map generator
42 // Returns Y one under area minimum if not found
43 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
44 INodeDefManager *ndef)
46 v3s16 em = vmanip.m_area.getExtent();
47 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
48 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
49 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
51 for(y=y_nodes_max; y>=y_nodes_min; y--)
53 MapNode &n = vmanip.m_data[i];
54 if(ndef->get(n).walkable)
57 vmanip.m_area.add_y(em, i, -1);
62 return y_nodes_min - 1;
66 // Returns Y one under area minimum if not found
67 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
68 INodeDefManager *ndef)
70 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
71 return vmanip.m_area.MinEdge.Y-1;
72 v3s16 em = vmanip.m_area.getExtent();
73 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
74 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
75 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
77 content_t c_tree = ndef->getId("mapgen_tree");
78 content_t c_leaves = ndef->getId("mapgen_leaves");
79 for(y=y_nodes_max; y>=y_nodes_min; y--)
81 MapNode &n = vmanip.m_data[i];
82 if(ndef->get(n).walkable
83 && n.getContent() != c_tree
84 && n.getContent() != c_leaves)
87 vmanip.m_area.add_y(em, i, -1);
92 return y_nodes_min - 1;
96 // Returns Y one under area minimum if not found
97 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
98 INodeDefManager *ndef)
100 v3s16 em = vmanip.m_area.getExtent();
101 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
102 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
103 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
105 content_t c_stone = ndef->getId("mapgen_stone");
106 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
107 for(y=y_nodes_max; y>=y_nodes_min; y--)
109 MapNode &n = vmanip.m_data[i];
110 content_t c = n.getContent();
111 if(c != CONTENT_IGNORE && (
112 c == c_stone || c == c_desert_stone))
115 vmanip.m_area.add_y(em, i, -1);
120 return y_nodes_min - 1;
126 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
127 INodeDefManager *ndef)
129 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
131 s16 trunk_h = myrand_range(2, 3);
133 for(s16 ii=0; ii<trunk_h; ii++)
135 if(vmanip.m_area.contains(p1))
136 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
141 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
142 INodeDefManager *ndef)
144 MapNode cactusnode(ndef->getId("mapgen_cactus"));
148 for(s16 ii=0; ii<trunk_h; ii++)
150 if(vmanip.m_area.contains(p1))
151 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
159 Dungeon making routines
162 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
163 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
164 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
165 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
167 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
168 INodeDefManager *ndef)
171 for(s16 z=0; z<roomsize.Z; z++)
172 for(s16 y=0; y<roomsize.Y; y++)
175 v3s16 p = roomplace + v3s16(0,y,z);
176 if(vmanip.m_area.contains(p) == false)
178 u32 vi = vmanip.m_area.index(p);
179 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
181 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
184 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
185 if(vmanip.m_area.contains(p) == false)
187 u32 vi = vmanip.m_area.index(p);
188 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
190 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
195 for(s16 x=0; x<roomsize.X; x++)
196 for(s16 y=0; y<roomsize.Y; y++)
199 v3s16 p = roomplace + v3s16(x,y,0);
200 if(vmanip.m_area.contains(p) == false)
202 u32 vi = vmanip.m_area.index(p);
203 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
205 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
208 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
209 if(vmanip.m_area.contains(p) == false)
211 u32 vi = vmanip.m_area.index(p);
212 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
214 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
218 // Make +-Y walls (floor and ceiling)
219 for(s16 z=0; z<roomsize.Z; z++)
220 for(s16 x=0; x<roomsize.X; x++)
223 v3s16 p = roomplace + v3s16(x,0,z);
224 if(vmanip.m_area.contains(p) == false)
226 u32 vi = vmanip.m_area.index(p);
227 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
229 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
232 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
233 if(vmanip.m_area.contains(p) == false)
235 u32 vi = vmanip.m_area.index(p);
236 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
238 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
243 for(s16 z=1; z<roomsize.Z-1; z++)
244 for(s16 y=1; y<roomsize.Y-1; y++)
245 for(s16 x=1; x<roomsize.X-1; x++)
247 v3s16 p = roomplace + v3s16(x,y,z);
248 if(vmanip.m_area.contains(p) == false)
250 u32 vi = vmanip.m_area.index(p);
251 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
252 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
256 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
257 u8 avoid_flags, MapNode n, u8 or_flags)
259 for(s16 z=0; z<size.Z; z++)
260 for(s16 y=0; y<size.Y; y++)
261 for(s16 x=0; x<size.X; x++)
263 v3s16 p = place + v3s16(x,y,z);
264 if(vmanip.m_area.contains(p) == false)
266 u32 vi = vmanip.m_area.index(p);
267 if(vmanip.m_flags[vi] & avoid_flags)
269 vmanip.m_flags[vi] |= or_flags;
270 vmanip.m_data[vi] = n;
274 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
275 INodeDefManager *ndef)
277 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
278 VMANIP_FLAG_DUNGEON_INSIDE);
281 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
282 INodeDefManager *ndef)
284 make_hole1(vmanip, doorplace, ndef);
285 // Place torch (for testing)
286 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
289 static v3s16 rand_ortho_dir(PseudoRandom &random)
291 if(random.next()%2==0)
292 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
294 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
297 static v3s16 turn_xz(v3s16 olddir, int t)
317 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
319 int turn = random.range(0,2);
328 dir = turn_xz(olddir, 0);
331 dir = turn_xz(olddir, 1);
335 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
336 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
337 PseudoRandom &random, INodeDefManager *ndef)
339 make_hole1(vmanip, doorplace, ndef);
340 v3s16 p0 = doorplace;
344 length = random.range(1,13);
346 length = random.range(1,6);
347 length = random.range(1,13);
348 u32 partlength = random.range(1,13);
351 if(random.next()%2 == 0 && partlength >= 3)
352 make_stairs = random.next()%2 ? 1 : -1;
353 for(u32 i=0; i<length; i++)
359 /*// If already empty
360 if(vmanip.getNodeNoExNoEmerge(p).getContent()
362 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
367 if(vmanip.m_area.contains(p) == true
368 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
372 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
373 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
374 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
375 VMANIP_FLAG_DUNGEON_INSIDE);
376 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
377 VMANIP_FLAG_DUNGEON_INSIDE);
381 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
382 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
383 make_hole1(vmanip, p, ndef);
384 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
385 VMANIP_FLAG_DUNGEON_INSIDE);*/
392 // Can't go here, turn away
393 dir = turn_xz(dir, random.range(0,1));
394 make_stairs = -make_stairs;
396 partlength = random.range(1,length);
401 if(partcount >= partlength)
405 dir = random_turn(random, dir);
407 partlength = random.range(1,length);
410 if(random.next()%2 == 0 && partlength >= 3)
411 make_stairs = random.next()%2 ? 1 : -1;
422 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
423 INodeDefManager *ndef):
434 m_dir = rand_ortho_dir(m_random);
437 void setPos(v3s16 pos)
442 void setDir(v3s16 dir)
447 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
449 for(u32 i=0; i<100; i++)
451 v3s16 p = m_pos + m_dir;
452 v3s16 p1 = p + v3s16(0,1,0);
453 if(vmanip.m_area.contains(p) == false
454 || vmanip.m_area.contains(p1) == false
460 if(vmanip.getNodeNoExNoEmerge(p).getContent()
461 == m_ndef->getId("mapgen_cobble")
462 && vmanip.getNodeNoExNoEmerge(p1).getContent()
463 == m_ndef->getId("mapgen_cobble"))
465 // Found wall, this is a good place!
468 // Randomize next direction
473 Determine where to move next
475 // Jump one up if the actual space is there
476 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
477 == m_ndef->getId("mapgen_cobble")
478 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
480 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
483 // Jump one down if the actual space is there
484 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
485 == m_ndef->getId("mapgen_cobble")
486 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
488 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
491 // Check if walking is now possible
492 if(vmanip.getNodeNoExNoEmerge(p).getContent()
494 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
497 // Cannot continue walking here
507 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
508 v3s16 &result_doordir, v3s16 &result_roomplace)
510 for(s16 trycount=0; trycount<30; trycount++)
514 bool r = findPlaceForDoor(doorplace, doordir);
518 // X east, Z north, Y up
520 if(doordir == v3s16(1,0,0)) // X+
521 roomplace = doorplace +
522 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
523 if(doordir == v3s16(-1,0,0)) // X-
524 roomplace = doorplace +
525 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
526 if(doordir == v3s16(0,0,1)) // Z+
527 roomplace = doorplace +
528 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
529 if(doordir == v3s16(0,0,-1)) // Z-
530 roomplace = doorplace +
531 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
534 if(doordir == v3s16(1,0,0)) // X+
535 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
536 if(doordir == v3s16(-1,0,0)) // X-
537 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
538 if(doordir == v3s16(0,0,1)) // Z+
539 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
540 if(doordir == v3s16(0,0,-1)) // Z-
541 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
546 for(s16 z=1; z<roomsize.Z-1; z++)
547 for(s16 y=1; y<roomsize.Y-1; y++)
548 for(s16 x=1; x<roomsize.X-1; x++)
550 v3s16 p = roomplace + v3s16(x,y,z);
551 if(vmanip.m_area.contains(p) == false)
556 if(vmanip.m_flags[vmanip.m_area.index(p)]
557 & VMANIP_FLAG_DUNGEON_INSIDE)
568 result_doorplace = doorplace;
569 result_doordir = doordir;
570 result_roomplace = roomplace;
577 VoxelManipulator &vmanip;
580 PseudoRandom &m_random;
581 INodeDefManager *m_ndef;
584 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
585 INodeDefManager *ndef)
587 v3s16 areasize = vmanip.m_area.getExtent();
592 Find place for first room
595 for(u32 i=0; i<100; i++)
597 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
598 roomplace = vmanip.m_area.MinEdge + v3s16(
599 random.range(0,areasize.X-roomsize.X-1),
600 random.range(0,areasize.Y-roomsize.Y-1),
601 random.range(0,areasize.Z-roomsize.Z-1));
603 Check that we're not putting the room to an unknown place,
604 otherwise it might end up floating in the air
607 for(s16 z=1; z<roomsize.Z-1; z++)
608 for(s16 y=1; y<roomsize.Y-1; y++)
609 for(s16 x=1; x<roomsize.X-1; x++)
611 v3s16 p = roomplace + v3s16(x,y,z);
612 u32 vi = vmanip.m_area.index(p);
613 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
618 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
632 Stores the center position of the last room made, so that
633 a new corridor can be started from the last room instead of
634 the new room, if chosen so.
636 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
638 u32 room_count = random.range(2,7);
639 for(u32 i=0; i<room_count; i++)
641 // Make a room to the determined place
642 make_room1(vmanip, roomsize, roomplace, ndef);
644 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
646 // Place torch at room center (for testing)
647 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
650 if(i == room_count-1)
653 // Determine walker start position
655 bool start_in_last_room = (random.range(0,2)!=0);
656 //bool start_in_last_room = true;
658 v3s16 walker_start_place;
660 if(start_in_last_room)
662 walker_start_place = last_room_center;
666 walker_start_place = room_center;
667 // Store center of current room as the last one
668 last_room_center = room_center;
671 // Create walker and find a place for a door
672 RoomWalker walker(vmanip, walker_start_place, random, ndef);
675 bool r = walker.findPlaceForDoor(doorplace, doordir);
679 if(random.range(0,1)==0)
681 make_door1(vmanip, doorplace, doordir, ndef);
683 // Don't actually make a door
684 doorplace -= doordir;
686 // Make a random corridor starting from the door
688 v3s16 corridor_end_dir;
689 make_corridor(vmanip, doorplace, doordir, corridor_end,
690 corridor_end_dir, random, ndef);
692 // Find a place for a random sized room
693 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
694 walker.setPos(corridor_end);
695 walker.setDir(corridor_end_dir);
696 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
700 if(random.range(0,1)==0)
702 make_door1(vmanip, doorplace, doordir, ndef);
704 // Don't actually make a door
705 roomplace -= doordir;
712 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
713 INodeDefManager *ndef)
717 s32 r = random.range(0, 3);
719 dir = v3s16( 1, 0, 0);
723 dir = v3s16(-1, 0, 0);
727 dir = v3s16( 0, 0, 1);
731 dir = v3s16( 0, 0,-1);
734 v3s16 p = vmanip.m_area.MinEdge + v3s16(
735 16+random.range(0,15),
736 16+random.range(0,15),
737 16+random.range(0,15));
738 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
739 u32 length = random.range(3,15);
740 for(u32 j=0; j<length; j++)
743 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
749 Noise functions. Make sure seed is mangled differently in each one.
754 Scaling the output of the noise function affects the overdrive of the
755 contour function, which affects the shape of the output considerably.
757 #define CAVE_NOISE_SCALE 12.0
758 //#define CAVE_NOISE_SCALE 10.0
759 //#define CAVE_NOISE_SCALE 7.5
760 //#define CAVE_NOISE_SCALE 5.0
761 //#define CAVE_NOISE_SCALE 1.0
763 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
764 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
766 NoiseParams get_cave_noise1_params(u64 seed)
768 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
769 200, CAVE_NOISE_SCALE);*/
770 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
771 100, CAVE_NOISE_SCALE);*/
772 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
773 100, CAVE_NOISE_SCALE);*/
774 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
775 100, CAVE_NOISE_SCALE);*/
776 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
777 50, CAVE_NOISE_SCALE);
778 //return NoiseParams(NOISE_CONSTANT_ONE);
781 NoiseParams get_cave_noise2_params(u64 seed)
783 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
784 200, CAVE_NOISE_SCALE);*/
785 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
786 100, CAVE_NOISE_SCALE);*/
787 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
788 100, CAVE_NOISE_SCALE);*/
789 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
790 50, CAVE_NOISE_SCALE);
791 //return NoiseParams(NOISE_CONSTANT_ONE);
794 NoiseParams get_ground_noise1_params(u64 seed)
796 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
800 NoiseParams get_ground_crumbleness_params(u64 seed)
802 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
806 NoiseParams get_ground_wetness_params(u64 seed)
808 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
812 bool is_cave(u64 seed, v3s16 p)
814 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
815 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
816 return d1*d2 > CAVE_NOISE_THRESHOLD;
820 Ground density noise shall be interpreted by using this.
822 TODO: No perlin noises here, they should be outsourced
824 NOTE: The speed of these actually isn't terrible
826 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
828 //return ((double)p.Y < ground_noise1_val);
830 double f = 0.55 + noise2d_perlin(
831 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
832 seed+920381, 3, 0.45);
837 double h = WATER_LEVEL + 10 * noise2d_perlin(
838 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
842 return ((double)p.Y - h < ground_noise1_val * f);
846 Queries whether a position is ground or not.
848 bool is_ground(u64 seed, v3s16 p)
850 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
851 return val_is_ground(val1, p, seed);
855 // Amount of trees per area in nodes
856 double tree_amount_2d(u64 seed, v2s16 p)
858 /*double noise = noise2d_perlin(
859 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
861 double noise = noise2d_perlin(
862 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
864 double zeroval = -0.39;
868 return 0.04 * (noise-zeroval) / (1.0-zeroval);
872 double surface_humidity_2d(u64 seed, v2s16 p)
874 double noise = noise2d_perlin(
875 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
876 seed+72384, 4, 0.66);
877 noise = (noise + 1.0)/2.0;
886 Incrementally find ground level from 3d noise
888 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
890 // Start a bit fuzzy to make averaging lower precision values
892 s16 level = myrand_range(-precision/2, precision/2);
893 s16 dec[] = {31000, 100, 20, 4, 1, 0};
895 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
897 // First find non-ground by going upwards
898 // Don't stop in caves.
900 s16 max = level+dec[i-1]*2;
901 v3s16 p(p2d.X, level, p2d.Y);
902 for(; p.Y < max; p.Y += dec[i])
904 if(!is_ground(seed, p))
911 // Then find ground by going downwards from there.
912 // Go in caves, too, when precision is 1.
914 s16 min = level-dec[i-1]*2;
915 v3s16 p(p2d.X, level, p2d.Y);
916 for(; p.Y>min; p.Y-=dec[i])
918 bool ground = is_ground(seed, p);
919 /*if(dec[i] == 1 && is_cave(seed, p))
930 // This is more like the actual ground level
936 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
938 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
940 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
941 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
943 a += find_ground_level_from_noise(seed,
944 v2s16(node_min.X, node_min.Y), p);
945 a += find_ground_level_from_noise(seed,
946 v2s16(node_min.X, node_max.Y), p);
947 a += find_ground_level_from_noise(seed,
948 v2s16(node_max.X, node_max.Y), p);
949 a += find_ground_level_from_noise(seed,
950 v2s16(node_max.X, node_min.Y), p);
951 a += find_ground_level_from_noise(seed,
952 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
957 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
959 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
961 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
962 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
965 a = MYMAX(a, find_ground_level_from_noise(seed,
966 v2s16(node_min.X, node_min.Y), p));
967 a = MYMAX(a, find_ground_level_from_noise(seed,
968 v2s16(node_min.X, node_max.Y), p));
969 a = MYMAX(a, find_ground_level_from_noise(seed,
970 v2s16(node_max.X, node_max.Y), p));
971 a = MYMAX(a, find_ground_level_from_noise(seed,
972 v2s16(node_min.X, node_min.Y), p));
974 a = MYMAX(a, find_ground_level_from_noise(seed,
975 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
976 // Side middle points
977 a = MYMAX(a, find_ground_level_from_noise(seed,
978 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
979 a = MYMAX(a, find_ground_level_from_noise(seed,
980 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
981 a = MYMAX(a, find_ground_level_from_noise(seed,
982 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
983 a = MYMAX(a, find_ground_level_from_noise(seed,
984 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
988 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
990 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
992 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
993 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
996 a = MYMIN(a, find_ground_level_from_noise(seed,
997 v2s16(node_min.X, node_min.Y), p));
998 a = MYMIN(a, find_ground_level_from_noise(seed,
999 v2s16(node_min.X, node_max.Y), p));
1000 a = MYMIN(a, find_ground_level_from_noise(seed,
1001 v2s16(node_max.X, node_max.Y), p));
1002 a = MYMIN(a, find_ground_level_from_noise(seed,
1003 v2s16(node_min.X, node_min.Y), p));
1005 a = MYMIN(a, find_ground_level_from_noise(seed,
1006 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1007 // Side middle points
1008 a = MYMIN(a, find_ground_level_from_noise(seed,
1009 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1010 a = MYMIN(a, find_ground_level_from_noise(seed,
1011 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1012 a = MYMIN(a, find_ground_level_from_noise(seed,
1013 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1014 a = MYMIN(a, find_ground_level_from_noise(seed,
1015 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1020 // Required by mapgen.h
1021 bool block_is_underground(u64 seed, v3s16 blockpos)
1023 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1024 seed, v2s16(blockpos.X, blockpos.Z));*/
1025 // Nah, this is just a heuristic, just return something
1026 s16 minimum_groundlevel = WATER_LEVEL;
1028 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1034 #define AVERAGE_MUD_AMOUNT 4
1036 double base_rock_level_2d(u64 seed, v2s16 p)
1038 // The base ground level
1039 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1040 + 20. * noise2d_perlin(
1041 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1042 seed+82341, 5, 0.6);
1044 /*// A bit hillier one
1045 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1046 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1047 seed+93413, 6, 0.69);
1051 // Higher ground level
1052 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1053 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1054 seed+85039, 5, 0.6);
1055 //higher = 30; // For debugging
1057 // Limit higher to at least base
1061 // Steepness factor of cliffs
1062 double b = 0.85 + 0.5 * noise2d_perlin(
1063 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1065 b = rangelim(b, 0.0, 1000.0);
1068 b = rangelim(b, 0.5, 1000.0);
1069 // Values 1.5...100 give quite horrible looking slopes
1070 if(b > 1.5 && b < 100.0){
1076 //dstream<<"b="<<b<<std::endl;
1080 // Offset to more low
1081 double a_off = -0.20;
1082 // High/low selector
1083 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1084 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1085 seed+4213, 6, 0.7));*/
1086 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1087 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1088 seed+4213, 5, 0.69));
1090 a = rangelim(a, 0.0, 1.0);
1092 //dstream<<"a="<<a<<std::endl;
1094 double h = base*(1.0-a) + higher*a;
1101 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1103 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1106 double get_mud_add_amount(u64 seed, v2s16 p)
1108 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1109 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1110 seed+91013, 3, 0.55));
1113 bool get_have_beach(u64 seed, v2s16 p2d)
1115 // Determine whether to have sand here
1116 double sandnoise = noise2d_perlin(
1117 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1118 seed+59420, 3, 0.50);
1120 return (sandnoise > 0.15);
1129 BiomeType get_biome(u64 seed, v2s16 p2d)
1131 // Just do something very simple as for now
1132 double d = noise2d_perlin(
1133 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1134 seed+9130, 3, 0.50);
1137 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1142 u32 get_blockseed(u64 seed, v3s16 p)
1144 s32 x=p.X, y=p.Y, z=p.Z;
1145 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1148 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1150 void make_block(BlockMakeData *data)
1154 //dstream<<"makeBlock: no-op"<<std::endl;
1158 assert(data->vmanip);
1159 assert(data->nodedef);
1160 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1161 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1162 data->blockpos_requested.Z >= data->blockpos_min.Z);
1163 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1164 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1165 data->blockpos_requested.Z <= data->blockpos_max.Z);
1167 INodeDefManager *ndef = data->nodedef;
1169 // Hack: use minimum block coordinates for old code that assumes
1171 v3s16 blockpos = data->blockpos_requested;
1173 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1174 <<blockpos.Z<<")"<<std::endl;*/
1176 v3s16 blockpos_min = data->blockpos_min;
1177 v3s16 blockpos_max = data->blockpos_max;
1178 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1179 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1181 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1182 // Area of central chunk
1183 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1184 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1185 // Full allocated area
1186 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1187 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1189 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1191 const s16 max_spread_amount = MAP_BLOCKSIZE;
1193 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1194 * (blockpos_max.Y - blockpos_min.Y + 1)
1195 * (blockpos_max.Z - blockpos_max.Z + 1);
1197 int volume_nodes = volume_blocks *
1198 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1200 // Generated surface area
1201 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1203 // Horribly wrong heuristic, but better than nothing
1204 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1207 Create a block-specific seed
1209 u32 blockseed = get_blockseed(data->seed, full_node_min);
1212 Cache some ground type values for speed
1215 // Creates variables c_name=id and n_name=node
1216 #define CONTENT_VARIABLE(ndef, name)\
1217 content_t c_##name = ndef->getId("mapgen_" #name);\
1218 MapNode n_##name(c_##name);
1219 // Default to something else if was CONTENT_IGNORE
1220 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1221 if(c_##name == CONTENT_IGNORE){\
1222 c_##name = c_##dname;\
1223 n_##name = n_##dname;\
1226 CONTENT_VARIABLE(ndef, stone);
1227 CONTENT_VARIABLE(ndef, air);
1228 CONTENT_VARIABLE(ndef, water_source);
1229 CONTENT_VARIABLE(ndef, dirt);
1230 CONTENT_VARIABLE(ndef, sand);
1231 CONTENT_VARIABLE(ndef, gravel);
1232 CONTENT_VARIABLE(ndef, clay);
1233 CONTENT_VARIABLE(ndef, lava_source);
1234 CONTENT_VARIABLE(ndef, cobble);
1235 CONTENT_VARIABLE(ndef, mossycobble);
1236 CONTENT_VARIABLE(ndef, dirt_with_grass);
1237 CONTENT_VARIABLE(ndef, junglegrass);
1238 CONTENT_VARIABLE(ndef, stone_with_coal);
1239 CONTENT_VARIABLE(ndef, stone_with_iron);
1240 CONTENT_VARIABLE(ndef, mese);
1241 CONTENT_VARIABLE(ndef, desert_sand);
1242 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1243 CONTENT_VARIABLE(ndef, desert_stone);
1244 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1246 // Maximum height of the stone surface and obstacles.
1247 // This is used to guide the cave generation
1248 s16 stone_surface_max_y = 0;
1251 Generate general ground level to full area
1255 TimeTaker timer1("Generating ground level");
1257 for(s16 x=node_min.X; x<=node_max.X; x++)
1258 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1261 v2s16 p2d = v2s16(x,z);
1264 Skip of already generated
1267 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1268 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1272 // Ground height at this point
1273 float surface_y_f = 0.0;
1275 // Use perlin noise for ground height
1276 surface_y_f = base_rock_level_2d(data->seed, p2d);
1278 /*// Experimental stuff
1280 float a = highlands_level_2d(data->seed, p2d);
1285 // Convert to integer
1286 s16 surface_y = (s16)surface_y_f;
1289 if(surface_y > stone_surface_max_y)
1290 stone_surface_max_y = surface_y;
1292 BiomeType bt = get_biome(data->seed, p2d);
1294 Fill ground with stone
1297 // Use fast index incrementing
1298 v3s16 em = vmanip.m_area.getExtent();
1299 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1300 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1302 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1304 if(y > WATER_LEVEL && bt == BT_DESERT)
1305 vmanip.m_data[i] = n_desert_stone;
1307 vmanip.m_data[i] = n_stone;
1308 } else if(y <= WATER_LEVEL){
1309 vmanip.m_data[i] = MapNode(c_water_source);
1311 vmanip.m_data[i] = MapNode(c_air);
1314 vmanip.m_area.add_y(em, i, 1);
1322 // Limit dirt flow area by 1 because mud is flown into neighbors.
1323 assert(central_area_size.X == central_area_size.Z);
1324 s16 mudflow_minpos = 0-max_spread_amount+1;
1325 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1328 Loop this part, it will make stuff look older and newer nicely
1331 const u32 age_loops = 2;
1332 for(u32 i_age=0; i_age<age_loops; i_age++)
1334 /******************************
1335 BEGINNING OF AGING LOOP
1336 ******************************/
1341 //TimeTaker timer1("caves");
1344 Make caves (this code is relatively horrible)
1346 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1347 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1348 data->seed+34329, 3, 0.50);
1349 cave_amount = MYMAX(0.0, cave_amount);
1350 u32 caves_count = cave_amount * volume_nodes / 50000;
1351 u32 bruises_count = 1;
1352 PseudoRandom ps(blockseed+21343);
1353 PseudoRandom ps2(blockseed+1032);
1354 if(ps.range(1, 6) == 1)
1355 bruises_count = ps.range(0, ps.range(0, 2));
1356 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1360 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1362 bool large_cave = (jj >= caves_count);
1363 s16 min_tunnel_diameter = 2;
1364 s16 max_tunnel_diameter = ps.range(2,6);
1365 int dswitchint = ps.range(1,14);
1366 u16 tunnel_routepoints = 0;
1367 int part_max_length_rs = 0;
1369 part_max_length_rs = ps.range(2,4);
1370 tunnel_routepoints = ps.range(5, ps.range(15,30));
1371 min_tunnel_diameter = 5;
1372 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1374 part_max_length_rs = ps.range(2,9);
1375 tunnel_routepoints = ps.range(10, ps.range(15,30));
1377 bool large_cave_is_flat = (ps.range(0,1) == 0);
1379 v3f main_direction(0,0,0);
1381 // Allowed route area size in nodes
1382 v3s16 ar = central_area_size;
1384 // Area starting point in nodes
1385 v3s16 of = node_min;
1388 //(this should be more than the maximum radius of the tunnel)
1389 //s16 insure = 5; // Didn't work with max_d = 20
1391 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1392 ar += v3s16(1,0,1) * more * 2;
1393 of -= v3s16(1,0,1) * more;
1395 s16 route_y_min = 0;
1396 // Allow half a diameter + 7 over stone surface
1397 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1399 /*// If caves, don't go through surface too often
1400 if(large_cave == false)
1401 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1403 // Limit maximum to area
1404 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1408 /*// Minimum is at y=0
1409 route_y_min = -of.Y - 0;*/
1410 // Minimum is at y=max_tunnel_diameter/4
1411 //route_y_min = -of.Y + max_tunnel_diameter/4;
1412 //s16 min = -of.Y + max_tunnel_diameter/4;
1413 //s16 min = -of.Y + 0;
1415 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1417 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1418 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1420 route_y_min = ps.range(min, min + max_tunnel_diameter);
1421 route_y_min = rangelim(route_y_min, 0, route_y_max);
1424 /*dstream<<"route_y_min = "<<route_y_min
1425 <<", route_y_max = "<<route_y_max<<std::endl;*/
1427 s16 route_start_y_min = route_y_min;
1428 s16 route_start_y_max = route_y_max;
1430 // Start every 4th cave from surface when applicable
1431 /*bool coming_from_surface = false;
1432 if(node_min.Y <= 0 && node_max.Y >= 0){
1433 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1434 if(coming_from_surface)
1435 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1438 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1439 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1441 // Randomize starting position
1443 (float)(ps.next()%ar.X)+0.5,
1444 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1445 (float)(ps.next()%ar.Z)+0.5
1448 v3s16 startp(orp.X, orp.Y, orp.Z);
1451 MapNode airnode(CONTENT_AIR);
1452 MapNode waternode(c_water_source);
1453 MapNode lavanode(c_lava_source);
1456 Generate some tunnel starting from orp
1459 for(u16 j=0; j<tunnel_routepoints; j++)
1461 if(j%dswitchint==0 && large_cave == false)
1463 main_direction = v3f(
1464 ((float)(ps.next()%20)-(float)10)/10,
1465 ((float)(ps.next()%20)-(float)10)/30,
1466 ((float)(ps.next()%20)-(float)10)/10
1468 main_direction *= (float)ps.range(0, 10)/10;
1472 s16 min_d = min_tunnel_diameter;
1473 s16 max_d = max_tunnel_diameter;
1474 s16 rs = ps.range(min_d, max_d);
1476 // Every second section is rough
1477 bool randomize_xz = (ps2.range(1,2) == 1);
1483 rs*part_max_length_rs,
1484 rs*part_max_length_rs/2,
1485 rs*part_max_length_rs
1491 rs*part_max_length_rs,
1492 ps.range(1, rs*part_max_length_rs),
1493 rs*part_max_length_rs
1500 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1501 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1502 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1505 // Jump downward sometimes
1506 if(!large_cave && ps.range(0,12) == 0)
1509 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1510 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1511 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1517 s16 h = find_ground_level_clever(vmanip,
1518 v2s16(p.X, p.Z), ndef);
1519 route_y_min = h - rs/3;
1520 route_y_max = h + rs;
1523 vec += main_direction;
1528 else if(rp.X >= ar.X)
1530 if(rp.Y < route_y_min)
1532 else if(rp.Y >= route_y_max)
1533 rp.Y = route_y_max-1;
1536 else if(rp.Z >= ar.Z)
1540 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1542 v3f fp = orp + vec * f;
1543 fp.X += 0.1*ps.range(-10,10);
1544 fp.Z += 0.1*ps.range(-10,10);
1545 v3s16 cp(fp.X, fp.Y, fp.Z);
1550 d0 += ps.range(-1,1);
1551 d1 += ps.range(-1,1);
1553 for(s16 z0=d0; z0<=d1; z0++)
1555 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1556 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1558 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1559 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1560 for(s16 y0=-si2; y0<=si2; y0++)
1562 /*// Make better floors in small caves
1563 if(y0 <= -rs/2 && rs<=7)
1565 if(large_cave_is_flat){
1566 // Make large caves not so tall
1567 if(rs > 7 && abs(y0) >= rs/3)
1577 if(vmanip.m_area.contains(p) == false)
1580 u32 i = vmanip.m_area.index(p);
1584 if(full_node_min.Y < WATER_LEVEL &&
1585 full_node_max.Y > WATER_LEVEL){
1586 if(p.Y <= WATER_LEVEL)
1587 vmanip.m_data[i] = waternode;
1589 vmanip.m_data[i] = airnode;
1590 } else if(full_node_max.Y < WATER_LEVEL){
1591 if(p.Y < startp.Y - 2)
1592 vmanip.m_data[i] = lavanode;
1594 vmanip.m_data[i] = airnode;
1596 vmanip.m_data[i] = airnode;
1599 // Don't replace air or water or lava or ignore
1600 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1601 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1602 vmanip.m_data[i].getContent() == c_water_source ||
1603 vmanip.m_data[i].getContent() == c_lava_source)
1606 vmanip.m_data[i] = airnode;
1609 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1627 TimeTaker timer1("add mud");
1630 Add mud to the central chunk
1633 for(s16 x=node_min.X; x<=node_max.X; x++)
1634 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1636 // Node position in 2d
1637 v2s16 p2d = v2s16(x,z);
1639 // Randomize mud amount
1640 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1642 // Find ground level
1643 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1644 // Handle area not found
1645 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1648 MapNode addnode(c_dirt);
1649 BiomeType bt = get_biome(data->seed, p2d);
1652 addnode = MapNode(c_desert_sand);
1654 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1655 addnode = MapNode(c_sand);
1656 } else if(mud_add_amount <= 0){
1657 mud_add_amount = 1 - mud_add_amount;
1658 addnode = MapNode(c_gravel);
1659 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1660 surface_y + mud_add_amount <= WATER_LEVEL+2){
1661 addnode = MapNode(c_sand);
1664 if(bt == BT_DESERT){
1666 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1671 If topmost node is grass, change it to mud.
1672 It might be if it was flown to there from a neighboring
1673 chunk and then converted.
1676 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1677 MapNode *n = &vmanip.m_data[i];
1678 if(n->getContent() == c_dirt_with_grass)
1679 *n = MapNode(c_dirt);
1687 v3s16 em = vmanip.m_area.getExtent();
1688 s16 y_start = surface_y+1;
1689 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1690 for(s16 y=y_start; y<=node_max.Y; y++)
1692 if(mudcount >= mud_add_amount)
1695 MapNode &n = vmanip.m_data[i];
1699 vmanip.m_area.add_y(em, i, 1);
1709 Add blobs of dirt and gravel underground
1711 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1713 PseudoRandom pr(blockseed+983);
1714 for(int i=0; i<volume_nodes/10/10/10; i++)
1716 bool only_fill_cave = (myrand_range(0,1) != 0);
1723 pr.range(node_min.X, node_max.X)-size.X/2,
1724 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1725 pr.range(node_min.Z, node_max.Z)-size.Z/2
1728 if(p0.Y > -32 && pr.range(0,1) == 0)
1729 n1 = MapNode(c_dirt);
1731 n1 = MapNode(c_gravel);
1732 for(int x1=0; x1<size.X; x1++)
1733 for(int y1=0; y1<size.Y; y1++)
1734 for(int z1=0; z1<size.Z; z1++)
1736 v3s16 p = p0 + v3s16(x1,y1,z1);
1737 u32 i = vmanip.m_area.index(p);
1738 if(!vmanip.m_area.contains(i))
1740 // Cancel if not stone and not cave air
1741 if(vmanip.m_data[i].getContent() != c_stone &&
1742 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1744 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1746 vmanip.m_data[i] = n1;
1754 TimeTaker timer1("flow mud");
1757 Flow mud away from steep edges
1760 // Iterate a few times
1761 for(s16 k=0; k<3; k++)
1764 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1765 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1767 // Invert coordinates every 2nd iteration
1770 x = mudflow_maxpos - (x-mudflow_minpos);
1771 z = mudflow_maxpos - (z-mudflow_minpos);
1774 // Node position in 2d
1775 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1777 v3s16 em = vmanip.m_area.getExtent();
1778 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1781 while(y >= node_min.Y)
1788 for(; y>=node_min.Y; y--)
1790 n = &vmanip.m_data[i];
1791 //if(content_walkable(n->d))
1793 if(n->getContent() == c_dirt ||
1794 n->getContent() == c_dirt_with_grass ||
1795 n->getContent() == c_gravel)
1798 vmanip.m_area.add_y(em, i, -1);
1801 // Stop if out of area
1802 //if(vmanip.m_area.contains(i) == false)
1806 /*// If not mud, do nothing to it
1807 MapNode *n = &vmanip.m_data[i];
1808 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1811 if(n->getContent() == c_dirt ||
1812 n->getContent() == c_dirt_with_grass)
1814 // Make it exactly mud
1815 n->setContent(c_dirt);
1818 Don't flow it if the stuff under it is not mud
1822 vmanip.m_area.add_y(em, i2, -1);
1823 // Cancel if out of area
1824 if(vmanip.m_area.contains(i2) == false)
1826 MapNode *n2 = &vmanip.m_data[i2];
1827 if(n2->getContent() != c_dirt &&
1828 n2->getContent() != c_dirt_with_grass)
1833 /*s16 recurse_count = 0;
1837 v3s16(0,0,1), // back
1838 v3s16(1,0,0), // right
1839 v3s16(0,0,-1), // front
1840 v3s16(-1,0,0), // left
1843 // Theck that upper is air or doesn't exist.
1844 // Cancel dropping if upper keeps it in place
1846 vmanip.m_area.add_y(em, i3, 1);
1847 if(vmanip.m_area.contains(i3) == true
1848 && ndef->get(vmanip.m_data[i3]).walkable)
1855 for(u32 di=0; di<4; di++)
1857 v3s16 dirp = dirs4[di];
1860 vmanip.m_area.add_p(em, i2, dirp);
1861 // Fail if out of area
1862 if(vmanip.m_area.contains(i2) == false)
1864 // Check that side is air
1865 MapNode *n2 = &vmanip.m_data[i2];
1866 if(ndef->get(*n2).walkable)
1868 // Check that under side is air
1869 vmanip.m_area.add_y(em, i2, -1);
1870 if(vmanip.m_area.contains(i2) == false)
1872 n2 = &vmanip.m_data[i2];
1873 if(ndef->get(*n2).walkable)
1875 /*// Check that under that is air (need a drop of 2)
1876 vmanip.m_area.add_y(em, i2, -1);
1877 if(vmanip.m_area.contains(i2) == false)
1879 n2 = &vmanip.m_data[i2];
1880 if(content_walkable(n2->d))
1882 // Loop further down until not air
1883 bool dropped_to_unknown = false;
1885 vmanip.m_area.add_y(em, i2, -1);
1886 n2 = &vmanip.m_data[i2];
1887 // if out of known area
1888 if(vmanip.m_area.contains(i2) == false
1889 || n2->getContent() == CONTENT_IGNORE){
1890 dropped_to_unknown = true;
1893 }while(ndef->get(*n2).walkable == false);
1894 // Loop one up so that we're in air
1895 vmanip.m_area.add_y(em, i2, 1);
1896 n2 = &vmanip.m_data[i2];
1898 bool old_is_water = (n->getContent() == c_water_source);
1899 // Move mud to new place
1900 if(!dropped_to_unknown) {
1902 // Set old place to be air (or water)
1904 *n = MapNode(c_water_source);
1906 *n = MapNode(CONTENT_AIR);
1922 /***********************
1924 ************************/
1927 Add top and bottom side of water to transforming_liquid queue
1930 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1931 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1936 bool water_found = false;
1937 // Use fast index incrementing
1938 v3s16 em = vmanip.m_area.getExtent();
1939 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1940 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1942 if(y == full_node_max.Y){
1944 (vmanip.m_data[i].getContent() == c_water_source ||
1945 vmanip.m_data[i].getContent() == c_lava_source);
1947 else if(water_found == false)
1949 if(vmanip.m_data[i].getContent() == c_water_source ||
1950 vmanip.m_data[i].getContent() == c_lava_source)
1952 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1953 data->transforming_liquid.push_back(p);
1959 // This can be done because water_found can only
1960 // turn to true and end up here after going through
1962 if(vmanip.m_data[i+1].getContent() != c_water_source ||
1963 vmanip.m_data[i+1].getContent() != c_lava_source)
1965 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1966 data->transforming_liquid.push_back(p);
1967 water_found = false;
1971 vmanip.m_area.add_y(em, i, -1);
1980 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1981 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1983 // Node position in 2d
1984 v2s16 p2d = v2s16(x,z);
1987 Find the lowest surface to which enough light ends up
1990 Basically just wait until not air and not leaves.
1994 v3s16 em = vmanip.m_area.getExtent();
1995 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1997 // Go to ground level
1998 for(y=node_max.Y; y>=full_node_min.Y; y--)
2000 MapNode &n = vmanip.m_data[i];
2001 if(ndef->get(n).param_type != CPT_LIGHT
2002 || ndef->get(n).liquid_type != LIQUID_NONE)
2004 vmanip.m_area.add_y(em, i, -1);
2006 if(y >= full_node_min.Y)
2009 surface_y = full_node_min.Y;
2012 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2013 MapNode *n = &vmanip.m_data[i];
2014 if(n->getContent() == c_dirt){
2015 // Well yeah, this can't be overground...
2016 if(surface_y < WATER_LEVEL - 20)
2018 n->setContent(c_dirt_with_grass);
2025 assert(central_area_size.X == central_area_size.Z);
2027 // Divide area into parts
2029 s16 sidelen = central_area_size.X / div;
2030 double area = sidelen * sidelen;
2031 for(s16 x0=0; x0<div; x0++)
2032 for(s16 z0=0; z0<div; z0++)
2034 // Center position of part of division
2036 node_min.X + sidelen/2 + sidelen*x0,
2037 node_min.Z + sidelen/2 + sidelen*z0
2039 // Minimum edge of part of division
2041 node_min.X + sidelen*x0,
2042 node_min.Z + sidelen*z0
2044 // Maximum edge of part of division
2046 node_min.X + sidelen + sidelen*x0 - 1,
2047 node_min.Z + sidelen + sidelen*z0 - 1
2050 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2051 // Put trees in random places on part of division
2052 for(u32 i=0; i<tree_count; i++)
2054 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2055 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2056 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2057 // Don't make a tree under water level
2060 // Don't make a tree so high that it doesn't fit
2061 if(y > node_max.Y - 6)
2065 Trees grow only on mud and grass
2068 u32 i = vmanip.m_area.index(v3s16(p));
2069 MapNode *n = &vmanip.m_data[i];
2070 if(n->getContent() != c_dirt
2071 && n->getContent() != c_dirt_with_grass)
2076 treegen::make_tree(vmanip, p, false, ndef);
2083 Make base ground level
2086 for(s16 x=node_min.X; x<=node_max.X; x++)
2087 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2092 // Use fast index incrementing
2093 v3s16 em = vmanip.m_area.getExtent();
2094 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2095 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2097 // Only modify places that have no content
2098 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2100 // First priority: make air and water.
2101 // This avoids caves inside water.
2102 if(all_is_ground_except_caves == false
2103 && val_is_ground(noisebuf_ground.get(x,y,z),
2104 v3s16(x,y,z), data->seed) == false)
2106 if(y <= WATER_LEVEL)
2107 vmanip.m_data[i] = n_water_source;
2109 vmanip.m_data[i] = n_air;
2111 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2112 vmanip.m_data[i] = n_air;
2114 vmanip.m_data[i] = n_stone;
2117 vmanip->m_area.add_y(em, i, 1);
2123 Add mud and sand and others underground (in place of stone)
2126 for(s16 x=node_min.X; x<=node_max.X; x++)
2127 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2132 // Use fast index incrementing
2133 v3s16 em = vmanip.m_area.getExtent();
2134 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2135 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2137 if(vmanip.m_data[i].getContent() == c_stone)
2139 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2141 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2142 vmanip.m_data[i] = n_dirt;
2144 vmanip.m_data[i] = n_sand;
2146 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2148 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2149 vmanip.m_data[i] = n_gravel;
2151 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2152 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2154 vmanip.m_data[i] = n_lava_source;
2155 for(s16 x1=-1; x1<=1; x1++)
2156 for(s16 y1=-1; y1<=1; y1++)
2157 for(s16 z1=-1; z1<=1; z1++)
2158 data->transforming_liquid.push_back(
2159 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2163 vmanip->m_area.add_y(em, i, -1);
2172 //if(node_min.Y < approx_groundlevel)
2173 //if(myrand() % 3 == 0)
2174 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2175 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2176 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2177 float dungeon_rarity = 0.02;
2178 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2180 && node_min.Y < approx_groundlevel)
2182 // Dungeon generator doesn't modify places which have this set
2183 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2184 | VMANIP_FLAG_DUNGEON_PRESERVE);
2186 // Set all air and water to be untouchable to make dungeons open
2187 // to caves and open air
2188 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2189 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2194 // Use fast index incrementing
2195 v3s16 em = vmanip.m_area.getExtent();
2196 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2197 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2199 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2200 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2201 else if(vmanip.m_data[i].getContent() == c_water_source)
2202 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2203 vmanip->m_area.add_y(em, i, -1);
2208 PseudoRandom random(blockseed+2);
2211 make_dungeon1(vmanip, random, ndef);
2213 // Convert some cobble to mossy cobble
2214 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2215 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2220 // Use fast index incrementing
2221 v3s16 em = vmanip.m_area.getExtent();
2222 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2223 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2225 // (noisebuf not used because it doesn't contain the
2227 double wetness = noise3d_param(
2228 get_ground_wetness_params(data->seed), x,y,z);
2229 double d = noise3d_perlin((float)x/2.5,
2230 (float)y/2.5,(float)z/2.5,
2232 if(vmanip.m_data[i].getContent() == c_cobble)
2236 vmanip.m_data[i].setContent(c_mossycobble);
2239 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2242 vmanip.m_data[i].setContent(c_dirt);
2244 vmanip->m_area.add_y(em, i, -1);
2254 PseudoRandom ncrandom(blockseed+9324342);
2255 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2257 make_nc(vmanip, ncrandom, ndef);
2262 Add top and bottom side of water to transforming_liquid queue
2265 for(s16 x=node_min.X; x<=node_max.X; x++)
2266 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2271 bool water_found = false;
2272 // Use fast index incrementing
2273 v3s16 em = vmanip.m_area.getExtent();
2274 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2275 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2277 if(water_found == false)
2279 if(vmanip.m_data[i].getContent() == c_water_source)
2281 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2282 data->transforming_liquid.push_back(p);
2288 // This can be done because water_found can only
2289 // turn to true and end up here after going through
2291 if(vmanip.m_data[i+1].getContent() != c_water_source)
2293 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2294 data->transforming_liquid.push_back(p);
2295 water_found = false;
2299 vmanip->m_area.add_y(em, i, -1);
2305 If close to ground level
2308 //if(abs(approx_ground_depth) < 30)
2309 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2315 for(s16 x=node_min.X; x<=node_max.X; x++)
2316 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2321 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2322 bool have_sand = false;
2323 u32 current_depth = 0;
2324 bool air_detected = false;
2325 bool water_detected = false;
2326 bool have_clay = false;
2328 // Use fast index incrementing
2329 s16 start_y = node_max.Y+2;
2330 v3s16 em = vmanip.m_area.getExtent();
2331 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2332 for(s16 y=start_y; y>=node_min.Y-3; y--)
2334 if(vmanip.m_data[i].getContent() == c_water_source)
2335 water_detected = true;
2336 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2337 air_detected = true;
2339 if((vmanip.m_data[i].getContent() == c_stone
2340 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2341 || vmanip.m_data[i].getContent() == c_dirt
2342 || vmanip.m_data[i].getContent() == c_sand
2343 || vmanip.m_data[i].getContent() == c_gravel
2344 ) && (air_detected || water_detected))
2346 if(current_depth == 0 && y <= WATER_LEVEL+2
2347 && possibly_have_sand)
2350 if(current_depth < 4)
2354 vmanip.m_data[i] = MapNode(c_sand);
2357 else if(current_depth==0 && !water_detected
2358 && y >= WATER_LEVEL && air_detected)
2359 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2362 vmanip.m_data[i] = MapNode(c_dirt);
2366 if(vmanip.m_data[i].getContent() == c_dirt
2367 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2368 vmanip.m_data[i] = MapNode(c_stone);
2373 if(current_depth >= 8)
2376 else if(current_depth != 0)
2379 vmanip->m_area.add_y(em, i, -1);
2385 Calculate some stuff
2388 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2389 bool is_jungle = surface_humidity > 0.75;
2391 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2398 PseudoRandom treerandom(blockseed);
2399 // Put trees in random places on part of division
2400 for(u32 i=0; i<tree_count; i++)
2402 s16 x = treerandom.range(node_min.X, node_max.X);
2403 s16 z = treerandom.range(node_min.Z, node_max.Z);
2404 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2405 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2406 // Don't make a tree under water level
2409 // Make sure tree fits (only trees whose starting point is
2410 // at this block are added)
2411 if(y < node_min.Y || y > node_max.Y)
2414 Find exact ground level
2418 for(; p.Y >= y-6; p.Y--)
2420 u32 i = vmanip->m_area.index(p);
2421 MapNode *n = &vmanip->m_data[i];
2422 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2428 // If not found, handle next one
2433 u32 i = vmanip->m_area.index(p);
2434 MapNode *n = &vmanip->m_data[i];
2436 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2439 // Papyrus grows only on mud and in water
2440 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2443 make_papyrus(vmanip, p, ndef);
2445 // Trees grow only on mud and grass, on land
2446 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2449 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2450 if(is_jungle == false)
2453 if(myrand_range(0,4) != 0)
2454 is_apple_tree = false;
2456 is_apple_tree = noise2d_perlin(
2457 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2458 data->seed+342902, 3, 0.45) > 0.2;
2459 make_tree(vmanip, p, is_apple_tree, ndef);
2462 make_jungletree(vmanip, p, ndef);
2464 // Cactii grow only on sand, on land
2465 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2468 make_cactus(vmanip, p, ndef);
2478 PseudoRandom grassrandom(blockseed);
2479 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2481 s16 x = grassrandom.range(node_min.X, node_max.X);
2482 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2483 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2486 if(y < node_min.Y || y > node_max.Y)
2489 Find exact ground level
2493 for(; p.Y >= y-6; p.Y--)
2495 u32 i = vmanip->m_area.index(p);
2496 MapNode *n = &vmanip->m_data[i];
2497 if(data->nodedef->get(*n).is_ground_content)
2503 // If not found, handle next one
2507 if(vmanip.m_area.contains(p) == false)
2509 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2512 if(vmanip.m_area.contains(p))
2513 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2515 if(vmanip.m_area.contains(p))
2516 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2522 Add some kind of random stones
2525 u32 random_stone_count = gen_area_nodes *
2526 randomstone_amount_2d(data->seed, p2d_center);
2527 // Put in random places on part of division
2528 for(u32 i=0; i<random_stone_count; i++)
2530 s16 x = myrand_range(node_min.X, node_max.X);
2531 s16 z = myrand_range(node_min.Z, node_max.Z);
2532 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2533 // Don't add under water level
2534 /*if(y < WATER_LEVEL)
2536 // Don't add if doesn't belong to this block
2537 if(y < node_min.Y || y > node_max.Y)
2542 u32 i = vmanip->m_area.index(v3s16(p));
2543 MapNode *n = &vmanip->m_data[i];
2544 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2547 // Will be placed one higher
2550 make_randomstone(vmanip, p);
2559 u32 large_stone_count = gen_area_nodes *
2560 largestone_amount_2d(data->seed, p2d_center);
2561 //u32 large_stone_count = 1;
2562 // Put in random places on part of division
2563 for(u32 i=0; i<large_stone_count; i++)
2565 s16 x = myrand_range(node_min.X, node_max.X);
2566 s16 z = myrand_range(node_min.Z, node_max.Z);
2567 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2568 // Don't add under water level
2569 /*if(y < WATER_LEVEL)
2571 // Don't add if doesn't belong to this block
2572 if(y < node_min.Y || y > node_max.Y)
2577 u32 i = vmanip->m_area.index(v3s16(p));
2578 MapNode *n = &vmanip->m_data[i];
2579 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2582 // Will be placed one lower
2585 make_largestone(vmanip, p);
2595 PseudoRandom mineralrandom(blockseed);
2600 for(s16 i=0; i<approx_ground_depth/4; i++)
2602 if(mineralrandom.next()%50 == 0)
2604 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2605 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2606 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2607 for(u16 i=0; i<27; i++)
2609 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2610 u32 vi = vmanip.m_area.index(p);
2611 if(vmanip.m_data[vi].getContent() == c_stone)
2612 if(mineralrandom.next()%8 == 0)
2613 vmanip.m_data[vi] = MapNode(c_mese);
2622 u16 a = mineralrandom.range(0,15);
2624 u16 amount = 20 * a/1000;
2625 for(s16 i=0; i<amount; i++)
2627 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2628 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2629 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2631 u8 base_content = c_stone;
2632 MapNode new_content(CONTENT_IGNORE);
2635 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2637 new_content = MapNode(c_stone_with_coal);
2641 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2642 new_content = MapNode(c_stone_with_iron);
2643 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2644 vmanip.m_data[i] = MapNode(c_dirt);
2646 vmanip.m_data[i] = MapNode(c_sand);*/
2648 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2652 if(new_content.getContent() != CONTENT_IGNORE)
2654 for(u16 i=0; i<27; i++)
2656 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2657 u32 vi = vmanip.m_area.index(p);
2658 if(vmanip.m_data[vi].getContent() == base_content)
2660 if(mineralrandom.next()%sparseness == 0)
2661 vmanip.m_data[vi] = new_content;
2670 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2671 //for(s16 i=0; i<50; i++)
2672 u16 coal_amount = 30;
2673 u16 coal_rareness = 60 / coal_amount;
2674 if(coal_rareness == 0)
2676 if(mineralrandom.next()%coal_rareness == 0)
2678 u16 a = mineralrandom.next() % 16;
2679 u16 amount = coal_amount * a*a*a / 1000;
2680 for(s16 i=0; i<amount; i++)
2682 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2683 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2684 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2685 for(u16 i=0; i<27; i++)
2687 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2688 u32 vi = vmanip.m_area.index(p);
2689 if(vmanip.m_data[vi].getContent() == c_stone)
2690 if(mineralrandom.next()%8 == 0)
2691 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2698 u16 iron_amount = 8;
2699 u16 iron_rareness = 60 / iron_amount;
2700 if(iron_rareness == 0)
2702 if(mineralrandom.next()%iron_rareness == 0)
2704 u16 a = mineralrandom.next() % 16;
2705 u16 amount = iron_amount * a*a*a / 1000;
2706 for(s16 i=0; i<amount; i++)
2708 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2709 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2710 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2711 for(u16 i=0; i<27; i++)
2713 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2714 u32 vi = vmanip.m_area.index(p);
2715 if(vmanip.m_data[vi].getContent() == c_stone)
2716 if(mineralrandom.next()%8 == 0)
2717 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2728 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2730 //VoxelArea a(node_min, node_max);
2731 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2732 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2733 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2734 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2735 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2736 for(int i=0; i<2; i++)
2738 enum LightBank bank = banks[i];
2740 core::map<v3s16, bool> light_sources;
2741 core::map<v3s16, u8> unlight_from;
2743 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2744 light_sources, unlight_from);
2746 bool inexistent_top_provides_sunlight = !block_is_underground;
2747 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2748 vmanip, a, inexistent_top_provides_sunlight,
2749 light_sources, ndef);
2750 // TODO: Do stuff according to bottom_sunlight_valid
2752 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2754 vmanip.spreadLight(bank, light_sources, ndef);
2759 BlockMakeData::BlockMakeData():
2766 BlockMakeData::~BlockMakeData()
2771 }; // namespace mapgen