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 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0, bool is_apple_tree)
85 MapNode treenode(CONTENT_TREE);
86 MapNode leavesnode(CONTENT_LEAVES);
87 MapNode applenode(CONTENT_APPLE);
89 s16 trunk_h = myrand_range(4, 5);
91 for(s16 ii=0; ii<trunk_h; ii++)
93 if(vmanip.m_area.contains(p1))
94 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
98 // p1 is now the last piece of the trunk
101 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
102 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
103 Buffer<u8> leaves_d(leaves_a.getVolume());
104 for(s32 i=0; i<leaves_a.getVolume(); i++)
107 // Force leaves at near the end of the trunk
110 for(s16 z=-d; z<=d; z++)
111 for(s16 y=-d; y<=d; y++)
112 for(s16 x=-d; x<=d; x++)
114 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
118 // Add leaves randomly
119 for(u32 iii=0; iii<7; iii++)
124 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
125 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
126 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
129 for(s16 z=0; z<=d; z++)
130 for(s16 y=0; y<=d; y++)
131 for(s16 x=0; x<=d; x++)
133 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
137 // Blit leaves to vmanip
138 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
139 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
140 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
144 if(vmanip.m_area.contains(p) == false)
146 u32 vi = vmanip.m_area.index(p);
147 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
148 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
150 u32 i = leaves_a.index(x,y,z);
151 if(leaves_d[i] == 1) {
152 bool is_apple = myrand_range(0,99) < 10;
153 if(is_apple_tree && is_apple) {
154 vmanip.m_data[vi] = applenode;
156 vmanip.m_data[vi] = leavesnode;
162 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0)
164 MapNode treenode(CONTENT_JUNGLETREE);
165 MapNode leavesnode(CONTENT_LEAVES);
167 for(s16 x=-1; x<=1; x++)
168 for(s16 z=-1; z<=1; z++)
170 if(myrand_range(0, 2) == 0)
172 v3s16 p1 = p0 + v3s16(x,0,z);
173 v3s16 p2 = p0 + v3s16(x,-1,z);
174 if(vmanip.m_area.contains(p2)
175 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
176 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
177 else if(vmanip.m_area.contains(p1))
178 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
181 s16 trunk_h = myrand_range(8, 12);
183 for(s16 ii=0; ii<trunk_h; ii++)
185 if(vmanip.m_area.contains(p1))
186 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
190 // p1 is now the last piece of the trunk
193 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
194 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
195 Buffer<u8> leaves_d(leaves_a.getVolume());
196 for(s32 i=0; i<leaves_a.getVolume(); i++)
199 // Force leaves at near the end of the trunk
202 for(s16 z=-d; z<=d; z++)
203 for(s16 y=-d; y<=d; y++)
204 for(s16 x=-d; x<=d; x++)
206 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
210 // Add leaves randomly
211 for(u32 iii=0; iii<30; iii++)
216 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
217 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
218 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
221 for(s16 z=0; z<=d; z++)
222 for(s16 y=0; y<=d; y++)
223 for(s16 x=0; x<=d; x++)
225 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
229 // Blit leaves to vmanip
230 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
231 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
232 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
236 if(vmanip.m_area.contains(p) == false)
238 u32 vi = vmanip.m_area.index(p);
239 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
240 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
242 u32 i = leaves_a.index(x,y,z);
244 vmanip.m_data[vi] = leavesnode;
248 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0)
250 MapNode papyrusnode(CONTENT_PAPYRUS);
252 s16 trunk_h = myrand_range(2, 3);
254 for(s16 ii=0; ii<trunk_h; ii++)
256 if(vmanip.m_area.contains(p1))
257 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
262 void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
264 MapNode cactusnode(CONTENT_CACTUS);
268 for(s16 ii=0; ii<trunk_h; ii++)
270 if(vmanip.m_area.contains(p1))
271 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
277 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
279 MapNode stonenode(CONTENT_STONE);
281 s16 size = myrand_range(3, 6);
283 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
284 Buffer<u8> stone_d(stone_a.getVolume());
285 for(s32 i=0; i<stone_a.getVolume(); i++)
288 // Force stone at bottom to make it usually touch the ground
290 for(s16 z=0; z<=0; z++)
291 for(s16 y=0; y<=0; y++)
292 for(s16 x=0; x<=0; x++)
294 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
298 // Generate from perlin noise
299 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
300 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
301 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
303 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
304 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
305 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
307 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
309 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
313 u32 vi = stone_a.index(v3s16(x,y,z));
318 /*// Add stone randomly
319 for(u32 iii=0; iii<7; iii++)
324 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
325 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
326 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
329 for(s16 z=0; z<=d; z++)
330 for(s16 y=0; y<=d; y++)
331 for(s16 x=0; x<=d; x++)
333 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
337 // Blit stone to vmanip
338 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
339 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
340 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
344 if(vmanip.m_area.contains(p) == false)
346 u32 vi = vmanip.m_area.index(p);
347 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
348 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
350 u32 i = stone_a.index(x,y,z);
352 vmanip.m_data[vi] = stonenode;
358 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
360 MapNode stonenode(CONTENT_STONE);
362 s16 size = myrand_range(8, 16);
364 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
365 Buffer<u8> stone_d(stone_a.getVolume());
366 for(s32 i=0; i<stone_a.getVolume(); i++)
369 // Force stone at bottom to make it usually touch the ground
371 for(s16 z=0; z<=0; z++)
372 for(s16 y=0; y<=0; y++)
373 for(s16 x=0; x<=0; x++)
375 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
379 // Generate from perlin noise
380 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
381 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
382 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
385 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
386 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
387 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
388 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
389 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
390 double dz = (double)z-mid_z;
391 double dx = (double)x-mid_x;
392 double dy = MYMAX(0, (double)y-mid_y);
393 double r = sqrt(dz*dz+dx*dx+dy*dy);
394 d /= (2*r/size)*2 + 0.01;
397 u32 vi = stone_a.index(v3s16(x,y,z));
402 /*// Add stone randomly
403 for(u32 iii=0; iii<7; iii++)
408 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
409 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
410 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
413 for(s16 z=0; z<=d; z++)
414 for(s16 y=0; y<=d; y++)
415 for(s16 x=0; x<=d; x++)
417 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
421 // Blit stone to vmanip
422 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
423 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
424 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
428 if(vmanip.m_area.contains(p) == false)
430 u32 vi = vmanip.m_area.index(p);
431 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
432 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
434 u32 i = stone_a.index(x,y,z);
436 vmanip.m_data[vi] = stonenode;
442 Dungeon making routines
445 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
446 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
447 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
448 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
450 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
453 for(s16 z=0; z<roomsize.Z; z++)
454 for(s16 y=0; y<roomsize.Y; y++)
457 v3s16 p = roomplace + v3s16(0,y,z);
458 if(vmanip.m_area.contains(p) == false)
460 u32 vi = vmanip.m_area.index(p);
461 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
463 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
466 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
467 if(vmanip.m_area.contains(p) == false)
469 u32 vi = vmanip.m_area.index(p);
470 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
472 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
477 for(s16 x=0; x<roomsize.X; x++)
478 for(s16 y=0; y<roomsize.Y; y++)
481 v3s16 p = roomplace + v3s16(x,y,0);
482 if(vmanip.m_area.contains(p) == false)
484 u32 vi = vmanip.m_area.index(p);
485 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
487 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
490 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
491 if(vmanip.m_area.contains(p) == false)
493 u32 vi = vmanip.m_area.index(p);
494 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
496 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
500 // Make +-Y walls (floor and ceiling)
501 for(s16 z=0; z<roomsize.Z; z++)
502 for(s16 x=0; x<roomsize.X; x++)
505 v3s16 p = roomplace + v3s16(x,0,z);
506 if(vmanip.m_area.contains(p) == false)
508 u32 vi = vmanip.m_area.index(p);
509 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
511 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
514 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
515 if(vmanip.m_area.contains(p) == false)
517 u32 vi = vmanip.m_area.index(p);
518 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
520 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
525 for(s16 z=1; z<roomsize.Z-1; z++)
526 for(s16 y=1; y<roomsize.Y-1; y++)
527 for(s16 x=1; x<roomsize.X-1; x++)
529 v3s16 p = roomplace + v3s16(x,y,z);
530 if(vmanip.m_area.contains(p) == false)
532 u32 vi = vmanip.m_area.index(p);
533 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
534 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
538 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
539 u8 avoid_flags, MapNode n, u8 or_flags)
541 for(s16 z=0; z<size.Z; z++)
542 for(s16 y=0; y<size.Y; y++)
543 for(s16 x=0; x<size.X; x++)
545 v3s16 p = place + v3s16(x,y,z);
546 if(vmanip.m_area.contains(p) == false)
548 u32 vi = vmanip.m_area.index(p);
549 if(vmanip.m_flags[vi] & avoid_flags)
551 vmanip.m_flags[vi] |= or_flags;
552 vmanip.m_data[vi] = n;
556 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
558 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
559 VMANIP_FLAG_DUNGEON_INSIDE);
562 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
564 make_hole1(vmanip, doorplace);
565 // Place torch (for testing)
566 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
569 static v3s16 rand_ortho_dir(PseudoRandom &random)
571 if(random.next()%2==0)
572 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
574 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
577 static v3s16 turn_xz(v3s16 olddir, int t)
597 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
599 int turn = random.range(0,2);
608 dir = turn_xz(olddir, 0);
611 dir = turn_xz(olddir, 1);
615 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
616 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
617 PseudoRandom &random)
619 make_hole1(vmanip, doorplace);
620 v3s16 p0 = doorplace;
624 length = random.range(1,13);
626 length = random.range(1,6);
627 length = random.range(1,13);
628 u32 partlength = random.range(1,13);
631 if(random.next()%2 == 0 && partlength >= 3)
632 make_stairs = random.next()%2 ? 1 : -1;
633 for(u32 i=0; i<length; i++)
639 /*// If already empty
640 if(vmanip.getNodeNoExNoEmerge(p).getContent()
642 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
647 if(vmanip.m_area.contains(p) == true
648 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
652 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
653 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
654 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
655 VMANIP_FLAG_DUNGEON_INSIDE);
656 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
657 VMANIP_FLAG_DUNGEON_INSIDE);
661 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
662 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
663 make_hole1(vmanip, p);
664 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
665 VMANIP_FLAG_DUNGEON_INSIDE);*/
672 // Can't go here, turn away
673 dir = turn_xz(dir, random.range(0,1));
674 make_stairs = -make_stairs;
676 partlength = random.range(1,length);
681 if(partcount >= partlength)
685 dir = random_turn(random, dir);
687 partlength = random.range(1,length);
690 if(random.next()%2 == 0 && partlength >= 3)
691 make_stairs = random.next()%2 ? 1 : -1;
702 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
712 m_dir = rand_ortho_dir(m_random);
715 void setPos(v3s16 pos)
720 void setDir(v3s16 dir)
725 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
727 for(u32 i=0; i<100; i++)
729 v3s16 p = m_pos + m_dir;
730 v3s16 p1 = p + v3s16(0,1,0);
731 if(vmanip.m_area.contains(p) == false
732 || vmanip.m_area.contains(p1) == false
738 if(vmanip.getNodeNoExNoEmerge(p).getContent()
740 && vmanip.getNodeNoExNoEmerge(p1).getContent()
743 // Found wall, this is a good place!
746 // Randomize next direction
751 Determine where to move next
753 // Jump one up if the actual space is there
754 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
756 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
758 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
761 // Jump one down if the actual space is there
762 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
764 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
766 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
769 // Check if walking is now possible
770 if(vmanip.getNodeNoExNoEmerge(p).getContent()
772 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
775 // Cannot continue walking here
785 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
786 v3s16 &result_doordir, v3s16 &result_roomplace)
788 for(s16 trycount=0; trycount<30; trycount++)
792 bool r = findPlaceForDoor(doorplace, doordir);
796 // X east, Z north, Y up
798 if(doordir == v3s16(1,0,0)) // X+
799 roomplace = doorplace +
800 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
801 if(doordir == v3s16(-1,0,0)) // X-
802 roomplace = doorplace +
803 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
804 if(doordir == v3s16(0,0,1)) // Z+
805 roomplace = doorplace +
806 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
807 if(doordir == v3s16(0,0,-1)) // Z-
808 roomplace = doorplace +
809 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
812 if(doordir == v3s16(1,0,0)) // X+
813 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
814 if(doordir == v3s16(-1,0,0)) // X-
815 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
816 if(doordir == v3s16(0,0,1)) // Z+
817 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
818 if(doordir == v3s16(0,0,-1)) // Z-
819 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
824 for(s16 z=1; z<roomsize.Z-1; z++)
825 for(s16 y=1; y<roomsize.Y-1; y++)
826 for(s16 x=1; x<roomsize.X-1; x++)
828 v3s16 p = roomplace + v3s16(x,y,z);
829 if(vmanip.m_area.contains(p) == false)
834 if(vmanip.m_flags[vmanip.m_area.index(p)]
835 & VMANIP_FLAG_DUNGEON_INSIDE)
846 result_doorplace = doorplace;
847 result_doordir = doordir;
848 result_roomplace = roomplace;
855 VoxelManipulator &vmanip;
858 PseudoRandom &m_random;
861 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
863 v3s16 areasize = vmanip.m_area.getExtent();
868 Find place for first room
871 for(u32 i=0; i<100; i++)
873 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
874 roomplace = vmanip.m_area.MinEdge + v3s16(
875 random.range(0,areasize.X-roomsize.X-1),
876 random.range(0,areasize.Y-roomsize.Y-1),
877 random.range(0,areasize.Z-roomsize.Z-1));
879 Check that we're not putting the room to an unknown place,
880 otherwise it might end up floating in the air
883 for(s16 z=1; z<roomsize.Z-1; z++)
884 for(s16 y=1; y<roomsize.Y-1; y++)
885 for(s16 x=1; x<roomsize.X-1; x++)
887 v3s16 p = roomplace + v3s16(x,y,z);
888 u32 vi = vmanip.m_area.index(p);
889 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
894 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
908 Stores the center position of the last room made, so that
909 a new corridor can be started from the last room instead of
910 the new room, if chosen so.
912 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
914 u32 room_count = random.range(2,7);
915 for(u32 i=0; i<room_count; i++)
917 // Make a room to the determined place
918 make_room1(vmanip, roomsize, roomplace);
920 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
922 // Place torch at room center (for testing)
923 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
926 if(i == room_count-1)
929 // Determine walker start position
931 bool start_in_last_room = (random.range(0,2)!=0);
932 //bool start_in_last_room = true;
934 v3s16 walker_start_place;
936 if(start_in_last_room)
938 walker_start_place = last_room_center;
942 walker_start_place = room_center;
943 // Store center of current room as the last one
944 last_room_center = room_center;
947 // Create walker and find a place for a door
948 RoomWalker walker(vmanip, walker_start_place, random);
951 bool r = walker.findPlaceForDoor(doorplace, doordir);
955 if(random.range(0,1)==0)
957 make_door1(vmanip, doorplace, doordir);
959 // Don't actually make a door
960 doorplace -= doordir;
962 // Make a random corridor starting from the door
964 v3s16 corridor_end_dir;
965 make_corridor(vmanip, doorplace, doordir, corridor_end,
966 corridor_end_dir, random);
968 // Find a place for a random sized room
969 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
970 walker.setPos(corridor_end);
971 walker.setDir(corridor_end_dir);
972 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
976 if(random.range(0,1)==0)
978 make_door1(vmanip, doorplace, doordir);
980 // Don't actually make a door
981 roomplace -= doordir;
986 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random)
990 s32 r = random.range(0, 3);
992 dir = v3s16( 1, 0, 0);
996 dir = v3s16(-1, 0, 0);
1000 dir = v3s16( 0, 0, 1);
1004 dir = v3s16( 0, 0,-1);
1007 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1008 16+random.range(0,15),
1009 16+random.range(0,15),
1010 16+random.range(0,15));
1011 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC, facedir_i);
1012 u32 length = random.range(3,15);
1013 for(u32 j=0; j<length; j++)
1016 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC_RB);
1021 Noise functions. Make sure seed is mangled differently in each one.
1025 Scaling the output of the noise function affects the overdrive of the
1026 contour function, which affects the shape of the output considerably.
1028 #define CAVE_NOISE_SCALE 12.0
1029 //#define CAVE_NOISE_SCALE 10.0
1030 //#define CAVE_NOISE_SCALE 7.5
1031 //#define CAVE_NOISE_SCALE 5.0
1032 //#define CAVE_NOISE_SCALE 1.0
1034 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1035 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1037 NoiseParams get_cave_noise1_params(u64 seed)
1039 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1040 200, CAVE_NOISE_SCALE);*/
1041 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1042 100, CAVE_NOISE_SCALE);*/
1043 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1044 100, CAVE_NOISE_SCALE);*/
1045 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1046 100, CAVE_NOISE_SCALE);*/
1047 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1048 50, CAVE_NOISE_SCALE);
1049 //return NoiseParams(NOISE_CONSTANT_ONE);
1052 NoiseParams get_cave_noise2_params(u64 seed)
1054 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1055 200, CAVE_NOISE_SCALE);*/
1056 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1057 100, CAVE_NOISE_SCALE);*/
1058 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1059 100, CAVE_NOISE_SCALE);*/
1060 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1061 50, CAVE_NOISE_SCALE);
1062 //return NoiseParams(NOISE_CONSTANT_ONE);
1065 NoiseParams get_ground_noise1_params(u64 seed)
1067 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1071 NoiseParams get_ground_crumbleness_params(u64 seed)
1073 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1077 NoiseParams get_ground_wetness_params(u64 seed)
1079 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1083 bool is_cave(u64 seed, v3s16 p)
1085 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1086 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1087 return d1*d2 > CAVE_NOISE_THRESHOLD;
1091 Ground density noise shall be interpreted by using this.
1093 TODO: No perlin noises here, they should be outsourced
1095 NOTE: The speed of these actually isn't terrible
1097 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1099 //return ((double)p.Y < ground_noise1_val);
1101 double f = 0.55 + noise2d_perlin(
1102 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1103 seed+920381, 3, 0.45);
1108 double h = WATER_LEVEL + 10 * noise2d_perlin(
1109 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1110 seed+84174, 4, 0.5);
1113 return ((double)p.Y - h < ground_noise1_val * f);
1117 Queries whether a position is ground or not.
1119 bool is_ground(u64 seed, v3s16 p)
1121 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1122 return val_is_ground(val1, p, seed);
1125 // Amount of trees per area in nodes
1126 double tree_amount_2d(u64 seed, v2s16 p)
1128 /*double noise = noise2d_perlin(
1129 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1131 double noise = noise2d_perlin(
1132 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1134 double zeroval = -0.39;
1138 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1141 double surface_humidity_2d(u64 seed, v2s16 p)
1143 double noise = noise2d_perlin(
1144 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1145 seed+72384, 4, 0.66);
1146 noise = (noise + 1.0)/2.0;
1155 double randomstone_amount_2d(u64 seed, v2s16 p)
1157 double noise = noise2d_perlin(
1158 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1159 seed+3829434, 5, 0.66);
1160 double zeroval = 0.1;
1164 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1168 double largestone_amount_2d(u64 seed, v2s16 p)
1170 double noise = noise2d_perlin(
1171 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1172 seed+14143242, 5, 0.66);
1173 double zeroval = 0.3;
1177 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1181 Incrementally find ground level from 3d noise
1183 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1185 // Start a bit fuzzy to make averaging lower precision values
1187 s16 level = myrand_range(-precision/2, precision/2);
1188 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1190 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1192 // First find non-ground by going upwards
1193 // Don't stop in caves.
1195 s16 max = level+dec[i-1]*2;
1196 v3s16 p(p2d.X, level, p2d.Y);
1197 for(; p.Y < max; p.Y += dec[i])
1199 if(!is_ground(seed, p))
1206 // Then find ground by going downwards from there.
1207 // Go in caves, too, when precision is 1.
1209 s16 min = level-dec[i-1]*2;
1210 v3s16 p(p2d.X, level, p2d.Y);
1211 for(; p.Y>min; p.Y-=dec[i])
1213 bool ground = is_ground(seed, p);
1214 /*if(dec[i] == 1 && is_cave(seed, p))
1225 // This is more like the actual ground level
1226 level += dec[i-1]/2;
1231 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1233 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1235 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1236 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1238 a += find_ground_level_from_noise(seed,
1239 v2s16(node_min.X, node_min.Y), p);
1240 a += find_ground_level_from_noise(seed,
1241 v2s16(node_min.X, node_max.Y), p);
1242 a += find_ground_level_from_noise(seed,
1243 v2s16(node_max.X, node_max.Y), p);
1244 a += find_ground_level_from_noise(seed,
1245 v2s16(node_max.X, node_min.Y), p);
1246 a += find_ground_level_from_noise(seed,
1247 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1252 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1254 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1256 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1257 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1260 a = MYMAX(a, find_ground_level_from_noise(seed,
1261 v2s16(node_min.X, node_min.Y), p));
1262 a = MYMAX(a, find_ground_level_from_noise(seed,
1263 v2s16(node_min.X, node_max.Y), p));
1264 a = MYMAX(a, find_ground_level_from_noise(seed,
1265 v2s16(node_max.X, node_max.Y), p));
1266 a = MYMAX(a, find_ground_level_from_noise(seed,
1267 v2s16(node_min.X, node_min.Y), p));
1269 a = MYMAX(a, find_ground_level_from_noise(seed,
1270 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1271 // Side middle points
1272 a = MYMAX(a, find_ground_level_from_noise(seed,
1273 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1274 a = MYMAX(a, find_ground_level_from_noise(seed,
1275 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1276 a = MYMAX(a, find_ground_level_from_noise(seed,
1277 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1278 a = MYMAX(a, find_ground_level_from_noise(seed,
1279 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1283 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1285 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1287 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1288 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1291 a = MYMIN(a, find_ground_level_from_noise(seed,
1292 v2s16(node_min.X, node_min.Y), p));
1293 a = MYMIN(a, find_ground_level_from_noise(seed,
1294 v2s16(node_min.X, node_max.Y), p));
1295 a = MYMIN(a, find_ground_level_from_noise(seed,
1296 v2s16(node_max.X, node_max.Y), p));
1297 a = MYMIN(a, find_ground_level_from_noise(seed,
1298 v2s16(node_min.X, node_min.Y), p));
1300 a = MYMIN(a, find_ground_level_from_noise(seed,
1301 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1302 // Side middle points
1303 a = MYMIN(a, find_ground_level_from_noise(seed,
1304 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1305 a = MYMIN(a, find_ground_level_from_noise(seed,
1306 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1307 a = MYMIN(a, find_ground_level_from_noise(seed,
1308 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1309 a = MYMIN(a, find_ground_level_from_noise(seed,
1310 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1314 bool block_is_underground(u64 seed, v3s16 blockpos)
1316 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1317 seed, v2s16(blockpos.X, blockpos.Z));
1319 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1326 #define AVERAGE_MUD_AMOUNT 4
1328 double base_rock_level_2d(u64 seed, v2s16 p)
1330 // The base ground level
1331 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1332 + 20. * noise2d_perlin(
1333 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1334 (seed>>32)+654879876, 6, 0.6);
1336 /*// A bit hillier one
1337 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1338 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1339 (seed>>27)+90340, 6, 0.69);
1343 // Higher ground level
1344 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1345 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1346 seed+85039, 5, 0.69);
1347 //higher = 30; // For debugging
1349 // Limit higher to at least base
1353 // Steepness factor of cliffs
1354 double b = 1.0 + 1.0 * noise2d_perlin(
1355 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1357 b = rangelim(b, 0.0, 1000.0);
1360 b = rangelim(b, 3.0, 1000.0);
1361 //dstream<<"b="<<b<<std::endl;
1364 // Offset to more low
1365 double a_off = -0.2;
1366 // High/low selector
1367 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1368 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1369 seed-359, 6, 0.7));*/
1370 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1371 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1372 seed-359, 5, 0.60));
1374 a = rangelim(a, 0.0, 1.0);
1376 //dstream<<"a="<<a<<std::endl;
1378 double h = base*(1.0-a) + higher*a;
1385 double get_mud_add_amount(u64 seed, v2s16 p)
1387 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1388 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1389 seed+91013, 3, 0.55));
1393 bool get_have_sand(u64 seed, v2s16 p2d)
1395 // Determine whether to have sand here
1396 double sandnoise = noise2d_perlin(
1397 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1398 seed+59420, 3, 0.50);
1400 return (sandnoise > -0.15);
1404 Adds random objects to block, depending on the content of the block
1406 void add_random_objects(MapBlock *block)
1409 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1410 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1412 bool last_node_walkable = false;
1413 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1416 MapNode n = block->getNodeNoEx(p);
1417 if(n.getContent() == CONTENT_IGNORE)
1419 if(content_features(n).liquid_type != LIQUID_NONE)
1421 if(content_features(n).walkable)
1423 last_node_walkable = true;
1426 if(last_node_walkable)
1428 // If block contains light information
1429 if(content_features(n).param_type == CPT_LIGHT)
1431 if(n.getLight(LIGHTBANK_DAY) <= 3)
1433 if(myrand() % 300 == 0)
1435 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1437 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1438 std::string data = obj->getStaticData();
1439 StaticObject s_obj(obj->getType(),
1440 obj->getBasePosition(), data);
1442 block->m_static_objects.insert(0, s_obj);
1443 block->m_static_objects.insert(0, s_obj);
1444 block->m_static_objects.insert(0, s_obj);
1445 block->m_static_objects.insert(0, s_obj);
1446 block->m_static_objects.insert(0, s_obj);
1447 block->m_static_objects.insert(0, s_obj);
1450 if(myrand() % 1000 == 0)
1452 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1454 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1455 std::string data = obj->getStaticData();
1456 StaticObject s_obj(obj->getType(),
1457 obj->getBasePosition(), data);
1459 block->m_static_objects.insert(0, s_obj);
1465 last_node_walkable = false;
1468 block->setChangedFlag();
1472 void make_block(BlockMakeData *data)
1476 //dstream<<"makeBlock: no-op"<<std::endl;
1480 v3s16 blockpos = data->blockpos;
1482 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1483 <<blockpos.Z<<")"<<std::endl;*/
1485 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1486 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1487 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1488 // Area of center block
1489 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1490 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1491 // Full allocated area
1492 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1493 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1495 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1497 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1500 Get average ground level from noise
1503 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1504 data->seed, v2s16(blockpos.X, blockpos.Z));
1505 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1507 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1509 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1510 data->seed, v2s16(blockpos.X, blockpos.Z));
1511 // Minimum amount of ground above the top of the central block
1512 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1514 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1515 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1516 // Maximum amount of ground above the bottom of the central block
1517 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1521 Special case for high air or water: Just fill with air and water.
1523 if(maximum_ground_depth < -20)
1525 for(s16 x=node_min.X; x<=node_max.X; x++)
1526 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1531 // Use fast index incrementing
1532 v3s16 em = vmanip.m_area.getExtent();
1533 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1534 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1536 // Only modify places that have no content
1537 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1539 if(y <= WATER_LEVEL)
1540 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1542 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1545 data->vmanip->m_area.add_y(em, i, 1);
1556 If block is deep underground, this is set to true and ground
1557 density noise is not generated, for speed optimization.
1559 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1562 Create a block-specific seed
1564 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1565 + full_node_min.Y*42123 + full_node_min.X*23;
1571 //NoiseBuffer noisebuf1;
1572 //NoiseBuffer noisebuf2;
1573 NoiseBuffer noisebuf_cave;
1574 NoiseBuffer noisebuf_ground;
1575 NoiseBuffer noisebuf_ground_crumbleness;
1576 NoiseBuffer noisebuf_ground_wetness;
1578 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1579 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1581 //TimeTaker timer("noisebuf.create");
1587 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1588 minpos_f.X, minpos_f.Y, minpos_f.Z,
1589 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1591 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1599 v3f sl = v3f(4.0, 4.0, 4.0);
1604 if(all_is_ground_except_caves == false)
1605 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1606 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1607 minpos_f.X, minpos_f.Y, minpos_f.Z,
1608 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1612 Ground property noise
1614 sl = v3f(2.5, 2.5, 2.5);
1615 noisebuf_ground_crumbleness.create(
1616 get_ground_crumbleness_params(data->seed),
1617 minpos_f.X, minpos_f.Y, minpos_f.Z,
1618 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1620 noisebuf_ground_wetness.create(
1621 get_ground_wetness_params(data->seed),
1622 minpos_f.X, minpos_f.Y, minpos_f.Z,
1623 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1628 Make base ground level
1631 for(s16 x=node_min.X; x<=node_max.X; x++)
1632 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1637 // Use fast index incrementing
1638 v3s16 em = vmanip.m_area.getExtent();
1639 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1640 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1642 // Only modify places that have no content
1643 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1645 // First priority: make air and water.
1646 // This avoids caves inside water.
1647 if(all_is_ground_except_caves == false
1648 && val_is_ground(noisebuf_ground.get(x,y,z),
1649 v3s16(x,y,z), data->seed) == false)
1651 if(y <= WATER_LEVEL)
1652 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1654 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1656 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1657 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1659 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1662 data->vmanip->m_area.add_y(em, i, 1);
1672 PseudoRandom mineralrandom(blockseed);
1677 for(s16 i=0; i<approx_ground_depth/4; i++)
1679 if(mineralrandom.next()%50 == 0)
1681 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1682 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1683 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1684 for(u16 i=0; i<27; i++)
1686 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1687 u32 vi = vmanip.m_area.index(p);
1688 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1689 if(mineralrandom.next()%8 == 0)
1690 vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1699 u16 a = mineralrandom.range(0,15);
1701 u16 amount = 20 * a/1000;
1702 for(s16 i=0; i<amount; i++)
1704 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1705 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1706 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1708 u8 base_content = CONTENT_STONE;
1709 MapNode new_content(CONTENT_IGNORE);
1712 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1714 new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1718 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1719 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1720 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1721 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1723 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1725 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1729 if(new_content.getContent() != CONTENT_IGNORE)
1731 for(u16 i=0; i<27; i++)
1733 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1734 u32 vi = vmanip.m_area.index(p);
1735 if(vmanip.m_data[vi].getContent() == base_content)
1737 if(mineralrandom.next()%sparseness == 0)
1738 vmanip.m_data[vi] = new_content;
1747 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1748 //for(s16 i=0; i<50; i++)
1749 u16 coal_amount = 30;
1750 u16 coal_rareness = 60 / coal_amount;
1751 if(coal_rareness == 0)
1753 if(mineralrandom.next()%coal_rareness == 0)
1755 u16 a = mineralrandom.next() % 16;
1756 u16 amount = coal_amount * a*a*a / 1000;
1757 for(s16 i=0; i<amount; i++)
1759 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1760 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1761 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1762 for(u16 i=0; i<27; i++)
1764 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1765 u32 vi = vmanip.m_area.index(p);
1766 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1767 if(mineralrandom.next()%8 == 0)
1768 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1775 u16 iron_amount = 8;
1776 u16 iron_rareness = 60 / iron_amount;
1777 if(iron_rareness == 0)
1779 if(mineralrandom.next()%iron_rareness == 0)
1781 u16 a = mineralrandom.next() % 16;
1782 u16 amount = iron_amount * a*a*a / 1000;
1783 for(s16 i=0; i<amount; i++)
1785 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1786 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1787 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1788 for(u16 i=0; i<27; i++)
1790 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1791 u32 vi = vmanip.m_area.index(p);
1792 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1793 if(mineralrandom.next()%8 == 0)
1794 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1801 Add mud and sand and others underground (in place of stone)
1804 for(s16 x=node_min.X; x<=node_max.X; x++)
1805 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1810 // Use fast index incrementing
1811 v3s16 em = vmanip.m_area.getExtent();
1812 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1813 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1815 if(vmanip.m_data[i].getContent() == CONTENT_STONE)
1817 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1819 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1820 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1822 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1824 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1826 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1827 vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1829 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1830 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1832 vmanip.m_data[i] = MapNode(CONTENT_LAVASOURCE);
1833 for(s16 x1=-1; x1<=1; x1++)
1834 for(s16 y1=-1; y1<=1; y1++)
1835 for(s16 z1=-1; z1<=1; z1++)
1836 data->transforming_liquid.push_back(
1837 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1841 data->vmanip->m_area.add_y(em, i, -1);
1850 //if(node_min.Y < approx_groundlevel)
1851 //if(myrand() % 3 == 0)
1852 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1853 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1854 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1855 float dungeon_rarity = 0.02;
1856 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1858 && node_min.Y < approx_groundlevel)
1860 // Dungeon generator doesn't modify places which have this set
1861 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1862 | VMANIP_FLAG_DUNGEON_PRESERVE);
1864 // Set all air and water to be untouchable to make dungeons open
1865 // to caves and open air
1866 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1867 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1872 // Use fast index incrementing
1873 v3s16 em = vmanip.m_area.getExtent();
1874 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1875 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1877 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1878 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1879 else if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1880 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1881 data->vmanip->m_area.add_y(em, i, -1);
1886 PseudoRandom random(blockseed+2);
1889 make_dungeon1(vmanip, random);
1891 // Convert some cobble to mossy cobble
1892 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1893 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1898 // Use fast index incrementing
1899 v3s16 em = vmanip.m_area.getExtent();
1900 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1901 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1903 // (noisebuf not used because it doesn't contain the
1905 double wetness = noise3d_param(
1906 get_ground_wetness_params(data->seed), x,y,z);
1907 double d = noise3d_perlin((float)x/2.5,
1908 (float)y/2.5,(float)z/2.5,
1910 if(vmanip.m_data[i].getContent() == CONTENT_COBBLE)
1914 vmanip.m_data[i].setContent(CONTENT_MOSSYCOBBLE);
1917 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1920 vmanip.m_data[i].setContent(CONTENT_MUD);
1922 data->vmanip->m_area.add_y(em, i, -1);
1932 PseudoRandom ncrandom(blockseed+9324342);
1933 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1935 make_nc(vmanip, ncrandom);
1940 Add top and bottom side of water to transforming_liquid queue
1943 for(s16 x=node_min.X; x<=node_max.X; x++)
1944 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1949 bool water_found = false;
1950 // Use fast index incrementing
1951 v3s16 em = vmanip.m_area.getExtent();
1952 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1953 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1955 if(water_found == false)
1957 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1959 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1960 data->transforming_liquid.push_back(p);
1966 // This can be done because water_found can only
1967 // turn to true and end up here after going through
1969 if(vmanip.m_data[i+1].getContent() != CONTENT_WATERSOURCE)
1971 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1972 data->transforming_liquid.push_back(p);
1973 water_found = false;
1977 data->vmanip->m_area.add_y(em, i, -1);
1983 If close to ground level
1986 //if(abs(approx_ground_depth) < 30)
1987 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1993 for(s16 x=node_min.X; x<=node_max.X; x++)
1994 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1999 bool possibly_have_sand = get_have_sand(data->seed, p2d);
2000 bool have_sand = false;
2001 u32 current_depth = 0;
2002 bool air_detected = false;
2003 bool water_detected = false;
2004 bool have_clay = false;
2006 // Use fast index incrementing
2007 s16 start_y = node_max.Y+2;
2008 v3s16 em = vmanip.m_area.getExtent();
2009 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2010 for(s16 y=start_y; y>=node_min.Y-3; y--)
2012 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
2013 water_detected = true;
2014 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2015 air_detected = true;
2017 if((vmanip.m_data[i].getContent() == CONTENT_STONE
2018 || vmanip.m_data[i].getContent() == CONTENT_GRASS
2019 || vmanip.m_data[i].getContent() == CONTENT_MUD
2020 || vmanip.m_data[i].getContent() == CONTENT_SAND
2021 || vmanip.m_data[i].getContent() == CONTENT_GRAVEL
2022 ) && (air_detected || water_detected))
2024 if(current_depth == 0 && y <= WATER_LEVEL+2
2025 && possibly_have_sand)
2028 if(current_depth < 4)
2032 // Determine whether to have clay in the sand here
2033 double claynoise = noise2d_perlin(
2034 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2035 data->seed+4321, 6, 0.95) + 0.5;
2037 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2038 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2039 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2042 vmanip.m_data[i] = MapNode(CONTENT_CLAY);
2044 vmanip.m_data[i] = MapNode(CONTENT_SAND);
2047 else if(current_depth==0 && !water_detected
2048 && y >= WATER_LEVEL && air_detected)
2049 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
2052 vmanip.m_data[i] = MapNode(CONTENT_MUD);
2056 if(vmanip.m_data[i].getContent() == CONTENT_MUD
2057 || vmanip.m_data[i].getContent() == CONTENT_GRASS)
2058 vmanip.m_data[i] = MapNode(CONTENT_STONE);
2063 if(current_depth >= 8)
2066 else if(current_depth != 0)
2069 data->vmanip->m_area.add_y(em, i, -1);
2075 Calculate some stuff
2078 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2079 bool is_jungle = surface_humidity > 0.75;
2081 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
2088 PseudoRandom treerandom(blockseed);
2089 // Put trees in random places on part of division
2090 for(u32 i=0; i<tree_count; i++)
2092 s16 x = treerandom.range(node_min.X, node_max.X);
2093 s16 z = treerandom.range(node_min.Z, node_max.Z);
2094 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2095 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2096 // Don't make a tree under water level
2099 // Make sure tree fits (only trees whose starting point is
2100 // at this block are added)
2101 if(y < node_min.Y || y > node_max.Y)
2104 Find exact ground level
2108 for(; p.Y >= y-6; p.Y--)
2110 u32 i = data->vmanip->m_area.index(p);
2111 MapNode *n = &data->vmanip->m_data[i];
2112 if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
2118 // If not found, handle next one
2123 u32 i = data->vmanip->m_area.index(p);
2124 MapNode *n = &data->vmanip->m_data[i];
2126 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
2129 // Papyrus grows only on mud and in water
2130 if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
2133 make_papyrus(vmanip, p);
2135 // Trees grow only on mud and grass, on land
2136 else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
2139 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2140 if(is_jungle == false)
2143 if(myrand_range(0,4) != 0)
2144 is_apple_tree = false;
2146 is_apple_tree = noise2d_perlin(
2147 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2148 data->seed+342902, 3, 0.45) > 0.2;
2149 make_tree(vmanip, p, is_apple_tree);
2152 make_jungletree(vmanip, p);
2154 // Cactii grow only on sand, on land
2155 else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
2158 make_cactus(vmanip, p);
2168 PseudoRandom grassrandom(blockseed);
2169 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2171 s16 x = grassrandom.range(node_min.X, node_max.X);
2172 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2173 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2176 if(y < node_min.Y || y > node_max.Y)
2179 Find exact ground level
2183 for(; p.Y >= y-6; p.Y--)
2185 u32 i = data->vmanip->m_area.index(p);
2186 MapNode *n = &data->vmanip->m_data[i];
2187 if(content_features(*n).is_ground_content
2188 || n->getContent() == CONTENT_JUNGLETREE)
2194 // If not found, handle next one
2198 if(vmanip.m_area.contains(p) == false)
2200 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2203 if(vmanip.m_area.contains(p))
2204 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
2206 if(vmanip.m_area.contains(p))
2207 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
2213 Add some kind of random stones
2216 u32 random_stone_count = block_area_nodes *
2217 randomstone_amount_2d(data->seed, p2d_center);
2218 // Put in random places on part of division
2219 for(u32 i=0; i<random_stone_count; i++)
2221 s16 x = myrand_range(node_min.X, node_max.X);
2222 s16 z = myrand_range(node_min.Z, node_max.Z);
2223 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2224 // Don't add under water level
2225 /*if(y < WATER_LEVEL)
2227 // Don't add if doesn't belong to this block
2228 if(y < node_min.Y || y > node_max.Y)
2233 u32 i = data->vmanip->m_area.index(v3s16(p));
2234 MapNode *n = &data->vmanip->m_data[i];
2235 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2238 // Will be placed one higher
2241 make_randomstone(data->vmanip, p);
2250 u32 large_stone_count = block_area_nodes *
2251 largestone_amount_2d(data->seed, p2d_center);
2252 //u32 large_stone_count = 1;
2253 // Put in random places on part of division
2254 for(u32 i=0; i<large_stone_count; i++)
2256 s16 x = myrand_range(node_min.X, node_max.X);
2257 s16 z = myrand_range(node_min.Z, node_max.Z);
2258 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2259 // Don't add under water level
2260 /*if(y < WATER_LEVEL)
2262 // Don't add if doesn't belong to this block
2263 if(y < node_min.Y || y > node_max.Y)
2268 u32 i = data->vmanip->m_area.index(v3s16(p));
2269 MapNode *n = &data->vmanip->m_data[i];
2270 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2273 // Will be placed one lower
2276 make_largestone(data->vmanip, p);
2283 BlockMakeData::BlockMakeData():
2289 BlockMakeData::~BlockMakeData()
2294 }; // namespace mapgen