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"
38 FlagDesc flagdesc_mapgen[] = {
41 {"dungeons", MG_DUNGEONS},
42 {"v6_forests", MGV6_FORESTS},
43 {"v6_biome_blend", MGV6_BIOME_BLEND},
48 ///////////////////////////////////////////////////////////////////////////////
49 /////////////////////////////// Emerge Manager ////////////////////////////////
52 EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
53 //register built-in mapgens
54 registerMapgen("v6", new MapgenFactoryV6());
56 //the order of these assignments is pretty important
57 this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
63 EmergeManager::~EmergeManager() {
70 void EmergeManager::initMapgens(MapgenParams *mgparams) {
74 this->params = mgparams;
75 this->mapgen = getMapgen(); //only one mapgen for now!
79 Mapgen *EmergeManager::getMapgen() {
81 mapgen = createMapgen(params->mg_name, 0, params, this);
83 infostream << "EmergeManager: falling back to mapgen v6" << std::endl;
85 params = createMapgenParams("v6");
86 mapgen = createMapgen("v6", 0, params, this);
92 void EmergeManager::addBlockToQueue() {
97 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
100 return mapgen->getGroundLevelAtPoint(p);
104 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
106 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
107 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
108 int ground_level = getGroundLevelAtPoint(p);
109 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
112 //yuck, but then again, should i bother being accurate?
113 //the height of the nodes in a single block is quite variable
114 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level;
118 u32 EmergeManager::getBlockSeed(v3s16 p) {
119 return (u32)(params->seed & 0xFFFFFFFF) +
126 Mapgen *EmergeManager::createMapgen(std::string mgname, int mgid,
127 MapgenParams *mgparams, EmergeManager *emerge) {
128 std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
129 if (iter == mglist.end()) {
130 errorstream << "EmergeManager; mapgen " << mgname <<
131 " not registered" << std::endl;
135 MapgenFactory *mgfactory = iter->second;
136 return mgfactory->createMapgen(mgid, mgparams, emerge);
140 MapgenParams *EmergeManager::createMapgenParams(std::string mgname) {
141 std::map<std::string, MapgenFactory *>::const_iterator iter = mglist.find(mgname);
142 if (iter == mglist.end()) {
143 errorstream << "EmergeManager: mapgen " << mgname <<
144 " not registered" << std::endl;
148 MapgenFactory *mgfactory = iter->second;
149 return mgfactory->createMapgenParams();
153 MapgenParams *EmergeManager::getParamsFromSettings(Settings *settings) {
154 std::string mg_name = settings->get("mg_name");
155 MapgenParams *mgparams = createMapgenParams(mg_name);
157 mgparams->mg_name = mg_name;
158 mgparams->seed = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
159 mgparams->water_level = settings->getS16("water_level");
160 mgparams->chunksize = settings->getS16("chunksize");
161 mgparams->flags = settings->getFlagStr("mg_flags", flagdesc_mapgen);
163 if (!mgparams->readParams(settings)) {
171 void EmergeManager::setParamsToSettings(Settings *settings) {
172 settings->set("mg_name", params->mg_name);
173 settings->setU64("seed", params->seed);
174 settings->setS16("water_level", params->water_level);
175 settings->setS16("chunksize", params->chunksize);
176 settings->setFlagStr("mg_flags", params->flags, flagdesc_mapgen);
178 params->writeParams(settings);
182 void EmergeManager::registerMapgen(std::string mgname, MapgenFactory *mgfactory) {
183 mglist.insert(std::make_pair(mgname, mgfactory));
184 infostream << "EmergeManager: registered mapgen " << mgname << std::endl;
188 /////////////////////
190 bool MapgenV6Params::readParams(Settings *settings) {
191 freq_desert = settings->getFloat("mgv6_freq_desert");
192 freq_beach = settings->getFloat("mgv6_freq_beach");
194 np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
195 np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
196 np_steepness = settings->getNoiseParams("mgv6_np_steepness");
197 np_height_select = settings->getNoiseParams("mgv6_np_height_select");
198 np_trees = settings->getNoiseParams("mgv6_np_trees");
199 np_mud = settings->getNoiseParams("mgv6_np_mud");
200 np_beach = settings->getNoiseParams("mgv6_np_beach");
201 np_biome = settings->getNoiseParams("mgv6_np_biome");
202 np_cave = settings->getNoiseParams("mgv6_np_cave");
205 np_terrain_base && np_terrain_higher && np_steepness &&
206 np_height_select && np_trees && np_mud &&
207 np_beach && np_biome && np_cave;
212 void MapgenV6Params::writeParams(Settings *settings) {
213 settings->setFloat("mgv6_freq_desert", freq_desert);
214 settings->setFloat("mgv6_freq_beach", freq_beach);
216 settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base);
217 settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
218 settings->setNoiseParams("mgv6_np_steepness", np_steepness);
219 settings->setNoiseParams("mgv6_np_height_select", np_height_select);
220 settings->setNoiseParams("mgv6_np_trees", np_trees);
221 settings->setNoiseParams("mgv6_np_mud", np_mud);
222 settings->setNoiseParams("mgv6_np_beach", np_beach);
223 settings->setNoiseParams("mgv6_np_biome", np_biome);
224 settings->setNoiseParams("mgv6_np_cave", np_cave);
228 /////////////////////////////////// legacy static functions for farmesh
231 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
232 //just need to return something
238 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
239 double sandnoise = noise2d_perlin(
240 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
241 seed+59420, 3, 0.50);
243 return (sandnoise > 0.15);
247 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
248 double noise = noise2d_perlin(
249 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
251 double zeroval = -0.39;
255 return 0.04 * (noise-zeroval) / (1.0-zeroval);
259 #if 0 /// BIG COMMENT
264 Some helper functions for the map generator
268 // Returns Y one under area minimum if not found
269 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
270 INodeDefManager *ndef)
272 v3s16 em = vmanip.m_area.getExtent();
273 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
274 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
275 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
277 for(y=y_nodes_max; y>=y_nodes_min; y--)
279 MapNode &n = vmanip.m_data[i];
280 if(ndef->get(n).walkable)
283 vmanip.m_area.add_y(em, i, -1);
288 return y_nodes_min - 1;
292 // Returns Y one under area minimum if not found
293 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
294 INodeDefManager *ndef)
296 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
297 return vmanip.m_area.MinEdge.Y-1;
298 v3s16 em = vmanip.m_area.getExtent();
299 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
300 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
301 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
303 content_t c_tree = ndef->getId("mapgen_tree");
304 content_t c_leaves = ndef->getId("mapgen_leaves");
305 for(y=y_nodes_max; y>=y_nodes_min; y--)
307 MapNode &n = vmanip.m_data[i];
308 if(ndef->get(n).walkable
309 && n.getContent() != c_tree
310 && n.getContent() != c_leaves)
313 vmanip.m_area.add_y(em, i, -1);
318 return y_nodes_min - 1;
322 // Returns Y one under area minimum if not found
323 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
324 INodeDefManager *ndef)
326 v3s16 em = vmanip.m_area.getExtent();
327 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
328 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
329 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
331 content_t c_stone = ndef->getId("mapgen_stone");
332 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
333 for(y=y_nodes_max; y>=y_nodes_min; y--)
335 MapNode &n = vmanip.m_data[i];
336 content_t c = n.getContent();
337 if(c != CONTENT_IGNORE && (
338 c == c_stone || c == c_desert_stone))
341 vmanip.m_area.add_y(em, i, -1);
346 return y_nodes_min - 1;
353 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
354 INodeDefManager *ndef)
356 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
358 s16 trunk_h = myrand_range(2, 3);
360 for(s16 ii=0; ii<trunk_h; ii++)
362 if(vmanip.m_area.contains(p1))
363 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
368 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
369 INodeDefManager *ndef)
371 MapNode cactusnode(ndef->getId("mapgen_cactus"));
375 for(s16 ii=0; ii<trunk_h; ii++)
377 if(vmanip.m_area.contains(p1))
378 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
386 Dungeon making routines
389 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
390 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
391 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
392 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
394 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
395 INodeDefManager *ndef)
398 for(s16 z=0; z<roomsize.Z; z++)
399 for(s16 y=0; y<roomsize.Y; y++)
402 v3s16 p = roomplace + v3s16(0,y,z);
403 if(vmanip.m_area.contains(p) == false)
405 u32 vi = vmanip.m_area.index(p);
406 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
408 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
411 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
412 if(vmanip.m_area.contains(p) == false)
414 u32 vi = vmanip.m_area.index(p);
415 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
417 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
422 for(s16 x=0; x<roomsize.X; x++)
423 for(s16 y=0; y<roomsize.Y; y++)
426 v3s16 p = roomplace + v3s16(x,y,0);
427 if(vmanip.m_area.contains(p) == false)
429 u32 vi = vmanip.m_area.index(p);
430 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
432 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
435 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
436 if(vmanip.m_area.contains(p) == false)
438 u32 vi = vmanip.m_area.index(p);
439 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
441 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
445 // Make +-Y walls (floor and ceiling)
446 for(s16 z=0; z<roomsize.Z; z++)
447 for(s16 x=0; x<roomsize.X; x++)
450 v3s16 p = roomplace + v3s16(x,0,z);
451 if(vmanip.m_area.contains(p) == false)
453 u32 vi = vmanip.m_area.index(p);
454 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
456 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
459 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
460 if(vmanip.m_area.contains(p) == false)
462 u32 vi = vmanip.m_area.index(p);
463 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
465 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
470 for(s16 z=1; z<roomsize.Z-1; z++)
471 for(s16 y=1; y<roomsize.Y-1; y++)
472 for(s16 x=1; x<roomsize.X-1; x++)
474 v3s16 p = roomplace + v3s16(x,y,z);
475 if(vmanip.m_area.contains(p) == false)
477 u32 vi = vmanip.m_area.index(p);
478 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
479 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
483 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
484 u8 avoid_flags, MapNode n, u8 or_flags)
486 for(s16 z=0; z<size.Z; z++)
487 for(s16 y=0; y<size.Y; y++)
488 for(s16 x=0; x<size.X; x++)
490 v3s16 p = place + v3s16(x,y,z);
491 if(vmanip.m_area.contains(p) == false)
493 u32 vi = vmanip.m_area.index(p);
494 if(vmanip.m_flags[vi] & avoid_flags)
496 vmanip.m_flags[vi] |= or_flags;
497 vmanip.m_data[vi] = n;
501 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
502 INodeDefManager *ndef)
504 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
505 VMANIP_FLAG_DUNGEON_INSIDE);
508 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
509 INodeDefManager *ndef)
511 make_hole1(vmanip, doorplace, ndef);
512 // Place torch (for testing)
513 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
516 static v3s16 rand_ortho_dir(PseudoRandom &random)
518 if(random.next()%2==0)
519 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
521 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
524 static v3s16 turn_xz(v3s16 olddir, int t)
544 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
546 int turn = random.range(0,2);
555 dir = turn_xz(olddir, 0);
558 dir = turn_xz(olddir, 1);
562 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
563 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
564 PseudoRandom &random, INodeDefManager *ndef)
566 make_hole1(vmanip, doorplace, ndef);
567 v3s16 p0 = doorplace;
571 length = random.range(1,13);
573 length = random.range(1,6);
574 length = random.range(1,13);
575 u32 partlength = random.range(1,13);
578 if(random.next()%2 == 0 && partlength >= 3)
579 make_stairs = random.next()%2 ? 1 : -1;
580 for(u32 i=0; i<length; i++)
586 /*// If already empty
587 if(vmanip.getNodeNoExNoEmerge(p).getContent()
589 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
594 if(vmanip.m_area.contains(p) == true
595 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
599 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
600 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
601 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
602 VMANIP_FLAG_DUNGEON_INSIDE);
603 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
604 VMANIP_FLAG_DUNGEON_INSIDE);
608 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
609 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
610 make_hole1(vmanip, p, ndef);
611 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
612 VMANIP_FLAG_DUNGEON_INSIDE);*/
619 // Can't go here, turn away
620 dir = turn_xz(dir, random.range(0,1));
621 make_stairs = -make_stairs;
623 partlength = random.range(1,length);
628 if(partcount >= partlength)
632 dir = random_turn(random, dir);
634 partlength = random.range(1,length);
637 if(random.next()%2 == 0 && partlength >= 3)
638 make_stairs = random.next()%2 ? 1 : -1;
649 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
650 INodeDefManager *ndef):
661 m_dir = rand_ortho_dir(m_random);
664 void setPos(v3s16 pos)
669 void setDir(v3s16 dir)
674 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
676 for(u32 i=0; i<100; i++)
678 v3s16 p = m_pos + m_dir;
679 v3s16 p1 = p + v3s16(0,1,0);
680 if(vmanip.m_area.contains(p) == false
681 || vmanip.m_area.contains(p1) == false
687 if(vmanip.getNodeNoExNoEmerge(p).getContent()
688 == m_ndef->getId("mapgen_cobble")
689 && vmanip.getNodeNoExNoEmerge(p1).getContent()
690 == m_ndef->getId("mapgen_cobble"))
692 // Found wall, this is a good place!
695 // Randomize next direction
700 Determine where to move next
702 // Jump one up if the actual space is there
703 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
704 == m_ndef->getId("mapgen_cobble")
705 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
707 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
710 // Jump one down if the actual space is there
711 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
712 == m_ndef->getId("mapgen_cobble")
713 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
715 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
718 // Check if walking is now possible
719 if(vmanip.getNodeNoExNoEmerge(p).getContent()
721 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
724 // Cannot continue walking here
734 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
735 v3s16 &result_doordir, v3s16 &result_roomplace)
737 for(s16 trycount=0; trycount<30; trycount++)
741 bool r = findPlaceForDoor(doorplace, doordir);
745 // X east, Z north, Y up
747 if(doordir == v3s16(1,0,0)) // X+
748 roomplace = doorplace +
749 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
750 if(doordir == v3s16(-1,0,0)) // X-
751 roomplace = doorplace +
752 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
753 if(doordir == v3s16(0,0,1)) // Z+
754 roomplace = doorplace +
755 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
756 if(doordir == v3s16(0,0,-1)) // Z-
757 roomplace = doorplace +
758 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
761 if(doordir == v3s16(1,0,0)) // X+
762 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
763 if(doordir == v3s16(-1,0,0)) // X-
764 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
765 if(doordir == v3s16(0,0,1)) // Z+
766 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
767 if(doordir == v3s16(0,0,-1)) // Z-
768 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
773 for(s16 z=1; z<roomsize.Z-1; z++)
774 for(s16 y=1; y<roomsize.Y-1; y++)
775 for(s16 x=1; x<roomsize.X-1; x++)
777 v3s16 p = roomplace + v3s16(x,y,z);
778 if(vmanip.m_area.contains(p) == false)
783 if(vmanip.m_flags[vmanip.m_area.index(p)]
784 & VMANIP_FLAG_DUNGEON_INSIDE)
795 result_doorplace = doorplace;
796 result_doordir = doordir;
797 result_roomplace = roomplace;
804 VoxelManipulator &vmanip;
807 PseudoRandom &m_random;
808 INodeDefManager *m_ndef;
811 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
812 INodeDefManager *ndef)
814 v3s16 areasize = vmanip.m_area.getExtent();
819 Find place for first room
822 for(u32 i=0; i<100; i++)
824 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
825 roomplace = vmanip.m_area.MinEdge + v3s16(
826 random.range(0,areasize.X-roomsize.X-1),
827 random.range(0,areasize.Y-roomsize.Y-1),
828 random.range(0,areasize.Z-roomsize.Z-1));
830 Check that we're not putting the room to an unknown place,
831 otherwise it might end up floating in the air
834 for(s16 z=1; z<roomsize.Z-1; z++)
835 for(s16 y=1; y<roomsize.Y-1; y++)
836 for(s16 x=1; x<roomsize.X-1; x++)
838 v3s16 p = roomplace + v3s16(x,y,z);
839 u32 vi = vmanip.m_area.index(p);
840 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
845 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
859 Stores the center position of the last room made, so that
860 a new corridor can be started from the last room instead of
861 the new room, if chosen so.
863 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
865 u32 room_count = random.range(2,7);
866 for(u32 i=0; i<room_count; i++)
868 // Make a room to the determined place
869 make_room1(vmanip, roomsize, roomplace, ndef);
871 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
873 // Place torch at room center (for testing)
874 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
877 if(i == room_count-1)
880 // Determine walker start position
882 bool start_in_last_room = (random.range(0,2)!=0);
883 //bool start_in_last_room = true;
885 v3s16 walker_start_place;
887 if(start_in_last_room)
889 walker_start_place = last_room_center;
893 walker_start_place = room_center;
894 // Store center of current room as the last one
895 last_room_center = room_center;
898 // Create walker and find a place for a door
899 RoomWalker walker(vmanip, walker_start_place, random, ndef);
902 bool r = walker.findPlaceForDoor(doorplace, doordir);
906 if(random.range(0,1)==0)
908 make_door1(vmanip, doorplace, doordir, ndef);
910 // Don't actually make a door
911 doorplace -= doordir;
913 // Make a random corridor starting from the door
915 v3s16 corridor_end_dir;
916 make_corridor(vmanip, doorplace, doordir, corridor_end,
917 corridor_end_dir, random, ndef);
919 // Find a place for a random sized room
920 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
921 walker.setPos(corridor_end);
922 walker.setDir(corridor_end_dir);
923 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
927 if(random.range(0,1)==0)
929 make_door1(vmanip, doorplace, doordir, ndef);
931 // Don't actually make a door
932 roomplace -= doordir;
939 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
940 INodeDefManager *ndef)
944 s32 r = random.range(0, 3);
946 dir = v3s16( 1, 0, 0);
950 dir = v3s16(-1, 0, 0);
954 dir = v3s16( 0, 0, 1);
958 dir = v3s16( 0, 0,-1);
961 v3s16 p = vmanip.m_area.MinEdge + v3s16(
962 16+random.range(0,15),
963 16+random.range(0,15),
964 16+random.range(0,15));
965 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
966 u32 length = random.range(3,15);
967 for(u32 j=0; j<length; j++)
970 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
976 Noise functions. Make sure seed is mangled differently in each one.
981 Scaling the output of the noise function affects the overdrive of the
982 contour function, which affects the shape of the output considerably.
984 #define CAVE_NOISE_SCALE 12.0
985 //#define CAVE_NOISE_SCALE 10.0
986 //#define CAVE_NOISE_SCALE 7.5
987 //#define CAVE_NOISE_SCALE 5.0
988 //#define CAVE_NOISE_SCALE 1.0
990 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
991 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
993 NoiseParams get_cave_noise1_params(u64 seed)
995 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
996 200, CAVE_NOISE_SCALE);*/
997 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
998 100, CAVE_NOISE_SCALE);*/
999 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1000 100, CAVE_NOISE_SCALE);*/
1001 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1002 100, CAVE_NOISE_SCALE);*/
1003 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1004 50, CAVE_NOISE_SCALE);
1005 //return NoiseParams(NOISE_CONSTANT_ONE);
1008 NoiseParams get_cave_noise2_params(u64 seed)
1010 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1011 200, CAVE_NOISE_SCALE);*/
1012 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1013 100, CAVE_NOISE_SCALE);*/
1014 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1015 100, CAVE_NOISE_SCALE);*/
1016 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1017 50, CAVE_NOISE_SCALE);
1018 //return NoiseParams(NOISE_CONSTANT_ONE);
1021 NoiseParams get_ground_noise1_params(u64 seed)
1023 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1027 NoiseParams get_ground_crumbleness_params(u64 seed)
1029 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1033 NoiseParams get_ground_wetness_params(u64 seed)
1035 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1039 bool is_cave(u64 seed, v3s16 p)
1041 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1042 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1043 return d1*d2 > CAVE_NOISE_THRESHOLD;
1047 Ground density noise shall be interpreted by using this.
1049 TODO: No perlin noises here, they should be outsourced
1051 NOTE: The speed of these actually isn't terrible
1053 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1055 //return ((double)p.Y < ground_noise1_val);
1057 double f = 0.55 + noise2d_perlin(
1058 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1059 seed+920381, 3, 0.45);
1064 double h = WATER_LEVEL + 10 * noise2d_perlin(
1065 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1066 seed+84174, 4, 0.5);
1069 return ((double)p.Y - h < ground_noise1_val * f);
1073 Queries whether a position is ground or not.
1075 bool is_ground(u64 seed, v3s16 p)
1077 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1078 return val_is_ground(val1, p, seed);
1082 // Amount of trees per area in nodes
1083 double tree_amount_2d(u64 seed, v2s16 p)
1085 /*double noise = noise2d_perlin(
1086 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1088 double noise = noise2d_perlin(
1089 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1091 double zeroval = -0.39;
1095 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1099 double surface_humidity_2d(u64 seed, v2s16 p)
1101 double noise = noise2d_perlin(
1102 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1103 seed+72384, 4, 0.66);
1104 noise = (noise + 1.0)/2.0;
1113 Incrementally find ground level from 3d noise
1115 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1117 // Start a bit fuzzy to make averaging lower precision values
1119 s16 level = myrand_range(-precision/2, precision/2);
1120 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1122 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1124 // First find non-ground by going upwards
1125 // Don't stop in caves.
1127 s16 max = level+dec[i-1]*2;
1128 v3s16 p(p2d.X, level, p2d.Y);
1129 for(; p.Y < max; p.Y += dec[i])
1131 if(!is_ground(seed, p))
1138 // Then find ground by going downwards from there.
1139 // Go in caves, too, when precision is 1.
1141 s16 min = level-dec[i-1]*2;
1142 v3s16 p(p2d.X, level, p2d.Y);
1143 for(; p.Y>min; p.Y-=dec[i])
1145 bool ground = is_ground(seed, p);
1146 /*if(dec[i] == 1 && is_cave(seed, p))
1157 // This is more like the actual ground level
1158 level += dec[i-1]/2;
1163 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1165 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1167 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1168 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1170 a += find_ground_level_from_noise(seed,
1171 v2s16(node_min.X, node_min.Y), p);
1172 a += find_ground_level_from_noise(seed,
1173 v2s16(node_min.X, node_max.Y), p);
1174 a += find_ground_level_from_noise(seed,
1175 v2s16(node_max.X, node_max.Y), p);
1176 a += find_ground_level_from_noise(seed,
1177 v2s16(node_max.X, node_min.Y), p);
1178 a += find_ground_level_from_noise(seed,
1179 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1184 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1186 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1188 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1189 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1192 a = MYMAX(a, find_ground_level_from_noise(seed,
1193 v2s16(node_min.X, node_min.Y), p));
1194 a = MYMAX(a, find_ground_level_from_noise(seed,
1195 v2s16(node_min.X, node_max.Y), p));
1196 a = MYMAX(a, find_ground_level_from_noise(seed,
1197 v2s16(node_max.X, node_max.Y), p));
1198 a = MYMAX(a, find_ground_level_from_noise(seed,
1199 v2s16(node_min.X, node_min.Y), p));
1201 a = MYMAX(a, find_ground_level_from_noise(seed,
1202 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1203 // Side middle points
1204 a = MYMAX(a, find_ground_level_from_noise(seed,
1205 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1206 a = MYMAX(a, find_ground_level_from_noise(seed,
1207 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1208 a = MYMAX(a, find_ground_level_from_noise(seed,
1209 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1210 a = MYMAX(a, find_ground_level_from_noise(seed,
1211 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1215 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1217 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1219 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1220 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1223 a = MYMIN(a, find_ground_level_from_noise(seed,
1224 v2s16(node_min.X, node_min.Y), p));
1225 a = MYMIN(a, find_ground_level_from_noise(seed,
1226 v2s16(node_min.X, node_max.Y), p));
1227 a = MYMIN(a, find_ground_level_from_noise(seed,
1228 v2s16(node_max.X, node_max.Y), p));
1229 a = MYMIN(a, find_ground_level_from_noise(seed,
1230 v2s16(node_min.X, node_min.Y), p));
1232 a = MYMIN(a, find_ground_level_from_noise(seed,
1233 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1234 // Side middle points
1235 a = MYMIN(a, find_ground_level_from_noise(seed,
1236 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1237 a = MYMIN(a, find_ground_level_from_noise(seed,
1238 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1239 a = MYMIN(a, find_ground_level_from_noise(seed,
1240 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1241 a = MYMIN(a, find_ground_level_from_noise(seed,
1242 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1247 // Required by mapgen.h
1248 bool block_is_underground(u64 seed, v3s16 blockpos)
1250 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1251 seed, v2s16(blockpos.X, blockpos.Z));*/
1252 // Nah, this is just a heuristic, just return something
1253 s16 minimum_groundlevel = WATER_LEVEL;
1255 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1261 #define AVERAGE_MUD_AMOUNT 4
1263 double base_rock_level_2d(u64 seed, v2s16 p)
1265 // The base ground level
1266 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1267 + 20. * noise2d_perlin(
1268 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1269 seed+82341, 5, 0.6);
1271 /*// A bit hillier one
1272 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1273 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1274 seed+93413, 6, 0.69);
1278 // Higher ground level
1279 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1280 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1281 seed+85039, 5, 0.6);
1282 //higher = 30; // For debugging
1284 // Limit higher to at least base
1288 // Steepness factor of cliffs
1289 double b = 0.85 + 0.5 * noise2d_perlin(
1290 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1292 b = rangelim(b, 0.0, 1000.0);
1295 b = rangelim(b, 0.5, 1000.0);
1296 // Values 1.5...100 give quite horrible looking slopes
1297 if(b > 1.5 && b < 100.0){
1303 //dstream<<"b="<<b<<std::endl;
1307 // Offset to more low
1308 double a_off = -0.20;
1309 // High/low selector
1310 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1311 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1312 seed+4213, 6, 0.7));*/
1313 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1314 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1315 seed+4213, 5, 0.69));
1317 a = rangelim(a, 0.0, 1.0);
1319 //dstream<<"a="<<a<<std::endl;
1321 double h = base*(1.0-a) + higher*a;
1328 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1330 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1333 double get_mud_add_amount(u64 seed, v2s16 p)
1335 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1336 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1337 seed+91013, 3, 0.55));
1340 bool get_have_beach(u64 seed, v2s16 p2d)
1342 // Determine whether to have sand here
1343 double sandnoise = noise2d_perlin(
1344 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1345 seed+59420, 3, 0.50);
1347 return (sandnoise > 0.15);
1356 BiomeType get_biome(u64 seed, v2s16 p2d)
1358 // Just do something very simple as for now
1359 double d = noise2d_perlin(
1360 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1361 seed+9130, 3, 0.50);
1364 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1369 u32 get_blockseed(u64 seed, v3s16 p)
1371 s32 x=p.X, y=p.Y, z=p.Z;
1372 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1375 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1377 void make_block(BlockMakeData *data)
1381 //dstream<<"makeBlock: no-op"<<std::endl;
1385 assert(data->vmanip);
1386 assert(data->nodedef);
1387 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1388 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1389 data->blockpos_requested.Z >= data->blockpos_min.Z);
1390 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1391 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1392 data->blockpos_requested.Z <= data->blockpos_max.Z);
1394 INodeDefManager *ndef = data->nodedef;
1396 // Hack: use minimum block coordinates for old code that assumes
1398 v3s16 blockpos = data->blockpos_requested;
1400 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1401 <<blockpos.Z<<")"<<std::endl;*/
1403 v3s16 blockpos_min = data->blockpos_min;
1404 v3s16 blockpos_max = data->blockpos_max;
1405 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1406 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1408 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1409 // Area of central chunk
1410 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1411 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1412 // Full allocated area
1413 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1414 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1416 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1418 const s16 max_spread_amount = MAP_BLOCKSIZE;
1420 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1421 * (blockpos_max.Y - blockpos_min.Y + 1)
1422 * (blockpos_max.Z - blockpos_max.Z + 1);
1424 int volume_nodes = volume_blocks *
1425 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1427 // Generated surface area
1428 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1430 // Horribly wrong heuristic, but better than nothing
1431 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1434 Create a block-specific seed
1436 u32 blockseed = get_blockseed(data->seed, full_node_min);
1439 Cache some ground type values for speed
1442 // Creates variables c_name=id and n_name=node
1443 #define CONTENT_VARIABLE(ndef, name)\
1444 content_t c_##name = ndef->getId("mapgen_" #name);\
1445 MapNode n_##name(c_##name);
1446 // Default to something else if was CONTENT_IGNORE
1447 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1448 if(c_##name == CONTENT_IGNORE){\
1449 c_##name = c_##dname;\
1450 n_##name = n_##dname;\
1453 CONTENT_VARIABLE(ndef, stone);
1454 CONTENT_VARIABLE(ndef, air);
1455 CONTENT_VARIABLE(ndef, water_source);
1456 CONTENT_VARIABLE(ndef, dirt);
1457 CONTENT_VARIABLE(ndef, sand);
1458 CONTENT_VARIABLE(ndef, gravel);
1459 CONTENT_VARIABLE(ndef, clay);
1460 CONTENT_VARIABLE(ndef, lava_source);
1461 CONTENT_VARIABLE(ndef, cobble);
1462 CONTENT_VARIABLE(ndef, mossycobble);
1463 CONTENT_VARIABLE(ndef, dirt_with_grass);
1464 CONTENT_VARIABLE(ndef, junglegrass);
1465 CONTENT_VARIABLE(ndef, stone_with_coal);
1466 CONTENT_VARIABLE(ndef, stone_with_iron);
1467 CONTENT_VARIABLE(ndef, mese);
1468 CONTENT_VARIABLE(ndef, desert_sand);
1469 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1470 CONTENT_VARIABLE(ndef, desert_stone);
1471 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1473 // Maximum height of the stone surface and obstacles.
1474 // This is used to guide the cave generation
1475 s16 stone_surface_max_y = 0;
1478 Generate general ground level to full area
1482 TimeTaker timer1("Generating ground level");
1484 for(s16 x=node_min.X; x<=node_max.X; x++)
1485 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1488 v2s16 p2d = v2s16(x,z);
1491 Skip of already generated
1494 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1495 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1499 // Ground height at this point
1500 float surface_y_f = 0.0;
1502 // Use perlin noise for ground height
1503 surface_y_f = base_rock_level_2d(data->seed, p2d);
1505 /*// Experimental stuff
1507 float a = highlands_level_2d(data->seed, p2d);
1512 // Convert to integer
1513 s16 surface_y = (s16)surface_y_f;
1516 if(surface_y > stone_surface_max_y)
1517 stone_surface_max_y = surface_y;
1519 BiomeType bt = get_biome(data->seed, p2d);
1521 Fill ground with stone
1524 // Use fast index incrementing
1525 v3s16 em = vmanip.m_area.getExtent();
1526 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1527 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1529 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1531 if(y > WATER_LEVEL && bt == BT_DESERT)
1532 vmanip.m_data[i] = n_desert_stone;
1534 vmanip.m_data[i] = n_stone;
1535 } else if(y <= WATER_LEVEL){
1536 vmanip.m_data[i] = MapNode(c_water_source);
1538 vmanip.m_data[i] = MapNode(c_air);
1541 vmanip.m_area.add_y(em, i, 1);
1549 // Limit dirt flow area by 1 because mud is flown into neighbors.
1550 assert(central_area_size.X == central_area_size.Z);
1551 s16 mudflow_minpos = 0-max_spread_amount+1;
1552 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1555 Loop this part, it will make stuff look older and newer nicely
1558 const u32 age_loops = 2;
1559 for(u32 i_age=0; i_age<age_loops; i_age++)
1561 /******************************
1562 BEGINNING OF AGING LOOP
1563 ******************************/
1568 //TimeTaker timer1("caves");
1571 Make caves (this code is relatively horrible)
1573 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1574 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1575 data->seed+34329, 3, 0.50);
1576 cave_amount = MYMAX(0.0, cave_amount);
1577 u32 caves_count = cave_amount * volume_nodes / 50000;
1578 u32 bruises_count = 1;
1579 PseudoRandom ps(blockseed+21343);
1580 PseudoRandom ps2(blockseed+1032);
1581 if(ps.range(1, 6) == 1)
1582 bruises_count = ps.range(0, ps.range(0, 2));
1583 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1587 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1589 bool large_cave = (jj >= caves_count);
1590 s16 min_tunnel_diameter = 2;
1591 s16 max_tunnel_diameter = ps.range(2,6);
1592 int dswitchint = ps.range(1,14);
1593 u16 tunnel_routepoints = 0;
1594 int part_max_length_rs = 0;
1596 part_max_length_rs = ps.range(2,4);
1597 tunnel_routepoints = ps.range(5, ps.range(15,30));
1598 min_tunnel_diameter = 5;
1599 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1601 part_max_length_rs = ps.range(2,9);
1602 tunnel_routepoints = ps.range(10, ps.range(15,30));
1604 bool large_cave_is_flat = (ps.range(0,1) == 0);
1606 v3f main_direction(0,0,0);
1608 // Allowed route area size in nodes
1609 v3s16 ar = central_area_size;
1611 // Area starting point in nodes
1612 v3s16 of = node_min;
1615 //(this should be more than the maximum radius of the tunnel)
1616 //s16 insure = 5; // Didn't work with max_d = 20
1618 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1619 ar += v3s16(1,0,1) * more * 2;
1620 of -= v3s16(1,0,1) * more;
1622 s16 route_y_min = 0;
1623 // Allow half a diameter + 7 over stone surface
1624 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1626 /*// If caves, don't go through surface too often
1627 if(large_cave == false)
1628 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1630 // Limit maximum to area
1631 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1635 /*// Minimum is at y=0
1636 route_y_min = -of.Y - 0;*/
1637 // Minimum is at y=max_tunnel_diameter/4
1638 //route_y_min = -of.Y + max_tunnel_diameter/4;
1639 //s16 min = -of.Y + max_tunnel_diameter/4;
1640 //s16 min = -of.Y + 0;
1642 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1644 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1645 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1647 route_y_min = ps.range(min, min + max_tunnel_diameter);
1648 route_y_min = rangelim(route_y_min, 0, route_y_max);
1651 /*dstream<<"route_y_min = "<<route_y_min
1652 <<", route_y_max = "<<route_y_max<<std::endl;*/
1654 s16 route_start_y_min = route_y_min;
1655 s16 route_start_y_max = route_y_max;
1657 // Start every 4th cave from surface when applicable
1658 /*bool coming_from_surface = false;
1659 if(node_min.Y <= 0 && node_max.Y >= 0){
1660 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1661 if(coming_from_surface)
1662 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1665 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1666 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1668 // Randomize starting position
1670 (float)(ps.next()%ar.X)+0.5,
1671 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1672 (float)(ps.next()%ar.Z)+0.5
1675 v3s16 startp(orp.X, orp.Y, orp.Z);
1678 MapNode airnode(CONTENT_AIR);
1679 MapNode waternode(c_water_source);
1680 MapNode lavanode(c_lava_source);
1683 Generate some tunnel starting from orp
1686 for(u16 j=0; j<tunnel_routepoints; j++)
1688 if(j%dswitchint==0 && large_cave == false)
1690 main_direction = v3f(
1691 ((float)(ps.next()%20)-(float)10)/10,
1692 ((float)(ps.next()%20)-(float)10)/30,
1693 ((float)(ps.next()%20)-(float)10)/10
1695 main_direction *= (float)ps.range(0, 10)/10;
1699 s16 min_d = min_tunnel_diameter;
1700 s16 max_d = max_tunnel_diameter;
1701 s16 rs = ps.range(min_d, max_d);
1703 // Every second section is rough
1704 bool randomize_xz = (ps2.range(1,2) == 1);
1710 rs*part_max_length_rs,
1711 rs*part_max_length_rs/2,
1712 rs*part_max_length_rs
1718 rs*part_max_length_rs,
1719 ps.range(1, rs*part_max_length_rs),
1720 rs*part_max_length_rs
1727 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1728 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1729 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1732 // Jump downward sometimes
1733 if(!large_cave && ps.range(0,12) == 0)
1736 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1737 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1738 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1744 s16 h = find_ground_level_clever(vmanip,
1745 v2s16(p.X, p.Z), ndef);
1746 route_y_min = h - rs/3;
1747 route_y_max = h + rs;
1750 vec += main_direction;
1755 else if(rp.X >= ar.X)
1757 if(rp.Y < route_y_min)
1759 else if(rp.Y >= route_y_max)
1760 rp.Y = route_y_max-1;
1763 else if(rp.Z >= ar.Z)
1767 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1769 v3f fp = orp + vec * f;
1770 fp.X += 0.1*ps.range(-10,10);
1771 fp.Z += 0.1*ps.range(-10,10);
1772 v3s16 cp(fp.X, fp.Y, fp.Z);
1777 d0 += ps.range(-1,1);
1778 d1 += ps.range(-1,1);
1780 for(s16 z0=d0; z0<=d1; z0++)
1782 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1783 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1785 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1786 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1787 for(s16 y0=-si2; y0<=si2; y0++)
1789 /*// Make better floors in small caves
1790 if(y0 <= -rs/2 && rs<=7)
1792 if(large_cave_is_flat){
1793 // Make large caves not so tall
1794 if(rs > 7 && abs(y0) >= rs/3)
1804 if(vmanip.m_area.contains(p) == false)
1807 u32 i = vmanip.m_area.index(p);
1811 if(full_node_min.Y < WATER_LEVEL &&
1812 full_node_max.Y > WATER_LEVEL){
1813 if(p.Y <= WATER_LEVEL)
1814 vmanip.m_data[i] = waternode;
1816 vmanip.m_data[i] = airnode;
1817 } else if(full_node_max.Y < WATER_LEVEL){
1818 if(p.Y < startp.Y - 2)
1819 vmanip.m_data[i] = lavanode;
1821 vmanip.m_data[i] = airnode;
1823 vmanip.m_data[i] = airnode;
1826 // Don't replace air or water or lava or ignore
1827 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1828 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1829 vmanip.m_data[i].getContent() == c_water_source ||
1830 vmanip.m_data[i].getContent() == c_lava_source)
1833 vmanip.m_data[i] = airnode;
1836 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1854 TimeTaker timer1("add mud");
1857 Add mud to the central chunk
1860 for(s16 x=node_min.X; x<=node_max.X; x++)
1861 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1863 // Node position in 2d
1864 v2s16 p2d = v2s16(x,z);
1866 // Randomize mud amount
1867 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1869 // Find ground level
1870 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1871 // Handle area not found
1872 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1875 MapNode addnode(c_dirt);
1876 BiomeType bt = get_biome(data->seed, p2d);
1879 addnode = MapNode(c_desert_sand);
1881 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1882 addnode = MapNode(c_sand);
1883 } else if(mud_add_amount <= 0){
1884 mud_add_amount = 1 - mud_add_amount;
1885 addnode = MapNode(c_gravel);
1886 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1887 surface_y + mud_add_amount <= WATER_LEVEL+2){
1888 addnode = MapNode(c_sand);
1891 if(bt == BT_DESERT){
1893 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1898 If topmost node is grass, change it to mud.
1899 It might be if it was flown to there from a neighboring
1900 chunk and then converted.
1903 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1904 MapNode *n = &vmanip.m_data[i];
1905 if(n->getContent() == c_dirt_with_grass)
1906 *n = MapNode(c_dirt);
1914 v3s16 em = vmanip.m_area.getExtent();
1915 s16 y_start = surface_y+1;
1916 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1917 for(s16 y=y_start; y<=node_max.Y; y++)
1919 if(mudcount >= mud_add_amount)
1922 MapNode &n = vmanip.m_data[i];
1926 vmanip.m_area.add_y(em, i, 1);
1936 Add blobs of dirt and gravel underground
1938 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1940 PseudoRandom pr(blockseed+983);
1941 for(int i=0; i<volume_nodes/10/10/10; i++)
1943 bool only_fill_cave = (myrand_range(0,1) != 0);
1950 pr.range(node_min.X, node_max.X)-size.X/2,
1951 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1952 pr.range(node_min.Z, node_max.Z)-size.Z/2
1955 if(p0.Y > -32 && pr.range(0,1) == 0)
1956 n1 = MapNode(c_dirt);
1958 n1 = MapNode(c_gravel);
1959 for(int x1=0; x1<size.X; x1++)
1960 for(int y1=0; y1<size.Y; y1++)
1961 for(int z1=0; z1<size.Z; z1++)
1963 v3s16 p = p0 + v3s16(x1,y1,z1);
1964 u32 i = vmanip.m_area.index(p);
1965 if(!vmanip.m_area.contains(i))
1967 // Cancel if not stone and not cave air
1968 if(vmanip.m_data[i].getContent() != c_stone &&
1969 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1971 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1973 vmanip.m_data[i] = n1;
1981 TimeTaker timer1("flow mud");
1984 Flow mud away from steep edges
1987 // Iterate a few times
1988 for(s16 k=0; k<3; k++)
1991 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1992 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1994 // Invert coordinates every 2nd iteration
1997 x = mudflow_maxpos - (x-mudflow_minpos);
1998 z = mudflow_maxpos - (z-mudflow_minpos);
2001 // Node position in 2d
2002 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
2004 v3s16 em = vmanip.m_area.getExtent();
2005 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2008 while(y >= node_min.Y)
2015 for(; y>=node_min.Y; y--)
2017 n = &vmanip.m_data[i];
2018 //if(content_walkable(n->d))
2020 if(n->getContent() == c_dirt ||
2021 n->getContent() == c_dirt_with_grass ||
2022 n->getContent() == c_gravel)
2025 vmanip.m_area.add_y(em, i, -1);
2028 // Stop if out of area
2029 //if(vmanip.m_area.contains(i) == false)
2033 /*// If not mud, do nothing to it
2034 MapNode *n = &vmanip.m_data[i];
2035 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2038 if(n->getContent() == c_dirt ||
2039 n->getContent() == c_dirt_with_grass)
2041 // Make it exactly mud
2042 n->setContent(c_dirt);
2045 Don't flow it if the stuff under it is not mud
2049 vmanip.m_area.add_y(em, i2, -1);
2050 // Cancel if out of area
2051 if(vmanip.m_area.contains(i2) == false)
2053 MapNode *n2 = &vmanip.m_data[i2];
2054 if(n2->getContent() != c_dirt &&
2055 n2->getContent() != c_dirt_with_grass)
2060 /*s16 recurse_count = 0;
2064 v3s16(0,0,1), // back
2065 v3s16(1,0,0), // right
2066 v3s16(0,0,-1), // front
2067 v3s16(-1,0,0), // left
2070 // Theck that upper is air or doesn't exist.
2071 // Cancel dropping if upper keeps it in place
2073 vmanip.m_area.add_y(em, i3, 1);
2074 if(vmanip.m_area.contains(i3) == true
2075 && ndef->get(vmanip.m_data[i3]).walkable)
2082 for(u32 di=0; di<4; di++)
2084 v3s16 dirp = dirs4[di];
2087 vmanip.m_area.add_p(em, i2, dirp);
2088 // Fail if out of area
2089 if(vmanip.m_area.contains(i2) == false)
2091 // Check that side is air
2092 MapNode *n2 = &vmanip.m_data[i2];
2093 if(ndef->get(*n2).walkable)
2095 // Check that under side is air
2096 vmanip.m_area.add_y(em, i2, -1);
2097 if(vmanip.m_area.contains(i2) == false)
2099 n2 = &vmanip.m_data[i2];
2100 if(ndef->get(*n2).walkable)
2102 /*// Check that under that is air (need a drop of 2)
2103 vmanip.m_area.add_y(em, i2, -1);
2104 if(vmanip.m_area.contains(i2) == false)
2106 n2 = &vmanip.m_data[i2];
2107 if(content_walkable(n2->d))
2109 // Loop further down until not air
2110 bool dropped_to_unknown = false;
2112 vmanip.m_area.add_y(em, i2, -1);
2113 n2 = &vmanip.m_data[i2];
2114 // if out of known area
2115 if(vmanip.m_area.contains(i2) == false
2116 || n2->getContent() == CONTENT_IGNORE){
2117 dropped_to_unknown = true;
2120 }while(ndef->get(*n2).walkable == false);
2121 // Loop one up so that we're in air
2122 vmanip.m_area.add_y(em, i2, 1);
2123 n2 = &vmanip.m_data[i2];
2125 bool old_is_water = (n->getContent() == c_water_source);
2126 // Move mud to new place
2127 if(!dropped_to_unknown) {
2129 // Set old place to be air (or water)
2131 *n = MapNode(c_water_source);
2133 *n = MapNode(CONTENT_AIR);
2149 /***********************
2151 ************************/
2154 Add top and bottom side of water to transforming_liquid queue
2157 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2158 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2163 bool water_found = false;
2164 // Use fast index incrementing
2165 v3s16 em = vmanip.m_area.getExtent();
2166 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2167 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2169 if(y == full_node_max.Y){
2171 (vmanip.m_data[i].getContent() == c_water_source ||
2172 vmanip.m_data[i].getContent() == c_lava_source);
2174 else if(water_found == false)
2176 if(vmanip.m_data[i].getContent() == c_water_source ||
2177 vmanip.m_data[i].getContent() == c_lava_source)
2179 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2180 data->transforming_liquid.push_back(p);
2186 // This can be done because water_found can only
2187 // turn to true and end up here after going through
2189 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2190 vmanip.m_data[i+1].getContent() != c_lava_source)
2192 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2193 data->transforming_liquid.push_back(p);
2194 water_found = false;
2198 vmanip.m_area.add_y(em, i, -1);
2207 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2208 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2210 // Node position in 2d
2211 v2s16 p2d = v2s16(x,z);
2214 Find the lowest surface to which enough light ends up
2217 Basically just wait until not air and not leaves.
2221 v3s16 em = vmanip.m_area.getExtent();
2222 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2224 // Go to ground level
2225 for(y=node_max.Y; y>=full_node_min.Y; y--)
2227 MapNode &n = vmanip.m_data[i];
2228 if(ndef->get(n).param_type != CPT_LIGHT
2229 || ndef->get(n).liquid_type != LIQUID_NONE)
2231 vmanip.m_area.add_y(em, i, -1);
2233 if(y >= full_node_min.Y)
2236 surface_y = full_node_min.Y;
2239 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2240 MapNode *n = &vmanip.m_data[i];
2241 if(n->getContent() == c_dirt){
2242 // Well yeah, this can't be overground...
2243 if(surface_y < WATER_LEVEL - 20)
2245 n->setContent(c_dirt_with_grass);
2252 assert(central_area_size.X == central_area_size.Z);
2254 // Divide area into parts
2256 s16 sidelen = central_area_size.X / div;
2257 double area = sidelen * sidelen;
2258 for(s16 x0=0; x0<div; x0++)
2259 for(s16 z0=0; z0<div; z0++)
2261 // Center position of part of division
2263 node_min.X + sidelen/2 + sidelen*x0,
2264 node_min.Z + sidelen/2 + sidelen*z0
2266 // Minimum edge of part of division
2268 node_min.X + sidelen*x0,
2269 node_min.Z + sidelen*z0
2271 // Maximum edge of part of division
2273 node_min.X + sidelen + sidelen*x0 - 1,
2274 node_min.Z + sidelen + sidelen*z0 - 1
2277 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2278 // Put trees in random places on part of division
2279 for(u32 i=0; i<tree_count; i++)
2281 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2282 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2283 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2284 // Don't make a tree under water level
2287 // Don't make a tree so high that it doesn't fit
2288 if(y > node_max.Y - 6)
2292 Trees grow only on mud and grass
2295 u32 i = vmanip.m_area.index(v3s16(p));
2296 MapNode *n = &vmanip.m_data[i];
2297 if(n->getContent() != c_dirt
2298 && n->getContent() != c_dirt_with_grass)
2303 treegen::make_tree(vmanip, p, false, ndef);
2310 Make base ground level
2313 for(s16 x=node_min.X; x<=node_max.X; x++)
2314 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2319 // Use fast index incrementing
2320 v3s16 em = vmanip.m_area.getExtent();
2321 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2322 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2324 // Only modify places that have no content
2325 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2327 // First priority: make air and water.
2328 // This avoids caves inside water.
2329 if(all_is_ground_except_caves == false
2330 && val_is_ground(noisebuf_ground.get(x,y,z),
2331 v3s16(x,y,z), data->seed) == false)
2333 if(y <= WATER_LEVEL)
2334 vmanip.m_data[i] = n_water_source;
2336 vmanip.m_data[i] = n_air;
2338 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2339 vmanip.m_data[i] = n_air;
2341 vmanip.m_data[i] = n_stone;
2344 vmanip->m_area.add_y(em, i, 1);
2350 Add mud and sand and others underground (in place of stone)
2353 for(s16 x=node_min.X; x<=node_max.X; x++)
2354 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2359 // Use fast index incrementing
2360 v3s16 em = vmanip.m_area.getExtent();
2361 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2362 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2364 if(vmanip.m_data[i].getContent() == c_stone)
2366 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2368 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2369 vmanip.m_data[i] = n_dirt;
2371 vmanip.m_data[i] = n_sand;
2373 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2375 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2376 vmanip.m_data[i] = n_gravel;
2378 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2379 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2381 vmanip.m_data[i] = n_lava_source;
2382 for(s16 x1=-1; x1<=1; x1++)
2383 for(s16 y1=-1; y1<=1; y1++)
2384 for(s16 z1=-1; z1<=1; z1++)
2385 data->transforming_liquid.push_back(
2386 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2390 vmanip->m_area.add_y(em, i, -1);
2399 //if(node_min.Y < approx_groundlevel)
2400 //if(myrand() % 3 == 0)
2401 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2402 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2403 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2404 float dungeon_rarity = 0.02;
2405 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2407 && node_min.Y < approx_groundlevel)
2409 // Dungeon generator doesn't modify places which have this set
2410 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2411 | VMANIP_FLAG_DUNGEON_PRESERVE);
2413 // Set all air and water to be untouchable to make dungeons open
2414 // to caves and open air
2415 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2416 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2421 // Use fast index incrementing
2422 v3s16 em = vmanip.m_area.getExtent();
2423 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2424 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2426 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2427 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2428 else if(vmanip.m_data[i].getContent() == c_water_source)
2429 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2430 vmanip->m_area.add_y(em, i, -1);
2435 PseudoRandom random(blockseed+2);
2438 make_dungeon1(vmanip, random, ndef);
2440 // Convert some cobble to mossy cobble
2441 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2442 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2447 // Use fast index incrementing
2448 v3s16 em = vmanip.m_area.getExtent();
2449 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2450 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2452 // (noisebuf not used because it doesn't contain the
2454 double wetness = noise3d_param(
2455 get_ground_wetness_params(data->seed), x,y,z);
2456 double d = noise3d_perlin((float)x/2.5,
2457 (float)y/2.5,(float)z/2.5,
2459 if(vmanip.m_data[i].getContent() == c_cobble)
2463 vmanip.m_data[i].setContent(c_mossycobble);
2466 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2469 vmanip.m_data[i].setContent(c_dirt);
2471 vmanip->m_area.add_y(em, i, -1);
2481 PseudoRandom ncrandom(blockseed+9324342);
2482 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2484 make_nc(vmanip, ncrandom, ndef);
2489 Add top and bottom side of water to transforming_liquid queue
2492 for(s16 x=node_min.X; x<=node_max.X; x++)
2493 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2498 bool water_found = false;
2499 // Use fast index incrementing
2500 v3s16 em = vmanip.m_area.getExtent();
2501 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2502 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2504 if(water_found == false)
2506 if(vmanip.m_data[i].getContent() == c_water_source)
2508 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2509 data->transforming_liquid.push_back(p);
2515 // This can be done because water_found can only
2516 // turn to true and end up here after going through
2518 if(vmanip.m_data[i+1].getContent() != c_water_source)
2520 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2521 data->transforming_liquid.push_back(p);
2522 water_found = false;
2526 vmanip->m_area.add_y(em, i, -1);
2532 If close to ground level
2535 //if(abs(approx_ground_depth) < 30)
2536 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2542 for(s16 x=node_min.X; x<=node_max.X; x++)
2543 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2548 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2549 bool have_sand = false;
2550 u32 current_depth = 0;
2551 bool air_detected = false;
2552 bool water_detected = false;
2553 bool have_clay = false;
2555 // Use fast index incrementing
2556 s16 start_y = node_max.Y+2;
2557 v3s16 em = vmanip.m_area.getExtent();
2558 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2559 for(s16 y=start_y; y>=node_min.Y-3; y--)
2561 if(vmanip.m_data[i].getContent() == c_water_source)
2562 water_detected = true;
2563 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2564 air_detected = true;
2566 if((vmanip.m_data[i].getContent() == c_stone
2567 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2568 || vmanip.m_data[i].getContent() == c_dirt
2569 || vmanip.m_data[i].getContent() == c_sand
2570 || vmanip.m_data[i].getContent() == c_gravel
2571 ) && (air_detected || water_detected))
2573 if(current_depth == 0 && y <= WATER_LEVEL+2
2574 && possibly_have_sand)
2577 if(current_depth < 4)
2581 vmanip.m_data[i] = MapNode(c_sand);
2584 else if(current_depth==0 && !water_detected
2585 && y >= WATER_LEVEL && air_detected)
2586 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2589 vmanip.m_data[i] = MapNode(c_dirt);
2593 if(vmanip.m_data[i].getContent() == c_dirt
2594 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2595 vmanip.m_data[i] = MapNode(c_stone);
2600 if(current_depth >= 8)
2603 else if(current_depth != 0)
2606 vmanip->m_area.add_y(em, i, -1);
2612 Calculate some stuff
2615 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2616 bool is_jungle = surface_humidity > 0.75;
2618 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2625 PseudoRandom treerandom(blockseed);
2626 // Put trees in random places on part of division
2627 for(u32 i=0; i<tree_count; i++)
2629 s16 x = treerandom.range(node_min.X, node_max.X);
2630 s16 z = treerandom.range(node_min.Z, node_max.Z);
2631 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2632 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2633 // Don't make a tree under water level
2636 // Make sure tree fits (only trees whose starting point is
2637 // at this block are added)
2638 if(y < node_min.Y || y > node_max.Y)
2641 Find exact ground level
2645 for(; p.Y >= y-6; p.Y--)
2647 u32 i = vmanip->m_area.index(p);
2648 MapNode *n = &vmanip->m_data[i];
2649 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2655 // If not found, handle next one
2660 u32 i = vmanip->m_area.index(p);
2661 MapNode *n = &vmanip->m_data[i];
2663 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2666 // Papyrus grows only on mud and in water
2667 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2670 make_papyrus(vmanip, p, ndef);
2672 // Trees grow only on mud and grass, on land
2673 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2676 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2677 if(is_jungle == false)
2680 if(myrand_range(0,4) != 0)
2681 is_apple_tree = false;
2683 is_apple_tree = noise2d_perlin(
2684 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2685 data->seed+342902, 3, 0.45) > 0.2;
2686 make_tree(vmanip, p, is_apple_tree, ndef);
2689 make_jungletree(vmanip, p, ndef);
2691 // Cactii grow only on sand, on land
2692 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2695 make_cactus(vmanip, p, ndef);
2705 PseudoRandom grassrandom(blockseed);
2706 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2708 s16 x = grassrandom.range(node_min.X, node_max.X);
2709 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2710 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2713 if(y < node_min.Y || y > node_max.Y)
2716 Find exact ground level
2720 for(; p.Y >= y-6; p.Y--)
2722 u32 i = vmanip->m_area.index(p);
2723 MapNode *n = &vmanip->m_data[i];
2724 if(data->nodedef->get(*n).is_ground_content)
2730 // If not found, handle next one
2734 if(vmanip.m_area.contains(p) == false)
2736 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2739 if(vmanip.m_area.contains(p))
2740 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2742 if(vmanip.m_area.contains(p))
2743 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2749 Add some kind of random stones
2752 u32 random_stone_count = gen_area_nodes *
2753 randomstone_amount_2d(data->seed, p2d_center);
2754 // Put in random places on part of division
2755 for(u32 i=0; i<random_stone_count; i++)
2757 s16 x = myrand_range(node_min.X, node_max.X);
2758 s16 z = myrand_range(node_min.Z, node_max.Z);
2759 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2760 // Don't add under water level
2761 /*if(y < WATER_LEVEL)
2763 // Don't add if doesn't belong to this block
2764 if(y < node_min.Y || y > node_max.Y)
2769 u32 i = vmanip->m_area.index(v3s16(p));
2770 MapNode *n = &vmanip->m_data[i];
2771 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2774 // Will be placed one higher
2777 make_randomstone(vmanip, p);
2786 u32 large_stone_count = gen_area_nodes *
2787 largestone_amount_2d(data->seed, p2d_center);
2788 //u32 large_stone_count = 1;
2789 // Put in random places on part of division
2790 for(u32 i=0; i<large_stone_count; i++)
2792 s16 x = myrand_range(node_min.X, node_max.X);
2793 s16 z = myrand_range(node_min.Z, node_max.Z);
2794 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2795 // Don't add under water level
2796 /*if(y < WATER_LEVEL)
2798 // Don't add if doesn't belong to this block
2799 if(y < node_min.Y || y > node_max.Y)
2804 u32 i = vmanip->m_area.index(v3s16(p));
2805 MapNode *n = &vmanip->m_data[i];
2806 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2809 // Will be placed one lower
2812 make_largestone(vmanip, p);
2822 PseudoRandom mineralrandom(blockseed);
2827 for(s16 i=0; i<approx_ground_depth/4; i++)
2829 if(mineralrandom.next()%50 == 0)
2831 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2832 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2833 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2834 for(u16 i=0; i<27; i++)
2836 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2837 u32 vi = vmanip.m_area.index(p);
2838 if(vmanip.m_data[vi].getContent() == c_stone)
2839 if(mineralrandom.next()%8 == 0)
2840 vmanip.m_data[vi] = MapNode(c_mese);
2849 u16 a = mineralrandom.range(0,15);
2851 u16 amount = 20 * a/1000;
2852 for(s16 i=0; i<amount; i++)
2854 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2855 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2856 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2858 u8 base_content = c_stone;
2859 MapNode new_content(CONTENT_IGNORE);
2862 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2864 new_content = MapNode(c_stone_with_coal);
2868 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2869 new_content = MapNode(c_stone_with_iron);
2870 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2871 vmanip.m_data[i] = MapNode(c_dirt);
2873 vmanip.m_data[i] = MapNode(c_sand);*/
2875 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2879 if(new_content.getContent() != CONTENT_IGNORE)
2881 for(u16 i=0; i<27; i++)
2883 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2884 u32 vi = vmanip.m_area.index(p);
2885 if(vmanip.m_data[vi].getContent() == base_content)
2887 if(mineralrandom.next()%sparseness == 0)
2888 vmanip.m_data[vi] = new_content;
2897 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2898 //for(s16 i=0; i<50; i++)
2899 u16 coal_amount = 30;
2900 u16 coal_rareness = 60 / coal_amount;
2901 if(coal_rareness == 0)
2903 if(mineralrandom.next()%coal_rareness == 0)
2905 u16 a = mineralrandom.next() % 16;
2906 u16 amount = coal_amount * a*a*a / 1000;
2907 for(s16 i=0; i<amount; i++)
2909 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2910 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2911 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2912 for(u16 i=0; i<27; i++)
2914 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2915 u32 vi = vmanip.m_area.index(p);
2916 if(vmanip.m_data[vi].getContent() == c_stone)
2917 if(mineralrandom.next()%8 == 0)
2918 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2925 u16 iron_amount = 8;
2926 u16 iron_rareness = 60 / iron_amount;
2927 if(iron_rareness == 0)
2929 if(mineralrandom.next()%iron_rareness == 0)
2931 u16 a = mineralrandom.next() % 16;
2932 u16 amount = iron_amount * a*a*a / 1000;
2933 for(s16 i=0; i<amount; i++)
2935 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2936 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2937 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2938 for(u16 i=0; i<27; i++)
2940 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2941 u32 vi = vmanip.m_area.index(p);
2942 if(vmanip.m_data[vi].getContent() == c_stone)
2943 if(mineralrandom.next()%8 == 0)
2944 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2955 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2957 //VoxelArea a(node_min, node_max);
2958 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2959 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2960 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2961 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2962 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2963 for(int i=0; i<2; i++)
2965 enum LightBank bank = banks[i];
2967 core::map<v3s16, bool> light_sources;
2968 core::map<v3s16, u8> unlight_from;
2970 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2971 light_sources, unlight_from);
2973 bool inexistent_top_provides_sunlight = !block_is_underground;
2974 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2975 vmanip, a, inexistent_top_provides_sunlight,
2976 light_sources, ndef);
2977 // TODO: Do stuff according to bottom_sunlight_valid
2979 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2981 vmanip.spreadLight(bank, light_sources, ndef);
2986 #endif ///BIG COMMENT
2988 BlockMakeData::BlockMakeData():
2995 BlockMakeData::~BlockMakeData()
3000 //}; // namespace mapgen