3 Copyright (C) 2010-2013 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.
27 //#include "serverobject.h"
28 #include "content_sao.h"
30 #include "content_mapnode.h" // For content_mapnode_get_new_name
31 #include "voxelalgorithms.h"
33 #include "settings.h" // For g_settings
34 #include "main.h" // For g_profiler
36 #include "mapgen_v6.h"
38 FlagDesc flagdesc_mapgen[] = {
41 {"dungeons", MG_DUNGEONS},
42 {"v6_forests", MGV6_FORESTS},
43 {"v6_biome_blend", MGV6_BIOME_BLEND},
48 ///////////////////////////////////////////////////////////////////////////////
52 bool MapgenV6Params::readParams(Settings *settings) {
53 freq_desert = settings->getFloat("mgv6_freq_desert");
54 freq_beach = settings->getFloat("mgv6_freq_beach");
56 np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
57 np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
58 np_steepness = settings->getNoiseParams("mgv6_np_steepness");
59 np_height_select = settings->getNoiseParams("mgv6_np_height_select");
60 np_trees = settings->getNoiseParams("mgv6_np_trees");
61 np_mud = settings->getNoiseParams("mgv6_np_mud");
62 np_beach = settings->getNoiseParams("mgv6_np_beach");
63 np_biome = settings->getNoiseParams("mgv6_np_biome");
64 np_cave = settings->getNoiseParams("mgv6_np_cave");
67 np_terrain_base && np_terrain_higher && np_steepness &&
68 np_height_select && np_trees && np_mud &&
69 np_beach && np_biome && np_cave;
74 void MapgenV6Params::writeParams(Settings *settings) {
75 settings->setFloat("mgv6_freq_desert", freq_desert);
76 settings->setFloat("mgv6_freq_beach", freq_beach);
78 settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base);
79 settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
80 settings->setNoiseParams("mgv6_np_steepness", np_steepness);
81 settings->setNoiseParams("mgv6_np_height_select", np_height_select);
82 settings->setNoiseParams("mgv6_np_trees", np_trees);
83 settings->setNoiseParams("mgv6_np_mud", np_mud);
84 settings->setNoiseParams("mgv6_np_beach", np_beach);
85 settings->setNoiseParams("mgv6_np_biome", np_biome);
86 settings->setNoiseParams("mgv6_np_cave", np_cave);
90 /////////////////////////////////// legacy static functions for farmesh
93 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
94 //just need to return something
100 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
101 double sandnoise = noise2d_perlin(
102 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
103 seed+59420, 3, 0.50);
105 return (sandnoise > 0.15);
109 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
110 double noise = noise2d_perlin(
111 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
113 double zeroval = -0.39;
117 return 0.04 * (noise-zeroval) / (1.0-zeroval);
121 #if 0 /// BIG COMMENT
126 Some helper functions for the map generator
130 // Returns Y one under area minimum if not found
131 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
132 INodeDefManager *ndef)
134 v3s16 em = vmanip.m_area.getExtent();
135 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
136 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
137 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
139 for(y=y_nodes_max; y>=y_nodes_min; y--)
141 MapNode &n = vmanip.m_data[i];
142 if(ndef->get(n).walkable)
145 vmanip.m_area.add_y(em, i, -1);
150 return y_nodes_min - 1;
154 // Returns Y one under area minimum if not found
155 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
156 INodeDefManager *ndef)
158 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
159 return vmanip.m_area.MinEdge.Y-1;
160 v3s16 em = vmanip.m_area.getExtent();
161 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
162 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
163 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
165 content_t c_tree = ndef->getId("mapgen_tree");
166 content_t c_leaves = ndef->getId("mapgen_leaves");
167 for(y=y_nodes_max; y>=y_nodes_min; y--)
169 MapNode &n = vmanip.m_data[i];
170 if(ndef->get(n).walkable
171 && n.getContent() != c_tree
172 && n.getContent() != c_leaves)
175 vmanip.m_area.add_y(em, i, -1);
180 return y_nodes_min - 1;
184 // Returns Y one under area minimum if not found
185 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
186 INodeDefManager *ndef)
188 v3s16 em = vmanip.m_area.getExtent();
189 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
190 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
191 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
193 content_t c_stone = ndef->getId("mapgen_stone");
194 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
195 for(y=y_nodes_max; y>=y_nodes_min; y--)
197 MapNode &n = vmanip.m_data[i];
198 content_t c = n.getContent();
199 if(c != CONTENT_IGNORE && (
200 c == c_stone || c == c_desert_stone))
203 vmanip.m_area.add_y(em, i, -1);
208 return y_nodes_min - 1;
215 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
216 INodeDefManager *ndef)
218 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
220 s16 trunk_h = myrand_range(2, 3);
222 for(s16 ii=0; ii<trunk_h; ii++)
224 if(vmanip.m_area.contains(p1))
225 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
230 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
231 INodeDefManager *ndef)
233 MapNode cactusnode(ndef->getId("mapgen_cactus"));
237 for(s16 ii=0; ii<trunk_h; ii++)
239 if(vmanip.m_area.contains(p1))
240 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
248 Dungeon making routines
251 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
252 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
253 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
254 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
256 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
257 INodeDefManager *ndef)
260 for(s16 z=0; z<roomsize.Z; z++)
261 for(s16 y=0; y<roomsize.Y; y++)
264 v3s16 p = roomplace + v3s16(0,y,z);
265 if(vmanip.m_area.contains(p) == false)
267 u32 vi = vmanip.m_area.index(p);
268 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
270 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
273 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
274 if(vmanip.m_area.contains(p) == false)
276 u32 vi = vmanip.m_area.index(p);
277 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
279 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
284 for(s16 x=0; x<roomsize.X; x++)
285 for(s16 y=0; y<roomsize.Y; y++)
288 v3s16 p = roomplace + v3s16(x,y,0);
289 if(vmanip.m_area.contains(p) == false)
291 u32 vi = vmanip.m_area.index(p);
292 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
294 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
297 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
298 if(vmanip.m_area.contains(p) == false)
300 u32 vi = vmanip.m_area.index(p);
301 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
303 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
307 // Make +-Y walls (floor and ceiling)
308 for(s16 z=0; z<roomsize.Z; z++)
309 for(s16 x=0; x<roomsize.X; x++)
312 v3s16 p = roomplace + v3s16(x,0,z);
313 if(vmanip.m_area.contains(p) == false)
315 u32 vi = vmanip.m_area.index(p);
316 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
318 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
321 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
322 if(vmanip.m_area.contains(p) == false)
324 u32 vi = vmanip.m_area.index(p);
325 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
327 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
332 for(s16 z=1; z<roomsize.Z-1; z++)
333 for(s16 y=1; y<roomsize.Y-1; y++)
334 for(s16 x=1; x<roomsize.X-1; x++)
336 v3s16 p = roomplace + v3s16(x,y,z);
337 if(vmanip.m_area.contains(p) == false)
339 u32 vi = vmanip.m_area.index(p);
340 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
341 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
345 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
346 u8 avoid_flags, MapNode n, u8 or_flags)
348 for(s16 z=0; z<size.Z; z++)
349 for(s16 y=0; y<size.Y; y++)
350 for(s16 x=0; x<size.X; x++)
352 v3s16 p = place + v3s16(x,y,z);
353 if(vmanip.m_area.contains(p) == false)
355 u32 vi = vmanip.m_area.index(p);
356 if(vmanip.m_flags[vi] & avoid_flags)
358 vmanip.m_flags[vi] |= or_flags;
359 vmanip.m_data[vi] = n;
363 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
364 INodeDefManager *ndef)
366 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
367 VMANIP_FLAG_DUNGEON_INSIDE);
370 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
371 INodeDefManager *ndef)
373 make_hole1(vmanip, doorplace, ndef);
374 // Place torch (for testing)
375 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
378 static v3s16 rand_ortho_dir(PseudoRandom &random)
380 if(random.next()%2==0)
381 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
383 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
386 static v3s16 turn_xz(v3s16 olddir, int t)
406 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
408 int turn = random.range(0,2);
417 dir = turn_xz(olddir, 0);
420 dir = turn_xz(olddir, 1);
424 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
425 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
426 PseudoRandom &random, INodeDefManager *ndef)
428 make_hole1(vmanip, doorplace, ndef);
429 v3s16 p0 = doorplace;
433 length = random.range(1,13);
435 length = random.range(1,6);
436 length = random.range(1,13);
437 u32 partlength = random.range(1,13);
440 if(random.next()%2 == 0 && partlength >= 3)
441 make_stairs = random.next()%2 ? 1 : -1;
442 for(u32 i=0; i<length; i++)
448 /*// If already empty
449 if(vmanip.getNodeNoExNoEmerge(p).getContent()
451 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
456 if(vmanip.m_area.contains(p) == true
457 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
461 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
462 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
463 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
464 VMANIP_FLAG_DUNGEON_INSIDE);
465 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
466 VMANIP_FLAG_DUNGEON_INSIDE);
470 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
471 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
472 make_hole1(vmanip, p, ndef);
473 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
474 VMANIP_FLAG_DUNGEON_INSIDE);*/
481 // Can't go here, turn away
482 dir = turn_xz(dir, random.range(0,1));
483 make_stairs = -make_stairs;
485 partlength = random.range(1,length);
490 if(partcount >= partlength)
494 dir = random_turn(random, dir);
496 partlength = random.range(1,length);
499 if(random.next()%2 == 0 && partlength >= 3)
500 make_stairs = random.next()%2 ? 1 : -1;
511 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
512 INodeDefManager *ndef):
523 m_dir = rand_ortho_dir(m_random);
526 void setPos(v3s16 pos)
531 void setDir(v3s16 dir)
536 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
538 for(u32 i=0; i<100; i++)
540 v3s16 p = m_pos + m_dir;
541 v3s16 p1 = p + v3s16(0,1,0);
542 if(vmanip.m_area.contains(p) == false
543 || vmanip.m_area.contains(p1) == false
549 if(vmanip.getNodeNoExNoEmerge(p).getContent()
550 == m_ndef->getId("mapgen_cobble")
551 && vmanip.getNodeNoExNoEmerge(p1).getContent()
552 == m_ndef->getId("mapgen_cobble"))
554 // Found wall, this is a good place!
557 // Randomize next direction
562 Determine where to move next
564 // Jump one up if the actual space is there
565 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
566 == m_ndef->getId("mapgen_cobble")
567 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
569 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
572 // Jump one down if the actual space is there
573 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
574 == m_ndef->getId("mapgen_cobble")
575 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
577 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
580 // Check if walking is now possible
581 if(vmanip.getNodeNoExNoEmerge(p).getContent()
583 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
586 // Cannot continue walking here
596 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
597 v3s16 &result_doordir, v3s16 &result_roomplace)
599 for(s16 trycount=0; trycount<30; trycount++)
603 bool r = findPlaceForDoor(doorplace, doordir);
607 // X east, Z north, Y up
609 if(doordir == v3s16(1,0,0)) // X+
610 roomplace = doorplace +
611 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
612 if(doordir == v3s16(-1,0,0)) // X-
613 roomplace = doorplace +
614 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
615 if(doordir == v3s16(0,0,1)) // Z+
616 roomplace = doorplace +
617 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
618 if(doordir == v3s16(0,0,-1)) // Z-
619 roomplace = doorplace +
620 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
623 if(doordir == v3s16(1,0,0)) // X+
624 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
625 if(doordir == v3s16(-1,0,0)) // X-
626 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
627 if(doordir == v3s16(0,0,1)) // Z+
628 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
629 if(doordir == v3s16(0,0,-1)) // Z-
630 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
635 for(s16 z=1; z<roomsize.Z-1; z++)
636 for(s16 y=1; y<roomsize.Y-1; y++)
637 for(s16 x=1; x<roomsize.X-1; x++)
639 v3s16 p = roomplace + v3s16(x,y,z);
640 if(vmanip.m_area.contains(p) == false)
645 if(vmanip.m_flags[vmanip.m_area.index(p)]
646 & VMANIP_FLAG_DUNGEON_INSIDE)
657 result_doorplace = doorplace;
658 result_doordir = doordir;
659 result_roomplace = roomplace;
666 VoxelManipulator &vmanip;
669 PseudoRandom &m_random;
670 INodeDefManager *m_ndef;
673 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
674 INodeDefManager *ndef)
676 v3s16 areasize = vmanip.m_area.getExtent();
681 Find place for first room
684 for(u32 i=0; i<100; i++)
686 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
687 roomplace = vmanip.m_area.MinEdge + v3s16(
688 random.range(0,areasize.X-roomsize.X-1),
689 random.range(0,areasize.Y-roomsize.Y-1),
690 random.range(0,areasize.Z-roomsize.Z-1));
692 Check that we're not putting the room to an unknown place,
693 otherwise it might end up floating in the air
696 for(s16 z=1; z<roomsize.Z-1; z++)
697 for(s16 y=1; y<roomsize.Y-1; y++)
698 for(s16 x=1; x<roomsize.X-1; x++)
700 v3s16 p = roomplace + v3s16(x,y,z);
701 u32 vi = vmanip.m_area.index(p);
702 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
707 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
721 Stores the center position of the last room made, so that
722 a new corridor can be started from the last room instead of
723 the new room, if chosen so.
725 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
727 u32 room_count = random.range(2,7);
728 for(u32 i=0; i<room_count; i++)
730 // Make a room to the determined place
731 make_room1(vmanip, roomsize, roomplace, ndef);
733 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
735 // Place torch at room center (for testing)
736 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
739 if(i == room_count-1)
742 // Determine walker start position
744 bool start_in_last_room = (random.range(0,2)!=0);
745 //bool start_in_last_room = true;
747 v3s16 walker_start_place;
749 if(start_in_last_room)
751 walker_start_place = last_room_center;
755 walker_start_place = room_center;
756 // Store center of current room as the last one
757 last_room_center = room_center;
760 // Create walker and find a place for a door
761 RoomWalker walker(vmanip, walker_start_place, random, ndef);
764 bool r = walker.findPlaceForDoor(doorplace, doordir);
768 if(random.range(0,1)==0)
770 make_door1(vmanip, doorplace, doordir, ndef);
772 // Don't actually make a door
773 doorplace -= doordir;
775 // Make a random corridor starting from the door
777 v3s16 corridor_end_dir;
778 make_corridor(vmanip, doorplace, doordir, corridor_end,
779 corridor_end_dir, random, ndef);
781 // Find a place for a random sized room
782 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
783 walker.setPos(corridor_end);
784 walker.setDir(corridor_end_dir);
785 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
789 if(random.range(0,1)==0)
791 make_door1(vmanip, doorplace, doordir, ndef);
793 // Don't actually make a door
794 roomplace -= doordir;
801 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
802 INodeDefManager *ndef)
806 s32 r = random.range(0, 3);
808 dir = v3s16( 1, 0, 0);
812 dir = v3s16(-1, 0, 0);
816 dir = v3s16( 0, 0, 1);
820 dir = v3s16( 0, 0,-1);
823 v3s16 p = vmanip.m_area.MinEdge + v3s16(
824 16+random.range(0,15),
825 16+random.range(0,15),
826 16+random.range(0,15));
827 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
828 u32 length = random.range(3,15);
829 for(u32 j=0; j<length; j++)
832 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
838 Noise functions. Make sure seed is mangled differently in each one.
843 Scaling the output of the noise function affects the overdrive of the
844 contour function, which affects the shape of the output considerably.
846 #define CAVE_NOISE_SCALE 12.0
847 //#define CAVE_NOISE_SCALE 10.0
848 //#define CAVE_NOISE_SCALE 7.5
849 //#define CAVE_NOISE_SCALE 5.0
850 //#define CAVE_NOISE_SCALE 1.0
852 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
853 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
855 NoiseParams get_cave_noise1_params(u64 seed)
857 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
858 200, CAVE_NOISE_SCALE);*/
859 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
860 100, CAVE_NOISE_SCALE);*/
861 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
862 100, CAVE_NOISE_SCALE);*/
863 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
864 100, CAVE_NOISE_SCALE);*/
865 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
866 50, CAVE_NOISE_SCALE);
867 //return NoiseParams(NOISE_CONSTANT_ONE);
870 NoiseParams get_cave_noise2_params(u64 seed)
872 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
873 200, CAVE_NOISE_SCALE);*/
874 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
875 100, CAVE_NOISE_SCALE);*/
876 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
877 100, CAVE_NOISE_SCALE);*/
878 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
879 50, CAVE_NOISE_SCALE);
880 //return NoiseParams(NOISE_CONSTANT_ONE);
883 NoiseParams get_ground_noise1_params(u64 seed)
885 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
889 NoiseParams get_ground_crumbleness_params(u64 seed)
891 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
895 NoiseParams get_ground_wetness_params(u64 seed)
897 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
901 bool is_cave(u64 seed, v3s16 p)
903 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
904 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
905 return d1*d2 > CAVE_NOISE_THRESHOLD;
909 Ground density noise shall be interpreted by using this.
911 TODO: No perlin noises here, they should be outsourced
913 NOTE: The speed of these actually isn't terrible
915 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
917 //return ((double)p.Y < ground_noise1_val);
919 double f = 0.55 + noise2d_perlin(
920 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
921 seed+920381, 3, 0.45);
926 double h = WATER_LEVEL + 10 * noise2d_perlin(
927 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
931 return ((double)p.Y - h < ground_noise1_val * f);
935 Queries whether a position is ground or not.
937 bool is_ground(u64 seed, v3s16 p)
939 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
940 return val_is_ground(val1, p, seed);
944 // Amount of trees per area in nodes
945 double tree_amount_2d(u64 seed, v2s16 p)
947 /*double noise = noise2d_perlin(
948 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
950 double noise = noise2d_perlin(
951 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
953 double zeroval = -0.39;
957 return 0.04 * (noise-zeroval) / (1.0-zeroval);
961 double surface_humidity_2d(u64 seed, v2s16 p)
963 double noise = noise2d_perlin(
964 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
965 seed+72384, 4, 0.66);
966 noise = (noise + 1.0)/2.0;
975 Incrementally find ground level from 3d noise
977 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
979 // Start a bit fuzzy to make averaging lower precision values
981 s16 level = myrand_range(-precision/2, precision/2);
982 s16 dec[] = {31000, 100, 20, 4, 1, 0};
984 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
986 // First find non-ground by going upwards
987 // Don't stop in caves.
989 s16 max = level+dec[i-1]*2;
990 v3s16 p(p2d.X, level, p2d.Y);
991 for(; p.Y < max; p.Y += dec[i])
993 if(!is_ground(seed, p))
1000 // Then find ground by going downwards from there.
1001 // Go in caves, too, when precision is 1.
1003 s16 min = level-dec[i-1]*2;
1004 v3s16 p(p2d.X, level, p2d.Y);
1005 for(; p.Y>min; p.Y-=dec[i])
1007 bool ground = is_ground(seed, p);
1008 /*if(dec[i] == 1 && is_cave(seed, p))
1019 // This is more like the actual ground level
1020 level += dec[i-1]/2;
1025 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1027 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1029 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1030 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1032 a += find_ground_level_from_noise(seed,
1033 v2s16(node_min.X, node_min.Y), p);
1034 a += find_ground_level_from_noise(seed,
1035 v2s16(node_min.X, node_max.Y), p);
1036 a += find_ground_level_from_noise(seed,
1037 v2s16(node_max.X, node_max.Y), p);
1038 a += find_ground_level_from_noise(seed,
1039 v2s16(node_max.X, node_min.Y), p);
1040 a += find_ground_level_from_noise(seed,
1041 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1046 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1048 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1050 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1051 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1054 a = MYMAX(a, find_ground_level_from_noise(seed,
1055 v2s16(node_min.X, node_min.Y), p));
1056 a = MYMAX(a, find_ground_level_from_noise(seed,
1057 v2s16(node_min.X, node_max.Y), p));
1058 a = MYMAX(a, find_ground_level_from_noise(seed,
1059 v2s16(node_max.X, node_max.Y), p));
1060 a = MYMAX(a, find_ground_level_from_noise(seed,
1061 v2s16(node_min.X, node_min.Y), p));
1063 a = MYMAX(a, find_ground_level_from_noise(seed,
1064 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1065 // Side middle points
1066 a = MYMAX(a, find_ground_level_from_noise(seed,
1067 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1068 a = MYMAX(a, find_ground_level_from_noise(seed,
1069 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1070 a = MYMAX(a, find_ground_level_from_noise(seed,
1071 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1072 a = MYMAX(a, find_ground_level_from_noise(seed,
1073 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1077 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1079 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1081 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1082 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1085 a = MYMIN(a, find_ground_level_from_noise(seed,
1086 v2s16(node_min.X, node_min.Y), p));
1087 a = MYMIN(a, find_ground_level_from_noise(seed,
1088 v2s16(node_min.X, node_max.Y), p));
1089 a = MYMIN(a, find_ground_level_from_noise(seed,
1090 v2s16(node_max.X, node_max.Y), p));
1091 a = MYMIN(a, find_ground_level_from_noise(seed,
1092 v2s16(node_min.X, node_min.Y), p));
1094 a = MYMIN(a, find_ground_level_from_noise(seed,
1095 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1096 // Side middle points
1097 a = MYMIN(a, find_ground_level_from_noise(seed,
1098 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1099 a = MYMIN(a, find_ground_level_from_noise(seed,
1100 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1101 a = MYMIN(a, find_ground_level_from_noise(seed,
1102 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1103 a = MYMIN(a, find_ground_level_from_noise(seed,
1104 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1109 // Required by mapgen.h
1110 bool block_is_underground(u64 seed, v3s16 blockpos)
1112 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1113 seed, v2s16(blockpos.X, blockpos.Z));*/
1114 // Nah, this is just a heuristic, just return something
1115 s16 minimum_groundlevel = WATER_LEVEL;
1117 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1123 #define AVERAGE_MUD_AMOUNT 4
1125 double base_rock_level_2d(u64 seed, v2s16 p)
1127 // The base ground level
1128 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1129 + 20. * noise2d_perlin(
1130 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1131 seed+82341, 5, 0.6);
1133 /*// A bit hillier one
1134 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1135 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1136 seed+93413, 6, 0.69);
1140 // Higher ground level
1141 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1142 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1143 seed+85039, 5, 0.6);
1144 //higher = 30; // For debugging
1146 // Limit higher to at least base
1150 // Steepness factor of cliffs
1151 double b = 0.85 + 0.5 * noise2d_perlin(
1152 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1154 b = rangelim(b, 0.0, 1000.0);
1157 b = rangelim(b, 0.5, 1000.0);
1158 // Values 1.5...100 give quite horrible looking slopes
1159 if(b > 1.5 && b < 100.0){
1165 //dstream<<"b="<<b<<std::endl;
1169 // Offset to more low
1170 double a_off = -0.20;
1171 // High/low selector
1172 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1173 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1174 seed+4213, 6, 0.7));*/
1175 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1176 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1177 seed+4213, 5, 0.69));
1179 a = rangelim(a, 0.0, 1.0);
1181 //dstream<<"a="<<a<<std::endl;
1183 double h = base*(1.0-a) + higher*a;
1190 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1192 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1195 double get_mud_add_amount(u64 seed, v2s16 p)
1197 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1198 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1199 seed+91013, 3, 0.55));
1202 bool get_have_beach(u64 seed, v2s16 p2d)
1204 // Determine whether to have sand here
1205 double sandnoise = noise2d_perlin(
1206 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1207 seed+59420, 3, 0.50);
1209 return (sandnoise > 0.15);
1218 BiomeType get_biome(u64 seed, v2s16 p2d)
1220 // Just do something very simple as for now
1221 double d = noise2d_perlin(
1222 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1223 seed+9130, 3, 0.50);
1226 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1231 u32 get_blockseed(u64 seed, v3s16 p)
1233 s32 x=p.X, y=p.Y, z=p.Z;
1234 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1237 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1239 void make_block(BlockMakeData *data)
1243 //dstream<<"makeBlock: no-op"<<std::endl;
1247 assert(data->vmanip);
1248 assert(data->nodedef);
1249 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1250 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1251 data->blockpos_requested.Z >= data->blockpos_min.Z);
1252 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1253 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1254 data->blockpos_requested.Z <= data->blockpos_max.Z);
1256 INodeDefManager *ndef = data->nodedef;
1258 // Hack: use minimum block coordinates for old code that assumes
1260 v3s16 blockpos = data->blockpos_requested;
1262 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1263 <<blockpos.Z<<")"<<std::endl;*/
1265 v3s16 blockpos_min = data->blockpos_min;
1266 v3s16 blockpos_max = data->blockpos_max;
1267 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1268 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1270 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1271 // Area of central chunk
1272 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1273 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1274 // Full allocated area
1275 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1276 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1278 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1280 const s16 max_spread_amount = MAP_BLOCKSIZE;
1282 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1283 * (blockpos_max.Y - blockpos_min.Y + 1)
1284 * (blockpos_max.Z - blockpos_max.Z + 1);
1286 int volume_nodes = volume_blocks *
1287 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1289 // Generated surface area
1290 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1292 // Horribly wrong heuristic, but better than nothing
1293 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1296 Create a block-specific seed
1298 u32 blockseed = get_blockseed(data->seed, full_node_min);
1301 Cache some ground type values for speed
1304 // Creates variables c_name=id and n_name=node
1305 #define CONTENT_VARIABLE(ndef, name)\
1306 content_t c_##name = ndef->getId("mapgen_" #name);\
1307 MapNode n_##name(c_##name);
1308 // Default to something else if was CONTENT_IGNORE
1309 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1310 if(c_##name == CONTENT_IGNORE){\
1311 c_##name = c_##dname;\
1312 n_##name = n_##dname;\
1315 CONTENT_VARIABLE(ndef, stone);
1316 CONTENT_VARIABLE(ndef, air);
1317 CONTENT_VARIABLE(ndef, water_source);
1318 CONTENT_VARIABLE(ndef, dirt);
1319 CONTENT_VARIABLE(ndef, sand);
1320 CONTENT_VARIABLE(ndef, gravel);
1321 CONTENT_VARIABLE(ndef, clay);
1322 CONTENT_VARIABLE(ndef, lava_source);
1323 CONTENT_VARIABLE(ndef, cobble);
1324 CONTENT_VARIABLE(ndef, mossycobble);
1325 CONTENT_VARIABLE(ndef, dirt_with_grass);
1326 CONTENT_VARIABLE(ndef, junglegrass);
1327 CONTENT_VARIABLE(ndef, stone_with_coal);
1328 CONTENT_VARIABLE(ndef, stone_with_iron);
1329 CONTENT_VARIABLE(ndef, mese);
1330 CONTENT_VARIABLE(ndef, desert_sand);
1331 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1332 CONTENT_VARIABLE(ndef, desert_stone);
1333 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1335 // Maximum height of the stone surface and obstacles.
1336 // This is used to guide the cave generation
1337 s16 stone_surface_max_y = 0;
1340 Generate general ground level to full area
1344 TimeTaker timer1("Generating ground level");
1346 for(s16 x=node_min.X; x<=node_max.X; x++)
1347 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1350 v2s16 p2d = v2s16(x,z);
1353 Skip of already generated
1356 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1357 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1361 // Ground height at this point
1362 float surface_y_f = 0.0;
1364 // Use perlin noise for ground height
1365 surface_y_f = base_rock_level_2d(data->seed, p2d);
1367 /*// Experimental stuff
1369 float a = highlands_level_2d(data->seed, p2d);
1374 // Convert to integer
1375 s16 surface_y = (s16)surface_y_f;
1378 if(surface_y > stone_surface_max_y)
1379 stone_surface_max_y = surface_y;
1381 BiomeType bt = get_biome(data->seed, p2d);
1383 Fill ground with stone
1386 // Use fast index incrementing
1387 v3s16 em = vmanip.m_area.getExtent();
1388 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1389 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1391 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1393 if(y > WATER_LEVEL && bt == BT_DESERT)
1394 vmanip.m_data[i] = n_desert_stone;
1396 vmanip.m_data[i] = n_stone;
1397 } else if(y <= WATER_LEVEL){
1398 vmanip.m_data[i] = MapNode(c_water_source);
1400 vmanip.m_data[i] = MapNode(c_air);
1403 vmanip.m_area.add_y(em, i, 1);
1411 // Limit dirt flow area by 1 because mud is flown into neighbors.
1412 assert(central_area_size.X == central_area_size.Z);
1413 s16 mudflow_minpos = 0-max_spread_amount+1;
1414 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1417 Loop this part, it will make stuff look older and newer nicely
1420 const u32 age_loops = 2;
1421 for(u32 i_age=0; i_age<age_loops; i_age++)
1423 /******************************
1424 BEGINNING OF AGING LOOP
1425 ******************************/
1430 //TimeTaker timer1("caves");
1433 Make caves (this code is relatively horrible)
1435 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1436 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1437 data->seed+34329, 3, 0.50);
1438 cave_amount = MYMAX(0.0, cave_amount);
1439 u32 caves_count = cave_amount * volume_nodes / 50000;
1440 u32 bruises_count = 1;
1441 PseudoRandom ps(blockseed+21343);
1442 PseudoRandom ps2(blockseed+1032);
1443 if(ps.range(1, 6) == 1)
1444 bruises_count = ps.range(0, ps.range(0, 2));
1445 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1449 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1451 bool large_cave = (jj >= caves_count);
1452 s16 min_tunnel_diameter = 2;
1453 s16 max_tunnel_diameter = ps.range(2,6);
1454 int dswitchint = ps.range(1,14);
1455 u16 tunnel_routepoints = 0;
1456 int part_max_length_rs = 0;
1458 part_max_length_rs = ps.range(2,4);
1459 tunnel_routepoints = ps.range(5, ps.range(15,30));
1460 min_tunnel_diameter = 5;
1461 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1463 part_max_length_rs = ps.range(2,9);
1464 tunnel_routepoints = ps.range(10, ps.range(15,30));
1466 bool large_cave_is_flat = (ps.range(0,1) == 0);
1468 v3f main_direction(0,0,0);
1470 // Allowed route area size in nodes
1471 v3s16 ar = central_area_size;
1473 // Area starting point in nodes
1474 v3s16 of = node_min;
1477 //(this should be more than the maximum radius of the tunnel)
1478 //s16 insure = 5; // Didn't work with max_d = 20
1480 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1481 ar += v3s16(1,0,1) * more * 2;
1482 of -= v3s16(1,0,1) * more;
1484 s16 route_y_min = 0;
1485 // Allow half a diameter + 7 over stone surface
1486 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1488 /*// If caves, don't go through surface too often
1489 if(large_cave == false)
1490 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1492 // Limit maximum to area
1493 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1497 /*// Minimum is at y=0
1498 route_y_min = -of.Y - 0;*/
1499 // Minimum is at y=max_tunnel_diameter/4
1500 //route_y_min = -of.Y + max_tunnel_diameter/4;
1501 //s16 min = -of.Y + max_tunnel_diameter/4;
1502 //s16 min = -of.Y + 0;
1504 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1506 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1507 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1509 route_y_min = ps.range(min, min + max_tunnel_diameter);
1510 route_y_min = rangelim(route_y_min, 0, route_y_max);
1513 /*dstream<<"route_y_min = "<<route_y_min
1514 <<", route_y_max = "<<route_y_max<<std::endl;*/
1516 s16 route_start_y_min = route_y_min;
1517 s16 route_start_y_max = route_y_max;
1519 // Start every 4th cave from surface when applicable
1520 /*bool coming_from_surface = false;
1521 if(node_min.Y <= 0 && node_max.Y >= 0){
1522 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1523 if(coming_from_surface)
1524 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1527 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1528 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1530 // Randomize starting position
1532 (float)(ps.next()%ar.X)+0.5,
1533 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1534 (float)(ps.next()%ar.Z)+0.5
1537 v3s16 startp(orp.X, orp.Y, orp.Z);
1540 MapNode airnode(CONTENT_AIR);
1541 MapNode waternode(c_water_source);
1542 MapNode lavanode(c_lava_source);
1545 Generate some tunnel starting from orp
1548 for(u16 j=0; j<tunnel_routepoints; j++)
1550 if(j%dswitchint==0 && large_cave == false)
1552 main_direction = v3f(
1553 ((float)(ps.next()%20)-(float)10)/10,
1554 ((float)(ps.next()%20)-(float)10)/30,
1555 ((float)(ps.next()%20)-(float)10)/10
1557 main_direction *= (float)ps.range(0, 10)/10;
1561 s16 min_d = min_tunnel_diameter;
1562 s16 max_d = max_tunnel_diameter;
1563 s16 rs = ps.range(min_d, max_d);
1565 // Every second section is rough
1566 bool randomize_xz = (ps2.range(1,2) == 1);
1572 rs*part_max_length_rs,
1573 rs*part_max_length_rs/2,
1574 rs*part_max_length_rs
1580 rs*part_max_length_rs,
1581 ps.range(1, rs*part_max_length_rs),
1582 rs*part_max_length_rs
1589 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1590 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1591 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1594 // Jump downward sometimes
1595 if(!large_cave && ps.range(0,12) == 0)
1598 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1599 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1600 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1606 s16 h = find_ground_level_clever(vmanip,
1607 v2s16(p.X, p.Z), ndef);
1608 route_y_min = h - rs/3;
1609 route_y_max = h + rs;
1612 vec += main_direction;
1617 else if(rp.X >= ar.X)
1619 if(rp.Y < route_y_min)
1621 else if(rp.Y >= route_y_max)
1622 rp.Y = route_y_max-1;
1625 else if(rp.Z >= ar.Z)
1629 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1631 v3f fp = orp + vec * f;
1632 fp.X += 0.1*ps.range(-10,10);
1633 fp.Z += 0.1*ps.range(-10,10);
1634 v3s16 cp(fp.X, fp.Y, fp.Z);
1639 d0 += ps.range(-1,1);
1640 d1 += ps.range(-1,1);
1642 for(s16 z0=d0; z0<=d1; z0++)
1644 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1645 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1647 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1648 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1649 for(s16 y0=-si2; y0<=si2; y0++)
1651 /*// Make better floors in small caves
1652 if(y0 <= -rs/2 && rs<=7)
1654 if(large_cave_is_flat){
1655 // Make large caves not so tall
1656 if(rs > 7 && abs(y0) >= rs/3)
1666 if(vmanip.m_area.contains(p) == false)
1669 u32 i = vmanip.m_area.index(p);
1673 if(full_node_min.Y < WATER_LEVEL &&
1674 full_node_max.Y > WATER_LEVEL){
1675 if(p.Y <= WATER_LEVEL)
1676 vmanip.m_data[i] = waternode;
1678 vmanip.m_data[i] = airnode;
1679 } else if(full_node_max.Y < WATER_LEVEL){
1680 if(p.Y < startp.Y - 2)
1681 vmanip.m_data[i] = lavanode;
1683 vmanip.m_data[i] = airnode;
1685 vmanip.m_data[i] = airnode;
1688 // Don't replace air or water or lava or ignore
1689 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1690 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1691 vmanip.m_data[i].getContent() == c_water_source ||
1692 vmanip.m_data[i].getContent() == c_lava_source)
1695 vmanip.m_data[i] = airnode;
1698 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1716 TimeTaker timer1("add mud");
1719 Add mud to the central chunk
1722 for(s16 x=node_min.X; x<=node_max.X; x++)
1723 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1725 // Node position in 2d
1726 v2s16 p2d = v2s16(x,z);
1728 // Randomize mud amount
1729 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1731 // Find ground level
1732 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1733 // Handle area not found
1734 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1737 MapNode addnode(c_dirt);
1738 BiomeType bt = get_biome(data->seed, p2d);
1741 addnode = MapNode(c_desert_sand);
1743 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1744 addnode = MapNode(c_sand);
1745 } else if(mud_add_amount <= 0){
1746 mud_add_amount = 1 - mud_add_amount;
1747 addnode = MapNode(c_gravel);
1748 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1749 surface_y + mud_add_amount <= WATER_LEVEL+2){
1750 addnode = MapNode(c_sand);
1753 if(bt == BT_DESERT){
1755 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1760 If topmost node is grass, change it to mud.
1761 It might be if it was flown to there from a neighboring
1762 chunk and then converted.
1765 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1766 MapNode *n = &vmanip.m_data[i];
1767 if(n->getContent() == c_dirt_with_grass)
1768 *n = MapNode(c_dirt);
1776 v3s16 em = vmanip.m_area.getExtent();
1777 s16 y_start = surface_y+1;
1778 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1779 for(s16 y=y_start; y<=node_max.Y; y++)
1781 if(mudcount >= mud_add_amount)
1784 MapNode &n = vmanip.m_data[i];
1788 vmanip.m_area.add_y(em, i, 1);
1798 Add blobs of dirt and gravel underground
1800 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1802 PseudoRandom pr(blockseed+983);
1803 for(int i=0; i<volume_nodes/10/10/10; i++)
1805 bool only_fill_cave = (myrand_range(0,1) != 0);
1812 pr.range(node_min.X, node_max.X)-size.X/2,
1813 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1814 pr.range(node_min.Z, node_max.Z)-size.Z/2
1817 if(p0.Y > -32 && pr.range(0,1) == 0)
1818 n1 = MapNode(c_dirt);
1820 n1 = MapNode(c_gravel);
1821 for(int x1=0; x1<size.X; x1++)
1822 for(int y1=0; y1<size.Y; y1++)
1823 for(int z1=0; z1<size.Z; z1++)
1825 v3s16 p = p0 + v3s16(x1,y1,z1);
1826 u32 i = vmanip.m_area.index(p);
1827 if(!vmanip.m_area.contains(i))
1829 // Cancel if not stone and not cave air
1830 if(vmanip.m_data[i].getContent() != c_stone &&
1831 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1833 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1835 vmanip.m_data[i] = n1;
1843 TimeTaker timer1("flow mud");
1846 Flow mud away from steep edges
1849 // Iterate a few times
1850 for(s16 k=0; k<3; k++)
1853 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1854 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1856 // Invert coordinates every 2nd iteration
1859 x = mudflow_maxpos - (x-mudflow_minpos);
1860 z = mudflow_maxpos - (z-mudflow_minpos);
1863 // Node position in 2d
1864 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1866 v3s16 em = vmanip.m_area.getExtent();
1867 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1870 while(y >= node_min.Y)
1877 for(; y>=node_min.Y; y--)
1879 n = &vmanip.m_data[i];
1880 //if(content_walkable(n->d))
1882 if(n->getContent() == c_dirt ||
1883 n->getContent() == c_dirt_with_grass ||
1884 n->getContent() == c_gravel)
1887 vmanip.m_area.add_y(em, i, -1);
1890 // Stop if out of area
1891 //if(vmanip.m_area.contains(i) == false)
1895 /*// If not mud, do nothing to it
1896 MapNode *n = &vmanip.m_data[i];
1897 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1900 if(n->getContent() == c_dirt ||
1901 n->getContent() == c_dirt_with_grass)
1903 // Make it exactly mud
1904 n->setContent(c_dirt);
1907 Don't flow it if the stuff under it is not mud
1911 vmanip.m_area.add_y(em, i2, -1);
1912 // Cancel if out of area
1913 if(vmanip.m_area.contains(i2) == false)
1915 MapNode *n2 = &vmanip.m_data[i2];
1916 if(n2->getContent() != c_dirt &&
1917 n2->getContent() != c_dirt_with_grass)
1922 /*s16 recurse_count = 0;
1926 v3s16(0,0,1), // back
1927 v3s16(1,0,0), // right
1928 v3s16(0,0,-1), // front
1929 v3s16(-1,0,0), // left
1932 // Theck that upper is air or doesn't exist.
1933 // Cancel dropping if upper keeps it in place
1935 vmanip.m_area.add_y(em, i3, 1);
1936 if(vmanip.m_area.contains(i3) == true
1937 && ndef->get(vmanip.m_data[i3]).walkable)
1944 for(u32 di=0; di<4; di++)
1946 v3s16 dirp = dirs4[di];
1949 vmanip.m_area.add_p(em, i2, dirp);
1950 // Fail if out of area
1951 if(vmanip.m_area.contains(i2) == false)
1953 // Check that side is air
1954 MapNode *n2 = &vmanip.m_data[i2];
1955 if(ndef->get(*n2).walkable)
1957 // Check that under side is air
1958 vmanip.m_area.add_y(em, i2, -1);
1959 if(vmanip.m_area.contains(i2) == false)
1961 n2 = &vmanip.m_data[i2];
1962 if(ndef->get(*n2).walkable)
1964 /*// Check that under that is air (need a drop of 2)
1965 vmanip.m_area.add_y(em, i2, -1);
1966 if(vmanip.m_area.contains(i2) == false)
1968 n2 = &vmanip.m_data[i2];
1969 if(content_walkable(n2->d))
1971 // Loop further down until not air
1972 bool dropped_to_unknown = false;
1974 vmanip.m_area.add_y(em, i2, -1);
1975 n2 = &vmanip.m_data[i2];
1976 // if out of known area
1977 if(vmanip.m_area.contains(i2) == false
1978 || n2->getContent() == CONTENT_IGNORE){
1979 dropped_to_unknown = true;
1982 }while(ndef->get(*n2).walkable == false);
1983 // Loop one up so that we're in air
1984 vmanip.m_area.add_y(em, i2, 1);
1985 n2 = &vmanip.m_data[i2];
1987 bool old_is_water = (n->getContent() == c_water_source);
1988 // Move mud to new place
1989 if(!dropped_to_unknown) {
1991 // Set old place to be air (or water)
1993 *n = MapNode(c_water_source);
1995 *n = MapNode(CONTENT_AIR);
2011 /***********************
2013 ************************/
2016 Add top and bottom side of water to transforming_liquid queue
2019 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2020 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2025 bool water_found = false;
2026 // Use fast index incrementing
2027 v3s16 em = vmanip.m_area.getExtent();
2028 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2029 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2031 if(y == full_node_max.Y){
2033 (vmanip.m_data[i].getContent() == c_water_source ||
2034 vmanip.m_data[i].getContent() == c_lava_source);
2036 else if(water_found == false)
2038 if(vmanip.m_data[i].getContent() == c_water_source ||
2039 vmanip.m_data[i].getContent() == c_lava_source)
2041 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2042 data->transforming_liquid.push_back(p);
2048 // This can be done because water_found can only
2049 // turn to true and end up here after going through
2051 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2052 vmanip.m_data[i+1].getContent() != c_lava_source)
2054 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2055 data->transforming_liquid.push_back(p);
2056 water_found = false;
2060 vmanip.m_area.add_y(em, i, -1);
2069 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2070 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2072 // Node position in 2d
2073 v2s16 p2d = v2s16(x,z);
2076 Find the lowest surface to which enough light ends up
2079 Basically just wait until not air and not leaves.
2083 v3s16 em = vmanip.m_area.getExtent();
2084 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2086 // Go to ground level
2087 for(y=node_max.Y; y>=full_node_min.Y; y--)
2089 MapNode &n = vmanip.m_data[i];
2090 if(ndef->get(n).param_type != CPT_LIGHT
2091 || ndef->get(n).liquid_type != LIQUID_NONE)
2093 vmanip.m_area.add_y(em, i, -1);
2095 if(y >= full_node_min.Y)
2098 surface_y = full_node_min.Y;
2101 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2102 MapNode *n = &vmanip.m_data[i];
2103 if(n->getContent() == c_dirt){
2104 // Well yeah, this can't be overground...
2105 if(surface_y < WATER_LEVEL - 20)
2107 n->setContent(c_dirt_with_grass);
2114 assert(central_area_size.X == central_area_size.Z);
2116 PseudoRandom ps (blockseed);
2117 // Divide area into parts
2119 s16 sidelen = central_area_size.X / div;
2120 double area = sidelen * sidelen;
2121 for(s16 x0=0; x0<div; x0++)
2122 for(s16 z0=0; z0<div; z0++)
2124 // Center position of part of division
2126 node_min.X + sidelen/2 + sidelen*x0,
2127 node_min.Z + sidelen/2 + sidelen*z0
2129 // Minimum edge of part of division
2131 node_min.X + sidelen*x0,
2132 node_min.Z + sidelen*z0
2134 // Maximum edge of part of division
2136 node_min.X + sidelen + sidelen*x0 - 1,
2137 node_min.Z + sidelen + sidelen*z0 - 1
2140 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2141 // Put trees in random places on part of division
2142 for(u32 i=0; i<tree_count; i++)
2144 s16 x = ps.range(p2d_min.X, p2d_max.X);
2145 s16 z = ps.range(p2d_min.Y, p2d_max.Y);
2146 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2147 // Don't make a tree under water level
2150 // Don't make a tree so high that it doesn't fit
2151 if(y > node_max.Y - 6)
2155 Trees grow only on mud and grass
2158 u32 i = vmanip.m_area.index(v3s16(p));
2159 MapNode *n = &vmanip.m_data[i];
2160 if(n->getContent() != c_dirt
2161 && n->getContent() != c_dirt_with_grass)
2166 treegen::make_tree(vmanip, p, false, ndef, ps.next());
2173 Make base ground level
2176 for(s16 x=node_min.X; x<=node_max.X; x++)
2177 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2182 // Use fast index incrementing
2183 v3s16 em = vmanip.m_area.getExtent();
2184 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2185 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2187 // Only modify places that have no content
2188 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2190 // First priority: make air and water.
2191 // This avoids caves inside water.
2192 if(all_is_ground_except_caves == false
2193 && val_is_ground(noisebuf_ground.get(x,y,z),
2194 v3s16(x,y,z), data->seed) == false)
2196 if(y <= WATER_LEVEL)
2197 vmanip.m_data[i] = n_water_source;
2199 vmanip.m_data[i] = n_air;
2201 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2202 vmanip.m_data[i] = n_air;
2204 vmanip.m_data[i] = n_stone;
2207 vmanip->m_area.add_y(em, i, 1);
2213 Add mud and sand and others underground (in place of stone)
2216 for(s16 x=node_min.X; x<=node_max.X; x++)
2217 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2222 // Use fast index incrementing
2223 v3s16 em = vmanip.m_area.getExtent();
2224 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2225 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2227 if(vmanip.m_data[i].getContent() == c_stone)
2229 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2231 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2232 vmanip.m_data[i] = n_dirt;
2234 vmanip.m_data[i] = n_sand;
2236 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2238 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2239 vmanip.m_data[i] = n_gravel;
2241 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2242 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2244 vmanip.m_data[i] = n_lava_source;
2245 for(s16 x1=-1; x1<=1; x1++)
2246 for(s16 y1=-1; y1<=1; y1++)
2247 for(s16 z1=-1; z1<=1; z1++)
2248 data->transforming_liquid.push_back(
2249 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2253 vmanip->m_area.add_y(em, i, -1);
2262 //if(node_min.Y < approx_groundlevel)
2263 //if(myrand() % 3 == 0)
2264 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2265 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2266 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2267 float dungeon_rarity = 0.02;
2268 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2270 && node_min.Y < approx_groundlevel)
2272 // Dungeon generator doesn't modify places which have this set
2273 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2274 | VMANIP_FLAG_DUNGEON_PRESERVE);
2276 // Set all air and water to be untouchable to make dungeons open
2277 // to caves and open air
2278 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2279 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2284 // Use fast index incrementing
2285 v3s16 em = vmanip.m_area.getExtent();
2286 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2287 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2289 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2290 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2291 else if(vmanip.m_data[i].getContent() == c_water_source)
2292 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2293 vmanip->m_area.add_y(em, i, -1);
2298 PseudoRandom random(blockseed+2);
2301 make_dungeon1(vmanip, random, ndef);
2303 // Convert some cobble to mossy cobble
2304 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2305 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2310 // Use fast index incrementing
2311 v3s16 em = vmanip.m_area.getExtent();
2312 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2313 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2315 // (noisebuf not used because it doesn't contain the
2317 double wetness = noise3d_param(
2318 get_ground_wetness_params(data->seed), x,y,z);
2319 double d = noise3d_perlin((float)x/2.5,
2320 (float)y/2.5,(float)z/2.5,
2322 if(vmanip.m_data[i].getContent() == c_cobble)
2326 vmanip.m_data[i].setContent(c_mossycobble);
2329 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2332 vmanip.m_data[i].setContent(c_dirt);
2334 vmanip->m_area.add_y(em, i, -1);
2344 PseudoRandom ncrandom(blockseed+9324342);
2345 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2347 make_nc(vmanip, ncrandom, ndef);
2352 Add top and bottom side of water to transforming_liquid queue
2355 for(s16 x=node_min.X; x<=node_max.X; x++)
2356 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2361 bool water_found = false;
2362 // Use fast index incrementing
2363 v3s16 em = vmanip.m_area.getExtent();
2364 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2365 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2367 if(water_found == false)
2369 if(vmanip.m_data[i].getContent() == c_water_source)
2371 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2372 data->transforming_liquid.push_back(p);
2378 // This can be done because water_found can only
2379 // turn to true and end up here after going through
2381 if(vmanip.m_data[i+1].getContent() != c_water_source)
2383 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2384 data->transforming_liquid.push_back(p);
2385 water_found = false;
2389 vmanip->m_area.add_y(em, i, -1);
2395 If close to ground level
2398 //if(abs(approx_ground_depth) < 30)
2399 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2405 for(s16 x=node_min.X; x<=node_max.X; x++)
2406 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2411 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2412 bool have_sand = false;
2413 u32 current_depth = 0;
2414 bool air_detected = false;
2415 bool water_detected = false;
2416 bool have_clay = false;
2418 // Use fast index incrementing
2419 s16 start_y = node_max.Y+2;
2420 v3s16 em = vmanip.m_area.getExtent();
2421 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2422 for(s16 y=start_y; y>=node_min.Y-3; y--)
2424 if(vmanip.m_data[i].getContent() == c_water_source)
2425 water_detected = true;
2426 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2427 air_detected = true;
2429 if((vmanip.m_data[i].getContent() == c_stone
2430 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2431 || vmanip.m_data[i].getContent() == c_dirt
2432 || vmanip.m_data[i].getContent() == c_sand
2433 || vmanip.m_data[i].getContent() == c_gravel
2434 ) && (air_detected || water_detected))
2436 if(current_depth == 0 && y <= WATER_LEVEL+2
2437 && possibly_have_sand)
2440 if(current_depth < 4)
2444 vmanip.m_data[i] = MapNode(c_sand);
2447 else if(current_depth==0 && !water_detected
2448 && y >= WATER_LEVEL && air_detected)
2449 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2452 vmanip.m_data[i] = MapNode(c_dirt);
2456 if(vmanip.m_data[i].getContent() == c_dirt
2457 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2458 vmanip.m_data[i] = MapNode(c_stone);
2463 if(current_depth >= 8)
2466 else if(current_depth != 0)
2469 vmanip->m_area.add_y(em, i, -1);
2475 Calculate some stuff
2478 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2479 bool is_jungle = surface_humidity > 0.75;
2481 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2488 PseudoRandom treerandom(blockseed);
2489 // Put trees in random places on part of division
2490 for(u32 i=0; i<tree_count; i++)
2492 s16 x = treerandom.range(node_min.X, node_max.X);
2493 s16 z = treerandom.range(node_min.Z, node_max.Z);
2494 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2495 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2496 // Don't make a tree under water level
2499 // Make sure tree fits (only trees whose starting point is
2500 // at this block are added)
2501 if(y < node_min.Y || y > node_max.Y)
2504 Find exact ground level
2508 for(; p.Y >= y-6; p.Y--)
2510 u32 i = vmanip->m_area.index(p);
2511 MapNode *n = &vmanip->m_data[i];
2512 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2518 // If not found, handle next one
2523 u32 i = vmanip->m_area.index(p);
2524 MapNode *n = &vmanip->m_data[i];
2526 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2529 // Papyrus grows only on mud and in water
2530 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2533 make_papyrus(vmanip, p, ndef);
2535 // Trees grow only on mud and grass, on land
2536 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2539 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2540 if(is_jungle == false)
2543 if(myrand_range(0,4) != 0)
2544 is_apple_tree = false;
2546 is_apple_tree = noise2d_perlin(
2547 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2548 data->seed+342902, 3, 0.45) > 0.2;
2549 make_tree(vmanip, p, is_apple_tree, ndef);
2552 make_jungletree(vmanip, p, ndef);
2554 // Cactii grow only on sand, on land
2555 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2558 make_cactus(vmanip, p, ndef);
2568 PseudoRandom grassrandom(blockseed);
2569 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2571 s16 x = grassrandom.range(node_min.X, node_max.X);
2572 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2573 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2576 if(y < node_min.Y || y > node_max.Y)
2579 Find exact ground level
2583 for(; p.Y >= y-6; p.Y--)
2585 u32 i = vmanip->m_area.index(p);
2586 MapNode *n = &vmanip->m_data[i];
2587 if(data->nodedef->get(*n).is_ground_content)
2593 // If not found, handle next one
2597 if(vmanip.m_area.contains(p) == false)
2599 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2602 if(vmanip.m_area.contains(p))
2603 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2605 if(vmanip.m_area.contains(p))
2606 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2612 Add some kind of random stones
2615 u32 random_stone_count = gen_area_nodes *
2616 randomstone_amount_2d(data->seed, p2d_center);
2617 // Put in random places on part of division
2618 for(u32 i=0; i<random_stone_count; i++)
2620 s16 x = myrand_range(node_min.X, node_max.X);
2621 s16 z = myrand_range(node_min.Z, node_max.Z);
2622 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2623 // Don't add under water level
2624 /*if(y < WATER_LEVEL)
2626 // Don't add if doesn't belong to this block
2627 if(y < node_min.Y || y > node_max.Y)
2632 u32 i = vmanip->m_area.index(v3s16(p));
2633 MapNode *n = &vmanip->m_data[i];
2634 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2637 // Will be placed one higher
2640 make_randomstone(vmanip, p);
2649 u32 large_stone_count = gen_area_nodes *
2650 largestone_amount_2d(data->seed, p2d_center);
2651 //u32 large_stone_count = 1;
2652 // Put in random places on part of division
2653 for(u32 i=0; i<large_stone_count; i++)
2655 s16 x = myrand_range(node_min.X, node_max.X);
2656 s16 z = myrand_range(node_min.Z, node_max.Z);
2657 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2658 // Don't add under water level
2659 /*if(y < WATER_LEVEL)
2661 // Don't add if doesn't belong to this block
2662 if(y < node_min.Y || y > node_max.Y)
2667 u32 i = vmanip->m_area.index(v3s16(p));
2668 MapNode *n = &vmanip->m_data[i];
2669 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2672 // Will be placed one lower
2675 make_largestone(vmanip, p);
2685 PseudoRandom mineralrandom(blockseed);
2690 for(s16 i=0; i<approx_ground_depth/4; i++)
2692 if(mineralrandom.next()%50 == 0)
2694 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2695 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2696 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2697 for(u16 i=0; i<27; i++)
2699 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2700 u32 vi = vmanip.m_area.index(p);
2701 if(vmanip.m_data[vi].getContent() == c_stone)
2702 if(mineralrandom.next()%8 == 0)
2703 vmanip.m_data[vi] = MapNode(c_mese);
2712 u16 a = mineralrandom.range(0,15);
2714 u16 amount = 20 * a/1000;
2715 for(s16 i=0; i<amount; i++)
2717 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2718 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2719 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2721 u8 base_content = c_stone;
2722 MapNode new_content(CONTENT_IGNORE);
2725 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2727 new_content = MapNode(c_stone_with_coal);
2731 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2732 new_content = MapNode(c_stone_with_iron);
2733 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2734 vmanip.m_data[i] = MapNode(c_dirt);
2736 vmanip.m_data[i] = MapNode(c_sand);*/
2738 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2742 if(new_content.getContent() != CONTENT_IGNORE)
2744 for(u16 i=0; i<27; i++)
2746 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2747 u32 vi = vmanip.m_area.index(p);
2748 if(vmanip.m_data[vi].getContent() == base_content)
2750 if(mineralrandom.next()%sparseness == 0)
2751 vmanip.m_data[vi] = new_content;
2760 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2761 //for(s16 i=0; i<50; i++)
2762 u16 coal_amount = 30;
2763 u16 coal_rareness = 60 / coal_amount;
2764 if(coal_rareness == 0)
2766 if(mineralrandom.next()%coal_rareness == 0)
2768 u16 a = mineralrandom.next() % 16;
2769 u16 amount = coal_amount * a*a*a / 1000;
2770 for(s16 i=0; i<amount; i++)
2772 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2773 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2774 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2775 for(u16 i=0; i<27; i++)
2777 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2778 u32 vi = vmanip.m_area.index(p);
2779 if(vmanip.m_data[vi].getContent() == c_stone)
2780 if(mineralrandom.next()%8 == 0)
2781 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2788 u16 iron_amount = 8;
2789 u16 iron_rareness = 60 / iron_amount;
2790 if(iron_rareness == 0)
2792 if(mineralrandom.next()%iron_rareness == 0)
2794 u16 a = mineralrandom.next() % 16;
2795 u16 amount = iron_amount * a*a*a / 1000;
2796 for(s16 i=0; i<amount; i++)
2798 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2799 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2800 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2801 for(u16 i=0; i<27; i++)
2803 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2804 u32 vi = vmanip.m_area.index(p);
2805 if(vmanip.m_data[vi].getContent() == c_stone)
2806 if(mineralrandom.next()%8 == 0)
2807 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2818 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2820 //VoxelArea a(node_min, node_max);
2821 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2822 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2823 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2824 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2825 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2826 for(int i=0; i<2; i++)
2828 enum LightBank bank = banks[i];
2830 core::map<v3s16, bool> light_sources;
2831 core::map<v3s16, u8> unlight_from;
2833 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2834 light_sources, unlight_from);
2836 bool inexistent_top_provides_sunlight = !block_is_underground;
2837 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2838 vmanip, a, inexistent_top_provides_sunlight,
2839 light_sources, ndef);
2840 // TODO: Do stuff according to bottom_sunlight_valid
2842 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2844 vmanip.spreadLight(bank, light_sources, ndef);
2849 #endif ///BIG COMMENT