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.
22 #include "content_mapnode.h"
27 //#include "serverobject.h"
28 #include "content_sao.h"
34 Some helper functions for the map generator
38 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
40 v3s16 em = vmanip.m_area.getExtent();
41 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
42 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
43 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
45 for(y=y_nodes_max; y>=y_nodes_min; y--)
47 MapNode &n = vmanip.m_data[i];
48 if(content_walkable(n.d))
51 vmanip.m_area.add_y(em, i, -1);
59 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
61 v3s16 em = vmanip.m_area.getExtent();
62 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
63 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
64 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
66 for(y=y_nodes_max; y>=y_nodes_min; y--)
68 MapNode &n = vmanip.m_data[i];
69 if(content_walkable(n.d)
70 && n.getContent() != CONTENT_TREE
71 && n.getContent() != CONTENT_LEAVES)
74 vmanip.m_area.add_y(em, i, -1);
83 static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
85 MapNode treenode(CONTENT_TREE);
86 MapNode leavesnode(CONTENT_LEAVES);
87 MapNode applenode(CONTENT_APPLE);
89 bool is_apple_tree = myrand_range(0,100) < 35?true:false;
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++)
146 bool is_apple = myrand_range(0,100) < 50?true:false;
149 if(vmanip.m_area.contains(p) == false)
151 u32 vi = vmanip.m_area.index(p);
152 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
153 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
155 u32 i = leaves_a.index(x,y,z);
156 if(leaves_d[i] == 1) {
157 if(is_apple_tree && is_apple && apple_count < 4) {
158 vmanip.m_data[vi] = applenode;
161 vmanip.m_data[vi] = leavesnode;
167 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0)
169 MapNode treenode(CONTENT_JUNGLETREE);
170 MapNode leavesnode(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)
255 MapNode papyrusnode(CONTENT_PAPYRUS);
257 s16 trunk_h = myrand_range(2, 3);
259 for(s16 ii=0; ii<trunk_h; ii++)
261 if(vmanip.m_area.contains(p1))
262 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
267 void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
269 MapNode cactusnode(CONTENT_CACTUS);
273 for(s16 ii=0; ii<trunk_h; ii++)
275 if(vmanip.m_area.contains(p1))
276 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
282 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
284 MapNode stonenode(CONTENT_STONE);
286 s16 size = myrand_range(3, 6);
288 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
289 Buffer<u8> stone_d(stone_a.getVolume());
290 for(s32 i=0; i<stone_a.getVolume(); i++)
293 // Force stone at bottom to make it usually touch the ground
295 for(s16 z=0; z<=0; z++)
296 for(s16 y=0; y<=0; y++)
297 for(s16 x=0; x<=0; x++)
299 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
303 // Generate from perlin noise
304 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
305 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
306 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
308 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
309 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
310 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
312 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
314 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
318 u32 vi = stone_a.index(v3s16(x,y,z));
323 /*// Add stone randomly
324 for(u32 iii=0; iii<7; iii++)
329 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
330 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
331 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
334 for(s16 z=0; z<=d; z++)
335 for(s16 y=0; y<=d; y++)
336 for(s16 x=0; x<=d; x++)
338 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
342 // Blit stone to vmanip
343 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
344 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
345 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
349 if(vmanip.m_area.contains(p) == false)
351 u32 vi = vmanip.m_area.index(p);
352 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
353 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
355 u32 i = stone_a.index(x,y,z);
357 vmanip.m_data[vi] = stonenode;
363 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
365 MapNode stonenode(CONTENT_STONE);
367 s16 size = myrand_range(8, 16);
369 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
370 Buffer<u8> stone_d(stone_a.getVolume());
371 for(s32 i=0; i<stone_a.getVolume(); i++)
374 // Force stone at bottom to make it usually touch the ground
376 for(s16 z=0; z<=0; z++)
377 for(s16 y=0; y<=0; y++)
378 for(s16 x=0; x<=0; x++)
380 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
384 // Generate from perlin noise
385 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
386 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
387 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
390 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
391 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
392 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
393 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
394 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
395 double dz = (double)z-mid_z;
396 double dx = (double)x-mid_x;
397 double dy = MYMAX(0, (double)y-mid_y);
398 double r = sqrt(dz*dz+dx*dx+dy*dy);
399 d /= (2*r/size)*2 + 0.01;
402 u32 vi = stone_a.index(v3s16(x,y,z));
407 /*// Add stone randomly
408 for(u32 iii=0; iii<7; iii++)
413 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
414 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
415 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
418 for(s16 z=0; z<=d; z++)
419 for(s16 y=0; y<=d; y++)
420 for(s16 x=0; x<=d; x++)
422 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
426 // Blit stone to vmanip
427 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
428 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
429 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
433 if(vmanip.m_area.contains(p) == false)
435 u32 vi = vmanip.m_area.index(p);
436 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
437 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
439 u32 i = stone_a.index(x,y,z);
441 vmanip.m_data[vi] = stonenode;
447 Dungeon making routines
450 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
451 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
452 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
453 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
455 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
458 for(s16 z=0; z<roomsize.Z; z++)
459 for(s16 y=0; y<roomsize.Y; y++)
462 v3s16 p = roomplace + v3s16(0,y,z);
463 if(vmanip.m_area.contains(p) == false)
465 u32 vi = vmanip.m_area.index(p);
466 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
468 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
471 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
472 if(vmanip.m_area.contains(p) == false)
474 u32 vi = vmanip.m_area.index(p);
475 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
477 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
482 for(s16 x=0; x<roomsize.X; x++)
483 for(s16 y=0; y<roomsize.Y; y++)
486 v3s16 p = roomplace + v3s16(x,y,0);
487 if(vmanip.m_area.contains(p) == false)
489 u32 vi = vmanip.m_area.index(p);
490 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
492 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
495 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
496 if(vmanip.m_area.contains(p) == false)
498 u32 vi = vmanip.m_area.index(p);
499 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
501 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
505 // Make +-Y walls (floor and ceiling)
506 for(s16 z=0; z<roomsize.Z; z++)
507 for(s16 x=0; x<roomsize.X; x++)
510 v3s16 p = roomplace + v3s16(x,0,z);
511 if(vmanip.m_area.contains(p) == false)
513 u32 vi = vmanip.m_area.index(p);
514 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
516 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
519 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
520 if(vmanip.m_area.contains(p) == false)
522 u32 vi = vmanip.m_area.index(p);
523 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
525 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
530 for(s16 z=1; z<roomsize.Z-1; z++)
531 for(s16 y=1; y<roomsize.Y-1; y++)
532 for(s16 x=1; x<roomsize.X-1; x++)
534 v3s16 p = roomplace + v3s16(x,y,z);
535 if(vmanip.m_area.contains(p) == false)
537 u32 vi = vmanip.m_area.index(p);
538 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
539 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
543 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
544 u8 avoid_flags, MapNode n, u8 or_flags)
546 for(s16 z=0; z<size.Z; z++)
547 for(s16 y=0; y<size.Y; y++)
548 for(s16 x=0; x<size.X; x++)
550 v3s16 p = place + v3s16(x,y,z);
551 if(vmanip.m_area.contains(p) == false)
553 u32 vi = vmanip.m_area.index(p);
554 if(vmanip.m_flags[vi] & avoid_flags)
556 vmanip.m_flags[vi] |= or_flags;
557 vmanip.m_data[vi] = n;
561 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
563 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
564 VMANIP_FLAG_DUNGEON_INSIDE);
567 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
569 make_hole1(vmanip, doorplace);
570 // Place torch (for testing)
571 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
574 static v3s16 rand_ortho_dir(PseudoRandom &random)
576 if(random.next()%2==0)
577 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
579 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
582 static v3s16 turn_xz(v3s16 olddir, int t)
602 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
604 int turn = random.range(0,2);
613 dir = turn_xz(olddir, 0);
616 dir = turn_xz(olddir, 1);
620 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
621 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
622 PseudoRandom &random)
624 make_hole1(vmanip, doorplace);
625 v3s16 p0 = doorplace;
629 length = random.range(1,13);
631 length = random.range(1,6);
632 length = random.range(1,13);
633 u32 partlength = random.range(1,13);
636 if(random.next()%2 == 0 && partlength >= 3)
637 make_stairs = random.next()%2 ? 1 : -1;
638 for(u32 i=0; i<length; i++)
644 /*// If already empty
645 if(vmanip.getNodeNoExNoEmerge(p).getContent()
647 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
652 if(vmanip.m_area.contains(p) == true
653 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
657 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
658 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
659 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
660 VMANIP_FLAG_DUNGEON_INSIDE);
661 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
662 VMANIP_FLAG_DUNGEON_INSIDE);
666 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
667 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
668 make_hole1(vmanip, p);
669 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
670 VMANIP_FLAG_DUNGEON_INSIDE);*/
677 // Can't go here, turn away
678 dir = turn_xz(dir, random.range(0,1));
679 make_stairs = -make_stairs;
681 partlength = random.range(1,length);
686 if(partcount >= partlength)
690 dir = random_turn(random, dir);
692 partlength = random.range(1,length);
695 if(random.next()%2 == 0 && partlength >= 3)
696 make_stairs = random.next()%2 ? 1 : -1;
707 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
717 m_dir = rand_ortho_dir(m_random);
720 void setPos(v3s16 pos)
725 void setDir(v3s16 dir)
730 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
732 for(u32 i=0; i<100; i++)
734 v3s16 p = m_pos + m_dir;
735 v3s16 p1 = p + v3s16(0,1,0);
736 if(vmanip.m_area.contains(p) == false
737 || vmanip.m_area.contains(p1) == false
743 if(vmanip.getNodeNoExNoEmerge(p).getContent()
745 && vmanip.getNodeNoExNoEmerge(p1).getContent()
748 // Found wall, this is a good place!
751 // Randomize next direction
756 Determine where to move next
758 // Jump one up if the actual space is there
759 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
761 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
763 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
766 // Jump one down if the actual space is there
767 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
769 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
771 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
774 // Check if walking is now possible
775 if(vmanip.getNodeNoExNoEmerge(p).getContent()
777 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
780 // Cannot continue walking here
790 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
791 v3s16 &result_doordir, v3s16 &result_roomplace)
793 for(s16 trycount=0; trycount<30; trycount++)
797 bool r = findPlaceForDoor(doorplace, doordir);
801 // X east, Z north, Y up
803 if(doordir == v3s16(1,0,0)) // X+
804 roomplace = doorplace +
805 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
806 if(doordir == v3s16(-1,0,0)) // X-
807 roomplace = doorplace +
808 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
809 if(doordir == v3s16(0,0,1)) // Z+
810 roomplace = doorplace +
811 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
812 if(doordir == v3s16(0,0,-1)) // Z-
813 roomplace = doorplace +
814 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
817 if(doordir == v3s16(1,0,0)) // X+
818 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
819 if(doordir == v3s16(-1,0,0)) // X-
820 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
821 if(doordir == v3s16(0,0,1)) // Z+
822 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
823 if(doordir == v3s16(0,0,-1)) // Z-
824 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
829 for(s16 z=1; z<roomsize.Z-1; z++)
830 for(s16 y=1; y<roomsize.Y-1; y++)
831 for(s16 x=1; x<roomsize.X-1; x++)
833 v3s16 p = roomplace + v3s16(x,y,z);
834 if(vmanip.m_area.contains(p) == false)
839 if(vmanip.m_flags[vmanip.m_area.index(p)]
840 & VMANIP_FLAG_DUNGEON_INSIDE)
851 result_doorplace = doorplace;
852 result_doordir = doordir;
853 result_roomplace = roomplace;
860 VoxelManipulator &vmanip;
863 PseudoRandom &m_random;
866 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
868 v3s16 areasize = vmanip.m_area.getExtent();
873 Find place for first room
876 for(u32 i=0; i<100; i++)
878 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
879 roomplace = vmanip.m_area.MinEdge + v3s16(
880 random.range(0,areasize.X-roomsize.X-1),
881 random.range(0,areasize.Y-roomsize.Y-1),
882 random.range(0,areasize.Z-roomsize.Z-1));
884 Check that we're not putting the room to an unknown place,
885 otherwise it might end up floating in the air
888 for(s16 z=1; z<roomsize.Z-1; z++)
889 for(s16 y=1; y<roomsize.Y-1; y++)
890 for(s16 x=1; x<roomsize.X-1; x++)
892 v3s16 p = roomplace + v3s16(x,y,z);
893 u32 vi = vmanip.m_area.index(p);
894 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
899 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
913 Stores the center position of the last room made, so that
914 a new corridor can be started from the last room instead of
915 the new room, if chosen so.
917 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
919 u32 room_count = random.range(2,7);
920 for(u32 i=0; i<room_count; i++)
922 // Make a room to the determined place
923 make_room1(vmanip, roomsize, roomplace);
925 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
927 // Place torch at room center (for testing)
928 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
931 if(i == room_count-1)
934 // Determine walker start position
936 bool start_in_last_room = (random.range(0,2)!=0);
937 //bool start_in_last_room = true;
939 v3s16 walker_start_place;
941 if(start_in_last_room)
943 walker_start_place = last_room_center;
947 walker_start_place = room_center;
948 // Store center of current room as the last one
949 last_room_center = room_center;
952 // Create walker and find a place for a door
953 RoomWalker walker(vmanip, walker_start_place, random);
956 bool r = walker.findPlaceForDoor(doorplace, doordir);
960 if(random.range(0,1)==0)
962 make_door1(vmanip, doorplace, doordir);
964 // Don't actually make a door
965 doorplace -= doordir;
967 // Make a random corridor starting from the door
969 v3s16 corridor_end_dir;
970 make_corridor(vmanip, doorplace, doordir, corridor_end,
971 corridor_end_dir, random);
973 // Find a place for a random sized room
974 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
975 walker.setPos(corridor_end);
976 walker.setDir(corridor_end_dir);
977 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
981 if(random.range(0,1)==0)
983 make_door1(vmanip, doorplace, doordir);
985 // Don't actually make a door
986 roomplace -= doordir;
991 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random)
995 s32 r = random.range(0, 3);
997 dir = v3s16( 1, 0, 0);
1001 dir = v3s16(-1, 0, 0);
1005 dir = v3s16( 0, 0, 1);
1009 dir = v3s16( 0, 0,-1);
1012 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1013 16+random.range(0,15),
1014 16+random.range(0,15),
1015 16+random.range(0,15));
1016 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC, facedir_i);
1017 u32 length = random.range(3,15);
1018 for(u32 j=0; j<length; j++)
1021 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC_RB);
1026 Noise functions. Make sure seed is mangled differently in each one.
1030 Scaling the output of the noise function affects the overdrive of the
1031 contour function, which affects the shape of the output considerably.
1033 #define CAVE_NOISE_SCALE 12.0
1034 //#define CAVE_NOISE_SCALE 10.0
1035 //#define CAVE_NOISE_SCALE 7.5
1036 //#define CAVE_NOISE_SCALE 5.0
1037 //#define CAVE_NOISE_SCALE 1.0
1039 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1040 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1042 NoiseParams get_cave_noise1_params(u64 seed)
1044 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1045 200, CAVE_NOISE_SCALE);*/
1046 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1047 100, CAVE_NOISE_SCALE);*/
1048 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1049 100, CAVE_NOISE_SCALE);*/
1050 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1051 100, CAVE_NOISE_SCALE);*/
1052 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1053 50, CAVE_NOISE_SCALE);
1054 //return NoiseParams(NOISE_CONSTANT_ONE);
1057 NoiseParams get_cave_noise2_params(u64 seed)
1059 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1060 200, CAVE_NOISE_SCALE);*/
1061 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1062 100, CAVE_NOISE_SCALE);*/
1063 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1064 100, CAVE_NOISE_SCALE);*/
1065 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1066 50, CAVE_NOISE_SCALE);
1067 //return NoiseParams(NOISE_CONSTANT_ONE);
1070 NoiseParams get_ground_noise1_params(u64 seed)
1072 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1076 NoiseParams get_ground_crumbleness_params(u64 seed)
1078 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1082 NoiseParams get_ground_wetness_params(u64 seed)
1084 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1088 bool is_cave(u64 seed, v3s16 p)
1090 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1091 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1092 return d1*d2 > CAVE_NOISE_THRESHOLD;
1096 Ground density noise shall be interpreted by using this.
1098 TODO: No perlin noises here, they should be outsourced
1100 NOTE: The speed of these actually isn't terrible
1102 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1104 //return ((double)p.Y < ground_noise1_val);
1106 double f = 0.55 + noise2d_perlin(
1107 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1108 seed+920381, 3, 0.45);
1113 double h = WATER_LEVEL + 10 * noise2d_perlin(
1114 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1115 seed+84174, 4, 0.5);
1118 return ((double)p.Y - h < ground_noise1_val * f);
1122 Queries whether a position is ground or not.
1124 bool is_ground(u64 seed, v3s16 p)
1126 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1127 return val_is_ground(val1, p, seed);
1130 // Amount of trees per area in nodes
1131 double tree_amount_2d(u64 seed, v2s16 p)
1133 /*double noise = noise2d_perlin(
1134 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1136 double noise = noise2d_perlin(
1137 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1139 double zeroval = -0.39;
1143 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1146 double surface_humidity_2d(u64 seed, v2s16 p)
1148 double noise = noise2d_perlin(
1149 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1150 seed+72384, 4, 0.66);
1151 noise = (noise + 1.0)/2.0;
1160 double randomstone_amount_2d(u64 seed, v2s16 p)
1162 double noise = noise2d_perlin(
1163 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1164 seed+3829434, 5, 0.66);
1165 double zeroval = 0.1;
1169 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1173 double largestone_amount_2d(u64 seed, v2s16 p)
1175 double noise = noise2d_perlin(
1176 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1177 seed+14143242, 5, 0.66);
1178 double zeroval = 0.3;
1182 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1186 Incrementally find ground level from 3d noise
1188 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1190 // Start a bit fuzzy to make averaging lower precision values
1192 s16 level = myrand_range(-precision/2, precision/2);
1193 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1195 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1197 // First find non-ground by going upwards
1198 // Don't stop in caves.
1200 s16 max = level+dec[i-1]*2;
1201 v3s16 p(p2d.X, level, p2d.Y);
1202 for(; p.Y < max; p.Y += dec[i])
1204 if(!is_ground(seed, p))
1211 // Then find ground by going downwards from there.
1212 // Go in caves, too, when precision is 1.
1214 s16 min = level-dec[i-1]*2;
1215 v3s16 p(p2d.X, level, p2d.Y);
1216 for(; p.Y>min; p.Y-=dec[i])
1218 bool ground = is_ground(seed, p);
1219 /*if(dec[i] == 1 && is_cave(seed, p))
1230 // This is more like the actual ground level
1231 level += dec[i-1]/2;
1236 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1238 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1240 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1241 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1243 a += find_ground_level_from_noise(seed,
1244 v2s16(node_min.X, node_min.Y), p);
1245 a += find_ground_level_from_noise(seed,
1246 v2s16(node_min.X, node_max.Y), p);
1247 a += find_ground_level_from_noise(seed,
1248 v2s16(node_max.X, node_max.Y), p);
1249 a += find_ground_level_from_noise(seed,
1250 v2s16(node_max.X, node_min.Y), p);
1251 a += find_ground_level_from_noise(seed,
1252 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1257 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1259 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1261 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1262 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1265 a = MYMAX(a, find_ground_level_from_noise(seed,
1266 v2s16(node_min.X, node_min.Y), p));
1267 a = MYMAX(a, find_ground_level_from_noise(seed,
1268 v2s16(node_min.X, node_max.Y), p));
1269 a = MYMAX(a, find_ground_level_from_noise(seed,
1270 v2s16(node_max.X, node_max.Y), p));
1271 a = MYMAX(a, find_ground_level_from_noise(seed,
1272 v2s16(node_min.X, node_min.Y), p));
1274 a = MYMAX(a, find_ground_level_from_noise(seed,
1275 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1276 // Side middle points
1277 a = MYMAX(a, find_ground_level_from_noise(seed,
1278 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1279 a = MYMAX(a, find_ground_level_from_noise(seed,
1280 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1281 a = MYMAX(a, find_ground_level_from_noise(seed,
1282 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1283 a = MYMAX(a, find_ground_level_from_noise(seed,
1284 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1288 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1290 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1292 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1293 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1296 a = MYMIN(a, find_ground_level_from_noise(seed,
1297 v2s16(node_min.X, node_min.Y), p));
1298 a = MYMIN(a, find_ground_level_from_noise(seed,
1299 v2s16(node_min.X, node_max.Y), p));
1300 a = MYMIN(a, find_ground_level_from_noise(seed,
1301 v2s16(node_max.X, node_max.Y), p));
1302 a = MYMIN(a, find_ground_level_from_noise(seed,
1303 v2s16(node_min.X, node_min.Y), p));
1305 a = MYMIN(a, find_ground_level_from_noise(seed,
1306 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1307 // Side middle points
1308 a = MYMIN(a, find_ground_level_from_noise(seed,
1309 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1310 a = MYMIN(a, find_ground_level_from_noise(seed,
1311 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1312 a = MYMIN(a, find_ground_level_from_noise(seed,
1313 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1314 a = MYMIN(a, find_ground_level_from_noise(seed,
1315 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1319 bool block_is_underground(u64 seed, v3s16 blockpos)
1321 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1322 seed, v2s16(blockpos.X, blockpos.Z));
1324 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1331 #define AVERAGE_MUD_AMOUNT 4
1333 double base_rock_level_2d(u64 seed, v2s16 p)
1335 // The base ground level
1336 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1337 + 20. * noise2d_perlin(
1338 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1339 (seed>>32)+654879876, 6, 0.6);
1341 /*// A bit hillier one
1342 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1343 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1344 (seed>>27)+90340, 6, 0.69);
1348 // Higher ground level
1349 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1350 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1351 seed+85039, 5, 0.69);
1352 //higher = 30; // For debugging
1354 // Limit higher to at least base
1358 // Steepness factor of cliffs
1359 double b = 1.0 + 1.0 * noise2d_perlin(
1360 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1362 b = rangelim(b, 0.0, 1000.0);
1365 b = rangelim(b, 3.0, 1000.0);
1366 //dstream<<"b="<<b<<std::endl;
1369 // Offset to more low
1370 double a_off = -0.2;
1371 // High/low selector
1372 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1373 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1374 seed-359, 6, 0.7));*/
1375 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1376 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1377 seed-359, 5, 0.60));
1379 a = rangelim(a, 0.0, 1.0);
1381 //dstream<<"a="<<a<<std::endl;
1383 double h = base*(1.0-a) + higher*a;
1390 double get_mud_add_amount(u64 seed, v2s16 p)
1392 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1393 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1394 seed+91013, 3, 0.55));
1398 bool get_have_sand(u64 seed, v2s16 p2d)
1400 // Determine whether to have sand here
1401 double sandnoise = noise2d_perlin(
1402 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1403 seed+59420, 3, 0.50);
1405 return (sandnoise > -0.15);
1409 Adds random objects to block, depending on the content of the block
1411 void add_random_objects(MapBlock *block)
1413 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1414 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1416 bool last_node_walkable = false;
1417 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1420 MapNode n = block->getNodeNoEx(p);
1421 if(n.getContent() == CONTENT_IGNORE)
1423 if(content_features(n).liquid_type != LIQUID_NONE)
1425 if(content_features(n).walkable)
1427 last_node_walkable = true;
1430 if(last_node_walkable)
1432 // If block contains light information
1433 if(content_features(n).param_type == CPT_LIGHT)
1435 if(n.getLight(LIGHTBANK_DAY) <= 3)
1437 if(myrand() % 300 == 0)
1439 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1441 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1442 std::string data = obj->getStaticData();
1443 StaticObject s_obj(obj->getType(),
1444 obj->getBasePosition(), data);
1446 block->m_static_objects.insert(0, s_obj);
1447 block->m_static_objects.insert(0, s_obj);
1448 block->m_static_objects.insert(0, s_obj);
1449 block->m_static_objects.insert(0, s_obj);
1450 block->m_static_objects.insert(0, s_obj);
1451 block->m_static_objects.insert(0, s_obj);
1454 if(myrand() % 1000 == 0)
1456 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1458 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1459 std::string data = obj->getStaticData();
1460 StaticObject s_obj(obj->getType(),
1461 obj->getBasePosition(), data);
1463 block->m_static_objects.insert(0, s_obj);
1469 last_node_walkable = false;
1472 block->setChangedFlag();
1475 void make_block(BlockMakeData *data)
1479 //dstream<<"makeBlock: no-op"<<std::endl;
1483 v3s16 blockpos = data->blockpos;
1485 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1486 <<blockpos.Z<<")"<<std::endl;*/
1488 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1489 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1490 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1491 // Area of center block
1492 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1493 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1494 // Full allocated area
1495 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1496 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1498 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1500 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1503 Get average ground level from noise
1506 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1507 data->seed, v2s16(blockpos.X, blockpos.Z));
1508 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1510 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1512 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1513 data->seed, v2s16(blockpos.X, blockpos.Z));
1514 // Minimum amount of ground above the top of the central block
1515 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1517 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1518 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1519 // Maximum amount of ground above the bottom of the central block
1520 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1524 Special case for high air or water: Just fill with air and water.
1526 if(maximum_ground_depth < -20)
1528 for(s16 x=node_min.X; x<=node_max.X; x++)
1529 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1534 // Use fast index incrementing
1535 v3s16 em = vmanip.m_area.getExtent();
1536 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1537 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1539 // Only modify places that have no content
1540 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1542 if(y <= WATER_LEVEL)
1543 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1545 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1548 data->vmanip->m_area.add_y(em, i, 1);
1559 If block is deep underground, this is set to true and ground
1560 density noise is not generated, for speed optimization.
1562 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1565 Create a block-specific seed
1567 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1568 + full_node_min.Y*42123 + full_node_min.X*23;
1574 //NoiseBuffer noisebuf1;
1575 //NoiseBuffer noisebuf2;
1576 NoiseBuffer noisebuf_cave;
1577 NoiseBuffer noisebuf_ground;
1578 NoiseBuffer noisebuf_ground_crumbleness;
1579 NoiseBuffer noisebuf_ground_wetness;
1581 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1582 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1584 //TimeTaker timer("noisebuf.create");
1590 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1591 minpos_f.X, minpos_f.Y, minpos_f.Z,
1592 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1594 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1602 v3f sl = v3f(4.0, 4.0, 4.0);
1607 if(all_is_ground_except_caves == false)
1608 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1609 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1610 minpos_f.X, minpos_f.Y, minpos_f.Z,
1611 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1615 Ground property noise
1617 sl = v3f(2.5, 2.5, 2.5);
1618 noisebuf_ground_crumbleness.create(
1619 get_ground_crumbleness_params(data->seed),
1620 minpos_f.X, minpos_f.Y, minpos_f.Z,
1621 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1623 noisebuf_ground_wetness.create(
1624 get_ground_wetness_params(data->seed),
1625 minpos_f.X, minpos_f.Y, minpos_f.Z,
1626 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1631 Make base ground level
1634 for(s16 x=node_min.X; x<=node_max.X; x++)
1635 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1640 // Use fast index incrementing
1641 v3s16 em = vmanip.m_area.getExtent();
1642 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1643 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1645 // Only modify places that have no content
1646 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1648 // First priority: make air and water.
1649 // This avoids caves inside water.
1650 if(all_is_ground_except_caves == false
1651 && val_is_ground(noisebuf_ground.get(x,y,z),
1652 v3s16(x,y,z), data->seed) == false)
1654 if(y <= WATER_LEVEL)
1655 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1657 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1659 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1660 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1662 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1665 data->vmanip->m_area.add_y(em, i, 1);
1675 PseudoRandom mineralrandom(blockseed);
1680 for(s16 i=0; i<approx_ground_depth/4; i++)
1682 if(mineralrandom.next()%50 == 0)
1684 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1685 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1686 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1687 for(u16 i=0; i<27; i++)
1689 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1690 u32 vi = vmanip.m_area.index(p);
1691 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1692 if(mineralrandom.next()%8 == 0)
1693 vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1702 u16 a = mineralrandom.range(0,15);
1704 u16 amount = 20 * a/1000;
1705 for(s16 i=0; i<amount; i++)
1707 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1708 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1709 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1711 u8 base_content = CONTENT_STONE;
1712 MapNode new_content(CONTENT_IGNORE);
1715 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1717 new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1721 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1722 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1723 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1724 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1726 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1728 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1732 if(new_content.getContent() != CONTENT_IGNORE)
1734 for(u16 i=0; i<27; i++)
1736 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1737 u32 vi = vmanip.m_area.index(p);
1738 if(vmanip.m_data[vi].getContent() == base_content)
1740 if(mineralrandom.next()%sparseness == 0)
1741 vmanip.m_data[vi] = new_content;
1750 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1751 //for(s16 i=0; i<50; i++)
1752 u16 coal_amount = 30;
1753 u16 coal_rareness = 60 / coal_amount;
1754 if(coal_rareness == 0)
1756 if(mineralrandom.next()%coal_rareness == 0)
1758 u16 a = mineralrandom.next() % 16;
1759 u16 amount = coal_amount * a*a*a / 1000;
1760 for(s16 i=0; i<amount; i++)
1762 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1763 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1764 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1765 for(u16 i=0; i<27; i++)
1767 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1768 u32 vi = vmanip.m_area.index(p);
1769 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1770 if(mineralrandom.next()%8 == 0)
1771 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1778 u16 iron_amount = 8;
1779 u16 iron_rareness = 60 / iron_amount;
1780 if(iron_rareness == 0)
1782 if(mineralrandom.next()%iron_rareness == 0)
1784 u16 a = mineralrandom.next() % 16;
1785 u16 amount = iron_amount * a*a*a / 1000;
1786 for(s16 i=0; i<amount; i++)
1788 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1789 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1790 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1791 for(u16 i=0; i<27; i++)
1793 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1794 u32 vi = vmanip.m_area.index(p);
1795 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1796 if(mineralrandom.next()%8 == 0)
1797 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1804 Add mud and sand and others underground (in place of stone)
1807 for(s16 x=node_min.X; x<=node_max.X; x++)
1808 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1813 // Use fast index incrementing
1814 v3s16 em = vmanip.m_area.getExtent();
1815 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1816 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1818 if(vmanip.m_data[i].getContent() == CONTENT_STONE)
1820 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1822 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1823 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1825 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1827 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1829 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1830 vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1832 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1833 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1835 vmanip.m_data[i] = MapNode(CONTENT_LAVASOURCE);
1836 for(s16 x1=-1; x1<=1; x1++)
1837 for(s16 y1=-1; y1<=1; y1++)
1838 for(s16 z1=-1; z1<=1; z1++)
1839 data->transforming_liquid.push_back(
1840 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1844 data->vmanip->m_area.add_y(em, i, -1);
1853 //if(node_min.Y < approx_groundlevel)
1854 //if(myrand() % 3 == 0)
1855 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1856 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1857 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1858 float dungeon_rarity = 0.02;
1859 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1861 && node_min.Y < approx_groundlevel)
1863 // Dungeon generator doesn't modify places which have this set
1864 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1865 | VMANIP_FLAG_DUNGEON_PRESERVE);
1867 // Set all air and water to be untouchable to make dungeons open
1868 // to caves and open air
1869 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1870 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1875 // Use fast index incrementing
1876 v3s16 em = vmanip.m_area.getExtent();
1877 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1878 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1880 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1881 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1882 else if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1883 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1884 data->vmanip->m_area.add_y(em, i, -1);
1889 PseudoRandom random(blockseed+2);
1892 make_dungeon1(vmanip, random);
1894 // Convert some cobble to mossy cobble
1895 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1896 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1901 // Use fast index incrementing
1902 v3s16 em = vmanip.m_area.getExtent();
1903 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1904 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1906 // (noisebuf not used because it doesn't contain the
1908 double wetness = noise3d_param(
1909 get_ground_wetness_params(data->seed), x,y,z);
1910 double d = noise3d_perlin((float)x/2.5,
1911 (float)y/2.5,(float)z/2.5,
1913 if(vmanip.m_data[i].getContent() == CONTENT_COBBLE)
1917 vmanip.m_data[i].setContent(CONTENT_MOSSYCOBBLE);
1920 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1923 vmanip.m_data[i].setContent(CONTENT_MUD);
1925 data->vmanip->m_area.add_y(em, i, -1);
1935 PseudoRandom ncrandom(blockseed+9324342);
1936 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1938 make_nc(vmanip, ncrandom);
1943 Add top and bottom side of water to transforming_liquid queue
1946 for(s16 x=node_min.X; x<=node_max.X; x++)
1947 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1952 bool water_found = false;
1953 // Use fast index incrementing
1954 v3s16 em = vmanip.m_area.getExtent();
1955 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1956 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1958 if(water_found == false)
1960 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1962 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1963 data->transforming_liquid.push_back(p);
1969 // This can be done because water_found can only
1970 // turn to true and end up here after going through
1972 if(vmanip.m_data[i+1].getContent() != CONTENT_WATERSOURCE)
1974 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1975 data->transforming_liquid.push_back(p);
1976 water_found = false;
1980 data->vmanip->m_area.add_y(em, i, -1);
1986 If close to ground level
1989 //if(abs(approx_ground_depth) < 30)
1990 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1996 for(s16 x=node_min.X; x<=node_max.X; x++)
1997 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2002 bool possibly_have_sand = get_have_sand(data->seed, p2d);
2003 bool have_sand = false;
2004 u32 current_depth = 0;
2005 bool air_detected = false;
2006 bool water_detected = false;
2007 bool have_clay = false;
2009 // Use fast index incrementing
2010 s16 start_y = node_max.Y+2;
2011 v3s16 em = vmanip.m_area.getExtent();
2012 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2013 for(s16 y=start_y; y>=node_min.Y-3; y--)
2015 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
2016 water_detected = true;
2017 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2018 air_detected = true;
2020 if((vmanip.m_data[i].getContent() == CONTENT_STONE
2021 || vmanip.m_data[i].getContent() == CONTENT_GRASS
2022 || vmanip.m_data[i].getContent() == CONTENT_MUD
2023 || vmanip.m_data[i].getContent() == CONTENT_SAND
2024 || vmanip.m_data[i].getContent() == CONTENT_GRAVEL
2025 ) && (air_detected || water_detected))
2027 if(current_depth == 0 && y <= WATER_LEVEL+2
2028 && possibly_have_sand)
2031 if(current_depth < 4)
2035 // Determine whether to have clay in the sand here
2036 double claynoise = noise2d_perlin(
2037 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2038 data->seed+4321, 6, 0.95) + 0.5;
2040 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2041 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2042 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2045 vmanip.m_data[i] = MapNode(CONTENT_CLAY);
2047 vmanip.m_data[i] = MapNode(CONTENT_SAND);
2050 else if(current_depth==0 && !water_detected
2051 && y >= WATER_LEVEL && air_detected)
2052 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
2055 vmanip.m_data[i] = MapNode(CONTENT_MUD);
2059 if(vmanip.m_data[i].getContent() == CONTENT_MUD
2060 || vmanip.m_data[i].getContent() == CONTENT_GRASS)
2061 vmanip.m_data[i] = MapNode(CONTENT_STONE);
2066 if(current_depth >= 8)
2069 else if(current_depth != 0)
2072 data->vmanip->m_area.add_y(em, i, -1);
2078 Calculate some stuff
2081 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2082 bool is_jungle = surface_humidity > 0.75;
2084 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
2091 PseudoRandom treerandom(blockseed);
2092 // Put trees in random places on part of division
2093 for(u32 i=0; i<tree_count; i++)
2095 s16 x = treerandom.range(node_min.X, node_max.X);
2096 s16 z = treerandom.range(node_min.Z, node_max.Z);
2097 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2098 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2099 // Don't make a tree under water level
2102 // Make sure tree fits (only trees whose starting point is
2103 // at this block are added)
2104 if(y < node_min.Y || y > node_max.Y)
2107 Find exact ground level
2111 for(; p.Y >= y-6; p.Y--)
2113 u32 i = data->vmanip->m_area.index(p);
2114 MapNode *n = &data->vmanip->m_data[i];
2115 if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
2121 // If not found, handle next one
2126 u32 i = data->vmanip->m_area.index(p);
2127 MapNode *n = &data->vmanip->m_data[i];
2129 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
2132 // Papyrus grows only on mud and in water
2133 if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
2136 make_papyrus(vmanip, p);
2138 // Trees grow only on mud and grass, on land
2139 else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
2142 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2143 if(is_jungle == false)
2144 make_tree(vmanip, p);
2146 make_jungletree(vmanip, p);
2148 // Cactii grow only on sand, on land
2149 else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
2152 make_cactus(vmanip, p);
2162 PseudoRandom grassrandom(blockseed);
2163 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2165 s16 x = grassrandom.range(node_min.X, node_max.X);
2166 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2167 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2170 if(y < node_min.Y || y > node_max.Y)
2173 Find exact ground level
2177 for(; p.Y >= y-6; p.Y--)
2179 u32 i = data->vmanip->m_area.index(p);
2180 MapNode *n = &data->vmanip->m_data[i];
2181 if(content_features(*n).is_ground_content
2182 || n->getContent() == CONTENT_JUNGLETREE)
2188 // If not found, handle next one
2192 if(vmanip.m_area.contains(p) == false)
2194 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2197 if(vmanip.m_area.contains(p))
2198 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
2200 if(vmanip.m_area.contains(p))
2201 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
2207 Add some kind of random stones
2210 u32 random_stone_count = block_area_nodes *
2211 randomstone_amount_2d(data->seed, p2d_center);
2212 // Put in random places on part of division
2213 for(u32 i=0; i<random_stone_count; i++)
2215 s16 x = myrand_range(node_min.X, node_max.X);
2216 s16 z = myrand_range(node_min.Z, node_max.Z);
2217 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2218 // Don't add under water level
2219 /*if(y < WATER_LEVEL)
2221 // Don't add if doesn't belong to this block
2222 if(y < node_min.Y || y > node_max.Y)
2227 u32 i = data->vmanip->m_area.index(v3s16(p));
2228 MapNode *n = &data->vmanip->m_data[i];
2229 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2232 // Will be placed one higher
2235 make_randomstone(data->vmanip, p);
2244 u32 large_stone_count = block_area_nodes *
2245 largestone_amount_2d(data->seed, p2d_center);
2246 //u32 large_stone_count = 1;
2247 // Put in random places on part of division
2248 for(u32 i=0; i<large_stone_count; i++)
2250 s16 x = myrand_range(node_min.X, node_max.X);
2251 s16 z = myrand_range(node_min.Z, node_max.Z);
2252 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2253 // Don't add under water level
2254 /*if(y < WATER_LEVEL)
2256 // Don't add if doesn't belong to this block
2257 if(y < node_min.Y || y > node_max.Y)
2262 u32 i = data->vmanip->m_area.index(v3s16(p));
2263 MapNode *n = &data->vmanip->m_data[i];
2264 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2267 // Will be placed one lower
2270 make_largestone(data->vmanip, p);
2277 BlockMakeData::BlockMakeData():
2283 BlockMakeData::~BlockMakeData()
2288 }; // namespace mapgen