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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
37 Some helper functions for the map generator
41 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
43 v3s16 em = vmanip.m_area.getExtent();
44 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
45 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
46 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
48 for(y=y_nodes_max; y>=y_nodes_min; y--)
50 MapNode &n = vmanip.m_data[i];
51 if(content_walkable(n.d))
54 vmanip.m_area.add_y(em, i, -1);
62 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
64 v3s16 em = vmanip.m_area.getExtent();
65 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
66 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
67 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
69 for(y=y_nodes_max; y>=y_nodes_min; y--)
71 MapNode &n = vmanip.m_data[i];
72 if(content_walkable(n.d)
73 && n.getContent() != LEGN(ndef, "CONTENT_TREE")
74 && n.getContent() != LEGN(ndef, "CONTENT_LEAVES"))
77 vmanip.m_area.add_y(em, i, -1);
86 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
87 bool is_apple_tree, INodeDefManager *ndef)
89 MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
90 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
91 MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
93 s16 trunk_h = myrand_range(4, 5);
95 for(s16 ii=0; ii<trunk_h; ii++)
97 if(vmanip.m_area.contains(p1))
98 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
102 // p1 is now the last piece of the trunk
105 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
106 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
107 Buffer<u8> leaves_d(leaves_a.getVolume());
108 for(s32 i=0; i<leaves_a.getVolume(); i++)
111 // Force leaves at near the end of the trunk
114 for(s16 z=-d; z<=d; z++)
115 for(s16 y=-d; y<=d; y++)
116 for(s16 x=-d; x<=d; x++)
118 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
122 // Add leaves randomly
123 for(u32 iii=0; iii<7; iii++)
128 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
129 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
130 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
133 for(s16 z=0; z<=d; z++)
134 for(s16 y=0; y<=d; y++)
135 for(s16 x=0; x<=d; x++)
137 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
141 // Blit leaves to vmanip
142 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
143 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
144 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
148 if(vmanip.m_area.contains(p) == false)
150 u32 vi = vmanip.m_area.index(p);
151 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
152 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
154 u32 i = leaves_a.index(x,y,z);
155 if(leaves_d[i] == 1) {
156 bool is_apple = myrand_range(0,99) < 10;
157 if(is_apple_tree && is_apple) {
158 vmanip.m_data[vi] = applenode;
160 vmanip.m_data[vi] = leavesnode;
166 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
167 INodeDefManager *ndef)
169 MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
170 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
172 for(s16 x=-1; x<=1; x++)
173 for(s16 z=-1; z<=1; z++)
175 if(myrand_range(0, 2) == 0)
177 v3s16 p1 = p0 + v3s16(x,0,z);
178 v3s16 p2 = p0 + v3s16(x,-1,z);
179 if(vmanip.m_area.contains(p2)
180 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
181 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
182 else if(vmanip.m_area.contains(p1))
183 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
186 s16 trunk_h = myrand_range(8, 12);
188 for(s16 ii=0; ii<trunk_h; ii++)
190 if(vmanip.m_area.contains(p1))
191 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
195 // p1 is now the last piece of the trunk
198 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
199 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
200 Buffer<u8> leaves_d(leaves_a.getVolume());
201 for(s32 i=0; i<leaves_a.getVolume(); i++)
204 // Force leaves at near the end of the trunk
207 for(s16 z=-d; z<=d; z++)
208 for(s16 y=-d; y<=d; y++)
209 for(s16 x=-d; x<=d; x++)
211 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
215 // Add leaves randomly
216 for(u32 iii=0; iii<30; iii++)
221 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
222 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
223 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
226 for(s16 z=0; z<=d; z++)
227 for(s16 y=0; y<=d; y++)
228 for(s16 x=0; x<=d; x++)
230 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
234 // Blit leaves to vmanip
235 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
236 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
237 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
241 if(vmanip.m_area.contains(p) == false)
243 u32 vi = vmanip.m_area.index(p);
244 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
245 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
247 u32 i = leaves_a.index(x,y,z);
249 vmanip.m_data[vi] = leavesnode;
253 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
254 INodeDefManager *ndef)
256 MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
258 s16 trunk_h = myrand_range(2, 3);
260 for(s16 ii=0; ii<trunk_h; ii++)
262 if(vmanip.m_area.contains(p1))
263 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
268 void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
269 INodeDefManager *ndef)
271 MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
275 for(s16 ii=0; ii<trunk_h; ii++)
277 if(vmanip.m_area.contains(p1))
278 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
284 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
286 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
288 s16 size = myrand_range(3, 6);
290 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
291 Buffer<u8> stone_d(stone_a.getVolume());
292 for(s32 i=0; i<stone_a.getVolume(); i++)
295 // Force stone at bottom to make it usually touch the ground
297 for(s16 z=0; z<=0; z++)
298 for(s16 y=0; y<=0; y++)
299 for(s16 x=0; x<=0; x++)
301 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
305 // Generate from perlin noise
306 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
307 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
308 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
310 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
311 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
312 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
314 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
316 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
320 u32 vi = stone_a.index(v3s16(x,y,z));
325 /*// Add stone randomly
326 for(u32 iii=0; iii<7; iii++)
331 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
332 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
333 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
336 for(s16 z=0; z<=d; z++)
337 for(s16 y=0; y<=d; y++)
338 for(s16 x=0; x<=d; x++)
340 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
344 // Blit stone to vmanip
345 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
346 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
347 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
351 if(vmanip.m_area.contains(p) == false)
353 u32 vi = vmanip.m_area.index(p);
354 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
355 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
357 u32 i = stone_a.index(x,y,z);
359 vmanip.m_data[vi] = stonenode;
365 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
367 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
369 s16 size = myrand_range(8, 16);
371 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
372 Buffer<u8> stone_d(stone_a.getVolume());
373 for(s32 i=0; i<stone_a.getVolume(); i++)
376 // Force stone at bottom to make it usually touch the ground
378 for(s16 z=0; z<=0; z++)
379 for(s16 y=0; y<=0; y++)
380 for(s16 x=0; x<=0; x++)
382 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
386 // Generate from perlin noise
387 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
388 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
389 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
392 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
393 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
394 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
395 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
396 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
397 double dz = (double)z-mid_z;
398 double dx = (double)x-mid_x;
399 double dy = MYMAX(0, (double)y-mid_y);
400 double r = sqrt(dz*dz+dx*dx+dy*dy);
401 d /= (2*r/size)*2 + 0.01;
404 u32 vi = stone_a.index(v3s16(x,y,z));
409 /*// Add stone randomly
410 for(u32 iii=0; iii<7; iii++)
415 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
416 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
417 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
420 for(s16 z=0; z<=d; z++)
421 for(s16 y=0; y<=d; y++)
422 for(s16 x=0; x<=d; x++)
424 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
428 // Blit stone to vmanip
429 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
430 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
431 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
435 if(vmanip.m_area.contains(p) == false)
437 u32 vi = vmanip.m_area.index(p);
438 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
439 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
441 u32 i = stone_a.index(x,y,z);
443 vmanip.m_data[vi] = stonenode;
449 Dungeon making routines
452 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
453 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
454 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
455 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
457 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
458 INodeDefManager *ndef)
461 for(s16 z=0; z<roomsize.Z; z++)
462 for(s16 y=0; y<roomsize.Y; y++)
465 v3s16 p = roomplace + v3s16(0,y,z);
466 if(vmanip.m_area.contains(p) == false)
468 u32 vi = vmanip.m_area.index(p);
469 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
471 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
474 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
475 if(vmanip.m_area.contains(p) == false)
477 u32 vi = vmanip.m_area.index(p);
478 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
480 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
485 for(s16 x=0; x<roomsize.X; x++)
486 for(s16 y=0; y<roomsize.Y; y++)
489 v3s16 p = roomplace + v3s16(x,y,0);
490 if(vmanip.m_area.contains(p) == false)
492 u32 vi = vmanip.m_area.index(p);
493 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
495 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
498 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
499 if(vmanip.m_area.contains(p) == false)
501 u32 vi = vmanip.m_area.index(p);
502 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
504 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
508 // Make +-Y walls (floor and ceiling)
509 for(s16 z=0; z<roomsize.Z; z++)
510 for(s16 x=0; x<roomsize.X; x++)
513 v3s16 p = roomplace + v3s16(x,0,z);
514 if(vmanip.m_area.contains(p) == false)
516 u32 vi = vmanip.m_area.index(p);
517 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
519 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
522 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
523 if(vmanip.m_area.contains(p) == false)
525 u32 vi = vmanip.m_area.index(p);
526 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
528 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
533 for(s16 z=1; z<roomsize.Z-1; z++)
534 for(s16 y=1; y<roomsize.Y-1; y++)
535 for(s16 x=1; x<roomsize.X-1; x++)
537 v3s16 p = roomplace + v3s16(x,y,z);
538 if(vmanip.m_area.contains(p) == false)
540 u32 vi = vmanip.m_area.index(p);
541 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
542 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
546 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
547 u8 avoid_flags, MapNode n, u8 or_flags)
549 for(s16 z=0; z<size.Z; z++)
550 for(s16 y=0; y<size.Y; y++)
551 for(s16 x=0; x<size.X; x++)
553 v3s16 p = place + v3s16(x,y,z);
554 if(vmanip.m_area.contains(p) == false)
556 u32 vi = vmanip.m_area.index(p);
557 if(vmanip.m_flags[vi] & avoid_flags)
559 vmanip.m_flags[vi] |= or_flags;
560 vmanip.m_data[vi] = n;
564 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
565 INodeDefManager *ndef)
567 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
568 VMANIP_FLAG_DUNGEON_INSIDE);
571 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
572 INodeDefManager *ndef)
574 make_hole1(vmanip, doorplace, ndef);
575 // Place torch (for testing)
576 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
579 static v3s16 rand_ortho_dir(PseudoRandom &random)
581 if(random.next()%2==0)
582 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
584 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
587 static v3s16 turn_xz(v3s16 olddir, int t)
607 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
609 int turn = random.range(0,2);
618 dir = turn_xz(olddir, 0);
621 dir = turn_xz(olddir, 1);
625 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
626 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
627 PseudoRandom &random, INodeDefManager *ndef)
629 make_hole1(vmanip, doorplace, ndef);
630 v3s16 p0 = doorplace;
634 length = random.range(1,13);
636 length = random.range(1,6);
637 length = random.range(1,13);
638 u32 partlength = random.range(1,13);
641 if(random.next()%2 == 0 && partlength >= 3)
642 make_stairs = random.next()%2 ? 1 : -1;
643 for(u32 i=0; i<length; i++)
649 /*// If already empty
650 if(vmanip.getNodeNoExNoEmerge(p).getContent()
652 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
657 if(vmanip.m_area.contains(p) == true
658 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
662 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
663 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
664 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
665 VMANIP_FLAG_DUNGEON_INSIDE);
666 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
667 VMANIP_FLAG_DUNGEON_INSIDE);
671 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
672 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
673 make_hole1(vmanip, p, ndef);
674 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
675 VMANIP_FLAG_DUNGEON_INSIDE);*/
682 // Can't go here, turn away
683 dir = turn_xz(dir, random.range(0,1));
684 make_stairs = -make_stairs;
686 partlength = random.range(1,length);
691 if(partcount >= partlength)
695 dir = random_turn(random, dir);
697 partlength = random.range(1,length);
700 if(random.next()%2 == 0 && partlength >= 3)
701 make_stairs = random.next()%2 ? 1 : -1;
712 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
713 INodeDefManager *ndef):
724 m_dir = rand_ortho_dir(m_random);
727 void setPos(v3s16 pos)
732 void setDir(v3s16 dir)
737 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
739 for(u32 i=0; i<100; i++)
741 v3s16 p = m_pos + m_dir;
742 v3s16 p1 = p + v3s16(0,1,0);
743 if(vmanip.m_area.contains(p) == false
744 || vmanip.m_area.contains(p1) == false
750 if(vmanip.getNodeNoExNoEmerge(p).getContent()
751 == LEGN(m_ndef, "CONTENT_COBBLE")
752 && vmanip.getNodeNoExNoEmerge(p1).getContent()
753 == LEGN(m_ndef, "CONTENT_COBBLE"))
755 // Found wall, this is a good place!
758 // Randomize next direction
763 Determine where to move next
765 // Jump one up if the actual space is there
766 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
767 == LEGN(m_ndef, "CONTENT_COBBLE")
768 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
769 == LEGN(m_ndef, "CONTENT_AIR")
770 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
771 == LEGN(m_ndef, "CONTENT_AIR"))
773 // Jump one down if the actual space is there
774 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
775 == LEGN(m_ndef, "CONTENT_COBBLE")
776 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
777 == LEGN(m_ndef, "CONTENT_AIR")
778 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
779 == LEGN(m_ndef, "CONTENT_AIR"))
781 // Check if walking is now possible
782 if(vmanip.getNodeNoExNoEmerge(p).getContent()
783 != LEGN(m_ndef, "CONTENT_AIR")
784 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
785 != LEGN(m_ndef, "CONTENT_AIR"))
787 // Cannot continue walking here
797 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
798 v3s16 &result_doordir, v3s16 &result_roomplace)
800 for(s16 trycount=0; trycount<30; trycount++)
804 bool r = findPlaceForDoor(doorplace, doordir);
808 // X east, Z north, Y up
810 if(doordir == v3s16(1,0,0)) // X+
811 roomplace = doorplace +
812 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
813 if(doordir == v3s16(-1,0,0)) // X-
814 roomplace = doorplace +
815 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
816 if(doordir == v3s16(0,0,1)) // Z+
817 roomplace = doorplace +
818 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
819 if(doordir == v3s16(0,0,-1)) // Z-
820 roomplace = doorplace +
821 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
824 if(doordir == v3s16(1,0,0)) // X+
825 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
826 if(doordir == v3s16(-1,0,0)) // X-
827 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
828 if(doordir == v3s16(0,0,1)) // Z+
829 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
830 if(doordir == v3s16(0,0,-1)) // Z-
831 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
836 for(s16 z=1; z<roomsize.Z-1; z++)
837 for(s16 y=1; y<roomsize.Y-1; y++)
838 for(s16 x=1; x<roomsize.X-1; x++)
840 v3s16 p = roomplace + v3s16(x,y,z);
841 if(vmanip.m_area.contains(p) == false)
846 if(vmanip.m_flags[vmanip.m_area.index(p)]
847 & VMANIP_FLAG_DUNGEON_INSIDE)
858 result_doorplace = doorplace;
859 result_doordir = doordir;
860 result_roomplace = roomplace;
867 VoxelManipulator &vmanip;
870 PseudoRandom &m_random;
871 INodeDefManager *m_ndef;
874 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
875 INodeDefManager *ndef)
877 v3s16 areasize = vmanip.m_area.getExtent();
882 Find place for first room
885 for(u32 i=0; i<100; i++)
887 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
888 roomplace = vmanip.m_area.MinEdge + v3s16(
889 random.range(0,areasize.X-roomsize.X-1),
890 random.range(0,areasize.Y-roomsize.Y-1),
891 random.range(0,areasize.Z-roomsize.Z-1));
893 Check that we're not putting the room to an unknown place,
894 otherwise it might end up floating in the air
897 for(s16 z=1; z<roomsize.Z-1; z++)
898 for(s16 y=1; y<roomsize.Y-1; y++)
899 for(s16 x=1; x<roomsize.X-1; x++)
901 v3s16 p = roomplace + v3s16(x,y,z);
902 u32 vi = vmanip.m_area.index(p);
903 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
908 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
922 Stores the center position of the last room made, so that
923 a new corridor can be started from the last room instead of
924 the new room, if chosen so.
926 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
928 u32 room_count = random.range(2,7);
929 for(u32 i=0; i<room_count; i++)
931 // Make a room to the determined place
932 make_room1(vmanip, roomsize, roomplace, ndef);
934 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
936 // Place torch at room center (for testing)
937 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
940 if(i == room_count-1)
943 // Determine walker start position
945 bool start_in_last_room = (random.range(0,2)!=0);
946 //bool start_in_last_room = true;
948 v3s16 walker_start_place;
950 if(start_in_last_room)
952 walker_start_place = last_room_center;
956 walker_start_place = room_center;
957 // Store center of current room as the last one
958 last_room_center = room_center;
961 // Create walker and find a place for a door
962 RoomWalker walker(vmanip, walker_start_place, random, ndef);
965 bool r = walker.findPlaceForDoor(doorplace, doordir);
969 if(random.range(0,1)==0)
971 make_door1(vmanip, doorplace, doordir, ndef);
973 // Don't actually make a door
974 doorplace -= doordir;
976 // Make a random corridor starting from the door
978 v3s16 corridor_end_dir;
979 make_corridor(vmanip, doorplace, doordir, corridor_end,
980 corridor_end_dir, random, ndef);
982 // Find a place for a random sized room
983 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
984 walker.setPos(corridor_end);
985 walker.setDir(corridor_end_dir);
986 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
990 if(random.range(0,1)==0)
992 make_door1(vmanip, doorplace, doordir, ndef);
994 // Don't actually make a door
995 roomplace -= doordir;
1000 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
1001 INodeDefManager *ndef)
1005 s32 r = random.range(0, 3);
1007 dir = v3s16( 1, 0, 0);
1011 dir = v3s16(-1, 0, 0);
1015 dir = v3s16( 0, 0, 1);
1019 dir = v3s16( 0, 0,-1);
1022 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1023 16+random.range(0,15),
1024 16+random.range(0,15),
1025 16+random.range(0,15));
1026 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC"), facedir_i);
1027 u32 length = random.range(3,15);
1028 for(u32 j=0; j<length; j++)
1031 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
1036 Noise functions. Make sure seed is mangled differently in each one.
1040 Scaling the output of the noise function affects the overdrive of the
1041 contour function, which affects the shape of the output considerably.
1043 #define CAVE_NOISE_SCALE 12.0
1044 //#define CAVE_NOISE_SCALE 10.0
1045 //#define CAVE_NOISE_SCALE 7.5
1046 //#define CAVE_NOISE_SCALE 5.0
1047 //#define CAVE_NOISE_SCALE 1.0
1049 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1050 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1052 NoiseParams get_cave_noise1_params(u64 seed)
1054 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1055 200, CAVE_NOISE_SCALE);*/
1056 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1057 100, CAVE_NOISE_SCALE);*/
1058 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1059 100, CAVE_NOISE_SCALE);*/
1060 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1061 100, CAVE_NOISE_SCALE);*/
1062 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1063 50, CAVE_NOISE_SCALE);
1064 //return NoiseParams(NOISE_CONSTANT_ONE);
1067 NoiseParams get_cave_noise2_params(u64 seed)
1069 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1070 200, CAVE_NOISE_SCALE);*/
1071 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1072 100, CAVE_NOISE_SCALE);*/
1073 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1074 100, CAVE_NOISE_SCALE);*/
1075 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1076 50, CAVE_NOISE_SCALE);
1077 //return NoiseParams(NOISE_CONSTANT_ONE);
1080 NoiseParams get_ground_noise1_params(u64 seed)
1082 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1086 NoiseParams get_ground_crumbleness_params(u64 seed)
1088 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1092 NoiseParams get_ground_wetness_params(u64 seed)
1094 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1098 bool is_cave(u64 seed, v3s16 p)
1100 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1101 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1102 return d1*d2 > CAVE_NOISE_THRESHOLD;
1106 Ground density noise shall be interpreted by using this.
1108 TODO: No perlin noises here, they should be outsourced
1110 NOTE: The speed of these actually isn't terrible
1112 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1114 //return ((double)p.Y < ground_noise1_val);
1116 double f = 0.55 + noise2d_perlin(
1117 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1118 seed+920381, 3, 0.45);
1123 double h = WATER_LEVEL + 10 * noise2d_perlin(
1124 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1125 seed+84174, 4, 0.5);
1128 return ((double)p.Y - h < ground_noise1_val * f);
1132 Queries whether a position is ground or not.
1134 bool is_ground(u64 seed, v3s16 p)
1136 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1137 return val_is_ground(val1, p, seed);
1140 // Amount of trees per area in nodes
1141 double tree_amount_2d(u64 seed, v2s16 p)
1143 /*double noise = noise2d_perlin(
1144 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1146 double noise = noise2d_perlin(
1147 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1149 double zeroval = -0.39;
1153 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1156 double surface_humidity_2d(u64 seed, v2s16 p)
1158 double noise = noise2d_perlin(
1159 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1160 seed+72384, 4, 0.66);
1161 noise = (noise + 1.0)/2.0;
1170 double randomstone_amount_2d(u64 seed, v2s16 p)
1172 double noise = noise2d_perlin(
1173 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1174 seed+3829434, 5, 0.66);
1175 double zeroval = 0.1;
1179 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1183 double largestone_amount_2d(u64 seed, v2s16 p)
1185 double noise = noise2d_perlin(
1186 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1187 seed+14143242, 5, 0.66);
1188 double zeroval = 0.3;
1192 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1196 Incrementally find ground level from 3d noise
1198 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1200 // Start a bit fuzzy to make averaging lower precision values
1202 s16 level = myrand_range(-precision/2, precision/2);
1203 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1205 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1207 // First find non-ground by going upwards
1208 // Don't stop in caves.
1210 s16 max = level+dec[i-1]*2;
1211 v3s16 p(p2d.X, level, p2d.Y);
1212 for(; p.Y < max; p.Y += dec[i])
1214 if(!is_ground(seed, p))
1221 // Then find ground by going downwards from there.
1222 // Go in caves, too, when precision is 1.
1224 s16 min = level-dec[i-1]*2;
1225 v3s16 p(p2d.X, level, p2d.Y);
1226 for(; p.Y>min; p.Y-=dec[i])
1228 bool ground = is_ground(seed, p);
1229 /*if(dec[i] == 1 && is_cave(seed, p))
1240 // This is more like the actual ground level
1241 level += dec[i-1]/2;
1246 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1248 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1250 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1251 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1253 a += find_ground_level_from_noise(seed,
1254 v2s16(node_min.X, node_min.Y), p);
1255 a += find_ground_level_from_noise(seed,
1256 v2s16(node_min.X, node_max.Y), p);
1257 a += find_ground_level_from_noise(seed,
1258 v2s16(node_max.X, node_max.Y), p);
1259 a += find_ground_level_from_noise(seed,
1260 v2s16(node_max.X, node_min.Y), p);
1261 a += find_ground_level_from_noise(seed,
1262 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1267 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1269 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1271 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1272 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1275 a = MYMAX(a, find_ground_level_from_noise(seed,
1276 v2s16(node_min.X, node_min.Y), p));
1277 a = MYMAX(a, find_ground_level_from_noise(seed,
1278 v2s16(node_min.X, node_max.Y), p));
1279 a = MYMAX(a, find_ground_level_from_noise(seed,
1280 v2s16(node_max.X, node_max.Y), p));
1281 a = MYMAX(a, find_ground_level_from_noise(seed,
1282 v2s16(node_min.X, node_min.Y), p));
1284 a = MYMAX(a, find_ground_level_from_noise(seed,
1285 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1286 // Side middle points
1287 a = MYMAX(a, find_ground_level_from_noise(seed,
1288 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1289 a = MYMAX(a, find_ground_level_from_noise(seed,
1290 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1291 a = MYMAX(a, find_ground_level_from_noise(seed,
1292 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1293 a = MYMAX(a, find_ground_level_from_noise(seed,
1294 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1298 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1300 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1302 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1303 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1306 a = MYMIN(a, find_ground_level_from_noise(seed,
1307 v2s16(node_min.X, node_min.Y), p));
1308 a = MYMIN(a, find_ground_level_from_noise(seed,
1309 v2s16(node_min.X, node_max.Y), p));
1310 a = MYMIN(a, find_ground_level_from_noise(seed,
1311 v2s16(node_max.X, node_max.Y), p));
1312 a = MYMIN(a, find_ground_level_from_noise(seed,
1313 v2s16(node_min.X, node_min.Y), p));
1315 a = MYMIN(a, find_ground_level_from_noise(seed,
1316 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1317 // Side middle points
1318 a = MYMIN(a, find_ground_level_from_noise(seed,
1319 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1320 a = MYMIN(a, find_ground_level_from_noise(seed,
1321 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1322 a = MYMIN(a, find_ground_level_from_noise(seed,
1323 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1324 a = MYMIN(a, find_ground_level_from_noise(seed,
1325 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1329 bool block_is_underground(u64 seed, v3s16 blockpos)
1331 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1332 seed, v2s16(blockpos.X, blockpos.Z));
1334 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1341 #define AVERAGE_MUD_AMOUNT 4
1343 double base_rock_level_2d(u64 seed, v2s16 p)
1345 // The base ground level
1346 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1347 + 20. * noise2d_perlin(
1348 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1349 (seed>>32)+654879876, 6, 0.6);
1351 /*// A bit hillier one
1352 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1353 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1354 (seed>>27)+90340, 6, 0.69);
1358 // Higher ground level
1359 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1360 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1361 seed+85039, 5, 0.69);
1362 //higher = 30; // For debugging
1364 // Limit higher to at least base
1368 // Steepness factor of cliffs
1369 double b = 1.0 + 1.0 * noise2d_perlin(
1370 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1372 b = rangelim(b, 0.0, 1000.0);
1375 b = rangelim(b, 3.0, 1000.0);
1376 //dstream<<"b="<<b<<std::endl;
1379 // Offset to more low
1380 double a_off = -0.2;
1381 // High/low selector
1382 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1383 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1384 seed-359, 6, 0.7));*/
1385 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1386 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1387 seed-359, 5, 0.60));
1389 a = rangelim(a, 0.0, 1.0);
1391 //dstream<<"a="<<a<<std::endl;
1393 double h = base*(1.0-a) + higher*a;
1400 double get_mud_add_amount(u64 seed, v2s16 p)
1402 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1403 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1404 seed+91013, 3, 0.55));
1408 bool get_have_sand(u64 seed, v2s16 p2d)
1410 // Determine whether to have sand here
1411 double sandnoise = noise2d_perlin(
1412 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1413 seed+59420, 3, 0.50);
1415 return (sandnoise > -0.15);
1419 Adds random objects to block, depending on the content of the block
1421 void add_random_objects(MapBlock *block)
1424 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1425 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1427 bool last_node_walkable = false;
1428 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1431 MapNode n = block->getNodeNoEx(p);
1432 if(n.getContent() == CONTENT_IGNORE)
1434 if(data->nodedef->get(n)->liquid_type != LIQUID_NONE)
1436 if(data->nodedef->get(n)->walkable)
1438 last_node_walkable = true;
1441 if(last_node_walkable)
1443 // If block contains light information
1444 if(content_features(n).param_type == CPT_LIGHT)
1446 if(n.getLight(LIGHTBANK_DAY) <= 3)
1448 if(myrand() % 300 == 0)
1450 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1452 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1453 std::string data = obj->getStaticData();
1454 StaticObject s_obj(obj->getType(),
1455 obj->getBasePosition(), data);
1457 block->m_static_objects.insert(0, s_obj);
1458 block->m_static_objects.insert(0, s_obj);
1459 block->m_static_objects.insert(0, s_obj);
1460 block->m_static_objects.insert(0, s_obj);
1461 block->m_static_objects.insert(0, s_obj);
1462 block->m_static_objects.insert(0, s_obj);
1465 if(myrand() % 1000 == 0)
1467 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1469 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1470 std::string data = obj->getStaticData();
1471 StaticObject s_obj(obj->getType(),
1472 obj->getBasePosition(), data);
1474 block->m_static_objects.insert(0, s_obj);
1480 last_node_walkable = false;
1483 block->raiseModified(MOD_STATE_WRITE_NEEDED, "mapgen::add_random_objects");
1487 void make_block(BlockMakeData *data)
1491 //dstream<<"makeBlock: no-op"<<std::endl;
1495 assert(data->vmanip);
1496 assert(data->nodedef);
1497 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1498 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1499 data->blockpos_requested.Z >= data->blockpos_min.Z);
1500 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1501 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1502 data->blockpos_requested.Z <= data->blockpos_max.Z);
1504 INodeDefManager *ndef = data->nodedef;
1506 // Hack: use minimum block coordinates for old code that assumes
1508 v3s16 blockpos = data->blockpos_requested;
1510 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1511 <<blockpos.Z<<")"<<std::endl;*/
1513 v3s16 blockpos_min = data->blockpos_min;
1514 v3s16 blockpos_max = data->blockpos_max;
1515 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1516 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1518 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1519 // Area of center block
1520 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1521 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1522 // Full allocated area
1523 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1524 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1526 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1528 int rel_volume = (blockpos_max.X - blockpos_min.X + 1)
1529 * (blockpos_max.Y - blockpos_min.Y + 1)
1530 * (blockpos_max.Z - blockpos_max.Z + 1);
1532 // Area of the block we are generating
1533 double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1536 Get average ground level from noise
1537 TODO: These are currently crap because they assume we are
1538 dealing with a single MapBlock only. Fix them.
1541 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1542 data->seed, v2s16(blockpos.X, blockpos.Z));
1543 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1545 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1547 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1548 data->seed, v2s16(blockpos.X, blockpos.Z));
1549 // Minimum amount of ground above the top of the central block
1550 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1552 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1553 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1554 // Maximum amount of ground above the bottom of the central block
1555 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1557 // Horribly wrong heuristic, but better than nothing
1558 bool block_is_underground = (minimum_ground_depth >
1559 MAP_BLOCKSIZE * (data->blockpos_max.X
1560 - data->blockpos_min.X + 1) / 2);
1563 If block is deep underground, this is set to true and ground
1564 density noise is not generated, for speed optimization.
1566 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1569 Create a block-specific seed
1571 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1572 + full_node_min.Y*42123 + full_node_min.X*23;
1578 //NoiseBuffer noisebuf1;
1579 //NoiseBuffer noisebuf2;
1580 NoiseBuffer noisebuf_cave;
1581 NoiseBuffer noisebuf_ground;
1582 NoiseBuffer noisebuf_ground_crumbleness;
1583 NoiseBuffer noisebuf_ground_wetness;
1585 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1586 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1588 //TimeTaker timer("noisebuf.create");
1594 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1595 minpos_f.X, minpos_f.Y, minpos_f.Z,
1596 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1598 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1606 v3f sl = v3f(4.0, 4.0, 4.0);
1611 if(all_is_ground_except_caves == false)
1612 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1613 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1614 minpos_f.X, minpos_f.Y, minpos_f.Z,
1615 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1619 Ground property noise
1621 sl = v3f(2.5, 2.5, 2.5);
1622 noisebuf_ground_crumbleness.create(
1623 get_ground_crumbleness_params(data->seed),
1624 minpos_f.X, minpos_f.Y, minpos_f.Z,
1625 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1627 noisebuf_ground_wetness.create(
1628 get_ground_wetness_params(data->seed),
1629 minpos_f.X, minpos_f.Y, minpos_f.Z,
1630 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1635 Cache some ground type values for speed
1638 // Creates variables c_name=id and n_name=node
1639 #define CONTENT_VARIABLE(ndef, name)\
1640 content_t c_##name = ndef->getId(#name);\
1641 MapNode n_##name(c_##name);
1643 CONTENT_VARIABLE(ndef, stone);
1644 CONTENT_VARIABLE(ndef, air);
1645 CONTENT_VARIABLE(ndef, water_source);
1646 CONTENT_VARIABLE(ndef, dirt);
1647 CONTENT_VARIABLE(ndef, sand);
1648 CONTENT_VARIABLE(ndef, gravel);
1649 CONTENT_VARIABLE(ndef, clay);
1650 CONTENT_VARIABLE(ndef, lava_source);
1651 CONTENT_VARIABLE(ndef, cobble);
1652 CONTENT_VARIABLE(ndef, mossycobble);
1653 CONTENT_VARIABLE(ndef, dirt_with_grass);
1654 CONTENT_VARIABLE(ndef, junglegrass);
1655 CONTENT_VARIABLE(ndef, stone_with_coal);
1656 CONTENT_VARIABLE(ndef, stone_with_iron);
1657 CONTENT_VARIABLE(ndef, mese);
1660 Make base ground level
1663 for(s16 x=node_min.X; x<=node_max.X; x++)
1664 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1669 // Use fast index incrementing
1670 v3s16 em = vmanip.m_area.getExtent();
1671 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1672 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1674 // Only modify places that have no content
1675 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1677 // First priority: make air and water.
1678 // This avoids caves inside water.
1679 if(all_is_ground_except_caves == false
1680 && val_is_ground(noisebuf_ground.get(x,y,z),
1681 v3s16(x,y,z), data->seed) == false)
1683 if(y <= WATER_LEVEL)
1684 vmanip.m_data[i] = n_water_source;
1686 vmanip.m_data[i] = n_air;
1688 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1689 vmanip.m_data[i] = n_air;
1691 vmanip.m_data[i] = n_stone;
1694 data->vmanip->m_area.add_y(em, i, 1);
1700 Add mud and sand and others underground (in place of stone)
1703 for(s16 x=node_min.X; x<=node_max.X; x++)
1704 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1709 // Use fast index incrementing
1710 v3s16 em = vmanip.m_area.getExtent();
1711 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1712 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1714 if(vmanip.m_data[i].getContent() == c_stone)
1716 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1718 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1719 vmanip.m_data[i] = n_dirt;
1721 vmanip.m_data[i] = n_sand;
1723 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1725 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1726 vmanip.m_data[i] = n_gravel;
1728 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1729 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1731 vmanip.m_data[i] = n_lava_source;
1732 for(s16 x1=-1; x1<=1; x1++)
1733 for(s16 y1=-1; y1<=1; y1++)
1734 for(s16 z1=-1; z1<=1; z1++)
1735 data->transforming_liquid.push_back(
1736 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1740 data->vmanip->m_area.add_y(em, i, -1);
1749 //if(node_min.Y < approx_groundlevel)
1750 //if(myrand() % 3 == 0)
1751 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1752 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1753 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1754 float dungeon_rarity = 0.02;
1755 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1757 && node_min.Y < approx_groundlevel)
1759 // Dungeon generator doesn't modify places which have this set
1760 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1761 | VMANIP_FLAG_DUNGEON_PRESERVE);
1763 // Set all air and water to be untouchable to make dungeons open
1764 // to caves and open air
1765 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1766 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1771 // Use fast index incrementing
1772 v3s16 em = vmanip.m_area.getExtent();
1773 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1774 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1776 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1777 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1778 else if(vmanip.m_data[i].getContent() == c_water_source)
1779 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1780 data->vmanip->m_area.add_y(em, i, -1);
1785 PseudoRandom random(blockseed+2);
1788 make_dungeon1(vmanip, random, ndef);
1790 // Convert some cobble to mossy cobble
1791 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1792 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1797 // Use fast index incrementing
1798 v3s16 em = vmanip.m_area.getExtent();
1799 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1800 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1802 // (noisebuf not used because it doesn't contain the
1804 double wetness = noise3d_param(
1805 get_ground_wetness_params(data->seed), x,y,z);
1806 double d = noise3d_perlin((float)x/2.5,
1807 (float)y/2.5,(float)z/2.5,
1809 if(vmanip.m_data[i].getContent() == c_cobble)
1813 vmanip.m_data[i].setContent(c_mossycobble);
1816 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1819 vmanip.m_data[i].setContent(c_dirt);
1821 data->vmanip->m_area.add_y(em, i, -1);
1831 PseudoRandom ncrandom(blockseed+9324342);
1832 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1834 make_nc(vmanip, ncrandom, ndef);
1839 Add top and bottom side of water to transforming_liquid queue
1842 for(s16 x=node_min.X; x<=node_max.X; x++)
1843 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1848 bool water_found = false;
1849 // Use fast index incrementing
1850 v3s16 em = vmanip.m_area.getExtent();
1851 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1852 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1854 if(water_found == false)
1856 if(vmanip.m_data[i].getContent() == c_water_source)
1858 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1859 data->transforming_liquid.push_back(p);
1865 // This can be done because water_found can only
1866 // turn to true and end up here after going through
1868 if(vmanip.m_data[i+1].getContent() != c_water_source)
1870 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1871 data->transforming_liquid.push_back(p);
1872 water_found = false;
1876 data->vmanip->m_area.add_y(em, i, -1);
1882 If close to ground level
1885 //if(abs(approx_ground_depth) < 30)
1886 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1892 for(s16 x=node_min.X; x<=node_max.X; x++)
1893 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1898 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1899 bool have_sand = false;
1900 u32 current_depth = 0;
1901 bool air_detected = false;
1902 bool water_detected = false;
1903 bool have_clay = false;
1905 // Use fast index incrementing
1906 s16 start_y = node_max.Y+2;
1907 v3s16 em = vmanip.m_area.getExtent();
1908 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1909 for(s16 y=start_y; y>=node_min.Y-3; y--)
1911 if(vmanip.m_data[i].getContent() == c_water_source)
1912 water_detected = true;
1913 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1914 air_detected = true;
1916 if((vmanip.m_data[i].getContent() == c_stone
1917 || vmanip.m_data[i].getContent() == c_dirt_with_grass
1918 || vmanip.m_data[i].getContent() == c_dirt
1919 || vmanip.m_data[i].getContent() == c_sand
1920 || vmanip.m_data[i].getContent() == c_gravel
1921 ) && (air_detected || water_detected))
1923 if(current_depth == 0 && y <= WATER_LEVEL+2
1924 && possibly_have_sand)
1927 if(current_depth < 4)
1931 // Determine whether to have clay in the sand here
1932 double claynoise = noise2d_perlin(
1933 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1934 data->seed+4321, 6, 0.95) + 0.5;
1936 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
1937 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
1938 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
1941 vmanip.m_data[i] = MapNode(c_clay);
1943 vmanip.m_data[i] = MapNode(c_sand);
1946 else if(current_depth==0 && !water_detected
1947 && y >= WATER_LEVEL && air_detected)
1948 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
1951 vmanip.m_data[i] = MapNode(c_dirt);
1955 if(vmanip.m_data[i].getContent() == c_dirt
1956 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
1957 vmanip.m_data[i] = MapNode(c_stone);
1962 if(current_depth >= 8)
1965 else if(current_depth != 0)
1968 data->vmanip->m_area.add_y(em, i, -1);
1974 Calculate some stuff
1977 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
1978 bool is_jungle = surface_humidity > 0.75;
1980 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
1987 PseudoRandom treerandom(blockseed);
1988 // Put trees in random places on part of division
1989 for(u32 i=0; i<tree_count; i++)
1991 s16 x = treerandom.range(node_min.X, node_max.X);
1992 s16 z = treerandom.range(node_min.Z, node_max.Z);
1993 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
1994 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
1995 // Don't make a tree under water level
1998 // Make sure tree fits (only trees whose starting point is
1999 // at this block are added)
2000 if(y < node_min.Y || y > node_max.Y)
2003 Find exact ground level
2007 for(; p.Y >= y-6; p.Y--)
2009 u32 i = data->vmanip->m_area.index(p);
2010 MapNode *n = &data->vmanip->m_data[i];
2011 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2017 // If not found, handle next one
2022 u32 i = data->vmanip->m_area.index(p);
2023 MapNode *n = &data->vmanip->m_data[i];
2025 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2028 // Papyrus grows only on mud and in water
2029 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2032 make_papyrus(vmanip, p, ndef);
2034 // Trees grow only on mud and grass, on land
2035 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2038 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2039 if(is_jungle == false)
2042 if(myrand_range(0,4) != 0)
2043 is_apple_tree = false;
2045 is_apple_tree = noise2d_perlin(
2046 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2047 data->seed+342902, 3, 0.45) > 0.2;
2048 make_tree(vmanip, p, is_apple_tree, ndef);
2051 make_jungletree(vmanip, p, ndef);
2053 // Cactii grow only on sand, on land
2054 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2057 make_cactus(vmanip, p, ndef);
2067 PseudoRandom grassrandom(blockseed);
2068 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2070 s16 x = grassrandom.range(node_min.X, node_max.X);
2071 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2072 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2075 if(y < node_min.Y || y > node_max.Y)
2078 Find exact ground level
2082 for(; p.Y >= y-6; p.Y--)
2084 u32 i = data->vmanip->m_area.index(p);
2085 MapNode *n = &data->vmanip->m_data[i];
2086 if(data->nodedef->get(*n).is_ground_content)
2092 // If not found, handle next one
2096 if(vmanip.m_area.contains(p) == false)
2098 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2101 if(vmanip.m_area.contains(p))
2102 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2104 if(vmanip.m_area.contains(p))
2105 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2111 Add some kind of random stones
2114 u32 random_stone_count = gen_area_nodes *
2115 randomstone_amount_2d(data->seed, p2d_center);
2116 // Put in random places on part of division
2117 for(u32 i=0; i<random_stone_count; i++)
2119 s16 x = myrand_range(node_min.X, node_max.X);
2120 s16 z = myrand_range(node_min.Z, node_max.Z);
2121 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2122 // Don't add under water level
2123 /*if(y < WATER_LEVEL)
2125 // Don't add if doesn't belong to this block
2126 if(y < node_min.Y || y > node_max.Y)
2131 u32 i = data->vmanip->m_area.index(v3s16(p));
2132 MapNode *n = &data->vmanip->m_data[i];
2133 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2136 // Will be placed one higher
2139 make_randomstone(data->vmanip, p);
2148 u32 large_stone_count = gen_area_nodes *
2149 largestone_amount_2d(data->seed, p2d_center);
2150 //u32 large_stone_count = 1;
2151 // Put in random places on part of division
2152 for(u32 i=0; i<large_stone_count; i++)
2154 s16 x = myrand_range(node_min.X, node_max.X);
2155 s16 z = myrand_range(node_min.Z, node_max.Z);
2156 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2157 // Don't add under water level
2158 /*if(y < WATER_LEVEL)
2160 // Don't add if doesn't belong to this block
2161 if(y < node_min.Y || y > node_max.Y)
2166 u32 i = data->vmanip->m_area.index(v3s16(p));
2167 MapNode *n = &data->vmanip->m_data[i];
2168 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2171 // Will be placed one lower
2174 make_largestone(data->vmanip, p);
2184 PseudoRandom mineralrandom(blockseed);
2189 for(s16 i=0; i<approx_ground_depth/4; i++)
2191 if(mineralrandom.next()%50 == 0)
2193 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2194 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2195 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2196 for(u16 i=0; i<27; i++)
2198 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2199 u32 vi = vmanip.m_area.index(p);
2200 if(vmanip.m_data[vi].getContent() == c_stone)
2201 if(mineralrandom.next()%8 == 0)
2202 vmanip.m_data[vi] = MapNode(c_mese);
2211 u16 a = mineralrandom.range(0,15);
2213 u16 amount = 20 * a/1000;
2214 for(s16 i=0; i<amount; i++)
2216 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2217 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2218 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2220 u8 base_content = c_stone;
2221 MapNode new_content(CONTENT_IGNORE);
2224 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2226 new_content = MapNode(c_stone_with_coal);
2230 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2231 new_content = MapNode(c_stone_with_iron);
2232 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2233 vmanip.m_data[i] = MapNode(c_dirt);
2235 vmanip.m_data[i] = MapNode(c_sand);*/
2237 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2241 if(new_content.getContent() != CONTENT_IGNORE)
2243 for(u16 i=0; i<27; i++)
2245 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2246 u32 vi = vmanip.m_area.index(p);
2247 if(vmanip.m_data[vi].getContent() == base_content)
2249 if(mineralrandom.next()%sparseness == 0)
2250 vmanip.m_data[vi] = new_content;
2259 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2260 //for(s16 i=0; i<50; i++)
2261 u16 coal_amount = 30;
2262 u16 coal_rareness = 60 / coal_amount;
2263 if(coal_rareness == 0)
2265 if(mineralrandom.next()%coal_rareness == 0)
2267 u16 a = mineralrandom.next() % 16;
2268 u16 amount = coal_amount * a*a*a / 1000;
2269 for(s16 i=0; i<amount; i++)
2271 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2272 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2273 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2274 for(u16 i=0; i<27; i++)
2276 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2277 u32 vi = vmanip.m_area.index(p);
2278 if(vmanip.m_data[vi].getContent() == c_stone)
2279 if(mineralrandom.next()%8 == 0)
2280 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2287 u16 iron_amount = 8;
2288 u16 iron_rareness = 60 / iron_amount;
2289 if(iron_rareness == 0)
2291 if(mineralrandom.next()%iron_rareness == 0)
2293 u16 a = mineralrandom.next() % 16;
2294 u16 amount = iron_amount * a*a*a / 1000;
2295 for(s16 i=0; i<amount; i++)
2297 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2298 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2299 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2300 for(u16 i=0; i<27; i++)
2302 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2303 u32 vi = vmanip.m_area.index(p);
2304 if(vmanip.m_data[vi].getContent() == c_stone)
2305 if(mineralrandom.next()%8 == 0)
2306 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2316 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2318 VoxelArea a(node_min, node_max);
2319 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2320 for(int i=0; i<2; i++)
2322 enum LightBank bank = banks[i];
2324 core::map<v3s16, bool> light_sources;
2325 core::map<v3s16, u8> unlight_from;
2327 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2328 light_sources, unlight_from);
2330 bool inexistent_top_provides_sunlight = !block_is_underground;
2331 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2332 vmanip, a, inexistent_top_provides_sunlight,
2333 light_sources, ndef);
2334 // TODO: Do stuff according to bottom_sunlight_valid
2336 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2338 vmanip.spreadLight(bank, light_sources, ndef);
2343 BlockMakeData::BlockMakeData():
2350 BlockMakeData::~BlockMakeData()
2355 }; // namespace mapgen