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
36 #include "mapgen_v6.h"
39 ///////////////////////////////////////////////////////////////////////////////
40 /////////////////////////////// Emerge Manager ////////////////////////////////
43 EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
44 //register built-in mapgens
45 registerMapgen("v6", new MapgenFactoryV6());
47 //the order of these assignments is pretty important
48 this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
54 EmergeManager::~EmergeManager() {
61 void EmergeManager::initMapgens(MapgenParams *mgparams) {
65 this->params = mgparams;
66 this->mapgen = getMapgen(); //only one mapgen for now!
70 Mapgen *EmergeManager::getMapgen() {
72 mapgen = createMapgen(params->mg_name, 0, params, this);
74 infostream << "EmergeManager: falling back to mapgen v6" << std::endl;
76 params = createMapgenParams("v6");
77 mapgen = createMapgen("v6", 0, params, this);
83 void EmergeManager::addBlockToQueue() {
88 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
91 return mapgen->getGroundLevelAtPoint(p);
95 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
97 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
98 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
99 int ground_level = getGroundLevelAtPoint(p);
100 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
103 //yuck, but then again, should i bother being accurate?
104 //the height of the nodes in a single block is quite variable
105 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level;
109 u32 EmergeManager::getBlockSeed(v3s16 p) {
110 return (u32)(params->seed & 0xFFFFFFFF) +
117 Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid,
118 MapgenParams *mgparams, EmergeManager *emerge) {
119 std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
120 if (iter == mglist.end()) {
121 errorstream << "EmergeManager; mapgen " << mgname <<
122 " not registered" << std::endl;
126 MapgenFactory *mgfactory = iter->second;
127 return mgfactory->createMapgen(mgid, mgparams, emerge);
131 MapgenParams *EmergeManager::createMapgenParams(std::string mgname) {
132 std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
133 if (iter == mglist.end()) {
134 errorstream << "EmergeManager: mapgen " << mgname <<
135 " not registered" << std::endl;
139 MapgenFactory *mgfactory = iter->second;
140 return mgfactory->createMapgenParams();
144 MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) {
145 std::string mg_name = settings->get("mg_name");
146 MapgenParams *mgparams = createMapgenParams(mg_name);
148 mgparams->mg_name = mg_name;
149 mgparams->seed = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
150 mgparams->water_level = settings->getS16("water_level");
151 mgparams->chunksize = settings->getS16("chunksize");
152 mgparams->flags = settings->getS32("mg_flags");
154 if (!mgparams->readParams(settings)) {
162 bool EmergeManager::registerMapgen(std::string mgname, MapgenFactory *mgfactory) {
163 mglist.insert(std::make_pair(mgname, mgfactory));
164 infostream << "EmergeManager: registered mapgen " << mgname << std::endl;
168 /////////////////////
170 bool MapgenV6Params::readParams(Settings *settings) {
171 freq_desert = settings->getFloat("mgv6_freq_desert");
172 freq_beach = settings->getFloat("mgv6_freq_beach");
174 np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
175 np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
176 np_steepness = settings->getNoiseParams("mgv6_np_steepness");
177 np_height_select = settings->getNoiseParams("mgv6_np_height_select");
178 np_trees = settings->getNoiseParams("mgv6_np_trees");
179 np_mud = settings->getNoiseParams("mgv6_np_mud");
180 np_beach = settings->getNoiseParams("mgv6_np_beach");
181 np_biome = settings->getNoiseParams("mgv6_np_biome");
182 np_cave = settings->getNoiseParams("mgv6_np_cave");
185 np_terrain_base && np_terrain_higher && np_steepness &&
186 np_height_select && np_trees && np_mud &&
187 np_beach && np_biome && np_cave;
192 void MapgenV6Params::writeParams(Settings *settings) {
193 settings->setFloat("mgv6_freq_desert", freq_desert);
194 settings->setFloat("mgv6_freq_beach", freq_beach);
196 settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base);
197 settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
198 settings->setNoiseParams("mgv6_np_steepness", np_steepness);
199 settings->setNoiseParams("mgv6_np_height_select", np_height_select);
200 settings->setNoiseParams("mgv6_np_trees", np_trees);
201 settings->setNoiseParams("mgv6_np_mud", np_mud);
202 settings->setNoiseParams("mgv6_np_beach", np_beach);
203 settings->setNoiseParams("mgv6_np_biome", np_biome);
204 settings->setNoiseParams("mgv6_np_cave", np_cave);
208 /////////////////////////////////// legacy static functions for farmesh
211 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
212 //just need to return something
218 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
219 double sandnoise = noise2d_perlin(
220 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
221 seed+59420, 3, 0.50);
223 return (sandnoise > 0.15);
227 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
228 double noise = noise2d_perlin(
229 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
231 double zeroval = -0.39;
235 return 0.04 * (noise-zeroval) / (1.0-zeroval);
239 #if 0 /// BIG COMMENT
244 Some helper functions for the map generator
248 // Returns Y one under area minimum if not found
249 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
250 INodeDefManager *ndef)
252 v3s16 em = vmanip.m_area.getExtent();
253 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
254 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
255 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
257 for(y=y_nodes_max; y>=y_nodes_min; y--)
259 MapNode &n = vmanip.m_data[i];
260 if(ndef->get(n).walkable)
263 vmanip.m_area.add_y(em, i, -1);
268 return y_nodes_min - 1;
272 // Returns Y one under area minimum if not found
273 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
274 INodeDefManager *ndef)
276 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
277 return vmanip.m_area.MinEdge.Y-1;
278 v3s16 em = vmanip.m_area.getExtent();
279 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
280 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
281 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
283 content_t c_tree = ndef->getId("mapgen_tree");
284 content_t c_leaves = ndef->getId("mapgen_leaves");
285 for(y=y_nodes_max; y>=y_nodes_min; y--)
287 MapNode &n = vmanip.m_data[i];
288 if(ndef->get(n).walkable
289 && n.getContent() != c_tree
290 && n.getContent() != c_leaves)
293 vmanip.m_area.add_y(em, i, -1);
298 return y_nodes_min - 1;
302 // Returns Y one under area minimum if not found
303 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
304 INodeDefManager *ndef)
306 v3s16 em = vmanip.m_area.getExtent();
307 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
308 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
309 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
311 content_t c_stone = ndef->getId("mapgen_stone");
312 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
313 for(y=y_nodes_max; y>=y_nodes_min; y--)
315 MapNode &n = vmanip.m_data[i];
316 content_t c = n.getContent();
317 if(c != CONTENT_IGNORE && (
318 c == c_stone || c == c_desert_stone))
321 vmanip.m_area.add_y(em, i, -1);
326 return y_nodes_min - 1;
333 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
334 INodeDefManager *ndef)
336 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
338 s16 trunk_h = myrand_range(2, 3);
340 for(s16 ii=0; ii<trunk_h; ii++)
342 if(vmanip.m_area.contains(p1))
343 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
348 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
349 INodeDefManager *ndef)
351 MapNode cactusnode(ndef->getId("mapgen_cactus"));
355 for(s16 ii=0; ii<trunk_h; ii++)
357 if(vmanip.m_area.contains(p1))
358 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
366 Dungeon making routines
369 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
370 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
371 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
372 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
374 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
375 INodeDefManager *ndef)
378 for(s16 z=0; z<roomsize.Z; z++)
379 for(s16 y=0; y<roomsize.Y; y++)
382 v3s16 p = roomplace + v3s16(0,y,z);
383 if(vmanip.m_area.contains(p) == false)
385 u32 vi = vmanip.m_area.index(p);
386 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
388 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
391 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
392 if(vmanip.m_area.contains(p) == false)
394 u32 vi = vmanip.m_area.index(p);
395 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
397 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
402 for(s16 x=0; x<roomsize.X; x++)
403 for(s16 y=0; y<roomsize.Y; y++)
406 v3s16 p = roomplace + v3s16(x,y,0);
407 if(vmanip.m_area.contains(p) == false)
409 u32 vi = vmanip.m_area.index(p);
410 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
412 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
415 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
416 if(vmanip.m_area.contains(p) == false)
418 u32 vi = vmanip.m_area.index(p);
419 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
421 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
425 // Make +-Y walls (floor and ceiling)
426 for(s16 z=0; z<roomsize.Z; z++)
427 for(s16 x=0; x<roomsize.X; x++)
430 v3s16 p = roomplace + v3s16(x,0,z);
431 if(vmanip.m_area.contains(p) == false)
433 u32 vi = vmanip.m_area.index(p);
434 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
436 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
439 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
440 if(vmanip.m_area.contains(p) == false)
442 u32 vi = vmanip.m_area.index(p);
443 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
445 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
450 for(s16 z=1; z<roomsize.Z-1; z++)
451 for(s16 y=1; y<roomsize.Y-1; y++)
452 for(s16 x=1; x<roomsize.X-1; x++)
454 v3s16 p = roomplace + v3s16(x,y,z);
455 if(vmanip.m_area.contains(p) == false)
457 u32 vi = vmanip.m_area.index(p);
458 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
459 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
463 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
464 u8 avoid_flags, MapNode n, u8 or_flags)
466 for(s16 z=0; z<size.Z; z++)
467 for(s16 y=0; y<size.Y; y++)
468 for(s16 x=0; x<size.X; x++)
470 v3s16 p = place + v3s16(x,y,z);
471 if(vmanip.m_area.contains(p) == false)
473 u32 vi = vmanip.m_area.index(p);
474 if(vmanip.m_flags[vi] & avoid_flags)
476 vmanip.m_flags[vi] |= or_flags;
477 vmanip.m_data[vi] = n;
481 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
482 INodeDefManager *ndef)
484 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
485 VMANIP_FLAG_DUNGEON_INSIDE);
488 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
489 INodeDefManager *ndef)
491 make_hole1(vmanip, doorplace, ndef);
492 // Place torch (for testing)
493 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
496 static v3s16 rand_ortho_dir(PseudoRandom &random)
498 if(random.next()%2==0)
499 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
501 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
504 static v3s16 turn_xz(v3s16 olddir, int t)
524 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
526 int turn = random.range(0,2);
535 dir = turn_xz(olddir, 0);
538 dir = turn_xz(olddir, 1);
542 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
543 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
544 PseudoRandom &random, INodeDefManager *ndef)
546 make_hole1(vmanip, doorplace, ndef);
547 v3s16 p0 = doorplace;
551 length = random.range(1,13);
553 length = random.range(1,6);
554 length = random.range(1,13);
555 u32 partlength = random.range(1,13);
558 if(random.next()%2 == 0 && partlength >= 3)
559 make_stairs = random.next()%2 ? 1 : -1;
560 for(u32 i=0; i<length; i++)
566 /*// If already empty
567 if(vmanip.getNodeNoExNoEmerge(p).getContent()
569 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
574 if(vmanip.m_area.contains(p) == true
575 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
579 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
580 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
581 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
582 VMANIP_FLAG_DUNGEON_INSIDE);
583 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
584 VMANIP_FLAG_DUNGEON_INSIDE);
588 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
589 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
590 make_hole1(vmanip, p, ndef);
591 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
592 VMANIP_FLAG_DUNGEON_INSIDE);*/
599 // Can't go here, turn away
600 dir = turn_xz(dir, random.range(0,1));
601 make_stairs = -make_stairs;
603 partlength = random.range(1,length);
608 if(partcount >= partlength)
612 dir = random_turn(random, dir);
614 partlength = random.range(1,length);
617 if(random.next()%2 == 0 && partlength >= 3)
618 make_stairs = random.next()%2 ? 1 : -1;
629 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
630 INodeDefManager *ndef):
641 m_dir = rand_ortho_dir(m_random);
644 void setPos(v3s16 pos)
649 void setDir(v3s16 dir)
654 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
656 for(u32 i=0; i<100; i++)
658 v3s16 p = m_pos + m_dir;
659 v3s16 p1 = p + v3s16(0,1,0);
660 if(vmanip.m_area.contains(p) == false
661 || vmanip.m_area.contains(p1) == false
667 if(vmanip.getNodeNoExNoEmerge(p).getContent()
668 == m_ndef->getId("mapgen_cobble")
669 && vmanip.getNodeNoExNoEmerge(p1).getContent()
670 == m_ndef->getId("mapgen_cobble"))
672 // Found wall, this is a good place!
675 // Randomize next direction
680 Determine where to move next
682 // Jump one up if the actual space is there
683 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
684 == m_ndef->getId("mapgen_cobble")
685 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
687 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
690 // Jump one down if the actual space is there
691 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
692 == m_ndef->getId("mapgen_cobble")
693 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
695 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
698 // Check if walking is now possible
699 if(vmanip.getNodeNoExNoEmerge(p).getContent()
701 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
704 // Cannot continue walking here
714 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
715 v3s16 &result_doordir, v3s16 &result_roomplace)
717 for(s16 trycount=0; trycount<30; trycount++)
721 bool r = findPlaceForDoor(doorplace, doordir);
725 // X east, Z north, Y up
727 if(doordir == v3s16(1,0,0)) // X+
728 roomplace = doorplace +
729 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
730 if(doordir == v3s16(-1,0,0)) // X-
731 roomplace = doorplace +
732 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
733 if(doordir == v3s16(0,0,1)) // Z+
734 roomplace = doorplace +
735 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
736 if(doordir == v3s16(0,0,-1)) // Z-
737 roomplace = doorplace +
738 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
741 if(doordir == v3s16(1,0,0)) // X+
742 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
743 if(doordir == v3s16(-1,0,0)) // X-
744 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
745 if(doordir == v3s16(0,0,1)) // Z+
746 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
747 if(doordir == v3s16(0,0,-1)) // Z-
748 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
753 for(s16 z=1; z<roomsize.Z-1; z++)
754 for(s16 y=1; y<roomsize.Y-1; y++)
755 for(s16 x=1; x<roomsize.X-1; x++)
757 v3s16 p = roomplace + v3s16(x,y,z);
758 if(vmanip.m_area.contains(p) == false)
763 if(vmanip.m_flags[vmanip.m_area.index(p)]
764 & VMANIP_FLAG_DUNGEON_INSIDE)
775 result_doorplace = doorplace;
776 result_doordir = doordir;
777 result_roomplace = roomplace;
784 VoxelManipulator &vmanip;
787 PseudoRandom &m_random;
788 INodeDefManager *m_ndef;
791 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
792 INodeDefManager *ndef)
794 v3s16 areasize = vmanip.m_area.getExtent();
799 Find place for first room
802 for(u32 i=0; i<100; i++)
804 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
805 roomplace = vmanip.m_area.MinEdge + v3s16(
806 random.range(0,areasize.X-roomsize.X-1),
807 random.range(0,areasize.Y-roomsize.Y-1),
808 random.range(0,areasize.Z-roomsize.Z-1));
810 Check that we're not putting the room to an unknown place,
811 otherwise it might end up floating in the air
814 for(s16 z=1; z<roomsize.Z-1; z++)
815 for(s16 y=1; y<roomsize.Y-1; y++)
816 for(s16 x=1; x<roomsize.X-1; x++)
818 v3s16 p = roomplace + v3s16(x,y,z);
819 u32 vi = vmanip.m_area.index(p);
820 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
825 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
839 Stores the center position of the last room made, so that
840 a new corridor can be started from the last room instead of
841 the new room, if chosen so.
843 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
845 u32 room_count = random.range(2,7);
846 for(u32 i=0; i<room_count; i++)
848 // Make a room to the determined place
849 make_room1(vmanip, roomsize, roomplace, ndef);
851 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
853 // Place torch at room center (for testing)
854 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
857 if(i == room_count-1)
860 // Determine walker start position
862 bool start_in_last_room = (random.range(0,2)!=0);
863 //bool start_in_last_room = true;
865 v3s16 walker_start_place;
867 if(start_in_last_room)
869 walker_start_place = last_room_center;
873 walker_start_place = room_center;
874 // Store center of current room as the last one
875 last_room_center = room_center;
878 // Create walker and find a place for a door
879 RoomWalker walker(vmanip, walker_start_place, random, ndef);
882 bool r = walker.findPlaceForDoor(doorplace, doordir);
886 if(random.range(0,1)==0)
888 make_door1(vmanip, doorplace, doordir, ndef);
890 // Don't actually make a door
891 doorplace -= doordir;
893 // Make a random corridor starting from the door
895 v3s16 corridor_end_dir;
896 make_corridor(vmanip, doorplace, doordir, corridor_end,
897 corridor_end_dir, random, ndef);
899 // Find a place for a random sized room
900 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
901 walker.setPos(corridor_end);
902 walker.setDir(corridor_end_dir);
903 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
907 if(random.range(0,1)==0)
909 make_door1(vmanip, doorplace, doordir, ndef);
911 // Don't actually make a door
912 roomplace -= doordir;
919 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
920 INodeDefManager *ndef)
924 s32 r = random.range(0, 3);
926 dir = v3s16( 1, 0, 0);
930 dir = v3s16(-1, 0, 0);
934 dir = v3s16( 0, 0, 1);
938 dir = v3s16( 0, 0,-1);
941 v3s16 p = vmanip.m_area.MinEdge + v3s16(
942 16+random.range(0,15),
943 16+random.range(0,15),
944 16+random.range(0,15));
945 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
946 u32 length = random.range(3,15);
947 for(u32 j=0; j<length; j++)
950 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
956 Noise functions. Make sure seed is mangled differently in each one.
961 Scaling the output of the noise function affects the overdrive of the
962 contour function, which affects the shape of the output considerably.
964 #define CAVE_NOISE_SCALE 12.0
965 //#define CAVE_NOISE_SCALE 10.0
966 //#define CAVE_NOISE_SCALE 7.5
967 //#define CAVE_NOISE_SCALE 5.0
968 //#define CAVE_NOISE_SCALE 1.0
970 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
971 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
973 NoiseParams get_cave_noise1_params(u64 seed)
975 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
976 200, CAVE_NOISE_SCALE);*/
977 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
978 100, CAVE_NOISE_SCALE);*/
979 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
980 100, CAVE_NOISE_SCALE);*/
981 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
982 100, CAVE_NOISE_SCALE);*/
983 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
984 50, CAVE_NOISE_SCALE);
985 //return NoiseParams(NOISE_CONSTANT_ONE);
988 NoiseParams get_cave_noise2_params(u64 seed)
990 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
991 200, CAVE_NOISE_SCALE);*/
992 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
993 100, CAVE_NOISE_SCALE);*/
994 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
995 100, CAVE_NOISE_SCALE);*/
996 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
997 50, CAVE_NOISE_SCALE);
998 //return NoiseParams(NOISE_CONSTANT_ONE);
1001 NoiseParams get_ground_noise1_params(u64 seed)
1003 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1007 NoiseParams get_ground_crumbleness_params(u64 seed)
1009 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1013 NoiseParams get_ground_wetness_params(u64 seed)
1015 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1019 bool is_cave(u64 seed, v3s16 p)
1021 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1022 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1023 return d1*d2 > CAVE_NOISE_THRESHOLD;
1027 Ground density noise shall be interpreted by using this.
1029 TODO: No perlin noises here, they should be outsourced
1031 NOTE: The speed of these actually isn't terrible
1033 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1035 //return ((double)p.Y < ground_noise1_val);
1037 double f = 0.55 + noise2d_perlin(
1038 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1039 seed+920381, 3, 0.45);
1044 double h = WATER_LEVEL + 10 * noise2d_perlin(
1045 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1046 seed+84174, 4, 0.5);
1049 return ((double)p.Y - h < ground_noise1_val * f);
1053 Queries whether a position is ground or not.
1055 bool is_ground(u64 seed, v3s16 p)
1057 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1058 return val_is_ground(val1, p, seed);
1062 // Amount of trees per area in nodes
1063 double tree_amount_2d(u64 seed, v2s16 p)
1065 /*double noise = noise2d_perlin(
1066 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1068 double noise = noise2d_perlin(
1069 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1071 double zeroval = -0.39;
1075 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1079 double surface_humidity_2d(u64 seed, v2s16 p)
1081 double noise = noise2d_perlin(
1082 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1083 seed+72384, 4, 0.66);
1084 noise = (noise + 1.0)/2.0;
1093 Incrementally find ground level from 3d noise
1095 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1097 // Start a bit fuzzy to make averaging lower precision values
1099 s16 level = myrand_range(-precision/2, precision/2);
1100 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1102 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1104 // First find non-ground by going upwards
1105 // Don't stop in caves.
1107 s16 max = level+dec[i-1]*2;
1108 v3s16 p(p2d.X, level, p2d.Y);
1109 for(; p.Y < max; p.Y += dec[i])
1111 if(!is_ground(seed, p))
1118 // Then find ground by going downwards from there.
1119 // Go in caves, too, when precision is 1.
1121 s16 min = level-dec[i-1]*2;
1122 v3s16 p(p2d.X, level, p2d.Y);
1123 for(; p.Y>min; p.Y-=dec[i])
1125 bool ground = is_ground(seed, p);
1126 /*if(dec[i] == 1 && is_cave(seed, p))
1137 // This is more like the actual ground level
1138 level += dec[i-1]/2;
1143 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1145 double get_sector_average_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);
1150 a += find_ground_level_from_noise(seed,
1151 v2s16(node_min.X, node_min.Y), p);
1152 a += find_ground_level_from_noise(seed,
1153 v2s16(node_min.X, node_max.Y), p);
1154 a += find_ground_level_from_noise(seed,
1155 v2s16(node_max.X, node_max.Y), p);
1156 a += find_ground_level_from_noise(seed,
1157 v2s16(node_max.X, node_min.Y), p);
1158 a += find_ground_level_from_noise(seed,
1159 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1164 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1166 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1168 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1169 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1172 a = MYMAX(a, find_ground_level_from_noise(seed,
1173 v2s16(node_min.X, node_min.Y), p));
1174 a = MYMAX(a, find_ground_level_from_noise(seed,
1175 v2s16(node_min.X, node_max.Y), p));
1176 a = MYMAX(a, find_ground_level_from_noise(seed,
1177 v2s16(node_max.X, node_max.Y), p));
1178 a = MYMAX(a, find_ground_level_from_noise(seed,
1179 v2s16(node_min.X, node_min.Y), p));
1181 a = MYMAX(a, find_ground_level_from_noise(seed,
1182 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1183 // Side middle points
1184 a = MYMAX(a, find_ground_level_from_noise(seed,
1185 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1186 a = MYMAX(a, find_ground_level_from_noise(seed,
1187 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1188 a = MYMAX(a, find_ground_level_from_noise(seed,
1189 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1190 a = MYMAX(a, find_ground_level_from_noise(seed,
1191 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1195 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1197 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1199 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1200 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1203 a = MYMIN(a, find_ground_level_from_noise(seed,
1204 v2s16(node_min.X, node_min.Y), p));
1205 a = MYMIN(a, find_ground_level_from_noise(seed,
1206 v2s16(node_min.X, node_max.Y), p));
1207 a = MYMIN(a, find_ground_level_from_noise(seed,
1208 v2s16(node_max.X, node_max.Y), p));
1209 a = MYMIN(a, find_ground_level_from_noise(seed,
1210 v2s16(node_min.X, node_min.Y), p));
1212 a = MYMIN(a, find_ground_level_from_noise(seed,
1213 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1214 // Side middle points
1215 a = MYMIN(a, find_ground_level_from_noise(seed,
1216 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1217 a = MYMIN(a, find_ground_level_from_noise(seed,
1218 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1219 a = MYMIN(a, find_ground_level_from_noise(seed,
1220 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1221 a = MYMIN(a, find_ground_level_from_noise(seed,
1222 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1227 // Required by mapgen.h
1228 bool block_is_underground(u64 seed, v3s16 blockpos)
1230 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1231 seed, v2s16(blockpos.X, blockpos.Z));*/
1232 // Nah, this is just a heuristic, just return something
1233 s16 minimum_groundlevel = WATER_LEVEL;
1235 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1241 #define AVERAGE_MUD_AMOUNT 4
1243 double base_rock_level_2d(u64 seed, v2s16 p)
1245 // The base ground level
1246 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1247 + 20. * noise2d_perlin(
1248 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1249 seed+82341, 5, 0.6);
1251 /*// A bit hillier one
1252 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1253 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1254 seed+93413, 6, 0.69);
1258 // Higher ground level
1259 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1260 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1261 seed+85039, 5, 0.6);
1262 //higher = 30; // For debugging
1264 // Limit higher to at least base
1268 // Steepness factor of cliffs
1269 double b = 0.85 + 0.5 * noise2d_perlin(
1270 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1272 b = rangelim(b, 0.0, 1000.0);
1275 b = rangelim(b, 0.5, 1000.0);
1276 // Values 1.5...100 give quite horrible looking slopes
1277 if(b > 1.5 && b < 100.0){
1283 //dstream<<"b="<<b<<std::endl;
1287 // Offset to more low
1288 double a_off = -0.20;
1289 // High/low selector
1290 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1291 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1292 seed+4213, 6, 0.7));*/
1293 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1294 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1295 seed+4213, 5, 0.69));
1297 a = rangelim(a, 0.0, 1.0);
1299 //dstream<<"a="<<a<<std::endl;
1301 double h = base*(1.0-a) + higher*a;
1308 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1310 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1313 double get_mud_add_amount(u64 seed, v2s16 p)
1315 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1316 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1317 seed+91013, 3, 0.55));
1320 bool get_have_beach(u64 seed, v2s16 p2d)
1322 // Determine whether to have sand here
1323 double sandnoise = noise2d_perlin(
1324 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1325 seed+59420, 3, 0.50);
1327 return (sandnoise > 0.15);
1336 BiomeType get_biome(u64 seed, v2s16 p2d)
1338 // Just do something very simple as for now
1339 double d = noise2d_perlin(
1340 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1341 seed+9130, 3, 0.50);
1344 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1349 u32 get_blockseed(u64 seed, v3s16 p)
1351 s32 x=p.X, y=p.Y, z=p.Z;
1352 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1355 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1357 void make_block(BlockMakeData *data)
1361 //dstream<<"makeBlock: no-op"<<std::endl;
1365 assert(data->vmanip);
1366 assert(data->nodedef);
1367 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1368 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1369 data->blockpos_requested.Z >= data->blockpos_min.Z);
1370 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1371 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1372 data->blockpos_requested.Z <= data->blockpos_max.Z);
1374 INodeDefManager *ndef = data->nodedef;
1376 // Hack: use minimum block coordinates for old code that assumes
1378 v3s16 blockpos = data->blockpos_requested;
1380 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1381 <<blockpos.Z<<")"<<std::endl;*/
1383 v3s16 blockpos_min = data->blockpos_min;
1384 v3s16 blockpos_max = data->blockpos_max;
1385 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1386 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1388 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1389 // Area of central chunk
1390 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1391 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1392 // Full allocated area
1393 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1394 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1396 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1398 const s16 max_spread_amount = MAP_BLOCKSIZE;
1400 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1401 * (blockpos_max.Y - blockpos_min.Y + 1)
1402 * (blockpos_max.Z - blockpos_max.Z + 1);
1404 int volume_nodes = volume_blocks *
1405 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1407 // Generated surface area
1408 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1410 // Horribly wrong heuristic, but better than nothing
1411 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1414 Create a block-specific seed
1416 u32 blockseed = get_blockseed(data->seed, full_node_min);
1419 Cache some ground type values for speed
1422 // Creates variables c_name=id and n_name=node
1423 #define CONTENT_VARIABLE(ndef, name)\
1424 content_t c_##name = ndef->getId("mapgen_" #name);\
1425 MapNode n_##name(c_##name);
1426 // Default to something else if was CONTENT_IGNORE
1427 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1428 if(c_##name == CONTENT_IGNORE){\
1429 c_##name = c_##dname;\
1430 n_##name = n_##dname;\
1433 CONTENT_VARIABLE(ndef, stone);
1434 CONTENT_VARIABLE(ndef, air);
1435 CONTENT_VARIABLE(ndef, water_source);
1436 CONTENT_VARIABLE(ndef, dirt);
1437 CONTENT_VARIABLE(ndef, sand);
1438 CONTENT_VARIABLE(ndef, gravel);
1439 CONTENT_VARIABLE(ndef, clay);
1440 CONTENT_VARIABLE(ndef, lava_source);
1441 CONTENT_VARIABLE(ndef, cobble);
1442 CONTENT_VARIABLE(ndef, mossycobble);
1443 CONTENT_VARIABLE(ndef, dirt_with_grass);
1444 CONTENT_VARIABLE(ndef, junglegrass);
1445 CONTENT_VARIABLE(ndef, stone_with_coal);
1446 CONTENT_VARIABLE(ndef, stone_with_iron);
1447 CONTENT_VARIABLE(ndef, mese);
1448 CONTENT_VARIABLE(ndef, desert_sand);
1449 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1450 CONTENT_VARIABLE(ndef, desert_stone);
1451 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1453 // Maximum height of the stone surface and obstacles.
1454 // This is used to guide the cave generation
1455 s16 stone_surface_max_y = 0;
1458 Generate general ground level to full area
1462 TimeTaker timer1("Generating ground level");
1464 for(s16 x=node_min.X; x<=node_max.X; x++)
1465 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1468 v2s16 p2d = v2s16(x,z);
1471 Skip of already generated
1474 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1475 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1479 // Ground height at this point
1480 float surface_y_f = 0.0;
1482 // Use perlin noise for ground height
1483 surface_y_f = base_rock_level_2d(data->seed, p2d);
1485 /*// Experimental stuff
1487 float a = highlands_level_2d(data->seed, p2d);
1492 // Convert to integer
1493 s16 surface_y = (s16)surface_y_f;
1496 if(surface_y > stone_surface_max_y)
1497 stone_surface_max_y = surface_y;
1499 BiomeType bt = get_biome(data->seed, p2d);
1501 Fill ground with stone
1504 // Use fast index incrementing
1505 v3s16 em = vmanip.m_area.getExtent();
1506 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1507 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1509 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1511 if(y > WATER_LEVEL && bt == BT_DESERT)
1512 vmanip.m_data[i] = n_desert_stone;
1514 vmanip.m_data[i] = n_stone;
1515 } else if(y <= WATER_LEVEL){
1516 vmanip.m_data[i] = MapNode(c_water_source);
1518 vmanip.m_data[i] = MapNode(c_air);
1521 vmanip.m_area.add_y(em, i, 1);
1529 // Limit dirt flow area by 1 because mud is flown into neighbors.
1530 assert(central_area_size.X == central_area_size.Z);
1531 s16 mudflow_minpos = 0-max_spread_amount+1;
1532 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1535 Loop this part, it will make stuff look older and newer nicely
1538 const u32 age_loops = 2;
1539 for(u32 i_age=0; i_age<age_loops; i_age++)
1541 /******************************
1542 BEGINNING OF AGING LOOP
1543 ******************************/
1548 //TimeTaker timer1("caves");
1551 Make caves (this code is relatively horrible)
1553 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1554 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1555 data->seed+34329, 3, 0.50);
1556 cave_amount = MYMAX(0.0, cave_amount);
1557 u32 caves_count = cave_amount * volume_nodes / 50000;
1558 u32 bruises_count = 1;
1559 PseudoRandom ps(blockseed+21343);
1560 PseudoRandom ps2(blockseed+1032);
1561 if(ps.range(1, 6) == 1)
1562 bruises_count = ps.range(0, ps.range(0, 2));
1563 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1567 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1569 bool large_cave = (jj >= caves_count);
1570 s16 min_tunnel_diameter = 2;
1571 s16 max_tunnel_diameter = ps.range(2,6);
1572 int dswitchint = ps.range(1,14);
1573 u16 tunnel_routepoints = 0;
1574 int part_max_length_rs = 0;
1576 part_max_length_rs = ps.range(2,4);
1577 tunnel_routepoints = ps.range(5, ps.range(15,30));
1578 min_tunnel_diameter = 5;
1579 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1581 part_max_length_rs = ps.range(2,9);
1582 tunnel_routepoints = ps.range(10, ps.range(15,30));
1584 bool large_cave_is_flat = (ps.range(0,1) == 0);
1586 v3f main_direction(0,0,0);
1588 // Allowed route area size in nodes
1589 v3s16 ar = central_area_size;
1591 // Area starting point in nodes
1592 v3s16 of = node_min;
1595 //(this should be more than the maximum radius of the tunnel)
1596 //s16 insure = 5; // Didn't work with max_d = 20
1598 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1599 ar += v3s16(1,0,1) * more * 2;
1600 of -= v3s16(1,0,1) * more;
1602 s16 route_y_min = 0;
1603 // Allow half a diameter + 7 over stone surface
1604 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1606 /*// If caves, don't go through surface too often
1607 if(large_cave == false)
1608 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1610 // Limit maximum to area
1611 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1615 /*// Minimum is at y=0
1616 route_y_min = -of.Y - 0;*/
1617 // Minimum is at y=max_tunnel_diameter/4
1618 //route_y_min = -of.Y + max_tunnel_diameter/4;
1619 //s16 min = -of.Y + max_tunnel_diameter/4;
1620 //s16 min = -of.Y + 0;
1622 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1624 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1625 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1627 route_y_min = ps.range(min, min + max_tunnel_diameter);
1628 route_y_min = rangelim(route_y_min, 0, route_y_max);
1631 /*dstream<<"route_y_min = "<<route_y_min
1632 <<", route_y_max = "<<route_y_max<<std::endl;*/
1634 s16 route_start_y_min = route_y_min;
1635 s16 route_start_y_max = route_y_max;
1637 // Start every 4th cave from surface when applicable
1638 /*bool coming_from_surface = false;
1639 if(node_min.Y <= 0 && node_max.Y >= 0){
1640 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1641 if(coming_from_surface)
1642 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1645 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1646 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1648 // Randomize starting position
1650 (float)(ps.next()%ar.X)+0.5,
1651 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1652 (float)(ps.next()%ar.Z)+0.5
1655 v3s16 startp(orp.X, orp.Y, orp.Z);
1658 MapNode airnode(CONTENT_AIR);
1659 MapNode waternode(c_water_source);
1660 MapNode lavanode(c_lava_source);
1663 Generate some tunnel starting from orp
1666 for(u16 j=0; j<tunnel_routepoints; j++)
1668 if(j%dswitchint==0 && large_cave == false)
1670 main_direction = v3f(
1671 ((float)(ps.next()%20)-(float)10)/10,
1672 ((float)(ps.next()%20)-(float)10)/30,
1673 ((float)(ps.next()%20)-(float)10)/10
1675 main_direction *= (float)ps.range(0, 10)/10;
1679 s16 min_d = min_tunnel_diameter;
1680 s16 max_d = max_tunnel_diameter;
1681 s16 rs = ps.range(min_d, max_d);
1683 // Every second section is rough
1684 bool randomize_xz = (ps2.range(1,2) == 1);
1690 rs*part_max_length_rs,
1691 rs*part_max_length_rs/2,
1692 rs*part_max_length_rs
1698 rs*part_max_length_rs,
1699 ps.range(1, rs*part_max_length_rs),
1700 rs*part_max_length_rs
1707 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1708 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1709 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1712 // Jump downward sometimes
1713 if(!large_cave && ps.range(0,12) == 0)
1716 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1717 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1718 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1724 s16 h = find_ground_level_clever(vmanip,
1725 v2s16(p.X, p.Z), ndef);
1726 route_y_min = h - rs/3;
1727 route_y_max = h + rs;
1730 vec += main_direction;
1735 else if(rp.X >= ar.X)
1737 if(rp.Y < route_y_min)
1739 else if(rp.Y >= route_y_max)
1740 rp.Y = route_y_max-1;
1743 else if(rp.Z >= ar.Z)
1747 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1749 v3f fp = orp + vec * f;
1750 fp.X += 0.1*ps.range(-10,10);
1751 fp.Z += 0.1*ps.range(-10,10);
1752 v3s16 cp(fp.X, fp.Y, fp.Z);
1757 d0 += ps.range(-1,1);
1758 d1 += ps.range(-1,1);
1760 for(s16 z0=d0; z0<=d1; z0++)
1762 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1763 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1765 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1766 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1767 for(s16 y0=-si2; y0<=si2; y0++)
1769 /*// Make better floors in small caves
1770 if(y0 <= -rs/2 && rs<=7)
1772 if(large_cave_is_flat){
1773 // Make large caves not so tall
1774 if(rs > 7 && abs(y0) >= rs/3)
1784 if(vmanip.m_area.contains(p) == false)
1787 u32 i = vmanip.m_area.index(p);
1791 if(full_node_min.Y < WATER_LEVEL &&
1792 full_node_max.Y > WATER_LEVEL){
1793 if(p.Y <= WATER_LEVEL)
1794 vmanip.m_data[i] = waternode;
1796 vmanip.m_data[i] = airnode;
1797 } else if(full_node_max.Y < WATER_LEVEL){
1798 if(p.Y < startp.Y - 2)
1799 vmanip.m_data[i] = lavanode;
1801 vmanip.m_data[i] = airnode;
1803 vmanip.m_data[i] = airnode;
1806 // Don't replace air or water or lava or ignore
1807 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1808 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1809 vmanip.m_data[i].getContent() == c_water_source ||
1810 vmanip.m_data[i].getContent() == c_lava_source)
1813 vmanip.m_data[i] = airnode;
1816 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1834 TimeTaker timer1("add mud");
1837 Add mud to the central chunk
1840 for(s16 x=node_min.X; x<=node_max.X; x++)
1841 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1843 // Node position in 2d
1844 v2s16 p2d = v2s16(x,z);
1846 // Randomize mud amount
1847 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1849 // Find ground level
1850 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1851 // Handle area not found
1852 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1855 MapNode addnode(c_dirt);
1856 BiomeType bt = get_biome(data->seed, p2d);
1859 addnode = MapNode(c_desert_sand);
1861 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1862 addnode = MapNode(c_sand);
1863 } else if(mud_add_amount <= 0){
1864 mud_add_amount = 1 - mud_add_amount;
1865 addnode = MapNode(c_gravel);
1866 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1867 surface_y + mud_add_amount <= WATER_LEVEL+2){
1868 addnode = MapNode(c_sand);
1871 if(bt == BT_DESERT){
1873 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1878 If topmost node is grass, change it to mud.
1879 It might be if it was flown to there from a neighboring
1880 chunk and then converted.
1883 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1884 MapNode *n = &vmanip.m_data[i];
1885 if(n->getContent() == c_dirt_with_grass)
1886 *n = MapNode(c_dirt);
1894 v3s16 em = vmanip.m_area.getExtent();
1895 s16 y_start = surface_y+1;
1896 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1897 for(s16 y=y_start; y<=node_max.Y; y++)
1899 if(mudcount >= mud_add_amount)
1902 MapNode &n = vmanip.m_data[i];
1906 vmanip.m_area.add_y(em, i, 1);
1916 Add blobs of dirt and gravel underground
1918 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1920 PseudoRandom pr(blockseed+983);
1921 for(int i=0; i<volume_nodes/10/10/10; i++)
1923 bool only_fill_cave = (myrand_range(0,1) != 0);
1930 pr.range(node_min.X, node_max.X)-size.X/2,
1931 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1932 pr.range(node_min.Z, node_max.Z)-size.Z/2
1935 if(p0.Y > -32 && pr.range(0,1) == 0)
1936 n1 = MapNode(c_dirt);
1938 n1 = MapNode(c_gravel);
1939 for(int x1=0; x1<size.X; x1++)
1940 for(int y1=0; y1<size.Y; y1++)
1941 for(int z1=0; z1<size.Z; z1++)
1943 v3s16 p = p0 + v3s16(x1,y1,z1);
1944 u32 i = vmanip.m_area.index(p);
1945 if(!vmanip.m_area.contains(i))
1947 // Cancel if not stone and not cave air
1948 if(vmanip.m_data[i].getContent() != c_stone &&
1949 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1951 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1953 vmanip.m_data[i] = n1;
1961 TimeTaker timer1("flow mud");
1964 Flow mud away from steep edges
1967 // Iterate a few times
1968 for(s16 k=0; k<3; k++)
1971 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1972 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1974 // Invert coordinates every 2nd iteration
1977 x = mudflow_maxpos - (x-mudflow_minpos);
1978 z = mudflow_maxpos - (z-mudflow_minpos);
1981 // Node position in 2d
1982 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1984 v3s16 em = vmanip.m_area.getExtent();
1985 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1988 while(y >= node_min.Y)
1995 for(; y>=node_min.Y; y--)
1997 n = &vmanip.m_data[i];
1998 //if(content_walkable(n->d))
2000 if(n->getContent() == c_dirt ||
2001 n->getContent() == c_dirt_with_grass ||
2002 n->getContent() == c_gravel)
2005 vmanip.m_area.add_y(em, i, -1);
2008 // Stop if out of area
2009 //if(vmanip.m_area.contains(i) == false)
2013 /*// If not mud, do nothing to it
2014 MapNode *n = &vmanip.m_data[i];
2015 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2018 if(n->getContent() == c_dirt ||
2019 n->getContent() == c_dirt_with_grass)
2021 // Make it exactly mud
2022 n->setContent(c_dirt);
2025 Don't flow it if the stuff under it is not mud
2029 vmanip.m_area.add_y(em, i2, -1);
2030 // Cancel if out of area
2031 if(vmanip.m_area.contains(i2) == false)
2033 MapNode *n2 = &vmanip.m_data[i2];
2034 if(n2->getContent() != c_dirt &&
2035 n2->getContent() != c_dirt_with_grass)
2040 /*s16 recurse_count = 0;
2044 v3s16(0,0,1), // back
2045 v3s16(1,0,0), // right
2046 v3s16(0,0,-1), // front
2047 v3s16(-1,0,0), // left
2050 // Theck that upper is air or doesn't exist.
2051 // Cancel dropping if upper keeps it in place
2053 vmanip.m_area.add_y(em, i3, 1);
2054 if(vmanip.m_area.contains(i3) == true
2055 && ndef->get(vmanip.m_data[i3]).walkable)
2062 for(u32 di=0; di<4; di++)
2064 v3s16 dirp = dirs4[di];
2067 vmanip.m_area.add_p(em, i2, dirp);
2068 // Fail if out of area
2069 if(vmanip.m_area.contains(i2) == false)
2071 // Check that side is air
2072 MapNode *n2 = &vmanip.m_data[i2];
2073 if(ndef->get(*n2).walkable)
2075 // Check that under side is air
2076 vmanip.m_area.add_y(em, i2, -1);
2077 if(vmanip.m_area.contains(i2) == false)
2079 n2 = &vmanip.m_data[i2];
2080 if(ndef->get(*n2).walkable)
2082 /*// Check that under that is air (need a drop of 2)
2083 vmanip.m_area.add_y(em, i2, -1);
2084 if(vmanip.m_area.contains(i2) == false)
2086 n2 = &vmanip.m_data[i2];
2087 if(content_walkable(n2->d))
2089 // Loop further down until not air
2090 bool dropped_to_unknown = false;
2092 vmanip.m_area.add_y(em, i2, -1);
2093 n2 = &vmanip.m_data[i2];
2094 // if out of known area
2095 if(vmanip.m_area.contains(i2) == false
2096 || n2->getContent() == CONTENT_IGNORE){
2097 dropped_to_unknown = true;
2100 }while(ndef->get(*n2).walkable == false);
2101 // Loop one up so that we're in air
2102 vmanip.m_area.add_y(em, i2, 1);
2103 n2 = &vmanip.m_data[i2];
2105 bool old_is_water = (n->getContent() == c_water_source);
2106 // Move mud to new place
2107 if(!dropped_to_unknown) {
2109 // Set old place to be air (or water)
2111 *n = MapNode(c_water_source);
2113 *n = MapNode(CONTENT_AIR);
2129 /***********************
2131 ************************/
2134 Add top and bottom side of water to transforming_liquid queue
2137 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2138 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2143 bool water_found = false;
2144 // Use fast index incrementing
2145 v3s16 em = vmanip.m_area.getExtent();
2146 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2147 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2149 if(y == full_node_max.Y){
2151 (vmanip.m_data[i].getContent() == c_water_source ||
2152 vmanip.m_data[i].getContent() == c_lava_source);
2154 else if(water_found == false)
2156 if(vmanip.m_data[i].getContent() == c_water_source ||
2157 vmanip.m_data[i].getContent() == c_lava_source)
2159 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2160 data->transforming_liquid.push_back(p);
2166 // This can be done because water_found can only
2167 // turn to true and end up here after going through
2169 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2170 vmanip.m_data[i+1].getContent() != c_lava_source)
2172 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2173 data->transforming_liquid.push_back(p);
2174 water_found = false;
2178 vmanip.m_area.add_y(em, i, -1);
2187 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2188 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2190 // Node position in 2d
2191 v2s16 p2d = v2s16(x,z);
2194 Find the lowest surface to which enough light ends up
2197 Basically just wait until not air and not leaves.
2201 v3s16 em = vmanip.m_area.getExtent();
2202 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2204 // Go to ground level
2205 for(y=node_max.Y; y>=full_node_min.Y; y--)
2207 MapNode &n = vmanip.m_data[i];
2208 if(ndef->get(n).param_type != CPT_LIGHT
2209 || ndef->get(n).liquid_type != LIQUID_NONE)
2211 vmanip.m_area.add_y(em, i, -1);
2213 if(y >= full_node_min.Y)
2216 surface_y = full_node_min.Y;
2219 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2220 MapNode *n = &vmanip.m_data[i];
2221 if(n->getContent() == c_dirt){
2222 // Well yeah, this can't be overground...
2223 if(surface_y < WATER_LEVEL - 20)
2225 n->setContent(c_dirt_with_grass);
2232 assert(central_area_size.X == central_area_size.Z);
2234 // Divide area into parts
2236 s16 sidelen = central_area_size.X / div;
2237 double area = sidelen * sidelen;
2238 for(s16 x0=0; x0<div; x0++)
2239 for(s16 z0=0; z0<div; z0++)
2241 // Center position of part of division
2243 node_min.X + sidelen/2 + sidelen*x0,
2244 node_min.Z + sidelen/2 + sidelen*z0
2246 // Minimum edge of part of division
2248 node_min.X + sidelen*x0,
2249 node_min.Z + sidelen*z0
2251 // Maximum edge of part of division
2253 node_min.X + sidelen + sidelen*x0 - 1,
2254 node_min.Z + sidelen + sidelen*z0 - 1
2257 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2258 // Put trees in random places on part of division
2259 for(u32 i=0; i<tree_count; i++)
2261 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2262 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2263 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2264 // Don't make a tree under water level
2267 // Don't make a tree so high that it doesn't fit
2268 if(y > node_max.Y - 6)
2272 Trees grow only on mud and grass
2275 u32 i = vmanip.m_area.index(v3s16(p));
2276 MapNode *n = &vmanip.m_data[i];
2277 if(n->getContent() != c_dirt
2278 && n->getContent() != c_dirt_with_grass)
2283 treegen::make_tree(vmanip, p, false, ndef);
2290 Make base ground level
2293 for(s16 x=node_min.X; x<=node_max.X; x++)
2294 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2299 // Use fast index incrementing
2300 v3s16 em = vmanip.m_area.getExtent();
2301 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2302 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2304 // Only modify places that have no content
2305 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2307 // First priority: make air and water.
2308 // This avoids caves inside water.
2309 if(all_is_ground_except_caves == false
2310 && val_is_ground(noisebuf_ground.get(x,y,z),
2311 v3s16(x,y,z), data->seed) == false)
2313 if(y <= WATER_LEVEL)
2314 vmanip.m_data[i] = n_water_source;
2316 vmanip.m_data[i] = n_air;
2318 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2319 vmanip.m_data[i] = n_air;
2321 vmanip.m_data[i] = n_stone;
2324 vmanip->m_area.add_y(em, i, 1);
2330 Add mud and sand and others underground (in place of stone)
2333 for(s16 x=node_min.X; x<=node_max.X; x++)
2334 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2339 // Use fast index incrementing
2340 v3s16 em = vmanip.m_area.getExtent();
2341 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2342 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2344 if(vmanip.m_data[i].getContent() == c_stone)
2346 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2348 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2349 vmanip.m_data[i] = n_dirt;
2351 vmanip.m_data[i] = n_sand;
2353 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2355 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2356 vmanip.m_data[i] = n_gravel;
2358 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2359 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2361 vmanip.m_data[i] = n_lava_source;
2362 for(s16 x1=-1; x1<=1; x1++)
2363 for(s16 y1=-1; y1<=1; y1++)
2364 for(s16 z1=-1; z1<=1; z1++)
2365 data->transforming_liquid.push_back(
2366 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2370 vmanip->m_area.add_y(em, i, -1);
2379 //if(node_min.Y < approx_groundlevel)
2380 //if(myrand() % 3 == 0)
2381 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2382 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2383 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2384 float dungeon_rarity = 0.02;
2385 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2387 && node_min.Y < approx_groundlevel)
2389 // Dungeon generator doesn't modify places which have this set
2390 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2391 | VMANIP_FLAG_DUNGEON_PRESERVE);
2393 // Set all air and water to be untouchable to make dungeons open
2394 // to caves and open air
2395 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2396 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2401 // Use fast index incrementing
2402 v3s16 em = vmanip.m_area.getExtent();
2403 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2404 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2406 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2407 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2408 else if(vmanip.m_data[i].getContent() == c_water_source)
2409 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2410 vmanip->m_area.add_y(em, i, -1);
2415 PseudoRandom random(blockseed+2);
2418 make_dungeon1(vmanip, random, ndef);
2420 // Convert some cobble to mossy cobble
2421 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2422 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2427 // Use fast index incrementing
2428 v3s16 em = vmanip.m_area.getExtent();
2429 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2430 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2432 // (noisebuf not used because it doesn't contain the
2434 double wetness = noise3d_param(
2435 get_ground_wetness_params(data->seed), x,y,z);
2436 double d = noise3d_perlin((float)x/2.5,
2437 (float)y/2.5,(float)z/2.5,
2439 if(vmanip.m_data[i].getContent() == c_cobble)
2443 vmanip.m_data[i].setContent(c_mossycobble);
2446 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2449 vmanip.m_data[i].setContent(c_dirt);
2451 vmanip->m_area.add_y(em, i, -1);
2461 PseudoRandom ncrandom(blockseed+9324342);
2462 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2464 make_nc(vmanip, ncrandom, ndef);
2469 Add top and bottom side of water to transforming_liquid queue
2472 for(s16 x=node_min.X; x<=node_max.X; x++)
2473 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2478 bool water_found = false;
2479 // Use fast index incrementing
2480 v3s16 em = vmanip.m_area.getExtent();
2481 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2482 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2484 if(water_found == false)
2486 if(vmanip.m_data[i].getContent() == c_water_source)
2488 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2489 data->transforming_liquid.push_back(p);
2495 // This can be done because water_found can only
2496 // turn to true and end up here after going through
2498 if(vmanip.m_data[i+1].getContent() != c_water_source)
2500 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2501 data->transforming_liquid.push_back(p);
2502 water_found = false;
2506 vmanip->m_area.add_y(em, i, -1);
2512 If close to ground level
2515 //if(abs(approx_ground_depth) < 30)
2516 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2522 for(s16 x=node_min.X; x<=node_max.X; x++)
2523 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2528 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2529 bool have_sand = false;
2530 u32 current_depth = 0;
2531 bool air_detected = false;
2532 bool water_detected = false;
2533 bool have_clay = false;
2535 // Use fast index incrementing
2536 s16 start_y = node_max.Y+2;
2537 v3s16 em = vmanip.m_area.getExtent();
2538 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2539 for(s16 y=start_y; y>=node_min.Y-3; y--)
2541 if(vmanip.m_data[i].getContent() == c_water_source)
2542 water_detected = true;
2543 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2544 air_detected = true;
2546 if((vmanip.m_data[i].getContent() == c_stone
2547 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2548 || vmanip.m_data[i].getContent() == c_dirt
2549 || vmanip.m_data[i].getContent() == c_sand
2550 || vmanip.m_data[i].getContent() == c_gravel
2551 ) && (air_detected || water_detected))
2553 if(current_depth == 0 && y <= WATER_LEVEL+2
2554 && possibly_have_sand)
2557 if(current_depth < 4)
2561 vmanip.m_data[i] = MapNode(c_sand);
2564 else if(current_depth==0 && !water_detected
2565 && y >= WATER_LEVEL && air_detected)
2566 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2569 vmanip.m_data[i] = MapNode(c_dirt);
2573 if(vmanip.m_data[i].getContent() == c_dirt
2574 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2575 vmanip.m_data[i] = MapNode(c_stone);
2580 if(current_depth >= 8)
2583 else if(current_depth != 0)
2586 vmanip->m_area.add_y(em, i, -1);
2592 Calculate some stuff
2595 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2596 bool is_jungle = surface_humidity > 0.75;
2598 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2605 PseudoRandom treerandom(blockseed);
2606 // Put trees in random places on part of division
2607 for(u32 i=0; i<tree_count; i++)
2609 s16 x = treerandom.range(node_min.X, node_max.X);
2610 s16 z = treerandom.range(node_min.Z, node_max.Z);
2611 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2612 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2613 // Don't make a tree under water level
2616 // Make sure tree fits (only trees whose starting point is
2617 // at this block are added)
2618 if(y < node_min.Y || y > node_max.Y)
2621 Find exact ground level
2625 for(; p.Y >= y-6; p.Y--)
2627 u32 i = vmanip->m_area.index(p);
2628 MapNode *n = &vmanip->m_data[i];
2629 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2635 // If not found, handle next one
2640 u32 i = vmanip->m_area.index(p);
2641 MapNode *n = &vmanip->m_data[i];
2643 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2646 // Papyrus grows only on mud and in water
2647 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2650 make_papyrus(vmanip, p, ndef);
2652 // Trees grow only on mud and grass, on land
2653 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2656 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2657 if(is_jungle == false)
2660 if(myrand_range(0,4) != 0)
2661 is_apple_tree = false;
2663 is_apple_tree = noise2d_perlin(
2664 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2665 data->seed+342902, 3, 0.45) > 0.2;
2666 make_tree(vmanip, p, is_apple_tree, ndef);
2669 make_jungletree(vmanip, p, ndef);
2671 // Cactii grow only on sand, on land
2672 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2675 make_cactus(vmanip, p, ndef);
2685 PseudoRandom grassrandom(blockseed);
2686 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2688 s16 x = grassrandom.range(node_min.X, node_max.X);
2689 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2690 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2693 if(y < node_min.Y || y > node_max.Y)
2696 Find exact ground level
2700 for(; p.Y >= y-6; p.Y--)
2702 u32 i = vmanip->m_area.index(p);
2703 MapNode *n = &vmanip->m_data[i];
2704 if(data->nodedef->get(*n).is_ground_content)
2710 // If not found, handle next one
2714 if(vmanip.m_area.contains(p) == false)
2716 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2719 if(vmanip.m_area.contains(p))
2720 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2722 if(vmanip.m_area.contains(p))
2723 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2729 Add some kind of random stones
2732 u32 random_stone_count = gen_area_nodes *
2733 randomstone_amount_2d(data->seed, p2d_center);
2734 // Put in random places on part of division
2735 for(u32 i=0; i<random_stone_count; i++)
2737 s16 x = myrand_range(node_min.X, node_max.X);
2738 s16 z = myrand_range(node_min.Z, node_max.Z);
2739 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2740 // Don't add under water level
2741 /*if(y < WATER_LEVEL)
2743 // Don't add if doesn't belong to this block
2744 if(y < node_min.Y || y > node_max.Y)
2749 u32 i = vmanip->m_area.index(v3s16(p));
2750 MapNode *n = &vmanip->m_data[i];
2751 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2754 // Will be placed one higher
2757 make_randomstone(vmanip, p);
2766 u32 large_stone_count = gen_area_nodes *
2767 largestone_amount_2d(data->seed, p2d_center);
2768 //u32 large_stone_count = 1;
2769 // Put in random places on part of division
2770 for(u32 i=0; i<large_stone_count; i++)
2772 s16 x = myrand_range(node_min.X, node_max.X);
2773 s16 z = myrand_range(node_min.Z, node_max.Z);
2774 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2775 // Don't add under water level
2776 /*if(y < WATER_LEVEL)
2778 // Don't add if doesn't belong to this block
2779 if(y < node_min.Y || y > node_max.Y)
2784 u32 i = vmanip->m_area.index(v3s16(p));
2785 MapNode *n = &vmanip->m_data[i];
2786 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2789 // Will be placed one lower
2792 make_largestone(vmanip, p);
2802 PseudoRandom mineralrandom(blockseed);
2807 for(s16 i=0; i<approx_ground_depth/4; i++)
2809 if(mineralrandom.next()%50 == 0)
2811 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2812 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2813 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2814 for(u16 i=0; i<27; i++)
2816 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2817 u32 vi = vmanip.m_area.index(p);
2818 if(vmanip.m_data[vi].getContent() == c_stone)
2819 if(mineralrandom.next()%8 == 0)
2820 vmanip.m_data[vi] = MapNode(c_mese);
2829 u16 a = mineralrandom.range(0,15);
2831 u16 amount = 20 * a/1000;
2832 for(s16 i=0; i<amount; i++)
2834 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2835 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2836 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2838 u8 base_content = c_stone;
2839 MapNode new_content(CONTENT_IGNORE);
2842 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2844 new_content = MapNode(c_stone_with_coal);
2848 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2849 new_content = MapNode(c_stone_with_iron);
2850 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2851 vmanip.m_data[i] = MapNode(c_dirt);
2853 vmanip.m_data[i] = MapNode(c_sand);*/
2855 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2859 if(new_content.getContent() != CONTENT_IGNORE)
2861 for(u16 i=0; i<27; i++)
2863 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2864 u32 vi = vmanip.m_area.index(p);
2865 if(vmanip.m_data[vi].getContent() == base_content)
2867 if(mineralrandom.next()%sparseness == 0)
2868 vmanip.m_data[vi] = new_content;
2877 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2878 //for(s16 i=0; i<50; i++)
2879 u16 coal_amount = 30;
2880 u16 coal_rareness = 60 / coal_amount;
2881 if(coal_rareness == 0)
2883 if(mineralrandom.next()%coal_rareness == 0)
2885 u16 a = mineralrandom.next() % 16;
2886 u16 amount = coal_amount * a*a*a / 1000;
2887 for(s16 i=0; i<amount; i++)
2889 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2890 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2891 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2892 for(u16 i=0; i<27; i++)
2894 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2895 u32 vi = vmanip.m_area.index(p);
2896 if(vmanip.m_data[vi].getContent() == c_stone)
2897 if(mineralrandom.next()%8 == 0)
2898 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2905 u16 iron_amount = 8;
2906 u16 iron_rareness = 60 / iron_amount;
2907 if(iron_rareness == 0)
2909 if(mineralrandom.next()%iron_rareness == 0)
2911 u16 a = mineralrandom.next() % 16;
2912 u16 amount = iron_amount * a*a*a / 1000;
2913 for(s16 i=0; i<amount; i++)
2915 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2916 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2917 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2918 for(u16 i=0; i<27; i++)
2920 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2921 u32 vi = vmanip.m_area.index(p);
2922 if(vmanip.m_data[vi].getContent() == c_stone)
2923 if(mineralrandom.next()%8 == 0)
2924 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2935 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2937 //VoxelArea a(node_min, node_max);
2938 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2939 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2940 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2941 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2942 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2943 for(int i=0; i<2; i++)
2945 enum LightBank bank = banks[i];
2947 core::map<v3s16, bool> light_sources;
2948 core::map<v3s16, u8> unlight_from;
2950 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2951 light_sources, unlight_from);
2953 bool inexistent_top_provides_sunlight = !block_is_underground;
2954 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2955 vmanip, a, inexistent_top_provides_sunlight,
2956 light_sources, ndef);
2957 // TODO: Do stuff according to bottom_sunlight_valid
2959 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2961 vmanip.spreadLight(bank, light_sources, ndef);
2966 #endif ///BIG COMMENT
2968 BlockMakeData::BlockMakeData():
2975 BlockMakeData::~BlockMakeData()
2980 //}; // namespace mapgen