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.
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
37 /////////////////// Mapgen V6 perlin noise default values
38 NoiseParams nparams_v6_def_terrain_base =
39 {-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6};
40 NoiseParams nparams_v6_def_terrain_higher =
41 {20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6};
42 NoiseParams nparams_v6_def_steepness =
43 {0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7};
44 NoiseParams nparams_v6_def_height_select =
45 {0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69};
46 NoiseParams nparams_v6_def_trees =
47 {0.0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66};
48 NoiseParams nparams_v6_def_mud =
49 {AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55};
50 NoiseParams nparams_v6_def_beach =
51 {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50};
52 NoiseParams nparams_v6_def_biome =
53 {0.0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50};
54 NoiseParams nparams_v6_def_cave =
55 {6.0, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50};
58 ///////////////////////////////////////////////////////////////////////////////
59 /////////////////////////////// Emerge Manager ////////////////////////////////
63 EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef,
64 MapgenParams *mgparams) {
65 //the order of these assignments is pretty important
66 this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
67 this->params = mgparams;
69 this->mapgen = getMapgen();
73 EmergeManager::~EmergeManager() {
79 Mapgen *EmergeManager::getMapgen() {
81 /*switch (params->mg_version) {
83 mapgen = new MapgenV6(0, (MapgenV6Params *)params);
86 errorstream << "EmergeManager: Unsupported mapgen version "
87 << params->mg_version << ", falling back to V6" << std::endl;
88 params->mg_version = 6;
89 mapgen = new MapgenV6(0, (MapgenV6Params *)params);
96 void EmergeManager::addBlockToQueue() {
101 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
104 return mapgen->getGroundLevelAtPoint(p);
108 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
110 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
111 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
112 int ground_level = getGroundLevelAtPoint(p);
113 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
116 //yuck, but then again, should i bother being accurate?
117 //the height of the nodes in a single block is quite variable
118 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level;
122 u32 EmergeManager::getBlockSeed(v3s16 p) {
123 return (u32)(params->seed & 0xFFFFFFFF) +
130 MapgenParams *MapgenParams::createMapgenParams(std::string &mgstr) {
131 return new MapgenV6Params(); // this will be fixed later
134 return new MapgenV6Params();
135 default: //instead of complaining, default to 6
136 return new MapgenV6Params();
141 MapgenParams *MapgenParams::getParamsFromSettings(Settings *settings) {
142 std::string mg_name = settings->get("mg_name");
143 MapgenParams *mgparams = MapgenParams::createMapgenParams(mg_name);
144 mgparams->mg_name = mg_name;
145 mgparams->seed = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
146 mgparams->water_level = settings->getS16("water_level");
147 mgparams->chunksize = settings->getS16("chunksize");
148 mgparams->flags = settings->getS32("mg_flags");
150 /* switch (mg_version) {
153 MapgenV6Params *v6params = (MapgenV6Params *)mgparams;
155 v6params->freq_desert = settings->getFloat("mgv6_freq_desert");
156 v6params->freq_beach = settings->getFloat("mgv6_freq_beach");
157 v6params->np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
158 v6params->np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
159 v6params->np_steepness = settings->getNoiseParams("mgv6_np_steepness");
160 v6params->np_height_select = settings->getNoiseParams("mgv6_np_height_select");
161 v6params->np_trees = settings->getNoiseParams("mgv6_np_trees");
162 v6params->np_mud = settings->getNoiseParams("mgv6_np_mud");
163 v6params->np_beach = settings->getNoiseParams("mgv6_np_beach");
164 v6params->np_biome = settings->getNoiseParams("mgv6_np_biome");
165 v6params->np_cave = settings->getNoiseParams("mgv6_np_cave");
167 if (!v6params->np_terrain_base || !v6params->np_terrain_higher ||
168 !v6params->np_steepness || !v6params->np_height_select ||
169 !v6params->np_trees || !v6params->np_mud ||
170 !v6params->np_beach || !v6params->np_biome || !v6params->np_cave) {
187 /////////////////////////////////// legacy static functions for farmesh
190 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
191 //just need to return something
197 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
198 double sandnoise = noise2d_perlin(
199 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
200 seed+59420, 3, 0.50);
202 return (sandnoise > 0.15);
206 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
207 double noise = noise2d_perlin(
208 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
210 double zeroval = -0.39;
214 return 0.04 * (noise-zeroval) / (1.0-zeroval);
218 #if 0 /// BIG COMMENT
223 Some helper functions for the map generator
227 // Returns Y one under area minimum if not found
228 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
229 INodeDefManager *ndef)
231 v3s16 em = vmanip.m_area.getExtent();
232 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
233 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
234 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
236 for(y=y_nodes_max; y>=y_nodes_min; y--)
238 MapNode &n = vmanip.m_data[i];
239 if(ndef->get(n).walkable)
242 vmanip.m_area.add_y(em, i, -1);
247 return y_nodes_min - 1;
251 // Returns Y one under area minimum if not found
252 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
253 INodeDefManager *ndef)
255 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
256 return vmanip.m_area.MinEdge.Y-1;
257 v3s16 em = vmanip.m_area.getExtent();
258 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
259 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
260 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
262 content_t c_tree = ndef->getId("mapgen_tree");
263 content_t c_leaves = ndef->getId("mapgen_leaves");
264 for(y=y_nodes_max; y>=y_nodes_min; y--)
266 MapNode &n = vmanip.m_data[i];
267 if(ndef->get(n).walkable
268 && n.getContent() != c_tree
269 && n.getContent() != c_leaves)
272 vmanip.m_area.add_y(em, i, -1);
277 return y_nodes_min - 1;
281 // Returns Y one under area minimum if not found
282 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
283 INodeDefManager *ndef)
285 v3s16 em = vmanip.m_area.getExtent();
286 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
287 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
288 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
290 content_t c_stone = ndef->getId("mapgen_stone");
291 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
292 for(y=y_nodes_max; y>=y_nodes_min; y--)
294 MapNode &n = vmanip.m_data[i];
295 content_t c = n.getContent();
296 if(c != CONTENT_IGNORE && (
297 c == c_stone || c == c_desert_stone))
300 vmanip.m_area.add_y(em, i, -1);
305 return y_nodes_min - 1;
312 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
313 INodeDefManager *ndef)
315 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
317 s16 trunk_h = myrand_range(2, 3);
319 for(s16 ii=0; ii<trunk_h; ii++)
321 if(vmanip.m_area.contains(p1))
322 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
327 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
328 INodeDefManager *ndef)
330 MapNode cactusnode(ndef->getId("mapgen_cactus"));
334 for(s16 ii=0; ii<trunk_h; ii++)
336 if(vmanip.m_area.contains(p1))
337 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
345 Dungeon making routines
348 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
349 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
350 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
351 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
353 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
354 INodeDefManager *ndef)
357 for(s16 z=0; z<roomsize.Z; z++)
358 for(s16 y=0; y<roomsize.Y; y++)
361 v3s16 p = roomplace + v3s16(0,y,z);
362 if(vmanip.m_area.contains(p) == false)
364 u32 vi = vmanip.m_area.index(p);
365 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
367 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
370 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
371 if(vmanip.m_area.contains(p) == false)
373 u32 vi = vmanip.m_area.index(p);
374 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
376 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
381 for(s16 x=0; x<roomsize.X; x++)
382 for(s16 y=0; y<roomsize.Y; y++)
385 v3s16 p = roomplace + v3s16(x,y,0);
386 if(vmanip.m_area.contains(p) == false)
388 u32 vi = vmanip.m_area.index(p);
389 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
391 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
394 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
395 if(vmanip.m_area.contains(p) == false)
397 u32 vi = vmanip.m_area.index(p);
398 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
400 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
404 // Make +-Y walls (floor and ceiling)
405 for(s16 z=0; z<roomsize.Z; z++)
406 for(s16 x=0; x<roomsize.X; x++)
409 v3s16 p = roomplace + v3s16(x,0,z);
410 if(vmanip.m_area.contains(p) == false)
412 u32 vi = vmanip.m_area.index(p);
413 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
415 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
418 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
419 if(vmanip.m_area.contains(p) == false)
421 u32 vi = vmanip.m_area.index(p);
422 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
424 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
429 for(s16 z=1; z<roomsize.Z-1; z++)
430 for(s16 y=1; y<roomsize.Y-1; y++)
431 for(s16 x=1; x<roomsize.X-1; x++)
433 v3s16 p = roomplace + v3s16(x,y,z);
434 if(vmanip.m_area.contains(p) == false)
436 u32 vi = vmanip.m_area.index(p);
437 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
438 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
442 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
443 u8 avoid_flags, MapNode n, u8 or_flags)
445 for(s16 z=0; z<size.Z; z++)
446 for(s16 y=0; y<size.Y; y++)
447 for(s16 x=0; x<size.X; x++)
449 v3s16 p = place + v3s16(x,y,z);
450 if(vmanip.m_area.contains(p) == false)
452 u32 vi = vmanip.m_area.index(p);
453 if(vmanip.m_flags[vi] & avoid_flags)
455 vmanip.m_flags[vi] |= or_flags;
456 vmanip.m_data[vi] = n;
460 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
461 INodeDefManager *ndef)
463 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
464 VMANIP_FLAG_DUNGEON_INSIDE);
467 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
468 INodeDefManager *ndef)
470 make_hole1(vmanip, doorplace, ndef);
471 // Place torch (for testing)
472 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
475 static v3s16 rand_ortho_dir(PseudoRandom &random)
477 if(random.next()%2==0)
478 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
480 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
483 static v3s16 turn_xz(v3s16 olddir, int t)
503 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
505 int turn = random.range(0,2);
514 dir = turn_xz(olddir, 0);
517 dir = turn_xz(olddir, 1);
521 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
522 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
523 PseudoRandom &random, INodeDefManager *ndef)
525 make_hole1(vmanip, doorplace, ndef);
526 v3s16 p0 = doorplace;
530 length = random.range(1,13);
532 length = random.range(1,6);
533 length = random.range(1,13);
534 u32 partlength = random.range(1,13);
537 if(random.next()%2 == 0 && partlength >= 3)
538 make_stairs = random.next()%2 ? 1 : -1;
539 for(u32 i=0; i<length; i++)
545 /*// If already empty
546 if(vmanip.getNodeNoExNoEmerge(p).getContent()
548 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
553 if(vmanip.m_area.contains(p) == true
554 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
558 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
559 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
560 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
561 VMANIP_FLAG_DUNGEON_INSIDE);
562 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
563 VMANIP_FLAG_DUNGEON_INSIDE);
567 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
568 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
569 make_hole1(vmanip, p, ndef);
570 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
571 VMANIP_FLAG_DUNGEON_INSIDE);*/
578 // Can't go here, turn away
579 dir = turn_xz(dir, random.range(0,1));
580 make_stairs = -make_stairs;
582 partlength = random.range(1,length);
587 if(partcount >= partlength)
591 dir = random_turn(random, dir);
593 partlength = random.range(1,length);
596 if(random.next()%2 == 0 && partlength >= 3)
597 make_stairs = random.next()%2 ? 1 : -1;
608 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
609 INodeDefManager *ndef):
620 m_dir = rand_ortho_dir(m_random);
623 void setPos(v3s16 pos)
628 void setDir(v3s16 dir)
633 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
635 for(u32 i=0; i<100; i++)
637 v3s16 p = m_pos + m_dir;
638 v3s16 p1 = p + v3s16(0,1,0);
639 if(vmanip.m_area.contains(p) == false
640 || vmanip.m_area.contains(p1) == false
646 if(vmanip.getNodeNoExNoEmerge(p).getContent()
647 == m_ndef->getId("mapgen_cobble")
648 && vmanip.getNodeNoExNoEmerge(p1).getContent()
649 == m_ndef->getId("mapgen_cobble"))
651 // Found wall, this is a good place!
654 // Randomize next direction
659 Determine where to move next
661 // Jump one up if the actual space is there
662 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
663 == m_ndef->getId("mapgen_cobble")
664 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
666 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
669 // Jump one down if the actual space is there
670 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
671 == m_ndef->getId("mapgen_cobble")
672 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
674 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
677 // Check if walking is now possible
678 if(vmanip.getNodeNoExNoEmerge(p).getContent()
680 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
683 // Cannot continue walking here
693 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
694 v3s16 &result_doordir, v3s16 &result_roomplace)
696 for(s16 trycount=0; trycount<30; trycount++)
700 bool r = findPlaceForDoor(doorplace, doordir);
704 // X east, Z north, Y up
706 if(doordir == v3s16(1,0,0)) // X+
707 roomplace = doorplace +
708 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
709 if(doordir == v3s16(-1,0,0)) // X-
710 roomplace = doorplace +
711 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
712 if(doordir == v3s16(0,0,1)) // Z+
713 roomplace = doorplace +
714 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
715 if(doordir == v3s16(0,0,-1)) // Z-
716 roomplace = doorplace +
717 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
720 if(doordir == v3s16(1,0,0)) // X+
721 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
722 if(doordir == v3s16(-1,0,0)) // X-
723 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
724 if(doordir == v3s16(0,0,1)) // Z+
725 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
726 if(doordir == v3s16(0,0,-1)) // Z-
727 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
732 for(s16 z=1; z<roomsize.Z-1; z++)
733 for(s16 y=1; y<roomsize.Y-1; y++)
734 for(s16 x=1; x<roomsize.X-1; x++)
736 v3s16 p = roomplace + v3s16(x,y,z);
737 if(vmanip.m_area.contains(p) == false)
742 if(vmanip.m_flags[vmanip.m_area.index(p)]
743 & VMANIP_FLAG_DUNGEON_INSIDE)
754 result_doorplace = doorplace;
755 result_doordir = doordir;
756 result_roomplace = roomplace;
763 VoxelManipulator &vmanip;
766 PseudoRandom &m_random;
767 INodeDefManager *m_ndef;
770 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
771 INodeDefManager *ndef)
773 v3s16 areasize = vmanip.m_area.getExtent();
778 Find place for first room
781 for(u32 i=0; i<100; i++)
783 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
784 roomplace = vmanip.m_area.MinEdge + v3s16(
785 random.range(0,areasize.X-roomsize.X-1),
786 random.range(0,areasize.Y-roomsize.Y-1),
787 random.range(0,areasize.Z-roomsize.Z-1));
789 Check that we're not putting the room to an unknown place,
790 otherwise it might end up floating in the air
793 for(s16 z=1; z<roomsize.Z-1; z++)
794 for(s16 y=1; y<roomsize.Y-1; y++)
795 for(s16 x=1; x<roomsize.X-1; x++)
797 v3s16 p = roomplace + v3s16(x,y,z);
798 u32 vi = vmanip.m_area.index(p);
799 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
804 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
818 Stores the center position of the last room made, so that
819 a new corridor can be started from the last room instead of
820 the new room, if chosen so.
822 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
824 u32 room_count = random.range(2,7);
825 for(u32 i=0; i<room_count; i++)
827 // Make a room to the determined place
828 make_room1(vmanip, roomsize, roomplace, ndef);
830 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
832 // Place torch at room center (for testing)
833 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
836 if(i == room_count-1)
839 // Determine walker start position
841 bool start_in_last_room = (random.range(0,2)!=0);
842 //bool start_in_last_room = true;
844 v3s16 walker_start_place;
846 if(start_in_last_room)
848 walker_start_place = last_room_center;
852 walker_start_place = room_center;
853 // Store center of current room as the last one
854 last_room_center = room_center;
857 // Create walker and find a place for a door
858 RoomWalker walker(vmanip, walker_start_place, random, ndef);
861 bool r = walker.findPlaceForDoor(doorplace, doordir);
865 if(random.range(0,1)==0)
867 make_door1(vmanip, doorplace, doordir, ndef);
869 // Don't actually make a door
870 doorplace -= doordir;
872 // Make a random corridor starting from the door
874 v3s16 corridor_end_dir;
875 make_corridor(vmanip, doorplace, doordir, corridor_end,
876 corridor_end_dir, random, ndef);
878 // Find a place for a random sized room
879 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
880 walker.setPos(corridor_end);
881 walker.setDir(corridor_end_dir);
882 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
886 if(random.range(0,1)==0)
888 make_door1(vmanip, doorplace, doordir, ndef);
890 // Don't actually make a door
891 roomplace -= doordir;
898 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
899 INodeDefManager *ndef)
903 s32 r = random.range(0, 3);
905 dir = v3s16( 1, 0, 0);
909 dir = v3s16(-1, 0, 0);
913 dir = v3s16( 0, 0, 1);
917 dir = v3s16( 0, 0,-1);
920 v3s16 p = vmanip.m_area.MinEdge + v3s16(
921 16+random.range(0,15),
922 16+random.range(0,15),
923 16+random.range(0,15));
924 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
925 u32 length = random.range(3,15);
926 for(u32 j=0; j<length; j++)
929 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
935 Noise functions. Make sure seed is mangled differently in each one.
940 Scaling the output of the noise function affects the overdrive of the
941 contour function, which affects the shape of the output considerably.
943 #define CAVE_NOISE_SCALE 12.0
944 //#define CAVE_NOISE_SCALE 10.0
945 //#define CAVE_NOISE_SCALE 7.5
946 //#define CAVE_NOISE_SCALE 5.0
947 //#define CAVE_NOISE_SCALE 1.0
949 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
950 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
952 NoiseParams get_cave_noise1_params(u64 seed)
954 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
955 200, CAVE_NOISE_SCALE);*/
956 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
957 100, CAVE_NOISE_SCALE);*/
958 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
959 100, CAVE_NOISE_SCALE);*/
960 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
961 100, CAVE_NOISE_SCALE);*/
962 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
963 50, CAVE_NOISE_SCALE);
964 //return NoiseParams(NOISE_CONSTANT_ONE);
967 NoiseParams get_cave_noise2_params(u64 seed)
969 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
970 200, CAVE_NOISE_SCALE);*/
971 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
972 100, CAVE_NOISE_SCALE);*/
973 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
974 100, CAVE_NOISE_SCALE);*/
975 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
976 50, CAVE_NOISE_SCALE);
977 //return NoiseParams(NOISE_CONSTANT_ONE);
980 NoiseParams get_ground_noise1_params(u64 seed)
982 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
986 NoiseParams get_ground_crumbleness_params(u64 seed)
988 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
992 NoiseParams get_ground_wetness_params(u64 seed)
994 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
998 bool is_cave(u64 seed, v3s16 p)
1000 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1001 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1002 return d1*d2 > CAVE_NOISE_THRESHOLD;
1006 Ground density noise shall be interpreted by using this.
1008 TODO: No perlin noises here, they should be outsourced
1010 NOTE: The speed of these actually isn't terrible
1012 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1014 //return ((double)p.Y < ground_noise1_val);
1016 double f = 0.55 + noise2d_perlin(
1017 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1018 seed+920381, 3, 0.45);
1023 double h = WATER_LEVEL + 10 * noise2d_perlin(
1024 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1025 seed+84174, 4, 0.5);
1028 return ((double)p.Y - h < ground_noise1_val * f);
1032 Queries whether a position is ground or not.
1034 bool is_ground(u64 seed, v3s16 p)
1036 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1037 return val_is_ground(val1, p, seed);
1041 // Amount of trees per area in nodes
1042 double tree_amount_2d(u64 seed, v2s16 p)
1044 /*double noise = noise2d_perlin(
1045 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1047 double noise = noise2d_perlin(
1048 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1050 double zeroval = -0.39;
1054 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1058 double surface_humidity_2d(u64 seed, v2s16 p)
1060 double noise = noise2d_perlin(
1061 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1062 seed+72384, 4, 0.66);
1063 noise = (noise + 1.0)/2.0;
1072 Incrementally find ground level from 3d noise
1074 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1076 // Start a bit fuzzy to make averaging lower precision values
1078 s16 level = myrand_range(-precision/2, precision/2);
1079 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1081 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1083 // First find non-ground by going upwards
1084 // Don't stop in caves.
1086 s16 max = level+dec[i-1]*2;
1087 v3s16 p(p2d.X, level, p2d.Y);
1088 for(; p.Y < max; p.Y += dec[i])
1090 if(!is_ground(seed, p))
1097 // Then find ground by going downwards from there.
1098 // Go in caves, too, when precision is 1.
1100 s16 min = level-dec[i-1]*2;
1101 v3s16 p(p2d.X, level, p2d.Y);
1102 for(; p.Y>min; p.Y-=dec[i])
1104 bool ground = is_ground(seed, p);
1105 /*if(dec[i] == 1 && is_cave(seed, p))
1116 // This is more like the actual ground level
1117 level += dec[i-1]/2;
1122 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1124 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1126 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1127 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1129 a += find_ground_level_from_noise(seed,
1130 v2s16(node_min.X, node_min.Y), p);
1131 a += find_ground_level_from_noise(seed,
1132 v2s16(node_min.X, node_max.Y), p);
1133 a += find_ground_level_from_noise(seed,
1134 v2s16(node_max.X, node_max.Y), p);
1135 a += find_ground_level_from_noise(seed,
1136 v2s16(node_max.X, node_min.Y), p);
1137 a += find_ground_level_from_noise(seed,
1138 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1143 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1145 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1147 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1148 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1151 a = MYMAX(a, find_ground_level_from_noise(seed,
1152 v2s16(node_min.X, node_min.Y), p));
1153 a = MYMAX(a, find_ground_level_from_noise(seed,
1154 v2s16(node_min.X, node_max.Y), p));
1155 a = MYMAX(a, find_ground_level_from_noise(seed,
1156 v2s16(node_max.X, node_max.Y), p));
1157 a = MYMAX(a, find_ground_level_from_noise(seed,
1158 v2s16(node_min.X, node_min.Y), p));
1160 a = MYMAX(a, find_ground_level_from_noise(seed,
1161 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1162 // Side middle points
1163 a = MYMAX(a, find_ground_level_from_noise(seed,
1164 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1165 a = MYMAX(a, find_ground_level_from_noise(seed,
1166 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1167 a = MYMAX(a, find_ground_level_from_noise(seed,
1168 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1169 a = MYMAX(a, find_ground_level_from_noise(seed,
1170 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1174 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1176 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1178 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1179 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1182 a = MYMIN(a, find_ground_level_from_noise(seed,
1183 v2s16(node_min.X, node_min.Y), p));
1184 a = MYMIN(a, find_ground_level_from_noise(seed,
1185 v2s16(node_min.X, node_max.Y), p));
1186 a = MYMIN(a, find_ground_level_from_noise(seed,
1187 v2s16(node_max.X, node_max.Y), p));
1188 a = MYMIN(a, find_ground_level_from_noise(seed,
1189 v2s16(node_min.X, node_min.Y), p));
1191 a = MYMIN(a, find_ground_level_from_noise(seed,
1192 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1193 // Side middle points
1194 a = MYMIN(a, find_ground_level_from_noise(seed,
1195 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1196 a = MYMIN(a, find_ground_level_from_noise(seed,
1197 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1198 a = MYMIN(a, find_ground_level_from_noise(seed,
1199 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1200 a = MYMIN(a, find_ground_level_from_noise(seed,
1201 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1206 // Required by mapgen.h
1207 bool block_is_underground(u64 seed, v3s16 blockpos)
1209 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1210 seed, v2s16(blockpos.X, blockpos.Z));*/
1211 // Nah, this is just a heuristic, just return something
1212 s16 minimum_groundlevel = WATER_LEVEL;
1214 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1220 #define AVERAGE_MUD_AMOUNT 4
1222 double base_rock_level_2d(u64 seed, v2s16 p)
1224 // The base ground level
1225 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1226 + 20. * noise2d_perlin(
1227 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1228 seed+82341, 5, 0.6);
1230 /*// A bit hillier one
1231 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1232 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1233 seed+93413, 6, 0.69);
1237 // Higher ground level
1238 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1239 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1240 seed+85039, 5, 0.6);
1241 //higher = 30; // For debugging
1243 // Limit higher to at least base
1247 // Steepness factor of cliffs
1248 double b = 0.85 + 0.5 * noise2d_perlin(
1249 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1251 b = rangelim(b, 0.0, 1000.0);
1254 b = rangelim(b, 0.5, 1000.0);
1255 // Values 1.5...100 give quite horrible looking slopes
1256 if(b > 1.5 && b < 100.0){
1262 //dstream<<"b="<<b<<std::endl;
1266 // Offset to more low
1267 double a_off = -0.20;
1268 // High/low selector
1269 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1270 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1271 seed+4213, 6, 0.7));*/
1272 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1273 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1274 seed+4213, 5, 0.69));
1276 a = rangelim(a, 0.0, 1.0);
1278 //dstream<<"a="<<a<<std::endl;
1280 double h = base*(1.0-a) + higher*a;
1287 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1289 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1292 double get_mud_add_amount(u64 seed, v2s16 p)
1294 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1295 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1296 seed+91013, 3, 0.55));
1299 bool get_have_beach(u64 seed, v2s16 p2d)
1301 // Determine whether to have sand here
1302 double sandnoise = noise2d_perlin(
1303 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1304 seed+59420, 3, 0.50);
1306 return (sandnoise > 0.15);
1315 BiomeType get_biome(u64 seed, v2s16 p2d)
1317 // Just do something very simple as for now
1318 double d = noise2d_perlin(
1319 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1320 seed+9130, 3, 0.50);
1323 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1328 u32 get_blockseed(u64 seed, v3s16 p)
1330 s32 x=p.X, y=p.Y, z=p.Z;
1331 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1334 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1336 void make_block(BlockMakeData *data)
1340 //dstream<<"makeBlock: no-op"<<std::endl;
1344 assert(data->vmanip);
1345 assert(data->nodedef);
1346 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1347 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1348 data->blockpos_requested.Z >= data->blockpos_min.Z);
1349 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1350 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1351 data->blockpos_requested.Z <= data->blockpos_max.Z);
1353 INodeDefManager *ndef = data->nodedef;
1355 // Hack: use minimum block coordinates for old code that assumes
1357 v3s16 blockpos = data->blockpos_requested;
1359 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1360 <<blockpos.Z<<")"<<std::endl;*/
1362 v3s16 blockpos_min = data->blockpos_min;
1363 v3s16 blockpos_max = data->blockpos_max;
1364 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1365 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1367 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1368 // Area of central chunk
1369 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1370 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1371 // Full allocated area
1372 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1373 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1375 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1377 const s16 max_spread_amount = MAP_BLOCKSIZE;
1379 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1380 * (blockpos_max.Y - blockpos_min.Y + 1)
1381 * (blockpos_max.Z - blockpos_max.Z + 1);
1383 int volume_nodes = volume_blocks *
1384 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1386 // Generated surface area
1387 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1389 // Horribly wrong heuristic, but better than nothing
1390 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1393 Create a block-specific seed
1395 u32 blockseed = get_blockseed(data->seed, full_node_min);
1398 Cache some ground type values for speed
1401 // Creates variables c_name=id and n_name=node
1402 #define CONTENT_VARIABLE(ndef, name)\
1403 content_t c_##name = ndef->getId("mapgen_" #name);\
1404 MapNode n_##name(c_##name);
1405 // Default to something else if was CONTENT_IGNORE
1406 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1407 if(c_##name == CONTENT_IGNORE){\
1408 c_##name = c_##dname;\
1409 n_##name = n_##dname;\
1412 CONTENT_VARIABLE(ndef, stone);
1413 CONTENT_VARIABLE(ndef, air);
1414 CONTENT_VARIABLE(ndef, water_source);
1415 CONTENT_VARIABLE(ndef, dirt);
1416 CONTENT_VARIABLE(ndef, sand);
1417 CONTENT_VARIABLE(ndef, gravel);
1418 CONTENT_VARIABLE(ndef, clay);
1419 CONTENT_VARIABLE(ndef, lava_source);
1420 CONTENT_VARIABLE(ndef, cobble);
1421 CONTENT_VARIABLE(ndef, mossycobble);
1422 CONTENT_VARIABLE(ndef, dirt_with_grass);
1423 CONTENT_VARIABLE(ndef, junglegrass);
1424 CONTENT_VARIABLE(ndef, stone_with_coal);
1425 CONTENT_VARIABLE(ndef, stone_with_iron);
1426 CONTENT_VARIABLE(ndef, mese);
1427 CONTENT_VARIABLE(ndef, desert_sand);
1428 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1429 CONTENT_VARIABLE(ndef, desert_stone);
1430 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1432 // Maximum height of the stone surface and obstacles.
1433 // This is used to guide the cave generation
1434 s16 stone_surface_max_y = 0;
1437 Generate general ground level to full area
1441 TimeTaker timer1("Generating ground level");
1443 for(s16 x=node_min.X; x<=node_max.X; x++)
1444 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1447 v2s16 p2d = v2s16(x,z);
1450 Skip of already generated
1453 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1454 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1458 // Ground height at this point
1459 float surface_y_f = 0.0;
1461 // Use perlin noise for ground height
1462 surface_y_f = base_rock_level_2d(data->seed, p2d);
1464 /*// Experimental stuff
1466 float a = highlands_level_2d(data->seed, p2d);
1471 // Convert to integer
1472 s16 surface_y = (s16)surface_y_f;
1475 if(surface_y > stone_surface_max_y)
1476 stone_surface_max_y = surface_y;
1478 BiomeType bt = get_biome(data->seed, p2d);
1480 Fill ground with stone
1483 // Use fast index incrementing
1484 v3s16 em = vmanip.m_area.getExtent();
1485 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1486 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1488 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1490 if(y > WATER_LEVEL && bt == BT_DESERT)
1491 vmanip.m_data[i] = n_desert_stone;
1493 vmanip.m_data[i] = n_stone;
1494 } else if(y <= WATER_LEVEL){
1495 vmanip.m_data[i] = MapNode(c_water_source);
1497 vmanip.m_data[i] = MapNode(c_air);
1500 vmanip.m_area.add_y(em, i, 1);
1508 // Limit dirt flow area by 1 because mud is flown into neighbors.
1509 assert(central_area_size.X == central_area_size.Z);
1510 s16 mudflow_minpos = 0-max_spread_amount+1;
1511 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1514 Loop this part, it will make stuff look older and newer nicely
1517 const u32 age_loops = 2;
1518 for(u32 i_age=0; i_age<age_loops; i_age++)
1520 /******************************
1521 BEGINNING OF AGING LOOP
1522 ******************************/
1527 //TimeTaker timer1("caves");
1530 Make caves (this code is relatively horrible)
1532 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1533 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1534 data->seed+34329, 3, 0.50);
1535 cave_amount = MYMAX(0.0, cave_amount);
1536 u32 caves_count = cave_amount * volume_nodes / 50000;
1537 u32 bruises_count = 1;
1538 PseudoRandom ps(blockseed+21343);
1539 PseudoRandom ps2(blockseed+1032);
1540 if(ps.range(1, 6) == 1)
1541 bruises_count = ps.range(0, ps.range(0, 2));
1542 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1546 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1548 bool large_cave = (jj >= caves_count);
1549 s16 min_tunnel_diameter = 2;
1550 s16 max_tunnel_diameter = ps.range(2,6);
1551 int dswitchint = ps.range(1,14);
1552 u16 tunnel_routepoints = 0;
1553 int part_max_length_rs = 0;
1555 part_max_length_rs = ps.range(2,4);
1556 tunnel_routepoints = ps.range(5, ps.range(15,30));
1557 min_tunnel_diameter = 5;
1558 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1560 part_max_length_rs = ps.range(2,9);
1561 tunnel_routepoints = ps.range(10, ps.range(15,30));
1563 bool large_cave_is_flat = (ps.range(0,1) == 0);
1565 v3f main_direction(0,0,0);
1567 // Allowed route area size in nodes
1568 v3s16 ar = central_area_size;
1570 // Area starting point in nodes
1571 v3s16 of = node_min;
1574 //(this should be more than the maximum radius of the tunnel)
1575 //s16 insure = 5; // Didn't work with max_d = 20
1577 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1578 ar += v3s16(1,0,1) * more * 2;
1579 of -= v3s16(1,0,1) * more;
1581 s16 route_y_min = 0;
1582 // Allow half a diameter + 7 over stone surface
1583 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1585 /*// If caves, don't go through surface too often
1586 if(large_cave == false)
1587 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1589 // Limit maximum to area
1590 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1594 /*// Minimum is at y=0
1595 route_y_min = -of.Y - 0;*/
1596 // Minimum is at y=max_tunnel_diameter/4
1597 //route_y_min = -of.Y + max_tunnel_diameter/4;
1598 //s16 min = -of.Y + max_tunnel_diameter/4;
1599 //s16 min = -of.Y + 0;
1601 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1603 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1604 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1606 route_y_min = ps.range(min, min + max_tunnel_diameter);
1607 route_y_min = rangelim(route_y_min, 0, route_y_max);
1610 /*dstream<<"route_y_min = "<<route_y_min
1611 <<", route_y_max = "<<route_y_max<<std::endl;*/
1613 s16 route_start_y_min = route_y_min;
1614 s16 route_start_y_max = route_y_max;
1616 // Start every 4th cave from surface when applicable
1617 /*bool coming_from_surface = false;
1618 if(node_min.Y <= 0 && node_max.Y >= 0){
1619 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1620 if(coming_from_surface)
1621 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1624 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1625 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1627 // Randomize starting position
1629 (float)(ps.next()%ar.X)+0.5,
1630 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1631 (float)(ps.next()%ar.Z)+0.5
1634 v3s16 startp(orp.X, orp.Y, orp.Z);
1637 MapNode airnode(CONTENT_AIR);
1638 MapNode waternode(c_water_source);
1639 MapNode lavanode(c_lava_source);
1642 Generate some tunnel starting from orp
1645 for(u16 j=0; j<tunnel_routepoints; j++)
1647 if(j%dswitchint==0 && large_cave == false)
1649 main_direction = v3f(
1650 ((float)(ps.next()%20)-(float)10)/10,
1651 ((float)(ps.next()%20)-(float)10)/30,
1652 ((float)(ps.next()%20)-(float)10)/10
1654 main_direction *= (float)ps.range(0, 10)/10;
1658 s16 min_d = min_tunnel_diameter;
1659 s16 max_d = max_tunnel_diameter;
1660 s16 rs = ps.range(min_d, max_d);
1662 // Every second section is rough
1663 bool randomize_xz = (ps2.range(1,2) == 1);
1669 rs*part_max_length_rs,
1670 rs*part_max_length_rs/2,
1671 rs*part_max_length_rs
1677 rs*part_max_length_rs,
1678 ps.range(1, rs*part_max_length_rs),
1679 rs*part_max_length_rs
1686 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1687 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1688 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1691 // Jump downward sometimes
1692 if(!large_cave && ps.range(0,12) == 0)
1695 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1696 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1697 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1703 s16 h = find_ground_level_clever(vmanip,
1704 v2s16(p.X, p.Z), ndef);
1705 route_y_min = h - rs/3;
1706 route_y_max = h + rs;
1709 vec += main_direction;
1714 else if(rp.X >= ar.X)
1716 if(rp.Y < route_y_min)
1718 else if(rp.Y >= route_y_max)
1719 rp.Y = route_y_max-1;
1722 else if(rp.Z >= ar.Z)
1726 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1728 v3f fp = orp + vec * f;
1729 fp.X += 0.1*ps.range(-10,10);
1730 fp.Z += 0.1*ps.range(-10,10);
1731 v3s16 cp(fp.X, fp.Y, fp.Z);
1736 d0 += ps.range(-1,1);
1737 d1 += ps.range(-1,1);
1739 for(s16 z0=d0; z0<=d1; z0++)
1741 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1742 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1744 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1745 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1746 for(s16 y0=-si2; y0<=si2; y0++)
1748 /*// Make better floors in small caves
1749 if(y0 <= -rs/2 && rs<=7)
1751 if(large_cave_is_flat){
1752 // Make large caves not so tall
1753 if(rs > 7 && abs(y0) >= rs/3)
1763 if(vmanip.m_area.contains(p) == false)
1766 u32 i = vmanip.m_area.index(p);
1770 if(full_node_min.Y < WATER_LEVEL &&
1771 full_node_max.Y > WATER_LEVEL){
1772 if(p.Y <= WATER_LEVEL)
1773 vmanip.m_data[i] = waternode;
1775 vmanip.m_data[i] = airnode;
1776 } else if(full_node_max.Y < WATER_LEVEL){
1777 if(p.Y < startp.Y - 2)
1778 vmanip.m_data[i] = lavanode;
1780 vmanip.m_data[i] = airnode;
1782 vmanip.m_data[i] = airnode;
1785 // Don't replace air or water or lava or ignore
1786 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1787 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1788 vmanip.m_data[i].getContent() == c_water_source ||
1789 vmanip.m_data[i].getContent() == c_lava_source)
1792 vmanip.m_data[i] = airnode;
1795 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1813 TimeTaker timer1("add mud");
1816 Add mud to the central chunk
1819 for(s16 x=node_min.X; x<=node_max.X; x++)
1820 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1822 // Node position in 2d
1823 v2s16 p2d = v2s16(x,z);
1825 // Randomize mud amount
1826 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1828 // Find ground level
1829 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1830 // Handle area not found
1831 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1834 MapNode addnode(c_dirt);
1835 BiomeType bt = get_biome(data->seed, p2d);
1838 addnode = MapNode(c_desert_sand);
1840 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1841 addnode = MapNode(c_sand);
1842 } else if(mud_add_amount <= 0){
1843 mud_add_amount = 1 - mud_add_amount;
1844 addnode = MapNode(c_gravel);
1845 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1846 surface_y + mud_add_amount <= WATER_LEVEL+2){
1847 addnode = MapNode(c_sand);
1850 if(bt == BT_DESERT){
1852 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1857 If topmost node is grass, change it to mud.
1858 It might be if it was flown to there from a neighboring
1859 chunk and then converted.
1862 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1863 MapNode *n = &vmanip.m_data[i];
1864 if(n->getContent() == c_dirt_with_grass)
1865 *n = MapNode(c_dirt);
1873 v3s16 em = vmanip.m_area.getExtent();
1874 s16 y_start = surface_y+1;
1875 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1876 for(s16 y=y_start; y<=node_max.Y; y++)
1878 if(mudcount >= mud_add_amount)
1881 MapNode &n = vmanip.m_data[i];
1885 vmanip.m_area.add_y(em, i, 1);
1895 Add blobs of dirt and gravel underground
1897 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1899 PseudoRandom pr(blockseed+983);
1900 for(int i=0; i<volume_nodes/10/10/10; i++)
1902 bool only_fill_cave = (myrand_range(0,1) != 0);
1909 pr.range(node_min.X, node_max.X)-size.X/2,
1910 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1911 pr.range(node_min.Z, node_max.Z)-size.Z/2
1914 if(p0.Y > -32 && pr.range(0,1) == 0)
1915 n1 = MapNode(c_dirt);
1917 n1 = MapNode(c_gravel);
1918 for(int x1=0; x1<size.X; x1++)
1919 for(int y1=0; y1<size.Y; y1++)
1920 for(int z1=0; z1<size.Z; z1++)
1922 v3s16 p = p0 + v3s16(x1,y1,z1);
1923 u32 i = vmanip.m_area.index(p);
1924 if(!vmanip.m_area.contains(i))
1926 // Cancel if not stone and not cave air
1927 if(vmanip.m_data[i].getContent() != c_stone &&
1928 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1930 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1932 vmanip.m_data[i] = n1;
1940 TimeTaker timer1("flow mud");
1943 Flow mud away from steep edges
1946 // Iterate a few times
1947 for(s16 k=0; k<3; k++)
1950 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1951 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1953 // Invert coordinates every 2nd iteration
1956 x = mudflow_maxpos - (x-mudflow_minpos);
1957 z = mudflow_maxpos - (z-mudflow_minpos);
1960 // Node position in 2d
1961 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1963 v3s16 em = vmanip.m_area.getExtent();
1964 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1967 while(y >= node_min.Y)
1974 for(; y>=node_min.Y; y--)
1976 n = &vmanip.m_data[i];
1977 //if(content_walkable(n->d))
1979 if(n->getContent() == c_dirt ||
1980 n->getContent() == c_dirt_with_grass ||
1981 n->getContent() == c_gravel)
1984 vmanip.m_area.add_y(em, i, -1);
1987 // Stop if out of area
1988 //if(vmanip.m_area.contains(i) == false)
1992 /*// If not mud, do nothing to it
1993 MapNode *n = &vmanip.m_data[i];
1994 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1997 if(n->getContent() == c_dirt ||
1998 n->getContent() == c_dirt_with_grass)
2000 // Make it exactly mud
2001 n->setContent(c_dirt);
2004 Don't flow it if the stuff under it is not mud
2008 vmanip.m_area.add_y(em, i2, -1);
2009 // Cancel if out of area
2010 if(vmanip.m_area.contains(i2) == false)
2012 MapNode *n2 = &vmanip.m_data[i2];
2013 if(n2->getContent() != c_dirt &&
2014 n2->getContent() != c_dirt_with_grass)
2019 /*s16 recurse_count = 0;
2023 v3s16(0,0,1), // back
2024 v3s16(1,0,0), // right
2025 v3s16(0,0,-1), // front
2026 v3s16(-1,0,0), // left
2029 // Theck that upper is air or doesn't exist.
2030 // Cancel dropping if upper keeps it in place
2032 vmanip.m_area.add_y(em, i3, 1);
2033 if(vmanip.m_area.contains(i3) == true
2034 && ndef->get(vmanip.m_data[i3]).walkable)
2041 for(u32 di=0; di<4; di++)
2043 v3s16 dirp = dirs4[di];
2046 vmanip.m_area.add_p(em, i2, dirp);
2047 // Fail if out of area
2048 if(vmanip.m_area.contains(i2) == false)
2050 // Check that side is air
2051 MapNode *n2 = &vmanip.m_data[i2];
2052 if(ndef->get(*n2).walkable)
2054 // Check that under side is air
2055 vmanip.m_area.add_y(em, i2, -1);
2056 if(vmanip.m_area.contains(i2) == false)
2058 n2 = &vmanip.m_data[i2];
2059 if(ndef->get(*n2).walkable)
2061 /*// Check that under that is air (need a drop of 2)
2062 vmanip.m_area.add_y(em, i2, -1);
2063 if(vmanip.m_area.contains(i2) == false)
2065 n2 = &vmanip.m_data[i2];
2066 if(content_walkable(n2->d))
2068 // Loop further down until not air
2069 bool dropped_to_unknown = false;
2071 vmanip.m_area.add_y(em, i2, -1);
2072 n2 = &vmanip.m_data[i2];
2073 // if out of known area
2074 if(vmanip.m_area.contains(i2) == false
2075 || n2->getContent() == CONTENT_IGNORE){
2076 dropped_to_unknown = true;
2079 }while(ndef->get(*n2).walkable == false);
2080 // Loop one up so that we're in air
2081 vmanip.m_area.add_y(em, i2, 1);
2082 n2 = &vmanip.m_data[i2];
2084 bool old_is_water = (n->getContent() == c_water_source);
2085 // Move mud to new place
2086 if(!dropped_to_unknown) {
2088 // Set old place to be air (or water)
2090 *n = MapNode(c_water_source);
2092 *n = MapNode(CONTENT_AIR);
2108 /***********************
2110 ************************/
2113 Add top and bottom side of water to transforming_liquid queue
2116 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2117 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2122 bool water_found = false;
2123 // Use fast index incrementing
2124 v3s16 em = vmanip.m_area.getExtent();
2125 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2126 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2128 if(y == full_node_max.Y){
2130 (vmanip.m_data[i].getContent() == c_water_source ||
2131 vmanip.m_data[i].getContent() == c_lava_source);
2133 else if(water_found == false)
2135 if(vmanip.m_data[i].getContent() == c_water_source ||
2136 vmanip.m_data[i].getContent() == c_lava_source)
2138 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2139 data->transforming_liquid.push_back(p);
2145 // This can be done because water_found can only
2146 // turn to true and end up here after going through
2148 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2149 vmanip.m_data[i+1].getContent() != c_lava_source)
2151 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2152 data->transforming_liquid.push_back(p);
2153 water_found = false;
2157 vmanip.m_area.add_y(em, i, -1);
2166 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2167 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2169 // Node position in 2d
2170 v2s16 p2d = v2s16(x,z);
2173 Find the lowest surface to which enough light ends up
2176 Basically just wait until not air and not leaves.
2180 v3s16 em = vmanip.m_area.getExtent();
2181 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2183 // Go to ground level
2184 for(y=node_max.Y; y>=full_node_min.Y; y--)
2186 MapNode &n = vmanip.m_data[i];
2187 if(ndef->get(n).param_type != CPT_LIGHT
2188 || ndef->get(n).liquid_type != LIQUID_NONE)
2190 vmanip.m_area.add_y(em, i, -1);
2192 if(y >= full_node_min.Y)
2195 surface_y = full_node_min.Y;
2198 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2199 MapNode *n = &vmanip.m_data[i];
2200 if(n->getContent() == c_dirt){
2201 // Well yeah, this can't be overground...
2202 if(surface_y < WATER_LEVEL - 20)
2204 n->setContent(c_dirt_with_grass);
2211 assert(central_area_size.X == central_area_size.Z);
2213 // Divide area into parts
2215 s16 sidelen = central_area_size.X / div;
2216 double area = sidelen * sidelen;
2217 for(s16 x0=0; x0<div; x0++)
2218 for(s16 z0=0; z0<div; z0++)
2220 // Center position of part of division
2222 node_min.X + sidelen/2 + sidelen*x0,
2223 node_min.Z + sidelen/2 + sidelen*z0
2225 // Minimum edge of part of division
2227 node_min.X + sidelen*x0,
2228 node_min.Z + sidelen*z0
2230 // Maximum edge of part of division
2232 node_min.X + sidelen + sidelen*x0 - 1,
2233 node_min.Z + sidelen + sidelen*z0 - 1
2236 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2237 // Put trees in random places on part of division
2238 for(u32 i=0; i<tree_count; i++)
2240 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2241 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2242 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2243 // Don't make a tree under water level
2246 // Don't make a tree so high that it doesn't fit
2247 if(y > node_max.Y - 6)
2251 Trees grow only on mud and grass
2254 u32 i = vmanip.m_area.index(v3s16(p));
2255 MapNode *n = &vmanip.m_data[i];
2256 if(n->getContent() != c_dirt
2257 && n->getContent() != c_dirt_with_grass)
2262 treegen::make_tree(vmanip, p, false, ndef);
2269 Make base ground level
2272 for(s16 x=node_min.X; x<=node_max.X; x++)
2273 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2278 // Use fast index incrementing
2279 v3s16 em = vmanip.m_area.getExtent();
2280 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2281 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2283 // Only modify places that have no content
2284 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2286 // First priority: make air and water.
2287 // This avoids caves inside water.
2288 if(all_is_ground_except_caves == false
2289 && val_is_ground(noisebuf_ground.get(x,y,z),
2290 v3s16(x,y,z), data->seed) == false)
2292 if(y <= WATER_LEVEL)
2293 vmanip.m_data[i] = n_water_source;
2295 vmanip.m_data[i] = n_air;
2297 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2298 vmanip.m_data[i] = n_air;
2300 vmanip.m_data[i] = n_stone;
2303 vmanip->m_area.add_y(em, i, 1);
2309 Add mud and sand and others underground (in place of stone)
2312 for(s16 x=node_min.X; x<=node_max.X; x++)
2313 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2318 // Use fast index incrementing
2319 v3s16 em = vmanip.m_area.getExtent();
2320 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2321 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2323 if(vmanip.m_data[i].getContent() == c_stone)
2325 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2327 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2328 vmanip.m_data[i] = n_dirt;
2330 vmanip.m_data[i] = n_sand;
2332 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2334 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2335 vmanip.m_data[i] = n_gravel;
2337 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2338 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2340 vmanip.m_data[i] = n_lava_source;
2341 for(s16 x1=-1; x1<=1; x1++)
2342 for(s16 y1=-1; y1<=1; y1++)
2343 for(s16 z1=-1; z1<=1; z1++)
2344 data->transforming_liquid.push_back(
2345 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2349 vmanip->m_area.add_y(em, i, -1);
2358 //if(node_min.Y < approx_groundlevel)
2359 //if(myrand() % 3 == 0)
2360 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2361 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2362 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2363 float dungeon_rarity = 0.02;
2364 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2366 && node_min.Y < approx_groundlevel)
2368 // Dungeon generator doesn't modify places which have this set
2369 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2370 | VMANIP_FLAG_DUNGEON_PRESERVE);
2372 // Set all air and water to be untouchable to make dungeons open
2373 // to caves and open air
2374 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2375 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2380 // Use fast index incrementing
2381 v3s16 em = vmanip.m_area.getExtent();
2382 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2383 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2385 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2386 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2387 else if(vmanip.m_data[i].getContent() == c_water_source)
2388 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2389 vmanip->m_area.add_y(em, i, -1);
2394 PseudoRandom random(blockseed+2);
2397 make_dungeon1(vmanip, random, ndef);
2399 // Convert some cobble to mossy cobble
2400 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2401 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2406 // Use fast index incrementing
2407 v3s16 em = vmanip.m_area.getExtent();
2408 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2409 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2411 // (noisebuf not used because it doesn't contain the
2413 double wetness = noise3d_param(
2414 get_ground_wetness_params(data->seed), x,y,z);
2415 double d = noise3d_perlin((float)x/2.5,
2416 (float)y/2.5,(float)z/2.5,
2418 if(vmanip.m_data[i].getContent() == c_cobble)
2422 vmanip.m_data[i].setContent(c_mossycobble);
2425 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2428 vmanip.m_data[i].setContent(c_dirt);
2430 vmanip->m_area.add_y(em, i, -1);
2440 PseudoRandom ncrandom(blockseed+9324342);
2441 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2443 make_nc(vmanip, ncrandom, ndef);
2448 Add top and bottom side of water to transforming_liquid queue
2451 for(s16 x=node_min.X; x<=node_max.X; x++)
2452 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2457 bool water_found = false;
2458 // Use fast index incrementing
2459 v3s16 em = vmanip.m_area.getExtent();
2460 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2461 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2463 if(water_found == false)
2465 if(vmanip.m_data[i].getContent() == c_water_source)
2467 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2468 data->transforming_liquid.push_back(p);
2474 // This can be done because water_found can only
2475 // turn to true and end up here after going through
2477 if(vmanip.m_data[i+1].getContent() != c_water_source)
2479 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2480 data->transforming_liquid.push_back(p);
2481 water_found = false;
2485 vmanip->m_area.add_y(em, i, -1);
2491 If close to ground level
2494 //if(abs(approx_ground_depth) < 30)
2495 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2501 for(s16 x=node_min.X; x<=node_max.X; x++)
2502 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2507 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2508 bool have_sand = false;
2509 u32 current_depth = 0;
2510 bool air_detected = false;
2511 bool water_detected = false;
2512 bool have_clay = false;
2514 // Use fast index incrementing
2515 s16 start_y = node_max.Y+2;
2516 v3s16 em = vmanip.m_area.getExtent();
2517 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2518 for(s16 y=start_y; y>=node_min.Y-3; y--)
2520 if(vmanip.m_data[i].getContent() == c_water_source)
2521 water_detected = true;
2522 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2523 air_detected = true;
2525 if((vmanip.m_data[i].getContent() == c_stone
2526 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2527 || vmanip.m_data[i].getContent() == c_dirt
2528 || vmanip.m_data[i].getContent() == c_sand
2529 || vmanip.m_data[i].getContent() == c_gravel
2530 ) && (air_detected || water_detected))
2532 if(current_depth == 0 && y <= WATER_LEVEL+2
2533 && possibly_have_sand)
2536 if(current_depth < 4)
2540 vmanip.m_data[i] = MapNode(c_sand);
2543 else if(current_depth==0 && !water_detected
2544 && y >= WATER_LEVEL && air_detected)
2545 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2548 vmanip.m_data[i] = MapNode(c_dirt);
2552 if(vmanip.m_data[i].getContent() == c_dirt
2553 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2554 vmanip.m_data[i] = MapNode(c_stone);
2559 if(current_depth >= 8)
2562 else if(current_depth != 0)
2565 vmanip->m_area.add_y(em, i, -1);
2571 Calculate some stuff
2574 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2575 bool is_jungle = surface_humidity > 0.75;
2577 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2584 PseudoRandom treerandom(blockseed);
2585 // Put trees in random places on part of division
2586 for(u32 i=0; i<tree_count; i++)
2588 s16 x = treerandom.range(node_min.X, node_max.X);
2589 s16 z = treerandom.range(node_min.Z, node_max.Z);
2590 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2591 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2592 // Don't make a tree under water level
2595 // Make sure tree fits (only trees whose starting point is
2596 // at this block are added)
2597 if(y < node_min.Y || y > node_max.Y)
2600 Find exact ground level
2604 for(; p.Y >= y-6; p.Y--)
2606 u32 i = vmanip->m_area.index(p);
2607 MapNode *n = &vmanip->m_data[i];
2608 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2614 // If not found, handle next one
2619 u32 i = vmanip->m_area.index(p);
2620 MapNode *n = &vmanip->m_data[i];
2622 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2625 // Papyrus grows only on mud and in water
2626 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2629 make_papyrus(vmanip, p, ndef);
2631 // Trees grow only on mud and grass, on land
2632 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2635 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2636 if(is_jungle == false)
2639 if(myrand_range(0,4) != 0)
2640 is_apple_tree = false;
2642 is_apple_tree = noise2d_perlin(
2643 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2644 data->seed+342902, 3, 0.45) > 0.2;
2645 make_tree(vmanip, p, is_apple_tree, ndef);
2648 make_jungletree(vmanip, p, ndef);
2650 // Cactii grow only on sand, on land
2651 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2654 make_cactus(vmanip, p, ndef);
2664 PseudoRandom grassrandom(blockseed);
2665 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2667 s16 x = grassrandom.range(node_min.X, node_max.X);
2668 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2669 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2672 if(y < node_min.Y || y > node_max.Y)
2675 Find exact ground level
2679 for(; p.Y >= y-6; p.Y--)
2681 u32 i = vmanip->m_area.index(p);
2682 MapNode *n = &vmanip->m_data[i];
2683 if(data->nodedef->get(*n).is_ground_content)
2689 // If not found, handle next one
2693 if(vmanip.m_area.contains(p) == false)
2695 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2698 if(vmanip.m_area.contains(p))
2699 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2701 if(vmanip.m_area.contains(p))
2702 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2708 Add some kind of random stones
2711 u32 random_stone_count = gen_area_nodes *
2712 randomstone_amount_2d(data->seed, p2d_center);
2713 // Put in random places on part of division
2714 for(u32 i=0; i<random_stone_count; i++)
2716 s16 x = myrand_range(node_min.X, node_max.X);
2717 s16 z = myrand_range(node_min.Z, node_max.Z);
2718 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2719 // Don't add under water level
2720 /*if(y < WATER_LEVEL)
2722 // Don't add if doesn't belong to this block
2723 if(y < node_min.Y || y > node_max.Y)
2728 u32 i = vmanip->m_area.index(v3s16(p));
2729 MapNode *n = &vmanip->m_data[i];
2730 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2733 // Will be placed one higher
2736 make_randomstone(vmanip, p);
2745 u32 large_stone_count = gen_area_nodes *
2746 largestone_amount_2d(data->seed, p2d_center);
2747 //u32 large_stone_count = 1;
2748 // Put in random places on part of division
2749 for(u32 i=0; i<large_stone_count; i++)
2751 s16 x = myrand_range(node_min.X, node_max.X);
2752 s16 z = myrand_range(node_min.Z, node_max.Z);
2753 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2754 // Don't add under water level
2755 /*if(y < WATER_LEVEL)
2757 // Don't add if doesn't belong to this block
2758 if(y < node_min.Y || y > node_max.Y)
2763 u32 i = vmanip->m_area.index(v3s16(p));
2764 MapNode *n = &vmanip->m_data[i];
2765 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2768 // Will be placed one lower
2771 make_largestone(vmanip, p);
2781 PseudoRandom mineralrandom(blockseed);
2786 for(s16 i=0; i<approx_ground_depth/4; i++)
2788 if(mineralrandom.next()%50 == 0)
2790 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2791 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2792 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2793 for(u16 i=0; i<27; i++)
2795 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2796 u32 vi = vmanip.m_area.index(p);
2797 if(vmanip.m_data[vi].getContent() == c_stone)
2798 if(mineralrandom.next()%8 == 0)
2799 vmanip.m_data[vi] = MapNode(c_mese);
2808 u16 a = mineralrandom.range(0,15);
2810 u16 amount = 20 * a/1000;
2811 for(s16 i=0; i<amount; i++)
2813 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2814 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2815 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2817 u8 base_content = c_stone;
2818 MapNode new_content(CONTENT_IGNORE);
2821 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2823 new_content = MapNode(c_stone_with_coal);
2827 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2828 new_content = MapNode(c_stone_with_iron);
2829 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2830 vmanip.m_data[i] = MapNode(c_dirt);
2832 vmanip.m_data[i] = MapNode(c_sand);*/
2834 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2838 if(new_content.getContent() != CONTENT_IGNORE)
2840 for(u16 i=0; i<27; i++)
2842 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2843 u32 vi = vmanip.m_area.index(p);
2844 if(vmanip.m_data[vi].getContent() == base_content)
2846 if(mineralrandom.next()%sparseness == 0)
2847 vmanip.m_data[vi] = new_content;
2856 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2857 //for(s16 i=0; i<50; i++)
2858 u16 coal_amount = 30;
2859 u16 coal_rareness = 60 / coal_amount;
2860 if(coal_rareness == 0)
2862 if(mineralrandom.next()%coal_rareness == 0)
2864 u16 a = mineralrandom.next() % 16;
2865 u16 amount = coal_amount * a*a*a / 1000;
2866 for(s16 i=0; i<amount; i++)
2868 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2869 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2870 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2871 for(u16 i=0; i<27; i++)
2873 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2874 u32 vi = vmanip.m_area.index(p);
2875 if(vmanip.m_data[vi].getContent() == c_stone)
2876 if(mineralrandom.next()%8 == 0)
2877 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2884 u16 iron_amount = 8;
2885 u16 iron_rareness = 60 / iron_amount;
2886 if(iron_rareness == 0)
2888 if(mineralrandom.next()%iron_rareness == 0)
2890 u16 a = mineralrandom.next() % 16;
2891 u16 amount = iron_amount * a*a*a / 1000;
2892 for(s16 i=0; i<amount; i++)
2894 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2895 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2896 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2897 for(u16 i=0; i<27; i++)
2899 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2900 u32 vi = vmanip.m_area.index(p);
2901 if(vmanip.m_data[vi].getContent() == c_stone)
2902 if(mineralrandom.next()%8 == 0)
2903 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2914 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2916 //VoxelArea a(node_min, node_max);
2917 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2918 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2919 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2920 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2921 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2922 for(int i=0; i<2; i++)
2924 enum LightBank bank = banks[i];
2926 core::map<v3s16, bool> light_sources;
2927 core::map<v3s16, u8> unlight_from;
2929 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2930 light_sources, unlight_from);
2932 bool inexistent_top_provides_sunlight = !block_is_underground;
2933 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2934 vmanip, a, inexistent_top_provides_sunlight,
2935 light_sources, ndef);
2936 // TODO: Do stuff according to bottom_sunlight_valid
2938 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2940 vmanip.spreadLight(bank, light_sources, ndef);
2945 #endif ///BIG COMMENT
2947 BlockMakeData::BlockMakeData():
2954 BlockMakeData::~BlockMakeData()
2959 //}; // namespace mapgen