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"
35 Some helper functions for the map generator
39 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
41 v3s16 em = vmanip.m_area.getExtent();
42 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
43 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
44 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
46 for(y=y_nodes_max; y>=y_nodes_min; y--)
48 MapNode &n = vmanip.m_data[i];
49 if(content_walkable(n.d))
52 vmanip.m_area.add_y(em, i, -1);
60 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
62 v3s16 em = vmanip.m_area.getExtent();
63 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
64 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
65 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
67 for(y=y_nodes_max; y>=y_nodes_min; y--)
69 MapNode &n = vmanip.m_data[i];
70 if(content_walkable(n.d)
71 && n.getContent() != CONTENT_TREE
72 && n.getContent() != CONTENT_LEAVES)
75 vmanip.m_area.add_y(em, i, -1);
84 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0, bool is_apple_tree)
86 MapNode treenode(CONTENT_TREE);
87 MapNode leavesnode(CONTENT_LEAVES);
88 MapNode applenode(CONTENT_APPLE);
90 s16 trunk_h = myrand_range(4, 5);
92 for(s16 ii=0; ii<trunk_h; ii++)
94 if(vmanip.m_area.contains(p1))
95 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
99 // p1 is now the last piece of the trunk
102 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
103 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
104 Buffer<u8> leaves_d(leaves_a.getVolume());
105 for(s32 i=0; i<leaves_a.getVolume(); i++)
108 // Force leaves at near the end of the trunk
111 for(s16 z=-d; z<=d; z++)
112 for(s16 y=-d; y<=d; y++)
113 for(s16 x=-d; x<=d; x++)
115 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
119 // Add leaves randomly
120 for(u32 iii=0; iii<7; iii++)
125 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
126 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
127 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
130 for(s16 z=0; z<=d; z++)
131 for(s16 y=0; y<=d; y++)
132 for(s16 x=0; x<=d; x++)
134 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
138 // Blit leaves to vmanip
139 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
140 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
141 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
145 if(vmanip.m_area.contains(p) == false)
147 u32 vi = vmanip.m_area.index(p);
148 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
149 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
151 u32 i = leaves_a.index(x,y,z);
152 if(leaves_d[i] == 1) {
153 bool is_apple = myrand_range(0,99) < 10;
154 if(is_apple_tree && is_apple) {
155 vmanip.m_data[vi] = applenode;
157 vmanip.m_data[vi] = leavesnode;
163 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0)
165 MapNode treenode(CONTENT_JUNGLETREE);
166 MapNode leavesnode(CONTENT_LEAVES);
168 for(s16 x=-1; x<=1; x++)
169 for(s16 z=-1; z<=1; z++)
171 if(myrand_range(0, 2) == 0)
173 v3s16 p1 = p0 + v3s16(x,0,z);
174 v3s16 p2 = p0 + v3s16(x,-1,z);
175 if(vmanip.m_area.contains(p2)
176 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
177 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
178 else if(vmanip.m_area.contains(p1))
179 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
182 s16 trunk_h = myrand_range(8, 12);
184 for(s16 ii=0; ii<trunk_h; ii++)
186 if(vmanip.m_area.contains(p1))
187 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
191 // p1 is now the last piece of the trunk
194 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
195 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
196 Buffer<u8> leaves_d(leaves_a.getVolume());
197 for(s32 i=0; i<leaves_a.getVolume(); i++)
200 // Force leaves at near the end of the trunk
203 for(s16 z=-d; z<=d; z++)
204 for(s16 y=-d; y<=d; y++)
205 for(s16 x=-d; x<=d; x++)
207 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
211 // Add leaves randomly
212 for(u32 iii=0; iii<30; iii++)
217 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
218 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
219 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
222 for(s16 z=0; z<=d; z++)
223 for(s16 y=0; y<=d; y++)
224 for(s16 x=0; x<=d; x++)
226 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
230 // Blit leaves to vmanip
231 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
232 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
233 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
237 if(vmanip.m_area.contains(p) == false)
239 u32 vi = vmanip.m_area.index(p);
240 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
241 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
243 u32 i = leaves_a.index(x,y,z);
245 vmanip.m_data[vi] = leavesnode;
249 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0)
251 MapNode papyrusnode(CONTENT_PAPYRUS);
253 s16 trunk_h = myrand_range(2, 3);
255 for(s16 ii=0; ii<trunk_h; ii++)
257 if(vmanip.m_area.contains(p1))
258 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
263 void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
265 MapNode cactusnode(CONTENT_CACTUS);
269 for(s16 ii=0; ii<trunk_h; ii++)
271 if(vmanip.m_area.contains(p1))
272 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
278 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
280 MapNode stonenode(CONTENT_STONE);
282 s16 size = myrand_range(3, 6);
284 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
285 Buffer<u8> stone_d(stone_a.getVolume());
286 for(s32 i=0; i<stone_a.getVolume(); i++)
289 // Force stone at bottom to make it usually touch the ground
291 for(s16 z=0; z<=0; z++)
292 for(s16 y=0; y<=0; y++)
293 for(s16 x=0; x<=0; x++)
295 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
299 // Generate from perlin noise
300 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
301 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
302 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
304 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
305 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
306 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
308 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
310 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
314 u32 vi = stone_a.index(v3s16(x,y,z));
319 /*// Add stone randomly
320 for(u32 iii=0; iii<7; iii++)
325 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
326 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
327 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
330 for(s16 z=0; z<=d; z++)
331 for(s16 y=0; y<=d; y++)
332 for(s16 x=0; x<=d; x++)
334 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
338 // Blit stone to vmanip
339 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
340 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
341 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
345 if(vmanip.m_area.contains(p) == false)
347 u32 vi = vmanip.m_area.index(p);
348 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
349 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
351 u32 i = stone_a.index(x,y,z);
353 vmanip.m_data[vi] = stonenode;
359 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
361 MapNode stonenode(CONTENT_STONE);
363 s16 size = myrand_range(8, 16);
365 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
366 Buffer<u8> stone_d(stone_a.getVolume());
367 for(s32 i=0; i<stone_a.getVolume(); i++)
370 // Force stone at bottom to make it usually touch the ground
372 for(s16 z=0; z<=0; z++)
373 for(s16 y=0; y<=0; y++)
374 for(s16 x=0; x<=0; x++)
376 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
380 // Generate from perlin noise
381 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
382 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
383 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
386 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
387 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
388 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
389 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
390 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
391 double dz = (double)z-mid_z;
392 double dx = (double)x-mid_x;
393 double dy = MYMAX(0, (double)y-mid_y);
394 double r = sqrt(dz*dz+dx*dx+dy*dy);
395 d /= (2*r/size)*2 + 0.01;
398 u32 vi = stone_a.index(v3s16(x,y,z));
403 /*// Add stone randomly
404 for(u32 iii=0; iii<7; iii++)
409 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
410 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
411 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
414 for(s16 z=0; z<=d; z++)
415 for(s16 y=0; y<=d; y++)
416 for(s16 x=0; x<=d; x++)
418 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
422 // Blit stone to vmanip
423 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
424 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
425 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
429 if(vmanip.m_area.contains(p) == false)
431 u32 vi = vmanip.m_area.index(p);
432 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
433 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
435 u32 i = stone_a.index(x,y,z);
437 vmanip.m_data[vi] = stonenode;
443 Dungeon making routines
446 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
447 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
448 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
449 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
451 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
454 for(s16 z=0; z<roomsize.Z; z++)
455 for(s16 y=0; y<roomsize.Y; y++)
458 v3s16 p = roomplace + v3s16(0,y,z);
459 if(vmanip.m_area.contains(p) == false)
461 u32 vi = vmanip.m_area.index(p);
462 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
464 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
467 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
468 if(vmanip.m_area.contains(p) == false)
470 u32 vi = vmanip.m_area.index(p);
471 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
473 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
478 for(s16 x=0; x<roomsize.X; x++)
479 for(s16 y=0; y<roomsize.Y; y++)
482 v3s16 p = roomplace + v3s16(x,y,0);
483 if(vmanip.m_area.contains(p) == false)
485 u32 vi = vmanip.m_area.index(p);
486 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
488 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
491 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
492 if(vmanip.m_area.contains(p) == false)
494 u32 vi = vmanip.m_area.index(p);
495 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
497 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
501 // Make +-Y walls (floor and ceiling)
502 for(s16 z=0; z<roomsize.Z; z++)
503 for(s16 x=0; x<roomsize.X; x++)
506 v3s16 p = roomplace + v3s16(x,0,z);
507 if(vmanip.m_area.contains(p) == false)
509 u32 vi = vmanip.m_area.index(p);
510 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
512 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
515 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
516 if(vmanip.m_area.contains(p) == false)
518 u32 vi = vmanip.m_area.index(p);
519 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
521 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
526 for(s16 z=1; z<roomsize.Z-1; z++)
527 for(s16 y=1; y<roomsize.Y-1; y++)
528 for(s16 x=1; x<roomsize.X-1; x++)
530 v3s16 p = roomplace + v3s16(x,y,z);
531 if(vmanip.m_area.contains(p) == false)
533 u32 vi = vmanip.m_area.index(p);
534 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
535 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
539 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
540 u8 avoid_flags, MapNode n, u8 or_flags)
542 for(s16 z=0; z<size.Z; z++)
543 for(s16 y=0; y<size.Y; y++)
544 for(s16 x=0; x<size.X; x++)
546 v3s16 p = place + v3s16(x,y,z);
547 if(vmanip.m_area.contains(p) == false)
549 u32 vi = vmanip.m_area.index(p);
550 if(vmanip.m_flags[vi] & avoid_flags)
552 vmanip.m_flags[vi] |= or_flags;
553 vmanip.m_data[vi] = n;
557 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
559 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
560 VMANIP_FLAG_DUNGEON_INSIDE);
563 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
565 make_hole1(vmanip, doorplace);
566 // Place torch (for testing)
567 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
570 static v3s16 rand_ortho_dir(PseudoRandom &random)
572 if(random.next()%2==0)
573 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
575 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
578 static v3s16 turn_xz(v3s16 olddir, int t)
598 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
600 int turn = random.range(0,2);
609 dir = turn_xz(olddir, 0);
612 dir = turn_xz(olddir, 1);
616 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
617 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
618 PseudoRandom &random)
620 make_hole1(vmanip, doorplace);
621 v3s16 p0 = doorplace;
625 length = random.range(1,13);
627 length = random.range(1,6);
628 length = random.range(1,13);
629 u32 partlength = random.range(1,13);
632 if(random.next()%2 == 0 && partlength >= 3)
633 make_stairs = random.next()%2 ? 1 : -1;
634 for(u32 i=0; i<length; i++)
640 /*// If already empty
641 if(vmanip.getNodeNoExNoEmerge(p).getContent()
643 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
648 if(vmanip.m_area.contains(p) == true
649 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
653 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
654 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
655 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
656 VMANIP_FLAG_DUNGEON_INSIDE);
657 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
658 VMANIP_FLAG_DUNGEON_INSIDE);
662 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
663 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
664 make_hole1(vmanip, p);
665 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
666 VMANIP_FLAG_DUNGEON_INSIDE);*/
673 // Can't go here, turn away
674 dir = turn_xz(dir, random.range(0,1));
675 make_stairs = -make_stairs;
677 partlength = random.range(1,length);
682 if(partcount >= partlength)
686 dir = random_turn(random, dir);
688 partlength = random.range(1,length);
691 if(random.next()%2 == 0 && partlength >= 3)
692 make_stairs = random.next()%2 ? 1 : -1;
703 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
713 m_dir = rand_ortho_dir(m_random);
716 void setPos(v3s16 pos)
721 void setDir(v3s16 dir)
726 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
728 for(u32 i=0; i<100; i++)
730 v3s16 p = m_pos + m_dir;
731 v3s16 p1 = p + v3s16(0,1,0);
732 if(vmanip.m_area.contains(p) == false
733 || vmanip.m_area.contains(p1) == false
739 if(vmanip.getNodeNoExNoEmerge(p).getContent()
741 && vmanip.getNodeNoExNoEmerge(p1).getContent()
744 // Found wall, this is a good place!
747 // Randomize next direction
752 Determine where to move next
754 // Jump one up if the actual space is there
755 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
757 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
759 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
762 // Jump one down if the actual space is there
763 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
765 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
767 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
770 // Check if walking is now possible
771 if(vmanip.getNodeNoExNoEmerge(p).getContent()
773 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
776 // Cannot continue walking here
786 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
787 v3s16 &result_doordir, v3s16 &result_roomplace)
789 for(s16 trycount=0; trycount<30; trycount++)
793 bool r = findPlaceForDoor(doorplace, doordir);
797 // X east, Z north, Y up
799 if(doordir == v3s16(1,0,0)) // X+
800 roomplace = doorplace +
801 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
802 if(doordir == v3s16(-1,0,0)) // X-
803 roomplace = doorplace +
804 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
805 if(doordir == v3s16(0,0,1)) // Z+
806 roomplace = doorplace +
807 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
808 if(doordir == v3s16(0,0,-1)) // Z-
809 roomplace = doorplace +
810 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
813 if(doordir == v3s16(1,0,0)) // X+
814 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
815 if(doordir == v3s16(-1,0,0)) // X-
816 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
817 if(doordir == v3s16(0,0,1)) // Z+
818 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
819 if(doordir == v3s16(0,0,-1)) // Z-
820 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
825 for(s16 z=1; z<roomsize.Z-1; z++)
826 for(s16 y=1; y<roomsize.Y-1; y++)
827 for(s16 x=1; x<roomsize.X-1; x++)
829 v3s16 p = roomplace + v3s16(x,y,z);
830 if(vmanip.m_area.contains(p) == false)
835 if(vmanip.m_flags[vmanip.m_area.index(p)]
836 & VMANIP_FLAG_DUNGEON_INSIDE)
847 result_doorplace = doorplace;
848 result_doordir = doordir;
849 result_roomplace = roomplace;
856 VoxelManipulator &vmanip;
859 PseudoRandom &m_random;
862 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
864 v3s16 areasize = vmanip.m_area.getExtent();
869 Find place for first room
872 for(u32 i=0; i<100; i++)
874 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
875 roomplace = vmanip.m_area.MinEdge + v3s16(
876 random.range(0,areasize.X-roomsize.X-1),
877 random.range(0,areasize.Y-roomsize.Y-1),
878 random.range(0,areasize.Z-roomsize.Z-1));
880 Check that we're not putting the room to an unknown place,
881 otherwise it might end up floating in the air
884 for(s16 z=1; z<roomsize.Z-1; z++)
885 for(s16 y=1; y<roomsize.Y-1; y++)
886 for(s16 x=1; x<roomsize.X-1; x++)
888 v3s16 p = roomplace + v3s16(x,y,z);
889 u32 vi = vmanip.m_area.index(p);
890 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
895 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
909 Stores the center position of the last room made, so that
910 a new corridor can be started from the last room instead of
911 the new room, if chosen so.
913 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
915 u32 room_count = random.range(2,7);
916 for(u32 i=0; i<room_count; i++)
918 // Make a room to the determined place
919 make_room1(vmanip, roomsize, roomplace);
921 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
923 // Place torch at room center (for testing)
924 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
927 if(i == room_count-1)
930 // Determine walker start position
932 bool start_in_last_room = (random.range(0,2)!=0);
933 //bool start_in_last_room = true;
935 v3s16 walker_start_place;
937 if(start_in_last_room)
939 walker_start_place = last_room_center;
943 walker_start_place = room_center;
944 // Store center of current room as the last one
945 last_room_center = room_center;
948 // Create walker and find a place for a door
949 RoomWalker walker(vmanip, walker_start_place, random);
952 bool r = walker.findPlaceForDoor(doorplace, doordir);
956 if(random.range(0,1)==0)
958 make_door1(vmanip, doorplace, doordir);
960 // Don't actually make a door
961 doorplace -= doordir;
963 // Make a random corridor starting from the door
965 v3s16 corridor_end_dir;
966 make_corridor(vmanip, doorplace, doordir, corridor_end,
967 corridor_end_dir, random);
969 // Find a place for a random sized room
970 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
971 walker.setPos(corridor_end);
972 walker.setDir(corridor_end_dir);
973 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
977 if(random.range(0,1)==0)
979 make_door1(vmanip, doorplace, doordir);
981 // Don't actually make a door
982 roomplace -= doordir;
987 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random)
991 s32 r = random.range(0, 3);
993 dir = v3s16( 1, 0, 0);
997 dir = v3s16(-1, 0, 0);
1001 dir = v3s16( 0, 0, 1);
1005 dir = v3s16( 0, 0,-1);
1008 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1009 16+random.range(0,15),
1010 16+random.range(0,15),
1011 16+random.range(0,15));
1012 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC, facedir_i);
1013 u32 length = random.range(3,15);
1014 for(u32 j=0; j<length; j++)
1017 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC_RB);
1022 Noise functions. Make sure seed is mangled differently in each one.
1026 Scaling the output of the noise function affects the overdrive of the
1027 contour function, which affects the shape of the output considerably.
1029 #define CAVE_NOISE_SCALE 12.0
1030 //#define CAVE_NOISE_SCALE 10.0
1031 //#define CAVE_NOISE_SCALE 7.5
1032 //#define CAVE_NOISE_SCALE 5.0
1033 //#define CAVE_NOISE_SCALE 1.0
1035 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1036 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1038 NoiseParams get_cave_noise1_params(u64 seed)
1040 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1041 200, CAVE_NOISE_SCALE);*/
1042 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1043 100, CAVE_NOISE_SCALE);*/
1044 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1045 100, CAVE_NOISE_SCALE);*/
1046 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1047 100, CAVE_NOISE_SCALE);*/
1048 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1049 50, CAVE_NOISE_SCALE);
1050 //return NoiseParams(NOISE_CONSTANT_ONE);
1053 NoiseParams get_cave_noise2_params(u64 seed)
1055 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1056 200, CAVE_NOISE_SCALE);*/
1057 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1058 100, CAVE_NOISE_SCALE);*/
1059 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1060 100, CAVE_NOISE_SCALE);*/
1061 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1062 50, CAVE_NOISE_SCALE);
1063 //return NoiseParams(NOISE_CONSTANT_ONE);
1066 NoiseParams get_ground_noise1_params(u64 seed)
1068 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1072 NoiseParams get_ground_crumbleness_params(u64 seed)
1074 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1078 NoiseParams get_ground_wetness_params(u64 seed)
1080 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1084 bool is_cave(u64 seed, v3s16 p)
1086 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1087 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1088 return d1*d2 > CAVE_NOISE_THRESHOLD;
1092 Ground density noise shall be interpreted by using this.
1094 TODO: No perlin noises here, they should be outsourced
1096 NOTE: The speed of these actually isn't terrible
1098 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1100 //return ((double)p.Y < ground_noise1_val);
1102 double f = 0.55 + noise2d_perlin(
1103 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1104 seed+920381, 3, 0.45);
1109 double h = WATER_LEVEL + 10 * noise2d_perlin(
1110 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1111 seed+84174, 4, 0.5);
1114 return ((double)p.Y - h < ground_noise1_val * f);
1118 Queries whether a position is ground or not.
1120 bool is_ground(u64 seed, v3s16 p)
1122 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1123 return val_is_ground(val1, p, seed);
1126 // Amount of trees per area in nodes
1127 double tree_amount_2d(u64 seed, v2s16 p)
1129 /*double noise = noise2d_perlin(
1130 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1132 double noise = noise2d_perlin(
1133 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1135 double zeroval = -0.39;
1139 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1142 double surface_humidity_2d(u64 seed, v2s16 p)
1144 double noise = noise2d_perlin(
1145 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1146 seed+72384, 4, 0.66);
1147 noise = (noise + 1.0)/2.0;
1156 double randomstone_amount_2d(u64 seed, v2s16 p)
1158 double noise = noise2d_perlin(
1159 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1160 seed+3829434, 5, 0.66);
1161 double zeroval = 0.1;
1165 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1169 double largestone_amount_2d(u64 seed, v2s16 p)
1171 double noise = noise2d_perlin(
1172 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1173 seed+14143242, 5, 0.66);
1174 double zeroval = 0.3;
1178 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1182 Incrementally find ground level from 3d noise
1184 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1186 // Start a bit fuzzy to make averaging lower precision values
1188 s16 level = myrand_range(-precision/2, precision/2);
1189 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1191 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1193 // First find non-ground by going upwards
1194 // Don't stop in caves.
1196 s16 max = level+dec[i-1]*2;
1197 v3s16 p(p2d.X, level, p2d.Y);
1198 for(; p.Y < max; p.Y += dec[i])
1200 if(!is_ground(seed, p))
1207 // Then find ground by going downwards from there.
1208 // Go in caves, too, when precision is 1.
1210 s16 min = level-dec[i-1]*2;
1211 v3s16 p(p2d.X, level, p2d.Y);
1212 for(; p.Y>min; p.Y-=dec[i])
1214 bool ground = is_ground(seed, p);
1215 /*if(dec[i] == 1 && is_cave(seed, p))
1226 // This is more like the actual ground level
1227 level += dec[i-1]/2;
1232 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1234 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1236 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1237 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1239 a += find_ground_level_from_noise(seed,
1240 v2s16(node_min.X, node_min.Y), p);
1241 a += find_ground_level_from_noise(seed,
1242 v2s16(node_min.X, node_max.Y), p);
1243 a += find_ground_level_from_noise(seed,
1244 v2s16(node_max.X, node_max.Y), p);
1245 a += find_ground_level_from_noise(seed,
1246 v2s16(node_max.X, node_min.Y), p);
1247 a += find_ground_level_from_noise(seed,
1248 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1253 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1255 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1257 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1258 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1261 a = MYMAX(a, find_ground_level_from_noise(seed,
1262 v2s16(node_min.X, node_min.Y), p));
1263 a = MYMAX(a, find_ground_level_from_noise(seed,
1264 v2s16(node_min.X, node_max.Y), p));
1265 a = MYMAX(a, find_ground_level_from_noise(seed,
1266 v2s16(node_max.X, node_max.Y), p));
1267 a = MYMAX(a, find_ground_level_from_noise(seed,
1268 v2s16(node_min.X, node_min.Y), p));
1270 a = MYMAX(a, find_ground_level_from_noise(seed,
1271 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1272 // Side middle points
1273 a = MYMAX(a, find_ground_level_from_noise(seed,
1274 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1275 a = MYMAX(a, find_ground_level_from_noise(seed,
1276 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1277 a = MYMAX(a, find_ground_level_from_noise(seed,
1278 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1279 a = MYMAX(a, find_ground_level_from_noise(seed,
1280 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1284 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1286 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1288 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1289 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1292 a = MYMIN(a, find_ground_level_from_noise(seed,
1293 v2s16(node_min.X, node_min.Y), p));
1294 a = MYMIN(a, find_ground_level_from_noise(seed,
1295 v2s16(node_min.X, node_max.Y), p));
1296 a = MYMIN(a, find_ground_level_from_noise(seed,
1297 v2s16(node_max.X, node_max.Y), p));
1298 a = MYMIN(a, find_ground_level_from_noise(seed,
1299 v2s16(node_min.X, node_min.Y), p));
1301 a = MYMIN(a, find_ground_level_from_noise(seed,
1302 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1303 // Side middle points
1304 a = MYMIN(a, find_ground_level_from_noise(seed,
1305 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1306 a = MYMIN(a, find_ground_level_from_noise(seed,
1307 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1308 a = MYMIN(a, find_ground_level_from_noise(seed,
1309 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1310 a = MYMIN(a, find_ground_level_from_noise(seed,
1311 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1315 bool block_is_underground(u64 seed, v3s16 blockpos)
1317 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1318 seed, v2s16(blockpos.X, blockpos.Z));
1320 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1327 #define AVERAGE_MUD_AMOUNT 4
1329 double base_rock_level_2d(u64 seed, v2s16 p)
1331 // The base ground level
1332 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1333 + 20. * noise2d_perlin(
1334 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1335 (seed>>32)+654879876, 6, 0.6);
1337 /*// A bit hillier one
1338 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1339 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1340 (seed>>27)+90340, 6, 0.69);
1344 // Higher ground level
1345 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1346 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1347 seed+85039, 5, 0.69);
1348 //higher = 30; // For debugging
1350 // Limit higher to at least base
1354 // Steepness factor of cliffs
1355 double b = 1.0 + 1.0 * noise2d_perlin(
1356 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1358 b = rangelim(b, 0.0, 1000.0);
1361 b = rangelim(b, 3.0, 1000.0);
1362 //dstream<<"b="<<b<<std::endl;
1365 // Offset to more low
1366 double a_off = -0.2;
1367 // High/low selector
1368 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1369 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1370 seed-359, 6, 0.7));*/
1371 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1372 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1373 seed-359, 5, 0.60));
1375 a = rangelim(a, 0.0, 1.0);
1377 //dstream<<"a="<<a<<std::endl;
1379 double h = base*(1.0-a) + higher*a;
1386 double get_mud_add_amount(u64 seed, v2s16 p)
1388 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1389 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1390 seed+91013, 3, 0.55));
1394 bool get_have_sand(u64 seed, v2s16 p2d)
1396 // Determine whether to have sand here
1397 double sandnoise = noise2d_perlin(
1398 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1399 seed+59420, 3, 0.50);
1401 return (sandnoise > -0.15);
1405 Adds random objects to block, depending on the content of the block
1407 void add_random_objects(MapBlock *block)
1410 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1411 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1413 bool last_node_walkable = false;
1414 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1417 MapNode n = block->getNodeNoEx(p);
1418 if(n.getContent() == CONTENT_IGNORE)
1420 if(data->nodemgr->get(n)->liquid_type != LIQUID_NONE)
1422 if(data->nodemgr->get(n)->walkable)
1424 last_node_walkable = true;
1427 if(last_node_walkable)
1429 // If block contains light information
1430 if(content_features(n).param_type == CPT_LIGHT)
1432 if(n.getLight(LIGHTBANK_DAY) <= 3)
1434 if(myrand() % 300 == 0)
1436 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1438 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1439 std::string data = obj->getStaticData();
1440 StaticObject s_obj(obj->getType(),
1441 obj->getBasePosition(), data);
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);
1448 block->m_static_objects.insert(0, s_obj);
1451 if(myrand() % 1000 == 0)
1453 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1455 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1456 std::string data = obj->getStaticData();
1457 StaticObject s_obj(obj->getType(),
1458 obj->getBasePosition(), data);
1460 block->m_static_objects.insert(0, s_obj);
1466 last_node_walkable = false;
1469 block->setChangedFlag();
1473 void make_block(BlockMakeData *data)
1477 //dstream<<"makeBlock: no-op"<<std::endl;
1481 assert(data->vmanip);
1482 assert(data->nodemgr);
1484 v3s16 blockpos = data->blockpos;
1486 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1487 <<blockpos.Z<<")"<<std::endl;*/
1489 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1490 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1491 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1492 // Area of center block
1493 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1494 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1495 // Full allocated area
1496 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1497 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1499 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1501 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1504 Get average ground level from noise
1507 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1508 data->seed, v2s16(blockpos.X, blockpos.Z));
1509 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1511 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1513 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1514 data->seed, v2s16(blockpos.X, blockpos.Z));
1515 // Minimum amount of ground above the top of the central block
1516 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1518 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1519 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1520 // Maximum amount of ground above the bottom of the central block
1521 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1525 Special case for high air or water: Just fill with air and water.
1527 if(maximum_ground_depth < -20)
1529 for(s16 x=node_min.X; x<=node_max.X; x++)
1530 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1535 // Use fast index incrementing
1536 v3s16 em = vmanip.m_area.getExtent();
1537 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1538 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1540 // Only modify places that have no content
1541 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1543 if(y <= WATER_LEVEL)
1544 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1546 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1549 data->vmanip->m_area.add_y(em, i, 1);
1560 If block is deep underground, this is set to true and ground
1561 density noise is not generated, for speed optimization.
1563 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1566 Create a block-specific seed
1568 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1569 + full_node_min.Y*42123 + full_node_min.X*23;
1575 //NoiseBuffer noisebuf1;
1576 //NoiseBuffer noisebuf2;
1577 NoiseBuffer noisebuf_cave;
1578 NoiseBuffer noisebuf_ground;
1579 NoiseBuffer noisebuf_ground_crumbleness;
1580 NoiseBuffer noisebuf_ground_wetness;
1582 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1583 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1585 //TimeTaker timer("noisebuf.create");
1591 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1592 minpos_f.X, minpos_f.Y, minpos_f.Z,
1593 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1595 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1603 v3f sl = v3f(4.0, 4.0, 4.0);
1608 if(all_is_ground_except_caves == false)
1609 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1610 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1611 minpos_f.X, minpos_f.Y, minpos_f.Z,
1612 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1616 Ground property noise
1618 sl = v3f(2.5, 2.5, 2.5);
1619 noisebuf_ground_crumbleness.create(
1620 get_ground_crumbleness_params(data->seed),
1621 minpos_f.X, minpos_f.Y, minpos_f.Z,
1622 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1624 noisebuf_ground_wetness.create(
1625 get_ground_wetness_params(data->seed),
1626 minpos_f.X, minpos_f.Y, minpos_f.Z,
1627 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1632 Make base ground level
1635 for(s16 x=node_min.X; x<=node_max.X; x++)
1636 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1641 // Use fast index incrementing
1642 v3s16 em = vmanip.m_area.getExtent();
1643 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1644 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1646 // Only modify places that have no content
1647 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1649 // First priority: make air and water.
1650 // This avoids caves inside water.
1651 if(all_is_ground_except_caves == false
1652 && val_is_ground(noisebuf_ground.get(x,y,z),
1653 v3s16(x,y,z), data->seed) == false)
1655 if(y <= WATER_LEVEL)
1656 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1658 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1660 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1661 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1663 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1666 data->vmanip->m_area.add_y(em, i, 1);
1676 PseudoRandom mineralrandom(blockseed);
1681 for(s16 i=0; i<approx_ground_depth/4; i++)
1683 if(mineralrandom.next()%50 == 0)
1685 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1686 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1687 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1688 for(u16 i=0; i<27; i++)
1690 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1691 u32 vi = vmanip.m_area.index(p);
1692 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1693 if(mineralrandom.next()%8 == 0)
1694 vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1703 u16 a = mineralrandom.range(0,15);
1705 u16 amount = 20 * a/1000;
1706 for(s16 i=0; i<amount; i++)
1708 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1709 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1710 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1712 u8 base_content = CONTENT_STONE;
1713 MapNode new_content(CONTENT_IGNORE);
1716 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1718 new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1722 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1723 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1724 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1725 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1727 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1729 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1733 if(new_content.getContent() != CONTENT_IGNORE)
1735 for(u16 i=0; i<27; i++)
1737 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1738 u32 vi = vmanip.m_area.index(p);
1739 if(vmanip.m_data[vi].getContent() == base_content)
1741 if(mineralrandom.next()%sparseness == 0)
1742 vmanip.m_data[vi] = new_content;
1751 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1752 //for(s16 i=0; i<50; i++)
1753 u16 coal_amount = 30;
1754 u16 coal_rareness = 60 / coal_amount;
1755 if(coal_rareness == 0)
1757 if(mineralrandom.next()%coal_rareness == 0)
1759 u16 a = mineralrandom.next() % 16;
1760 u16 amount = coal_amount * a*a*a / 1000;
1761 for(s16 i=0; i<amount; i++)
1763 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1764 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1765 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1766 for(u16 i=0; i<27; i++)
1768 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1769 u32 vi = vmanip.m_area.index(p);
1770 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1771 if(mineralrandom.next()%8 == 0)
1772 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1779 u16 iron_amount = 8;
1780 u16 iron_rareness = 60 / iron_amount;
1781 if(iron_rareness == 0)
1783 if(mineralrandom.next()%iron_rareness == 0)
1785 u16 a = mineralrandom.next() % 16;
1786 u16 amount = iron_amount * a*a*a / 1000;
1787 for(s16 i=0; i<amount; i++)
1789 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1790 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1791 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1792 for(u16 i=0; i<27; i++)
1794 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1795 u32 vi = vmanip.m_area.index(p);
1796 if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
1797 if(mineralrandom.next()%8 == 0)
1798 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1805 Add mud and sand and others underground (in place of stone)
1808 for(s16 x=node_min.X; x<=node_max.X; x++)
1809 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1814 // Use fast index incrementing
1815 v3s16 em = vmanip.m_area.getExtent();
1816 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1817 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1819 if(vmanip.m_data[i].getContent() == CONTENT_STONE)
1821 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1823 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1824 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1826 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1828 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1830 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1831 vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1833 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1834 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1836 vmanip.m_data[i] = MapNode(CONTENT_LAVASOURCE);
1837 for(s16 x1=-1; x1<=1; x1++)
1838 for(s16 y1=-1; y1<=1; y1++)
1839 for(s16 z1=-1; z1<=1; z1++)
1840 data->transforming_liquid.push_back(
1841 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1845 data->vmanip->m_area.add_y(em, i, -1);
1854 //if(node_min.Y < approx_groundlevel)
1855 //if(myrand() % 3 == 0)
1856 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1857 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1858 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1859 float dungeon_rarity = 0.02;
1860 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1862 && node_min.Y < approx_groundlevel)
1864 // Dungeon generator doesn't modify places which have this set
1865 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1866 | VMANIP_FLAG_DUNGEON_PRESERVE);
1868 // Set all air and water to be untouchable to make dungeons open
1869 // to caves and open air
1870 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1871 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1876 // Use fast index incrementing
1877 v3s16 em = vmanip.m_area.getExtent();
1878 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1879 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1881 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1882 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1883 else if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1884 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1885 data->vmanip->m_area.add_y(em, i, -1);
1890 PseudoRandom random(blockseed+2);
1893 make_dungeon1(vmanip, random);
1895 // Convert some cobble to mossy cobble
1896 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1897 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1902 // Use fast index incrementing
1903 v3s16 em = vmanip.m_area.getExtent();
1904 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1905 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1907 // (noisebuf not used because it doesn't contain the
1909 double wetness = noise3d_param(
1910 get_ground_wetness_params(data->seed), x,y,z);
1911 double d = noise3d_perlin((float)x/2.5,
1912 (float)y/2.5,(float)z/2.5,
1914 if(vmanip.m_data[i].getContent() == CONTENT_COBBLE)
1918 vmanip.m_data[i].setContent(CONTENT_MOSSYCOBBLE);
1921 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1924 vmanip.m_data[i].setContent(CONTENT_MUD);
1926 data->vmanip->m_area.add_y(em, i, -1);
1936 PseudoRandom ncrandom(blockseed+9324342);
1937 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1939 make_nc(vmanip, ncrandom);
1944 Add top and bottom side of water to transforming_liquid queue
1947 for(s16 x=node_min.X; x<=node_max.X; x++)
1948 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1953 bool water_found = false;
1954 // Use fast index incrementing
1955 v3s16 em = vmanip.m_area.getExtent();
1956 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1957 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1959 if(water_found == false)
1961 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
1963 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1964 data->transforming_liquid.push_back(p);
1970 // This can be done because water_found can only
1971 // turn to true and end up here after going through
1973 if(vmanip.m_data[i+1].getContent() != CONTENT_WATERSOURCE)
1975 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1976 data->transforming_liquid.push_back(p);
1977 water_found = false;
1981 data->vmanip->m_area.add_y(em, i, -1);
1987 If close to ground level
1990 //if(abs(approx_ground_depth) < 30)
1991 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1997 for(s16 x=node_min.X; x<=node_max.X; x++)
1998 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2003 bool possibly_have_sand = get_have_sand(data->seed, p2d);
2004 bool have_sand = false;
2005 u32 current_depth = 0;
2006 bool air_detected = false;
2007 bool water_detected = false;
2008 bool have_clay = false;
2010 // Use fast index incrementing
2011 s16 start_y = node_max.Y+2;
2012 v3s16 em = vmanip.m_area.getExtent();
2013 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2014 for(s16 y=start_y; y>=node_min.Y-3; y--)
2016 if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
2017 water_detected = true;
2018 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2019 air_detected = true;
2021 if((vmanip.m_data[i].getContent() == CONTENT_STONE
2022 || vmanip.m_data[i].getContent() == CONTENT_GRASS
2023 || vmanip.m_data[i].getContent() == CONTENT_MUD
2024 || vmanip.m_data[i].getContent() == CONTENT_SAND
2025 || vmanip.m_data[i].getContent() == CONTENT_GRAVEL
2026 ) && (air_detected || water_detected))
2028 if(current_depth == 0 && y <= WATER_LEVEL+2
2029 && possibly_have_sand)
2032 if(current_depth < 4)
2036 // Determine whether to have clay in the sand here
2037 double claynoise = noise2d_perlin(
2038 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2039 data->seed+4321, 6, 0.95) + 0.5;
2041 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2042 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2043 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2046 vmanip.m_data[i] = MapNode(CONTENT_CLAY);
2048 vmanip.m_data[i] = MapNode(CONTENT_SAND);
2051 else if(current_depth==0 && !water_detected
2052 && y >= WATER_LEVEL && air_detected)
2053 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
2056 vmanip.m_data[i] = MapNode(CONTENT_MUD);
2060 if(vmanip.m_data[i].getContent() == CONTENT_MUD
2061 || vmanip.m_data[i].getContent() == CONTENT_GRASS)
2062 vmanip.m_data[i] = MapNode(CONTENT_STONE);
2067 if(current_depth >= 8)
2070 else if(current_depth != 0)
2073 data->vmanip->m_area.add_y(em, i, -1);
2079 Calculate some stuff
2082 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2083 bool is_jungle = surface_humidity > 0.75;
2085 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
2092 PseudoRandom treerandom(blockseed);
2093 // Put trees in random places on part of division
2094 for(u32 i=0; i<tree_count; i++)
2096 s16 x = treerandom.range(node_min.X, node_max.X);
2097 s16 z = treerandom.range(node_min.Z, node_max.Z);
2098 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2099 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2100 // Don't make a tree under water level
2103 // Make sure tree fits (only trees whose starting point is
2104 // at this block are added)
2105 if(y < node_min.Y || y > node_max.Y)
2108 Find exact ground level
2112 for(; p.Y >= y-6; p.Y--)
2114 u32 i = data->vmanip->m_area.index(p);
2115 MapNode *n = &data->vmanip->m_data[i];
2116 if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
2122 // If not found, handle next one
2127 u32 i = data->vmanip->m_area.index(p);
2128 MapNode *n = &data->vmanip->m_data[i];
2130 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
2133 // Papyrus grows only on mud and in water
2134 if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
2137 make_papyrus(vmanip, p);
2139 // Trees grow only on mud and grass, on land
2140 else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
2143 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2144 if(is_jungle == false)
2147 if(myrand_range(0,4) != 0)
2148 is_apple_tree = false;
2150 is_apple_tree = noise2d_perlin(
2151 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2152 data->seed+342902, 3, 0.45) > 0.2;
2153 make_tree(vmanip, p, is_apple_tree);
2156 make_jungletree(vmanip, p);
2158 // Cactii grow only on sand, on land
2159 else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
2162 make_cactus(vmanip, p);
2172 PseudoRandom grassrandom(blockseed);
2173 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2175 s16 x = grassrandom.range(node_min.X, node_max.X);
2176 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2177 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2180 if(y < node_min.Y || y > node_max.Y)
2183 Find exact ground level
2187 for(; p.Y >= y-6; p.Y--)
2189 u32 i = data->vmanip->m_area.index(p);
2190 MapNode *n = &data->vmanip->m_data[i];
2191 if(data->nodemgr->get(*n).is_ground_content
2192 || n->getContent() == CONTENT_JUNGLETREE)
2198 // If not found, handle next one
2202 if(vmanip.m_area.contains(p) == false)
2204 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2207 if(vmanip.m_area.contains(p))
2208 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
2210 if(vmanip.m_area.contains(p))
2211 vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
2217 Add some kind of random stones
2220 u32 random_stone_count = block_area_nodes *
2221 randomstone_amount_2d(data->seed, p2d_center);
2222 // Put in random places on part of division
2223 for(u32 i=0; i<random_stone_count; i++)
2225 s16 x = myrand_range(node_min.X, node_max.X);
2226 s16 z = myrand_range(node_min.Z, node_max.Z);
2227 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2228 // Don't add under water level
2229 /*if(y < WATER_LEVEL)
2231 // Don't add if doesn't belong to this block
2232 if(y < node_min.Y || y > node_max.Y)
2237 u32 i = data->vmanip->m_area.index(v3s16(p));
2238 MapNode *n = &data->vmanip->m_data[i];
2239 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2242 // Will be placed one higher
2245 make_randomstone(data->vmanip, p);
2254 u32 large_stone_count = block_area_nodes *
2255 largestone_amount_2d(data->seed, p2d_center);
2256 //u32 large_stone_count = 1;
2257 // Put in random places on part of division
2258 for(u32 i=0; i<large_stone_count; i++)
2260 s16 x = myrand_range(node_min.X, node_max.X);
2261 s16 z = myrand_range(node_min.Z, node_max.Z);
2262 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2263 // Don't add under water level
2264 /*if(y < WATER_LEVEL)
2266 // Don't add if doesn't belong to this block
2267 if(y < node_min.Y || y > node_max.Y)
2272 u32 i = data->vmanip->m_area.index(v3s16(p));
2273 MapNode *n = &data->vmanip->m_data[i];
2274 if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
2277 // Will be placed one lower
2280 make_largestone(data->vmanip, p);
2287 BlockMakeData::BlockMakeData():
2294 BlockMakeData::~BlockMakeData()
2299 }; // namespace mapgen