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);
88 s16 trunk_h = myrand_range(4, 5);
90 for(s16 ii=0; ii<trunk_h; ii++)
92 if(vmanip.m_area.contains(p1))
93 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
97 // p1 is now the last piece of the trunk
100 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
101 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
102 Buffer<u8> leaves_d(leaves_a.getVolume());
103 for(s32 i=0; i<leaves_a.getVolume(); i++)
106 // Force leaves at near the end of the trunk
109 for(s16 z=-d; z<=d; z++)
110 for(s16 y=-d; y<=d; y++)
111 for(s16 x=-d; x<=d; x++)
113 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
117 // Add leaves randomly
118 for(u32 iii=0; iii<7; iii++)
123 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
124 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
125 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
128 for(s16 z=0; z<=d; z++)
129 for(s16 y=0; y<=d; y++)
130 for(s16 x=0; x<=d; x++)
132 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
136 // Blit leaves to vmanip
137 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
138 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
139 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
143 if(vmanip.m_area.contains(p) == false)
145 u32 vi = vmanip.m_area.index(p);
146 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
147 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
149 u32 i = leaves_a.index(x,y,z);
151 vmanip.m_data[vi] = leavesnode;
155 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0)
157 MapNode treenode(CONTENT_JUNGLETREE);
158 MapNode leavesnode(CONTENT_LEAVES);
160 for(s16 x=-1; x<=1; x++)
161 for(s16 z=-1; z<=1; z++)
163 if(myrand_range(0, 2) == 0)
165 v3s16 p1 = p0 + v3s16(x,0,z);
166 v3s16 p2 = p0 + v3s16(x,-1,z);
167 if(vmanip.m_area.contains(p2)
168 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
169 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
170 else if(vmanip.m_area.contains(p1))
171 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
174 s16 trunk_h = myrand_range(8, 12);
176 for(s16 ii=0; ii<trunk_h; ii++)
178 if(vmanip.m_area.contains(p1))
179 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
183 // p1 is now the last piece of the trunk
186 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
187 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
188 Buffer<u8> leaves_d(leaves_a.getVolume());
189 for(s32 i=0; i<leaves_a.getVolume(); i++)
192 // Force leaves at near the end of the trunk
195 for(s16 z=-d; z<=d; z++)
196 for(s16 y=-d; y<=d; y++)
197 for(s16 x=-d; x<=d; x++)
199 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
203 // Add leaves randomly
204 for(u32 iii=0; iii<30; iii++)
209 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
210 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
211 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
214 for(s16 z=0; z<=d; z++)
215 for(s16 y=0; y<=d; y++)
216 for(s16 x=0; x<=d; x++)
218 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
222 // Blit leaves to vmanip
223 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
224 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
225 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
229 if(vmanip.m_area.contains(p) == false)
231 u32 vi = vmanip.m_area.index(p);
232 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
233 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
235 u32 i = leaves_a.index(x,y,z);
237 vmanip.m_data[vi] = leavesnode;
241 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0)
243 MapNode papyrusnode(CONTENT_PAPYRUS);
245 s16 trunk_h = myrand_range(2, 3);
247 for(s16 ii=0; ii<trunk_h; ii++)
249 if(vmanip.m_area.contains(p1))
250 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
255 void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
257 MapNode cactusnode(CONTENT_CACTUS);
261 for(s16 ii=0; ii<trunk_h; ii++)
263 if(vmanip.m_area.contains(p1))
264 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
270 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
272 MapNode stonenode(CONTENT_STONE);
274 s16 size = myrand_range(3, 6);
276 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
277 Buffer<u8> stone_d(stone_a.getVolume());
278 for(s32 i=0; i<stone_a.getVolume(); i++)
281 // Force stone at bottom to make it usually touch the ground
283 for(s16 z=0; z<=0; z++)
284 for(s16 y=0; y<=0; y++)
285 for(s16 x=0; x<=0; x++)
287 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
291 // Generate from perlin noise
292 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
293 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
294 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
296 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
297 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
298 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
300 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
302 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
306 u32 vi = stone_a.index(v3s16(x,y,z));
311 /*// Add stone randomly
312 for(u32 iii=0; iii<7; iii++)
317 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
318 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
319 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
322 for(s16 z=0; z<=d; z++)
323 for(s16 y=0; y<=d; y++)
324 for(s16 x=0; x<=d; x++)
326 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
330 // Blit stone to vmanip
331 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
332 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
333 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
337 if(vmanip.m_area.contains(p) == false)
339 u32 vi = vmanip.m_area.index(p);
340 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
341 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
343 u32 i = stone_a.index(x,y,z);
345 vmanip.m_data[vi] = stonenode;
351 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
353 MapNode stonenode(CONTENT_STONE);
355 s16 size = myrand_range(8, 16);
357 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
358 Buffer<u8> stone_d(stone_a.getVolume());
359 for(s32 i=0; i<stone_a.getVolume(); i++)
362 // Force stone at bottom to make it usually touch the ground
364 for(s16 z=0; z<=0; z++)
365 for(s16 y=0; y<=0; y++)
366 for(s16 x=0; x<=0; x++)
368 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
372 // Generate from perlin noise
373 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
374 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
375 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
378 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
379 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
380 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
381 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
382 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
383 double dz = (double)z-mid_z;
384 double dx = (double)x-mid_x;
385 double dy = MYMAX(0, (double)y-mid_y);
386 double r = sqrt(dz*dz+dx*dx+dy*dy);
387 d /= (2*r/size)*2 + 0.01;
390 u32 vi = stone_a.index(v3s16(x,y,z));
395 /*// Add stone randomly
396 for(u32 iii=0; iii<7; iii++)
401 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
402 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
403 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
406 for(s16 z=0; z<=d; z++)
407 for(s16 y=0; y<=d; y++)
408 for(s16 x=0; x<=d; x++)
410 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
414 // Blit stone to vmanip
415 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
416 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
417 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
421 if(vmanip.m_area.contains(p) == false)
423 u32 vi = vmanip.m_area.index(p);
424 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
425 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
427 u32 i = stone_a.index(x,y,z);
429 vmanip.m_data[vi] = stonenode;
435 Dungeon making routines
438 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
439 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
440 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
441 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
443 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
446 for(s16 z=0; z<roomsize.Z; z++)
447 for(s16 y=0; y<roomsize.Y; y++)
450 v3s16 p = roomplace + v3s16(0,y,z);
451 if(vmanip.m_area.contains(p) == false)
453 u32 vi = vmanip.m_area.index(p);
454 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
456 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
459 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
460 if(vmanip.m_area.contains(p) == false)
462 u32 vi = vmanip.m_area.index(p);
463 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
465 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
470 for(s16 x=0; x<roomsize.X; x++)
471 for(s16 y=0; y<roomsize.Y; y++)
474 v3s16 p = roomplace + v3s16(x,y,0);
475 if(vmanip.m_area.contains(p) == false)
477 u32 vi = vmanip.m_area.index(p);
478 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
480 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
483 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
484 if(vmanip.m_area.contains(p) == false)
486 u32 vi = vmanip.m_area.index(p);
487 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
489 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
493 // Make +-Y walls (floor and ceiling)
494 for(s16 z=0; z<roomsize.Z; z++)
495 for(s16 x=0; x<roomsize.X; x++)
498 v3s16 p = roomplace + v3s16(x,0,z);
499 if(vmanip.m_area.contains(p) == false)
501 u32 vi = vmanip.m_area.index(p);
502 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
504 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
507 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
508 if(vmanip.m_area.contains(p) == false)
510 u32 vi = vmanip.m_area.index(p);
511 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
513 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
518 for(s16 z=1; z<roomsize.Z-1; z++)
519 for(s16 y=1; y<roomsize.Y-1; y++)
520 for(s16 x=1; x<roomsize.X-1; x++)
522 v3s16 p = roomplace + v3s16(x,y,z);
523 if(vmanip.m_area.contains(p) == false)
525 u32 vi = vmanip.m_area.index(p);
526 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
527 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
531 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
532 u8 avoid_flags, MapNode n, u8 or_flags)
534 for(s16 z=0; z<size.Z; z++)
535 for(s16 y=0; y<size.Y; y++)
536 for(s16 x=0; x<size.X; x++)
538 v3s16 p = place + v3s16(x,y,z);
539 if(vmanip.m_area.contains(p) == false)
541 u32 vi = vmanip.m_area.index(p);
542 if(vmanip.m_flags[vi] & avoid_flags)
544 vmanip.m_flags[vi] |= or_flags;
545 vmanip.m_data[vi] = n;
549 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
551 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
552 VMANIP_FLAG_DUNGEON_INSIDE);
555 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
557 make_hole1(vmanip, doorplace);
558 // Place torch (for testing)
559 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
562 static v3s16 rand_ortho_dir(PseudoRandom &random)
564 if(random.next()%2==0)
565 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
567 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
570 static v3s16 turn_xz(v3s16 olddir, int t)
590 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
592 int turn = random.range(0,2);
601 dir = turn_xz(olddir, 0);
604 dir = turn_xz(olddir, 1);
608 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
609 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
610 PseudoRandom &random)
612 make_hole1(vmanip, doorplace);
613 v3s16 p0 = doorplace;
617 length = random.range(1,13);
619 length = random.range(1,6);
620 length = random.range(1,13);
621 u32 partlength = random.range(1,13);
624 if(random.next()%2 == 0 && partlength >= 3)
625 make_stairs = random.next()%2 ? 1 : -1;
626 for(u32 i=0; i<length; i++)
632 /*// If already empty
633 if(vmanip.getNodeNoExNoEmerge(p).getContent()
635 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
640 if(vmanip.m_area.contains(p) == true
641 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
645 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
646 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
647 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
648 VMANIP_FLAG_DUNGEON_INSIDE);
649 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
650 VMANIP_FLAG_DUNGEON_INSIDE);
654 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
655 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
656 make_hole1(vmanip, p);
657 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
658 VMANIP_FLAG_DUNGEON_INSIDE);*/
665 // Can't go here, turn away
666 dir = turn_xz(dir, random.range(0,1));
667 make_stairs = -make_stairs;
669 partlength = random.range(1,length);
674 if(partcount >= partlength)
678 dir = random_turn(random, dir);
680 partlength = random.range(1,length);
683 if(random.next()%2 == 0 && partlength >= 3)
684 make_stairs = random.next()%2 ? 1 : -1;
695 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
705 m_dir = rand_ortho_dir(m_random);
708 void setPos(v3s16 pos)
713 void setDir(v3s16 dir)
718 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
720 for(u32 i=0; i<100; i++)
722 v3s16 p = m_pos + m_dir;
723 v3s16 p1 = p + v3s16(0,1,0);
724 if(vmanip.m_area.contains(p) == false
725 || vmanip.m_area.contains(p1) == false
731 if(vmanip.getNodeNoExNoEmerge(p).getContent()
733 && vmanip.getNodeNoExNoEmerge(p1).getContent()
736 // Found wall, this is a good place!
739 // Randomize next direction
744 Determine where to move next
746 // Jump one up if the actual space is there
747 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
749 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
751 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
754 // Jump one down if the actual space is there
755 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
757 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
759 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
762 // Check if walking is now possible
763 if(vmanip.getNodeNoExNoEmerge(p).getContent()
765 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
768 // Cannot continue walking here
778 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
779 v3s16 &result_doordir, v3s16 &result_roomplace)
781 for(s16 trycount=0; trycount<30; trycount++)
785 bool r = findPlaceForDoor(doorplace, doordir);
789 // X east, Z north, Y up
791 if(doordir == v3s16(1,0,0)) // X+
792 roomplace = doorplace +
793 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
794 if(doordir == v3s16(-1,0,0)) // X-
795 roomplace = doorplace +
796 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
797 if(doordir == v3s16(0,0,1)) // Z+
798 roomplace = doorplace +
799 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
800 if(doordir == v3s16(0,0,-1)) // Z-
801 roomplace = doorplace +
802 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
805 if(doordir == v3s16(1,0,0)) // X+
806 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
807 if(doordir == v3s16(-1,0,0)) // X-
808 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
809 if(doordir == v3s16(0,0,1)) // Z+
810 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
811 if(doordir == v3s16(0,0,-1)) // Z-
812 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
817 for(s16 z=1; z<roomsize.Z-1; z++)
818 for(s16 y=1; y<roomsize.Y-1; y++)
819 for(s16 x=1; x<roomsize.X-1; x++)
821 v3s16 p = roomplace + v3s16(x,y,z);
822 if(vmanip.m_area.contains(p) == false)
827 if(vmanip.m_flags[vmanip.m_area.index(p)]
828 & VMANIP_FLAG_DUNGEON_INSIDE)
839 result_doorplace = doorplace;
840 result_doordir = doordir;
841 result_roomplace = roomplace;
848 VoxelManipulator &vmanip;
851 PseudoRandom &m_random;
854 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
856 v3s16 areasize = vmanip.m_area.getExtent();
861 Find place for first room
864 for(u32 i=0; i<100; i++)
866 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
867 roomplace = vmanip.m_area.MinEdge + v3s16(
868 random.range(0,areasize.X-roomsize.X-1),
869 random.range(0,areasize.Y-roomsize.Y-1),
870 random.range(0,areasize.Z-roomsize.Z-1));
872 Check that we're not putting the room to an unknown place,
873 otherwise it might end up floating in the air
876 for(s16 z=1; z<roomsize.Z-1; z++)
877 for(s16 y=1; y<roomsize.Y-1; y++)
878 for(s16 x=1; x<roomsize.X-1; x++)
880 v3s16 p = roomplace + v3s16(x,y,z);
881 u32 vi = vmanip.m_area.index(p);
882 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
887 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
901 Stores the center position of the last room made, so that
902 a new corridor can be started from the last room instead of
903 the new room, if chosen so.
905 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
907 u32 room_count = random.range(2,7);
908 for(u32 i=0; i<room_count; i++)
910 // Make a room to the determined place
911 make_room1(vmanip, roomsize, roomplace);
913 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
915 // Place torch at room center (for testing)
916 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
919 if(i == room_count-1)
922 // Determine walker start position
924 bool start_in_last_room = (random.range(0,2)!=0);
925 //bool start_in_last_room = true;
927 v3s16 walker_start_place;
929 if(start_in_last_room)
931 walker_start_place = last_room_center;
935 walker_start_place = room_center;
936 // Store center of current room as the last one
937 last_room_center = room_center;
940 // Create walker and find a place for a door
941 RoomWalker walker(vmanip, walker_start_place, random);
944 bool r = walker.findPlaceForDoor(doorplace, doordir);
948 if(random.range(0,1)==0)
950 make_door1(vmanip, doorplace, doordir);
952 // Don't actually make a door
953 doorplace -= doordir;
955 // Make a random corridor starting from the door
957 v3s16 corridor_end_dir;
958 make_corridor(vmanip, doorplace, doordir, corridor_end,
959 corridor_end_dir, random);
961 // Find a place for a random sized room
962 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
963 walker.setPos(corridor_end);
964 walker.setDir(corridor_end_dir);
965 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
969 if(random.range(0,1)==0)
971 make_door1(vmanip, doorplace, doordir);
973 // Don't actually make a door
974 roomplace -= doordir;
979 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random)
983 s32 r = random.range(0, 3);
985 dir = v3s16( 1, 0, 0);
989 dir = v3s16(-1, 0, 0);
993 dir = v3s16( 0, 0, 1);
997 dir = v3s16( 0, 0,-1);
1000 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1001 16+random.range(0,15),
1002 16+random.range(0,15),
1003 16+random.range(0,15));
1004 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC, facedir_i);
1005 u32 length = random.range(3,15);
1006 for(u32 j=0; j<length; j++)
1009 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC_RB);
1014 Noise functions. Make sure seed is mangled differently in each one.
1018 Scaling the output of the noise function affects the overdrive of the
1019 contour function, which affects the shape of the output considerably.
1021 #define CAVE_NOISE_SCALE 12.0
1022 //#define CAVE_NOISE_SCALE 10.0
1023 //#define CAVE_NOISE_SCALE 7.5
1024 //#define CAVE_NOISE_SCALE 5.0
1025 //#define CAVE_NOISE_SCALE 1.0
1027 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1028 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1030 NoiseParams get_cave_noise1_params(u64 seed)
1032 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1033 200, CAVE_NOISE_SCALE);*/
1034 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1035 100, CAVE_NOISE_SCALE);*/
1036 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1037 100, CAVE_NOISE_SCALE);*/
1038 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1039 100, CAVE_NOISE_SCALE);*/
1040 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1041 50, CAVE_NOISE_SCALE);
1042 //return NoiseParams(NOISE_CONSTANT_ONE);
1045 NoiseParams get_cave_noise2_params(u64 seed)
1047 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1048 200, CAVE_NOISE_SCALE);*/
1049 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1050 100, CAVE_NOISE_SCALE);*/
1051 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1052 100, CAVE_NOISE_SCALE);*/
1053 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1054 50, CAVE_NOISE_SCALE);
1055 //return NoiseParams(NOISE_CONSTANT_ONE);
1058 NoiseParams get_ground_noise1_params(u64 seed)
1060 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1064 NoiseParams get_ground_crumbleness_params(u64 seed)
1066 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1070 NoiseParams get_ground_wetness_params(u64 seed)
1072 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1076 bool is_cave(u64 seed, v3s16 p)
1078 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1079 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1080 return d1*d2 > CAVE_NOISE_THRESHOLD;
1084 Ground density noise shall be interpreted by using this.
1086 TODO: No perlin noises here, they should be outsourced
1088 NOTE: The speed of these actually isn't terrible
1090 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1092 //return ((double)p.Y < ground_noise1_val);
1094 double f = 0.55 + noise2d_perlin(
1095 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1096 seed+920381, 3, 0.45);
1101 double h = WATER_LEVEL + 10 * noise2d_perlin(
1102 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1103 seed+84174, 4, 0.5);
1106 return ((double)p.Y - h < ground_noise1_val * f);
1110 Queries whether a position is ground or not.
1112 bool is_ground(u64 seed, v3s16 p)
1114 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1115 return val_is_ground(val1, p, seed);
1118 // Amount of trees per area in nodes
1119 double tree_amount_2d(u64 seed, v2s16 p)
1121 /*double noise = noise2d_perlin(
1122 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1124 double noise = noise2d_perlin(
1125 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1127 double zeroval = -0.39;
1131 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1134 double surface_humidity_2d(u64 seed, v2s16 p)
1136 double noise = noise2d_perlin(
1137 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1138 seed+72384, 4, 0.66);
1139 noise = (noise + 1.0)/2.0;
1148 double randomstone_amount_2d(u64 seed, v2s16 p)
1150 double noise = noise2d_perlin(
1151 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1152 seed+3829434, 5, 0.66);
1153 double zeroval = 0.1;
1157 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1161 double largestone_amount_2d(u64 seed, v2s16 p)
1163 double noise = noise2d_perlin(
1164 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1165 seed+14143242, 5, 0.66);
1166 double zeroval = 0.3;
1170 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1174 Incrementally find ground level from 3d noise
1176 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1178 // Start a bit fuzzy to make averaging lower precision values
1180 s16 level = myrand_range(-precision/2, precision/2);
1181 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1183 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1185 // First find non-ground by going upwards
1186 // Don't stop in caves.
1188 s16 max = level+dec[i-1]*2;
1189 v3s16 p(p2d.X, level, p2d.Y);
1190 for(; p.Y < max; p.Y += dec[i])
1192 if(!is_ground(seed, p))
1199 // Then find ground by going downwards from there.
1200 // Go in caves, too, when precision is 1.
1202 s16 min = level-dec[i-1]*2;
1203 v3s16 p(p2d.X, level, p2d.Y);
1204 for(; p.Y>min; p.Y-=dec[i])
1206 bool ground = is_ground(seed, p);
1207 /*if(dec[i] == 1 && is_cave(seed, p))
1218 // This is more like the actual ground level
1219 level += dec[i-1]/2;
1224 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1226 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1228 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1229 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1231 a += find_ground_level_from_noise(seed,
1232 v2s16(node_min.X, node_min.Y), p);
1233 a += find_ground_level_from_noise(seed,
1234 v2s16(node_min.X, node_max.Y), p);
1235 a += find_ground_level_from_noise(seed,
1236 v2s16(node_max.X, node_max.Y), p);
1237 a += find_ground_level_from_noise(seed,
1238 v2s16(node_max.X, node_min.Y), p);
1239 a += find_ground_level_from_noise(seed,
1240 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1245 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1247 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1249 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1250 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1253 a = MYMAX(a, find_ground_level_from_noise(seed,
1254 v2s16(node_min.X, node_min.Y), p));
1255 a = MYMAX(a, find_ground_level_from_noise(seed,
1256 v2s16(node_min.X, node_max.Y), p));
1257 a = MYMAX(a, find_ground_level_from_noise(seed,
1258 v2s16(node_max.X, node_max.Y), p));
1259 a = MYMAX(a, find_ground_level_from_noise(seed,
1260 v2s16(node_min.X, node_min.Y), p));
1262 a = MYMAX(a, find_ground_level_from_noise(seed,
1263 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1264 // Side middle points
1265 a = MYMAX(a, find_ground_level_from_noise(seed,
1266 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1267 a = MYMAX(a, find_ground_level_from_noise(seed,
1268 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1269 a = MYMAX(a, find_ground_level_from_noise(seed,
1270 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1271 a = MYMAX(a, find_ground_level_from_noise(seed,
1272 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1276 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1278 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1280 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1281 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1284 a = MYMIN(a, find_ground_level_from_noise(seed,
1285 v2s16(node_min.X, node_min.Y), p));
1286 a = MYMIN(a, find_ground_level_from_noise(seed,
1287 v2s16(node_min.X, node_max.Y), p));
1288 a = MYMIN(a, find_ground_level_from_noise(seed,
1289 v2s16(node_max.X, node_max.Y), p));
1290 a = MYMIN(a, find_ground_level_from_noise(seed,
1291 v2s16(node_min.X, node_min.Y), p));
1293 a = MYMIN(a, find_ground_level_from_noise(seed,
1294 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1295 // Side middle points
1296 a = MYMIN(a, find_ground_level_from_noise(seed,
1297 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1298 a = MYMIN(a, find_ground_level_from_noise(seed,
1299 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1300 a = MYMIN(a, find_ground_level_from_noise(seed,
1301 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1302 a = MYMIN(a, find_ground_level_from_noise(seed,
1303 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1307 bool block_is_underground(u64 seed, v3s16 blockpos)
1309 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1310 seed, v2s16(blockpos.X, blockpos.Z));
1312 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1319 #define AVERAGE_MUD_AMOUNT 4
1321 double base_rock_level_2d(u64 seed, v2s16 p)
1323 // The base ground level
1324 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1325 + 20. * noise2d_perlin(
1326 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1327 (seed>>32)+654879876, 6, 0.6);
1329 /*// A bit hillier one
1330 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1331 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1332 (seed>>27)+90340, 6, 0.69);
1336 // Higher ground level
1337 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1338 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1339 seed+85039, 5, 0.69);
1340 //higher = 30; // For debugging
1342 // Limit higher to at least base
1346 // Steepness factor of cliffs
1347 double b = 1.0 + 1.0 * noise2d_perlin(
1348 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1350 b = rangelim(b, 0.0, 1000.0);
1353 b = rangelim(b, 3.0, 1000.0);
1354 //dstream<<"b="<<b<<std::endl;
1357 // Offset to more low
1358 double a_off = -0.2;
1359 // High/low selector
1360 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1361 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1362 seed-359, 6, 0.7));*/
1363 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1364 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1365 seed-359, 5, 0.60));
1367 a = rangelim(a, 0.0, 1.0);
1369 //dstream<<"a="<<a<<std::endl;
1371 double h = base*(1.0-a) + higher*a;
1378 double get_mud_add_amount(u64 seed, v2s16 p)
1380 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1381 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1382 seed+91013, 3, 0.55));
1386 bool get_have_sand(u64 seed, v2s16 p2d)
1388 // Determine whether to have sand here
1389 double sandnoise = noise2d_perlin(
1390 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1391 seed+59420, 3, 0.50);
1393 return (sandnoise > -0.15);
1397 Adds random objects to block, depending on the content of the block
1399 void add_random_objects(MapBlock *block)
1401 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1402 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1404 bool last_node_walkable = false;
1405 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1408 MapNode n = block->getNodeNoEx(p);
1409 if(n.getContent() == CONTENT_IGNORE)
1411 if(content_features(n).liquid_type != LIQUID_NONE)
1413 if(content_features(n).walkable)
1415 last_node_walkable = true;
1418 if(last_node_walkable)
1420 // If block contains light information
1421 if(content_features(n).param_type == CPT_LIGHT)
1423 if(n.getLight(LIGHTBANK_DAY) <= 3)
1425 if(myrand() % 300 == 0)
1427 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1429 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1430 std::string data = obj->getStaticData();
1431 StaticObject s_obj(obj->getType(),
1432 obj->getBasePosition(), data);
1434 block->m_static_objects.insert(0, s_obj);
1435 block->m_static_objects.insert(0, s_obj);
1436 block->m_static_objects.insert(0, s_obj);
1437 block->m_static_objects.insert(0, s_obj);
1438 block->m_static_objects.insert(0, s_obj);
1439 block->m_static_objects.insert(0, s_obj);
1442 if(myrand() % 1000 == 0)
1444 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1446 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1447 std::string data = obj->getStaticData();
1448 StaticObject s_obj(obj->getType(),
1449 obj->getBasePosition(), data);
1451 block->m_static_objects.insert(0, s_obj);
1457 last_node_walkable = false;
1460 block->setChangedFlag();
1463 void make_block(BlockMakeData *data)
1467 //dstream<<"makeBlock: no-op"<<std::endl;
1471 v3s16 blockpos = data->blockpos;
1473 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1474 <<blockpos.Z<<")"<<std::endl;*/
1476 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1477 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1478 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1479 // Area of center block
1480 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1481 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1482 // Full allocated area
1483 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1484 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1486 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1488 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1491 Get average ground level from noise
1494 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1495 data->seed, v2s16(blockpos.X, blockpos.Z));
1496 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1498 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1500 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1501 data->seed, v2s16(blockpos.X, blockpos.Z));
1502 // Minimum amount of ground above the top of the central block
1503 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1505 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1506 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1507 // Maximum amount of ground above the bottom of the central block
1508 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1512 Special case for high air or water: Just fill with air and water.
1514 if(maximum_ground_depth < -20)
1516 for(s16 x=node_min.X; x<=node_max.X; x++)
1517 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1522 // Use fast index incrementing
1523 v3s16 em = vmanip.m_area.getExtent();
1524 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1525 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1527 // Only modify places that have no content
1528 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1530 if(y <= WATER_LEVEL)
1531 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1533 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1536 data->vmanip->m_area.add_y(em, i, 1);
1547 If block is deep underground, this is set to true and ground
1548 density noise is not generated, for speed optimization.
1550 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1553 Create a block-specific seed
1555 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1556 + full_node_min.Y*42123 + full_node_min.X*23;
1562 //NoiseBuffer noisebuf1;
1563 //NoiseBuffer noisebuf2;
1564 NoiseBuffer noisebuf_cave;
1565 NoiseBuffer noisebuf_ground;
1566 NoiseBuffer noisebuf_ground_crumbleness;
1567 NoiseBuffer noisebuf_ground_wetness;
1569 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1570 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1572 //TimeTaker timer("noisebuf.create");
1578 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1579 minpos_f.X, minpos_f.Y, minpos_f.Z,
1580 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1582 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1590 v3f sl = v3f(4.0, 4.0, 4.0);
1595 if(all_is_ground_except_caves == false)
1596 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1597 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1598 minpos_f.X, minpos_f.Y, minpos_f.Z,
1599 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1603 Ground property noise
1605 sl = v3f(2.5, 2.5, 2.5);
1606 noisebuf_ground_crumbleness.create(
1607 get_ground_crumbleness_params(data->seed),
1608 minpos_f.X, minpos_f.Y, minpos_f.Z,
1609 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1611 noisebuf_ground_wetness.create(
1612 get_ground_wetness_params(data->seed),
1613 minpos_f.X, minpos_f.Y, minpos_f.Z,
1614 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1619 Make base ground level
1622 for(s16 x=node_min.X; x<=node_max.X; x++)
1623 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1628 // Use fast index incrementing
1629 v3s16 em = vmanip.m_area.getExtent();
1630 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1631 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1633 // Only modify places that have no content
1634 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1636 // First priority: make air and water.
1637 // This avoids caves inside water.
1638 if(all_is_ground_except_caves == false
1639 && val_is_ground(noisebuf_ground.get(x,y,z),
1640 v3s16(x,y,z), data->seed) == false)
1642 if(y <= WATER_LEVEL)
1643 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1645 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1647 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1648 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1650 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1653 data->vmanip->m_area.add_y(em, i, 1);
1663 PseudoRandom mineralrandom(blockseed);
1668 for(s16 i=0; i<approx_ground_depth/4; i++)
1670 if(mineralrandom.next()%50 == 0)
1672 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1673 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1674 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1675 for(u16 i=0; i<27; i++)
1677 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1678 u32 vi = vmanip.m_area.index(p);
1679 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1680 if(mineralrandom.next()%8 == 0)
1681 vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1690 u16 a = mineralrandom.range(0,15);
1692 u16 amount = 20 * a/1000;
1693 for(s16 i=0; i<amount; i++)
1695 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1696 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1697 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1699 u8 base_content = CONTENT_STONE;
1700 MapNode new_content(CONTENT_IGNORE);
1703 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1705 new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1709 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1710 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1711 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1712 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1714 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1716 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1720 if(new_content.getContent() != CONTENT_IGNORE)
1722 for(u16 i=0; i<27; i++)
1724 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1725 u32 vi = vmanip.m_area.index(p);
1726 if(vmanip.m_data[vi].getContent() == base_content)
1728 if(mineralrandom.next()%sparseness == 0)
1729 vmanip.m_data[vi] = new_content;
1738 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1739 //for(s16 i=0; i<50; i++)
1740 u16 coal_amount = 30;
1741 u16 coal_rareness = 60 / coal_amount;
1742 if(coal_rareness == 0)
1744 if(mineralrandom.next()%coal_rareness == 0)
1746 u16 a = mineralrandom.next() % 16;
1747 u16 amount = coal_amount * a*a*a / 1000;
1748 for(s16 i=0; i<amount; i++)
1750 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1751 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1752 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1753 for(u16 i=0; i<27; i++)
1755 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1756 u32 vi = vmanip.m_area.index(p);
1757 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1758 if(mineralrandom.next()%8 == 0)
1759 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1766 u16 iron_amount = 8;
1767 u16 iron_rareness = 60 / iron_amount;
1768 if(iron_rareness == 0)
1770 if(mineralrandom.next()%iron_rareness == 0)
1772 u16 a = mineralrandom.next() % 16;
1773 u16 amount = iron_amount * a*a*a / 1000;
1774 for(s16 i=0; i<amount; i++)
1776 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1777 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1778 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1779 for(u16 i=0; i<27; i++)
1781 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1782 u32 vi = vmanip.m_area.index(p);
1783 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1784 if(mineralrandom.next()%8 == 0)
1785 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1792 Add mud and sand and others underground (in place of stone)
1795 for(s16 x=node_min.X; x<=node_max.X; x++)
1796 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1801 // Use fast index incrementing
1802 v3s16 em = vmanip.m_area.getExtent();
1803 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1804 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1806 if(vmanip.m_data[i].getContent() == CONTENT_STONE)
1808 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1810 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1811 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1813 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1815 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1817 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1818 vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1820 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1821 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1823 vmanip.m_data[i] = MapNode(CONTENT_LAVASOURCE);
1824 for(s16 x1=-1; x1<=1; x1++)
1825 for(s16 y1=-1; y1<=1; y1++)
1826 for(s16 z1=-1; z1<=1; z1++)
1827 data->transforming_liquid.push_back(
1828 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1832 data->vmanip->m_area.add_y(em, i, -1);
1841 //if(node_min.Y < approx_groundlevel)
1842 //if(myrand() % 3 == 0)
1843 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1844 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1845 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1846 float dungeon_rarity = 0.02;
1847 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1849 && node_min.Y < approx_groundlevel)
1851 // Dungeon generator doesn't modify places which have this set
1852 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1853 | VMANIP_FLAG_DUNGEON_PRESERVE);
1855 // Set all air and water to be untouchable to make dungeons open
1856 // to caves and open air
1857 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1858 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1863 // Use fast index incrementing
1864 v3s16 em = vmanip.m_area.getExtent();
1865 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1866 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1868 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1869 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1870 else if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1871 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1872 data->vmanip->m_area.add_y(em, i, -1);
1877 PseudoRandom random(blockseed+2);
1880 make_dungeon1(vmanip, random);
1882 // Convert some cobble to mossy cobble
1883 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1884 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1889 // Use fast index incrementing
1890 v3s16 em = vmanip.m_area.getExtent();
1891 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1892 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1894 // (noisebuf not used because it doesn't contain the
1896 double wetness = noise3d_param(
1897 get_ground_wetness_params(data->seed), x,y,z);
1898 double d = noise3d_perlin((float)x/2.5,
1899 (float)y/2.5,(float)z/2.5,
1901 if(vmanip.m_data[i].getContent() == CONTENT_COBBLE)
1905 vmanip.m_data[i].setContent(CONTENT_MOSSYCOBBLE);
1908 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1911 vmanip.m_data[i].setContent(CONTENT_MUD);
1913 data->vmanip->m_area.add_y(em, i, -1);
1923 PseudoRandom ncrandom(blockseed+9324342);
1924 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1926 make_nc(vmanip, ncrandom);
1931 Add top and bottom side of water to transforming_liquid queue
1934 for(s16 x=node_min.X; x<=node_max.X; x++)
1935 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1940 bool water_found = false;
1941 // Use fast index incrementing
1942 v3s16 em = vmanip.m_area.getExtent();
1943 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1944 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1946 if(water_found == false)
1948 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1950 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1951 data->transforming_liquid.push_back(p);
1957 // This can be done because water_found can only
1958 // turn to true and end up here after going through
1960 if(vmanip.m_data[i+1].getContent() != CONTENT_WATERSOURCE)
1962 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1963 data->transforming_liquid.push_back(p);
1964 water_found = false;
1968 data->vmanip->m_area.add_y(em, i, -1);
1974 If close to ground level
1977 //if(abs(approx_ground_depth) < 30)
1978 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1984 for(s16 x=node_min.X; x<=node_max.X; x++)
1985 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1990 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1991 bool have_sand = false;
1992 u32 current_depth = 0;
1993 bool air_detected = false;
1994 bool water_detected = false;
1995 bool have_clay = false;
1997 // Use fast index incrementing
1998 s16 start_y = node_max.Y+2;
1999 v3s16 em = vmanip.m_area.getExtent();
2000 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2001 for(s16 y=start_y; y>=node_min.Y-3; y--)
2003 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
2004 water_detected = true;
2005 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2006 air_detected = true;
2008 if((vmanip.m_data[i].getContent() == CONTENT_STONE
2009 || vmanip.m_data[i].getContent() == CONTENT_GRASS
2010 || vmanip.m_data[i].getContent() == CONTENT_MUD
2011 || vmanip.m_data[i].getContent() == CONTENT_SAND
2012 || vmanip.m_data[i].getContent() == CONTENT_GRAVEL
2013 ) && (air_detected || water_detected))
2015 if(current_depth == 0 && y <= WATER_LEVEL+2
2016 && possibly_have_sand)
2019 if(current_depth < 4)
2023 // Determine whether to have clay in the sand here
2024 double claynoise = noise2d_perlin(
2025 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2026 data->seed+4321, 6, 0.95) + 0.5;
2028 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2029 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2030 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2033 vmanip.m_data[i] = MapNode(CONTENT_CLAY);
2035 vmanip.m_data[i] = MapNode(CONTENT_SAND);
2038 else if(current_depth==0 && !water_detected
2039 && y >= WATER_LEVEL && air_detected)
2040 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
2043 vmanip.m_data[i] = MapNode(CONTENT_MUD);
2047 if(vmanip.m_data[i].getContent() == CONTENT_MUD
2048 || vmanip.m_data[i].getContent() == CONTENT_GRASS)
2049 vmanip.m_data[i] = MapNode(CONTENT_STONE);
2054 if(current_depth >= 8)
2057 else if(current_depth != 0)
2060 data->vmanip->m_area.add_y(em, i, -1);
2066 Calculate some stuff
2069 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2070 bool is_jungle = surface_humidity > 0.75;
2072 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
2079 PseudoRandom treerandom(blockseed);
2080 // Put trees in random places on part of division
2081 for(u32 i=0; i<tree_count; i++)
2083 s16 x = treerandom.range(node_min.X, node_max.X);
2084 s16 z = treerandom.range(node_min.Z, node_max.Z);
2085 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2086 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2087 // Don't make a tree under water level
2090 // Make sure tree fits (only trees whose starting point is
2091 // at this block are added)
2092 if(y < node_min.Y || y > node_max.Y)
2095 Find exact ground level
2099 for(; p.Y >= y-6; p.Y--)
2101 u32 i = data->vmanip->m_area.index(p);
2102 MapNode *n = &data->vmanip->m_data[i];
2103 if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
2109 // If not found, handle next one
2114 u32 i = data->vmanip->m_area.index(p);
2115 MapNode *n = &data->vmanip->m_data[i];
2117 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
2120 // Papyrus grows only on mud and in water
2121 if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
2124 make_papyrus(vmanip, p);
2126 // Trees grow only on mud and grass, on land
2127 else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
2130 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2131 if(is_jungle == false)
2132 make_tree(vmanip, p);
2134 make_jungletree(vmanip, p);
2136 // Cactii grow only on sand, on land
2137 else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
2140 make_cactus(vmanip, p);
2150 PseudoRandom grassrandom(blockseed);
2151 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2153 s16 x = grassrandom.range(node_min.X, node_max.X);
2154 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2155 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2158 if(y < node_min.Y || y > node_max.Y)
2161 Find exact ground level
2165 for(; p.Y >= y-6; p.Y--)
2167 u32 i = data->vmanip->m_area.index(p);
2168 MapNode *n = &data->vmanip->m_data[i];
2169 if(content_features(*n).is_ground_content
2170 || n->getContent() == CONTENT_JUNGLETREE)
2176 // If not found, handle next one
2180 if(vmanip.m_area.contains(p) == false)
2182 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2185 if(vmanip.m_area.contains(p))
2186 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
2188 if(vmanip.m_area.contains(p))
2189 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
2195 Add some kind of random stones
2198 u32 random_stone_count = block_area_nodes *
2199 randomstone_amount_2d(data->seed, p2d_center);
2200 // Put in random places on part of division
2201 for(u32 i=0; i<random_stone_count; i++)
2203 s16 x = myrand_range(node_min.X, node_max.X);
2204 s16 z = myrand_range(node_min.Z, node_max.Z);
2205 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2206 // Don't add under water level
2207 /*if(y < WATER_LEVEL)
2209 // Don't add if doesn't belong to this block
2210 if(y < node_min.Y || y > node_max.Y)
2215 u32 i = data->vmanip->m_area.index(v3s16(p));
2216 MapNode *n = &data->vmanip->m_data[i];
2217 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2220 // Will be placed one higher
2223 make_randomstone(data->vmanip, p);
2232 u32 large_stone_count = block_area_nodes *
2233 largestone_amount_2d(data->seed, p2d_center);
2234 //u32 large_stone_count = 1;
2235 // Put in random places on part of division
2236 for(u32 i=0; i<large_stone_count; i++)
2238 s16 x = myrand_range(node_min.X, node_max.X);
2239 s16 z = myrand_range(node_min.Z, node_max.Z);
2240 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2241 // Don't add under water level
2242 /*if(y < WATER_LEVEL)
2244 // Don't add if doesn't belong to this block
2245 if(y < node_min.Y || y > node_max.Y)
2250 u32 i = data->vmanip->m_area.index(v3s16(p));
2251 MapNode *n = &data->vmanip->m_data[i];
2252 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2255 // Will be placed one lower
2258 make_largestone(data->vmanip, p);
2265 BlockMakeData::BlockMakeData():
2271 BlockMakeData::~BlockMakeData()
2276 }; // namespace mapgen