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.
26 //#include "serverobject.h"
27 #include "content_sao.h"
29 #include "content_mapnode.h" // For content_mapnode_get_new_name
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() != LEGN(ndef, "CONTENT_TREE")
72 && n.getContent() != LEGN(ndef, "CONTENT_LEAVES"))
75 vmanip.m_area.add_y(em, i, -1);
84 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
85 bool is_apple_tree, INodeDefManager *ndef)
87 MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
88 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
89 MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
91 s16 trunk_h = myrand_range(4, 5);
93 for(s16 ii=0; ii<trunk_h; ii++)
95 if(vmanip.m_area.contains(p1))
96 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
100 // p1 is now the last piece of the trunk
103 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
104 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
105 Buffer<u8> leaves_d(leaves_a.getVolume());
106 for(s32 i=0; i<leaves_a.getVolume(); i++)
109 // Force leaves at near the end of the trunk
112 for(s16 z=-d; z<=d; z++)
113 for(s16 y=-d; y<=d; y++)
114 for(s16 x=-d; x<=d; x++)
116 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
120 // Add leaves randomly
121 for(u32 iii=0; iii<7; iii++)
126 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
127 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
128 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
131 for(s16 z=0; z<=d; z++)
132 for(s16 y=0; y<=d; y++)
133 for(s16 x=0; x<=d; x++)
135 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
139 // Blit leaves to vmanip
140 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
141 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
142 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
146 if(vmanip.m_area.contains(p) == false)
148 u32 vi = vmanip.m_area.index(p);
149 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
150 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
152 u32 i = leaves_a.index(x,y,z);
153 if(leaves_d[i] == 1) {
154 bool is_apple = myrand_range(0,99) < 10;
155 if(is_apple_tree && is_apple) {
156 vmanip.m_data[vi] = applenode;
158 vmanip.m_data[vi] = leavesnode;
164 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
165 INodeDefManager *ndef)
167 MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
168 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
170 for(s16 x=-1; x<=1; x++)
171 for(s16 z=-1; z<=1; z++)
173 if(myrand_range(0, 2) == 0)
175 v3s16 p1 = p0 + v3s16(x,0,z);
176 v3s16 p2 = p0 + v3s16(x,-1,z);
177 if(vmanip.m_area.contains(p2)
178 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
179 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
180 else if(vmanip.m_area.contains(p1))
181 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
184 s16 trunk_h = myrand_range(8, 12);
186 for(s16 ii=0; ii<trunk_h; ii++)
188 if(vmanip.m_area.contains(p1))
189 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
193 // p1 is now the last piece of the trunk
196 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
197 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
198 Buffer<u8> leaves_d(leaves_a.getVolume());
199 for(s32 i=0; i<leaves_a.getVolume(); i++)
202 // Force leaves at near the end of the trunk
205 for(s16 z=-d; z<=d; z++)
206 for(s16 y=-d; y<=d; y++)
207 for(s16 x=-d; x<=d; x++)
209 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
213 // Add leaves randomly
214 for(u32 iii=0; iii<30; iii++)
219 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
220 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
221 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
224 for(s16 z=0; z<=d; z++)
225 for(s16 y=0; y<=d; y++)
226 for(s16 x=0; x<=d; x++)
228 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
232 // Blit leaves to vmanip
233 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
234 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
235 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
239 if(vmanip.m_area.contains(p) == false)
241 u32 vi = vmanip.m_area.index(p);
242 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
243 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
245 u32 i = leaves_a.index(x,y,z);
247 vmanip.m_data[vi] = leavesnode;
251 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
252 INodeDefManager *ndef)
254 MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
256 s16 trunk_h = myrand_range(2, 3);
258 for(s16 ii=0; ii<trunk_h; ii++)
260 if(vmanip.m_area.contains(p1))
261 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
266 void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
267 INodeDefManager *ndef)
269 MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
273 for(s16 ii=0; ii<trunk_h; ii++)
275 if(vmanip.m_area.contains(p1))
276 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
282 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
284 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
286 s16 size = myrand_range(3, 6);
288 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
289 Buffer<u8> stone_d(stone_a.getVolume());
290 for(s32 i=0; i<stone_a.getVolume(); i++)
293 // Force stone at bottom to make it usually touch the ground
295 for(s16 z=0; z<=0; z++)
296 for(s16 y=0; y<=0; y++)
297 for(s16 x=0; x<=0; x++)
299 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
303 // Generate from perlin noise
304 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
305 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
306 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
308 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
309 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
310 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
312 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
314 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
318 u32 vi = stone_a.index(v3s16(x,y,z));
323 /*// Add stone randomly
324 for(u32 iii=0; iii<7; iii++)
329 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
330 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
331 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
334 for(s16 z=0; z<=d; z++)
335 for(s16 y=0; y<=d; y++)
336 for(s16 x=0; x<=d; x++)
338 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
342 // Blit stone to vmanip
343 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
344 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
345 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
349 if(vmanip.m_area.contains(p) == false)
351 u32 vi = vmanip.m_area.index(p);
352 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
353 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
355 u32 i = stone_a.index(x,y,z);
357 vmanip.m_data[vi] = stonenode;
363 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
365 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
367 s16 size = myrand_range(8, 16);
369 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
370 Buffer<u8> stone_d(stone_a.getVolume());
371 for(s32 i=0; i<stone_a.getVolume(); i++)
374 // Force stone at bottom to make it usually touch the ground
376 for(s16 z=0; z<=0; z++)
377 for(s16 y=0; y<=0; y++)
378 for(s16 x=0; x<=0; x++)
380 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
384 // Generate from perlin noise
385 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
386 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
387 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
390 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
391 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
392 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
393 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
394 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
395 double dz = (double)z-mid_z;
396 double dx = (double)x-mid_x;
397 double dy = MYMAX(0, (double)y-mid_y);
398 double r = sqrt(dz*dz+dx*dx+dy*dy);
399 d /= (2*r/size)*2 + 0.01;
402 u32 vi = stone_a.index(v3s16(x,y,z));
407 /*// Add stone randomly
408 for(u32 iii=0; iii<7; iii++)
413 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
414 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
415 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
418 for(s16 z=0; z<=d; z++)
419 for(s16 y=0; y<=d; y++)
420 for(s16 x=0; x<=d; x++)
422 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
426 // Blit stone to vmanip
427 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
428 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
429 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
433 if(vmanip.m_area.contains(p) == false)
435 u32 vi = vmanip.m_area.index(p);
436 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
437 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
439 u32 i = stone_a.index(x,y,z);
441 vmanip.m_data[vi] = stonenode;
447 Dungeon making routines
450 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
451 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
452 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
453 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
455 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
456 INodeDefManager *ndef)
459 for(s16 z=0; z<roomsize.Z; z++)
460 for(s16 y=0; y<roomsize.Y; y++)
463 v3s16 p = roomplace + v3s16(0,y,z);
464 if(vmanip.m_area.contains(p) == false)
466 u32 vi = vmanip.m_area.index(p);
467 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
469 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
472 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
473 if(vmanip.m_area.contains(p) == false)
475 u32 vi = vmanip.m_area.index(p);
476 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
478 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
483 for(s16 x=0; x<roomsize.X; x++)
484 for(s16 y=0; y<roomsize.Y; y++)
487 v3s16 p = roomplace + v3s16(x,y,0);
488 if(vmanip.m_area.contains(p) == false)
490 u32 vi = vmanip.m_area.index(p);
491 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
493 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
496 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
497 if(vmanip.m_area.contains(p) == false)
499 u32 vi = vmanip.m_area.index(p);
500 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
502 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
506 // Make +-Y walls (floor and ceiling)
507 for(s16 z=0; z<roomsize.Z; z++)
508 for(s16 x=0; x<roomsize.X; x++)
511 v3s16 p = roomplace + v3s16(x,0,z);
512 if(vmanip.m_area.contains(p) == false)
514 u32 vi = vmanip.m_area.index(p);
515 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
517 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
520 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
521 if(vmanip.m_area.contains(p) == false)
523 u32 vi = vmanip.m_area.index(p);
524 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
526 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
531 for(s16 z=1; z<roomsize.Z-1; z++)
532 for(s16 y=1; y<roomsize.Y-1; y++)
533 for(s16 x=1; x<roomsize.X-1; x++)
535 v3s16 p = roomplace + v3s16(x,y,z);
536 if(vmanip.m_area.contains(p) == false)
538 u32 vi = vmanip.m_area.index(p);
539 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
540 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
544 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
545 u8 avoid_flags, MapNode n, u8 or_flags)
547 for(s16 z=0; z<size.Z; z++)
548 for(s16 y=0; y<size.Y; y++)
549 for(s16 x=0; x<size.X; x++)
551 v3s16 p = place + v3s16(x,y,z);
552 if(vmanip.m_area.contains(p) == false)
554 u32 vi = vmanip.m_area.index(p);
555 if(vmanip.m_flags[vi] & avoid_flags)
557 vmanip.m_flags[vi] |= or_flags;
558 vmanip.m_data[vi] = n;
562 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
563 INodeDefManager *ndef)
565 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
566 VMANIP_FLAG_DUNGEON_INSIDE);
569 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
570 INodeDefManager *ndef)
572 make_hole1(vmanip, doorplace, ndef);
573 // Place torch (for testing)
574 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
577 static v3s16 rand_ortho_dir(PseudoRandom &random)
579 if(random.next()%2==0)
580 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
582 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
585 static v3s16 turn_xz(v3s16 olddir, int t)
605 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
607 int turn = random.range(0,2);
616 dir = turn_xz(olddir, 0);
619 dir = turn_xz(olddir, 1);
623 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
624 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
625 PseudoRandom &random, INodeDefManager *ndef)
627 make_hole1(vmanip, doorplace, ndef);
628 v3s16 p0 = doorplace;
632 length = random.range(1,13);
634 length = random.range(1,6);
635 length = random.range(1,13);
636 u32 partlength = random.range(1,13);
639 if(random.next()%2 == 0 && partlength >= 3)
640 make_stairs = random.next()%2 ? 1 : -1;
641 for(u32 i=0; i<length; i++)
647 /*// If already empty
648 if(vmanip.getNodeNoExNoEmerge(p).getContent()
650 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
655 if(vmanip.m_area.contains(p) == true
656 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
660 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
661 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
662 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
663 VMANIP_FLAG_DUNGEON_INSIDE);
664 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
665 VMANIP_FLAG_DUNGEON_INSIDE);
669 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
670 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
671 make_hole1(vmanip, p, ndef);
672 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
673 VMANIP_FLAG_DUNGEON_INSIDE);*/
680 // Can't go here, turn away
681 dir = turn_xz(dir, random.range(0,1));
682 make_stairs = -make_stairs;
684 partlength = random.range(1,length);
689 if(partcount >= partlength)
693 dir = random_turn(random, dir);
695 partlength = random.range(1,length);
698 if(random.next()%2 == 0 && partlength >= 3)
699 make_stairs = random.next()%2 ? 1 : -1;
710 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
711 INodeDefManager *ndef):
722 m_dir = rand_ortho_dir(m_random);
725 void setPos(v3s16 pos)
730 void setDir(v3s16 dir)
735 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
737 for(u32 i=0; i<100; i++)
739 v3s16 p = m_pos + m_dir;
740 v3s16 p1 = p + v3s16(0,1,0);
741 if(vmanip.m_area.contains(p) == false
742 || vmanip.m_area.contains(p1) == false
748 if(vmanip.getNodeNoExNoEmerge(p).getContent()
749 == LEGN(m_ndef, "CONTENT_COBBLE")
750 && vmanip.getNodeNoExNoEmerge(p1).getContent()
751 == LEGN(m_ndef, "CONTENT_COBBLE"))
753 // Found wall, this is a good place!
756 // Randomize next direction
761 Determine where to move next
763 // Jump one up if the actual space is there
764 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
765 == LEGN(m_ndef, "CONTENT_COBBLE")
766 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
767 == LEGN(m_ndef, "CONTENT_AIR")
768 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
769 == LEGN(m_ndef, "CONTENT_AIR"))
771 // Jump one down if the actual space is there
772 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
773 == LEGN(m_ndef, "CONTENT_COBBLE")
774 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
775 == LEGN(m_ndef, "CONTENT_AIR")
776 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
777 == LEGN(m_ndef, "CONTENT_AIR"))
779 // Check if walking is now possible
780 if(vmanip.getNodeNoExNoEmerge(p).getContent()
781 != LEGN(m_ndef, "CONTENT_AIR")
782 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
783 != LEGN(m_ndef, "CONTENT_AIR"))
785 // Cannot continue walking here
795 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
796 v3s16 &result_doordir, v3s16 &result_roomplace)
798 for(s16 trycount=0; trycount<30; trycount++)
802 bool r = findPlaceForDoor(doorplace, doordir);
806 // X east, Z north, Y up
808 if(doordir == v3s16(1,0,0)) // X+
809 roomplace = doorplace +
810 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
811 if(doordir == v3s16(-1,0,0)) // X-
812 roomplace = doorplace +
813 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
814 if(doordir == v3s16(0,0,1)) // Z+
815 roomplace = doorplace +
816 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
817 if(doordir == v3s16(0,0,-1)) // Z-
818 roomplace = doorplace +
819 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
822 if(doordir == v3s16(1,0,0)) // X+
823 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
824 if(doordir == v3s16(-1,0,0)) // X-
825 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
826 if(doordir == v3s16(0,0,1)) // Z+
827 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
828 if(doordir == v3s16(0,0,-1)) // Z-
829 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
834 for(s16 z=1; z<roomsize.Z-1; z++)
835 for(s16 y=1; y<roomsize.Y-1; y++)
836 for(s16 x=1; x<roomsize.X-1; x++)
838 v3s16 p = roomplace + v3s16(x,y,z);
839 if(vmanip.m_area.contains(p) == false)
844 if(vmanip.m_flags[vmanip.m_area.index(p)]
845 & VMANIP_FLAG_DUNGEON_INSIDE)
856 result_doorplace = doorplace;
857 result_doordir = doordir;
858 result_roomplace = roomplace;
865 VoxelManipulator &vmanip;
868 PseudoRandom &m_random;
869 INodeDefManager *m_ndef;
872 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
873 INodeDefManager *ndef)
875 v3s16 areasize = vmanip.m_area.getExtent();
880 Find place for first room
883 for(u32 i=0; i<100; i++)
885 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
886 roomplace = vmanip.m_area.MinEdge + v3s16(
887 random.range(0,areasize.X-roomsize.X-1),
888 random.range(0,areasize.Y-roomsize.Y-1),
889 random.range(0,areasize.Z-roomsize.Z-1));
891 Check that we're not putting the room to an unknown place,
892 otherwise it might end up floating in the air
895 for(s16 z=1; z<roomsize.Z-1; z++)
896 for(s16 y=1; y<roomsize.Y-1; y++)
897 for(s16 x=1; x<roomsize.X-1; x++)
899 v3s16 p = roomplace + v3s16(x,y,z);
900 u32 vi = vmanip.m_area.index(p);
901 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
906 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
920 Stores the center position of the last room made, so that
921 a new corridor can be started from the last room instead of
922 the new room, if chosen so.
924 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
926 u32 room_count = random.range(2,7);
927 for(u32 i=0; i<room_count; i++)
929 // Make a room to the determined place
930 make_room1(vmanip, roomsize, roomplace, ndef);
932 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
934 // Place torch at room center (for testing)
935 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
938 if(i == room_count-1)
941 // Determine walker start position
943 bool start_in_last_room = (random.range(0,2)!=0);
944 //bool start_in_last_room = true;
946 v3s16 walker_start_place;
948 if(start_in_last_room)
950 walker_start_place = last_room_center;
954 walker_start_place = room_center;
955 // Store center of current room as the last one
956 last_room_center = room_center;
959 // Create walker and find a place for a door
960 RoomWalker walker(vmanip, walker_start_place, random, ndef);
963 bool r = walker.findPlaceForDoor(doorplace, doordir);
967 if(random.range(0,1)==0)
969 make_door1(vmanip, doorplace, doordir, ndef);
971 // Don't actually make a door
972 doorplace -= doordir;
974 // Make a random corridor starting from the door
976 v3s16 corridor_end_dir;
977 make_corridor(vmanip, doorplace, doordir, corridor_end,
978 corridor_end_dir, random, ndef);
980 // Find a place for a random sized room
981 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
982 walker.setPos(corridor_end);
983 walker.setDir(corridor_end_dir);
984 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
988 if(random.range(0,1)==0)
990 make_door1(vmanip, doorplace, doordir, ndef);
992 // Don't actually make a door
993 roomplace -= doordir;
998 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
999 INodeDefManager *ndef)
1003 s32 r = random.range(0, 3);
1005 dir = v3s16( 1, 0, 0);
1009 dir = v3s16(-1, 0, 0);
1013 dir = v3s16( 0, 0, 1);
1017 dir = v3s16( 0, 0,-1);
1020 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1021 16+random.range(0,15),
1022 16+random.range(0,15),
1023 16+random.range(0,15));
1024 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC"), facedir_i);
1025 u32 length = random.range(3,15);
1026 for(u32 j=0; j<length; j++)
1029 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
1034 Noise functions. Make sure seed is mangled differently in each one.
1038 Scaling the output of the noise function affects the overdrive of the
1039 contour function, which affects the shape of the output considerably.
1041 #define CAVE_NOISE_SCALE 12.0
1042 //#define CAVE_NOISE_SCALE 10.0
1043 //#define CAVE_NOISE_SCALE 7.5
1044 //#define CAVE_NOISE_SCALE 5.0
1045 //#define CAVE_NOISE_SCALE 1.0
1047 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1048 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1050 NoiseParams get_cave_noise1_params(u64 seed)
1052 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1053 200, CAVE_NOISE_SCALE);*/
1054 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1055 100, CAVE_NOISE_SCALE);*/
1056 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1057 100, CAVE_NOISE_SCALE);*/
1058 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1059 100, CAVE_NOISE_SCALE);*/
1060 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1061 50, CAVE_NOISE_SCALE);
1062 //return NoiseParams(NOISE_CONSTANT_ONE);
1065 NoiseParams get_cave_noise2_params(u64 seed)
1067 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1068 200, CAVE_NOISE_SCALE);*/
1069 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1070 100, CAVE_NOISE_SCALE);*/
1071 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1072 100, CAVE_NOISE_SCALE);*/
1073 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1074 50, CAVE_NOISE_SCALE);
1075 //return NoiseParams(NOISE_CONSTANT_ONE);
1078 NoiseParams get_ground_noise1_params(u64 seed)
1080 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1084 NoiseParams get_ground_crumbleness_params(u64 seed)
1086 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1090 NoiseParams get_ground_wetness_params(u64 seed)
1092 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1096 bool is_cave(u64 seed, v3s16 p)
1098 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1099 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1100 return d1*d2 > CAVE_NOISE_THRESHOLD;
1104 Ground density noise shall be interpreted by using this.
1106 TODO: No perlin noises here, they should be outsourced
1108 NOTE: The speed of these actually isn't terrible
1110 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1112 //return ((double)p.Y < ground_noise1_val);
1114 double f = 0.55 + noise2d_perlin(
1115 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1116 seed+920381, 3, 0.45);
1121 double h = WATER_LEVEL + 10 * noise2d_perlin(
1122 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1123 seed+84174, 4, 0.5);
1126 return ((double)p.Y - h < ground_noise1_val * f);
1130 Queries whether a position is ground or not.
1132 bool is_ground(u64 seed, v3s16 p)
1134 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1135 return val_is_ground(val1, p, seed);
1138 // Amount of trees per area in nodes
1139 double tree_amount_2d(u64 seed, v2s16 p)
1141 /*double noise = noise2d_perlin(
1142 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1144 double noise = noise2d_perlin(
1145 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1147 double zeroval = -0.39;
1151 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1154 double surface_humidity_2d(u64 seed, v2s16 p)
1156 double noise = noise2d_perlin(
1157 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1158 seed+72384, 4, 0.66);
1159 noise = (noise + 1.0)/2.0;
1168 double randomstone_amount_2d(u64 seed, v2s16 p)
1170 double noise = noise2d_perlin(
1171 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1172 seed+3829434, 5, 0.66);
1173 double zeroval = 0.1;
1177 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1181 double largestone_amount_2d(u64 seed, v2s16 p)
1183 double noise = noise2d_perlin(
1184 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1185 seed+14143242, 5, 0.66);
1186 double zeroval = 0.3;
1190 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1194 Incrementally find ground level from 3d noise
1196 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1198 // Start a bit fuzzy to make averaging lower precision values
1200 s16 level = myrand_range(-precision/2, precision/2);
1201 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1203 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1205 // First find non-ground by going upwards
1206 // Don't stop in caves.
1208 s16 max = level+dec[i-1]*2;
1209 v3s16 p(p2d.X, level, p2d.Y);
1210 for(; p.Y < max; p.Y += dec[i])
1212 if(!is_ground(seed, p))
1219 // Then find ground by going downwards from there.
1220 // Go in caves, too, when precision is 1.
1222 s16 min = level-dec[i-1]*2;
1223 v3s16 p(p2d.X, level, p2d.Y);
1224 for(; p.Y>min; p.Y-=dec[i])
1226 bool ground = is_ground(seed, p);
1227 /*if(dec[i] == 1 && is_cave(seed, p))
1238 // This is more like the actual ground level
1239 level += dec[i-1]/2;
1244 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1246 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1248 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1249 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1251 a += find_ground_level_from_noise(seed,
1252 v2s16(node_min.X, node_min.Y), p);
1253 a += find_ground_level_from_noise(seed,
1254 v2s16(node_min.X, node_max.Y), p);
1255 a += find_ground_level_from_noise(seed,
1256 v2s16(node_max.X, node_max.Y), p);
1257 a += find_ground_level_from_noise(seed,
1258 v2s16(node_max.X, node_min.Y), p);
1259 a += find_ground_level_from_noise(seed,
1260 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1265 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1267 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1269 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1270 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1273 a = MYMAX(a, find_ground_level_from_noise(seed,
1274 v2s16(node_min.X, node_min.Y), p));
1275 a = MYMAX(a, find_ground_level_from_noise(seed,
1276 v2s16(node_min.X, node_max.Y), p));
1277 a = MYMAX(a, find_ground_level_from_noise(seed,
1278 v2s16(node_max.X, node_max.Y), p));
1279 a = MYMAX(a, find_ground_level_from_noise(seed,
1280 v2s16(node_min.X, node_min.Y), p));
1282 a = MYMAX(a, find_ground_level_from_noise(seed,
1283 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1284 // Side middle points
1285 a = MYMAX(a, find_ground_level_from_noise(seed,
1286 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1287 a = MYMAX(a, find_ground_level_from_noise(seed,
1288 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1289 a = MYMAX(a, find_ground_level_from_noise(seed,
1290 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1291 a = MYMAX(a, find_ground_level_from_noise(seed,
1292 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1296 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1298 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1300 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1301 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1304 a = MYMIN(a, find_ground_level_from_noise(seed,
1305 v2s16(node_min.X, node_min.Y), p));
1306 a = MYMIN(a, find_ground_level_from_noise(seed,
1307 v2s16(node_min.X, node_max.Y), p));
1308 a = MYMIN(a, find_ground_level_from_noise(seed,
1309 v2s16(node_max.X, node_max.Y), p));
1310 a = MYMIN(a, find_ground_level_from_noise(seed,
1311 v2s16(node_min.X, node_min.Y), p));
1313 a = MYMIN(a, find_ground_level_from_noise(seed,
1314 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1315 // Side middle points
1316 a = MYMIN(a, find_ground_level_from_noise(seed,
1317 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1318 a = MYMIN(a, find_ground_level_from_noise(seed,
1319 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1320 a = MYMIN(a, find_ground_level_from_noise(seed,
1321 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1322 a = MYMIN(a, find_ground_level_from_noise(seed,
1323 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1327 bool block_is_underground(u64 seed, v3s16 blockpos)
1329 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1330 seed, v2s16(blockpos.X, blockpos.Z));
1332 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1339 #define AVERAGE_MUD_AMOUNT 4
1341 double base_rock_level_2d(u64 seed, v2s16 p)
1343 // The base ground level
1344 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1345 + 20. * noise2d_perlin(
1346 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1347 (seed>>32)+654879876, 6, 0.6);
1349 /*// A bit hillier one
1350 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1351 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1352 (seed>>27)+90340, 6, 0.69);
1356 // Higher ground level
1357 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1358 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1359 seed+85039, 5, 0.69);
1360 //higher = 30; // For debugging
1362 // Limit higher to at least base
1366 // Steepness factor of cliffs
1367 double b = 1.0 + 1.0 * noise2d_perlin(
1368 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1370 b = rangelim(b, 0.0, 1000.0);
1373 b = rangelim(b, 3.0, 1000.0);
1374 //dstream<<"b="<<b<<std::endl;
1377 // Offset to more low
1378 double a_off = -0.2;
1379 // High/low selector
1380 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1381 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1382 seed-359, 6, 0.7));*/
1383 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1384 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1385 seed-359, 5, 0.60));
1387 a = rangelim(a, 0.0, 1.0);
1389 //dstream<<"a="<<a<<std::endl;
1391 double h = base*(1.0-a) + higher*a;
1398 double get_mud_add_amount(u64 seed, v2s16 p)
1400 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1401 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1402 seed+91013, 3, 0.55));
1406 bool get_have_sand(u64 seed, v2s16 p2d)
1408 // Determine whether to have sand here
1409 double sandnoise = noise2d_perlin(
1410 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1411 seed+59420, 3, 0.50);
1413 return (sandnoise > -0.15);
1417 Adds random objects to block, depending on the content of the block
1419 void add_random_objects(MapBlock *block)
1422 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1423 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1425 bool last_node_walkable = false;
1426 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1429 MapNode n = block->getNodeNoEx(p);
1430 if(n.getContent() == CONTENT_IGNORE)
1432 if(data->nodedef->get(n)->liquid_type != LIQUID_NONE)
1434 if(data->nodedef->get(n)->walkable)
1436 last_node_walkable = true;
1439 if(last_node_walkable)
1441 // If block contains light information
1442 if(content_features(n).param_type == CPT_LIGHT)
1444 if(n.getLight(LIGHTBANK_DAY) <= 3)
1446 if(myrand() % 300 == 0)
1448 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1450 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1451 std::string data = obj->getStaticData();
1452 StaticObject s_obj(obj->getType(),
1453 obj->getBasePosition(), data);
1455 block->m_static_objects.insert(0, s_obj);
1456 block->m_static_objects.insert(0, s_obj);
1457 block->m_static_objects.insert(0, s_obj);
1458 block->m_static_objects.insert(0, s_obj);
1459 block->m_static_objects.insert(0, s_obj);
1460 block->m_static_objects.insert(0, s_obj);
1463 if(myrand() % 1000 == 0)
1465 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1467 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1468 std::string data = obj->getStaticData();
1469 StaticObject s_obj(obj->getType(),
1470 obj->getBasePosition(), data);
1472 block->m_static_objects.insert(0, s_obj);
1478 last_node_walkable = false;
1481 block->setChangedFlag();
1485 void make_block(BlockMakeData *data)
1489 //dstream<<"makeBlock: no-op"<<std::endl;
1493 assert(data->vmanip);
1494 assert(data->nodedef);
1496 INodeDefManager *ndef = data->nodedef;
1498 v3s16 blockpos = data->blockpos;
1500 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1501 <<blockpos.Z<<")"<<std::endl;*/
1503 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1504 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1505 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1506 // Area of center block
1507 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1508 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1509 // Full allocated area
1510 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1511 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1513 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1515 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1518 Get average ground level from noise
1521 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1522 data->seed, v2s16(blockpos.X, blockpos.Z));
1523 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1525 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1527 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1528 data->seed, v2s16(blockpos.X, blockpos.Z));
1529 // Minimum amount of ground above the top of the central block
1530 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1532 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1533 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1534 // Maximum amount of ground above the bottom of the central block
1535 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1539 Special case for high air or water: Just fill with air and water.
1541 if(maximum_ground_depth < -20)
1543 for(s16 x=node_min.X; x<=node_max.X; x++)
1544 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1549 // Use fast index incrementing
1550 v3s16 em = vmanip.m_area.getExtent();
1551 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1552 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1554 // Only modify places that have no content
1555 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1557 if(y <= WATER_LEVEL)
1558 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_WATERSOURCE"));
1560 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1563 data->vmanip->m_area.add_y(em, i, 1);
1574 If block is deep underground, this is set to true and ground
1575 density noise is not generated, for speed optimization.
1577 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1580 Create a block-specific seed
1582 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1583 + full_node_min.Y*42123 + full_node_min.X*23;
1589 //NoiseBuffer noisebuf1;
1590 //NoiseBuffer noisebuf2;
1591 NoiseBuffer noisebuf_cave;
1592 NoiseBuffer noisebuf_ground;
1593 NoiseBuffer noisebuf_ground_crumbleness;
1594 NoiseBuffer noisebuf_ground_wetness;
1596 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1597 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1599 //TimeTaker timer("noisebuf.create");
1605 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1606 minpos_f.X, minpos_f.Y, minpos_f.Z,
1607 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1609 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1617 v3f sl = v3f(4.0, 4.0, 4.0);
1622 if(all_is_ground_except_caves == false)
1623 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1624 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1625 minpos_f.X, minpos_f.Y, minpos_f.Z,
1626 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1630 Ground property noise
1632 sl = v3f(2.5, 2.5, 2.5);
1633 noisebuf_ground_crumbleness.create(
1634 get_ground_crumbleness_params(data->seed),
1635 minpos_f.X, minpos_f.Y, minpos_f.Z,
1636 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1638 noisebuf_ground_wetness.create(
1639 get_ground_wetness_params(data->seed),
1640 minpos_f.X, minpos_f.Y, minpos_f.Z,
1641 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1646 Make base ground level
1649 for(s16 x=node_min.X; x<=node_max.X; x++)
1650 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1655 // Use fast index incrementing
1656 v3s16 em = vmanip.m_area.getExtent();
1657 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1658 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1660 // Only modify places that have no content
1661 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1663 // First priority: make air and water.
1664 // This avoids caves inside water.
1665 if(all_is_ground_except_caves == false
1666 && val_is_ground(noisebuf_ground.get(x,y,z),
1667 v3s16(x,y,z), data->seed) == false)
1669 if(y <= WATER_LEVEL)
1670 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_WATERSOURCE"));
1672 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1674 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1675 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1677 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE"));
1680 data->vmanip->m_area.add_y(em, i, 1);
1690 PseudoRandom mineralrandom(blockseed);
1695 for(s16 i=0; i<approx_ground_depth/4; i++)
1697 if(mineralrandom.next()%50 == 0)
1699 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1700 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1701 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1702 for(u16 i=0; i<27; i++)
1704 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1705 u32 vi = vmanip.m_area.index(p);
1706 if(vmanip.m_data[vi].getContent() == LEGN(ndef, "CONTENT_STONE"))
1707 if(mineralrandom.next()%8 == 0)
1708 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_MESE"));
1717 u16 a = mineralrandom.range(0,15);
1719 u16 amount = 20 * a/1000;
1720 for(s16 i=0; i<amount; i++)
1722 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1723 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1724 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1726 u8 base_content = LEGN(ndef, "CONTENT_STONE");
1727 MapNode new_content(CONTENT_IGNORE);
1730 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1732 new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_COAL);
1736 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1737 new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON);
1738 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1739 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD"));
1741 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));*/
1743 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1747 if(new_content.getContent() != CONTENT_IGNORE)
1749 for(u16 i=0; i<27; i++)
1751 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1752 u32 vi = vmanip.m_area.index(p);
1753 if(vmanip.m_data[vi].getContent() == base_content)
1755 if(mineralrandom.next()%sparseness == 0)
1756 vmanip.m_data[vi] = new_content;
1765 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1766 //for(s16 i=0; i<50; i++)
1767 u16 coal_amount = 30;
1768 u16 coal_rareness = 60 / coal_amount;
1769 if(coal_rareness == 0)
1771 if(mineralrandom.next()%coal_rareness == 0)
1773 u16 a = mineralrandom.next() % 16;
1774 u16 amount = coal_amount * a*a*a / 1000;
1775 for(s16 i=0; i<amount; i++)
1777 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1778 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1779 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1780 for(u16 i=0; i<27; i++)
1782 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1783 u32 vi = vmanip.m_area.index(p);
1784 if(vmanip.m_data[vi].getContent() == LEGN(ndef, "CONTENT_STONE"))
1785 if(mineralrandom.next()%8 == 0)
1786 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_COAL);
1793 u16 iron_amount = 8;
1794 u16 iron_rareness = 60 / iron_amount;
1795 if(iron_rareness == 0)
1797 if(mineralrandom.next()%iron_rareness == 0)
1799 u16 a = mineralrandom.next() % 16;
1800 u16 amount = iron_amount * a*a*a / 1000;
1801 for(s16 i=0; i<amount; i++)
1803 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1804 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1805 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1806 for(u16 i=0; i<27; i++)
1808 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1809 u32 vi = vmanip.m_area.index(p);
1810 if(vmanip.m_data[vi].getContent() == LEGN(ndef, "CONTENT_STONE"))
1811 if(mineralrandom.next()%8 == 0)
1812 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON);
1819 Add mud and sand and others underground (in place of stone)
1822 for(s16 x=node_min.X; x<=node_max.X; x++)
1823 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1828 // Use fast index incrementing
1829 v3s16 em = vmanip.m_area.getExtent();
1830 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1831 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1833 if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_STONE"))
1835 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1837 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1838 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD"));
1840 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));
1842 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1844 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1845 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_GRAVEL"));
1847 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1848 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1850 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_LAVASOURCE"));
1851 for(s16 x1=-1; x1<=1; x1++)
1852 for(s16 y1=-1; y1<=1; y1++)
1853 for(s16 z1=-1; z1<=1; z1++)
1854 data->transforming_liquid.push_back(
1855 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1859 data->vmanip->m_area.add_y(em, i, -1);
1868 //if(node_min.Y < approx_groundlevel)
1869 //if(myrand() % 3 == 0)
1870 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1871 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1872 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1873 float dungeon_rarity = 0.02;
1874 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1876 && node_min.Y < approx_groundlevel)
1878 // Dungeon generator doesn't modify places which have this set
1879 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1880 | VMANIP_FLAG_DUNGEON_PRESERVE);
1882 // Set all air and water to be untouchable to make dungeons open
1883 // to caves and open air
1884 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1885 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1890 // Use fast index incrementing
1891 v3s16 em = vmanip.m_area.getExtent();
1892 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1893 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1895 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1896 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1897 else if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_WATERSOURCE"))
1898 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1899 data->vmanip->m_area.add_y(em, i, -1);
1904 PseudoRandom random(blockseed+2);
1907 make_dungeon1(vmanip, random, ndef);
1909 // Convert some cobble to mossy cobble
1910 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1911 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1916 // Use fast index incrementing
1917 v3s16 em = vmanip.m_area.getExtent();
1918 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1919 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1921 // (noisebuf not used because it doesn't contain the
1923 double wetness = noise3d_param(
1924 get_ground_wetness_params(data->seed), x,y,z);
1925 double d = noise3d_perlin((float)x/2.5,
1926 (float)y/2.5,(float)z/2.5,
1928 if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_COBBLE"))
1932 vmanip.m_data[i].setContent(LEGN(ndef, "CONTENT_MOSSYCOBBLE"));
1935 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1938 vmanip.m_data[i].setContent(LEGN(ndef, "CONTENT_MUD"));
1940 data->vmanip->m_area.add_y(em, i, -1);
1950 PseudoRandom ncrandom(blockseed+9324342);
1951 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1953 make_nc(vmanip, ncrandom, ndef);
1958 Add top and bottom side of water to transforming_liquid queue
1961 for(s16 x=node_min.X; x<=node_max.X; x++)
1962 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1967 bool water_found = false;
1968 // Use fast index incrementing
1969 v3s16 em = vmanip.m_area.getExtent();
1970 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1971 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1973 if(water_found == false)
1975 if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_WATERSOURCE"))
1977 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1978 data->transforming_liquid.push_back(p);
1984 // This can be done because water_found can only
1985 // turn to true and end up here after going through
1987 if(vmanip.m_data[i+1].getContent() != LEGN(ndef, "CONTENT_WATERSOURCE"))
1989 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1990 data->transforming_liquid.push_back(p);
1991 water_found = false;
1995 data->vmanip->m_area.add_y(em, i, -1);
2001 If close to ground level
2004 //if(abs(approx_ground_depth) < 30)
2005 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2011 for(s16 x=node_min.X; x<=node_max.X; x++)
2012 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2017 bool possibly_have_sand = get_have_sand(data->seed, p2d);
2018 bool have_sand = false;
2019 u32 current_depth = 0;
2020 bool air_detected = false;
2021 bool water_detected = false;
2022 bool have_clay = false;
2024 // Use fast index incrementing
2025 s16 start_y = node_max.Y+2;
2026 v3s16 em = vmanip.m_area.getExtent();
2027 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2028 for(s16 y=start_y; y>=node_min.Y-3; y--)
2030 if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_WATERSOURCE"))
2031 water_detected = true;
2032 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2033 air_detected = true;
2035 if((vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_STONE")
2036 || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS")
2037 || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD")
2038 || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_SAND")
2039 || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRAVEL")
2040 ) && (air_detected || water_detected))
2042 if(current_depth == 0 && y <= WATER_LEVEL+2
2043 && possibly_have_sand)
2046 if(current_depth < 4)
2050 // Determine whether to have clay in the sand here
2051 double claynoise = noise2d_perlin(
2052 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2053 data->seed+4321, 6, 0.95) + 0.5;
2055 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
2056 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
2057 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
2060 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_CLAY"));
2062 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));
2065 else if(current_depth==0 && !water_detected
2066 && y >= WATER_LEVEL && air_detected)
2067 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_GRASS"));
2070 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD"));
2074 if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD")
2075 || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS"))
2076 vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE"));
2081 if(current_depth >= 8)
2084 else if(current_depth != 0)
2087 data->vmanip->m_area.add_y(em, i, -1);
2093 Calculate some stuff
2096 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2097 bool is_jungle = surface_humidity > 0.75;
2099 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
2106 PseudoRandom treerandom(blockseed);
2107 // Put trees in random places on part of division
2108 for(u32 i=0; i<tree_count; i++)
2110 s16 x = treerandom.range(node_min.X, node_max.X);
2111 s16 z = treerandom.range(node_min.Z, node_max.Z);
2112 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
2113 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2114 // Don't make a tree under water level
2117 // Make sure tree fits (only trees whose starting point is
2118 // at this block are added)
2119 if(y < node_min.Y || y > node_max.Y)
2122 Find exact ground level
2126 for(; p.Y >= y-6; p.Y--)
2128 u32 i = data->vmanip->m_area.index(p);
2129 MapNode *n = &data->vmanip->m_data[i];
2130 if(n->getContent() != CONTENT_AIR && n->getContent() != LEGN(ndef, "CONTENT_WATERSOURCE") && n->getContent() != CONTENT_IGNORE)
2136 // If not found, handle next one
2141 u32 i = data->vmanip->m_area.index(p);
2142 MapNode *n = &data->vmanip->m_data[i];
2144 if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS") && n->getContent() != LEGN(ndef, "CONTENT_SAND"))
2147 // Papyrus grows only on mud and in water
2148 if(n->getContent() == LEGN(ndef, "CONTENT_MUD") && y <= WATER_LEVEL)
2151 make_papyrus(vmanip, p, ndef);
2153 // Trees grow only on mud and grass, on land
2154 else if((n->getContent() == LEGN(ndef, "CONTENT_MUD") || n->getContent() == LEGN(ndef, "CONTENT_GRASS")) && y > WATER_LEVEL + 2)
2157 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2158 if(is_jungle == false)
2161 if(myrand_range(0,4) != 0)
2162 is_apple_tree = false;
2164 is_apple_tree = noise2d_perlin(
2165 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2166 data->seed+342902, 3, 0.45) > 0.2;
2167 make_tree(vmanip, p, is_apple_tree, ndef);
2170 make_jungletree(vmanip, p, ndef);
2172 // Cactii grow only on sand, on land
2173 else if(n->getContent() == LEGN(ndef, "CONTENT_SAND") && y > WATER_LEVEL + 2)
2176 make_cactus(vmanip, p, ndef);
2186 PseudoRandom grassrandom(blockseed);
2187 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2189 s16 x = grassrandom.range(node_min.X, node_max.X);
2190 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2191 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2194 if(y < node_min.Y || y > node_max.Y)
2197 Find exact ground level
2201 for(; p.Y >= y-6; p.Y--)
2203 u32 i = data->vmanip->m_area.index(p);
2204 MapNode *n = &data->vmanip->m_data[i];
2205 if(data->nodedef->get(*n).is_ground_content
2206 || n->getContent() == LEGN(ndef, "CONTENT_JUNGLETREE"))
2212 // If not found, handle next one
2216 if(vmanip.m_area.contains(p) == false)
2218 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2221 if(vmanip.m_area.contains(p))
2222 vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_MUD");
2224 if(vmanip.m_area.contains(p))
2225 vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_JUNGLEGRASS");
2231 Add some kind of random stones
2234 u32 random_stone_count = block_area_nodes *
2235 randomstone_amount_2d(data->seed, p2d_center);
2236 // Put in random places on part of division
2237 for(u32 i=0; i<random_stone_count; i++)
2239 s16 x = myrand_range(node_min.X, node_max.X);
2240 s16 z = myrand_range(node_min.Z, node_max.Z);
2241 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2242 // Don't add under water level
2243 /*if(y < WATER_LEVEL)
2245 // Don't add if doesn't belong to this block
2246 if(y < node_min.Y || y > node_max.Y)
2251 u32 i = data->vmanip->m_area.index(v3s16(p));
2252 MapNode *n = &data->vmanip->m_data[i];
2253 if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS"))
2256 // Will be placed one higher
2259 make_randomstone(data->vmanip, p);
2268 u32 large_stone_count = block_area_nodes *
2269 largestone_amount_2d(data->seed, p2d_center);
2270 //u32 large_stone_count = 1;
2271 // Put in random places on part of division
2272 for(u32 i=0; i<large_stone_count; i++)
2274 s16 x = myrand_range(node_min.X, node_max.X);
2275 s16 z = myrand_range(node_min.Z, node_max.Z);
2276 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2277 // Don't add under water level
2278 /*if(y < WATER_LEVEL)
2280 // Don't add if doesn't belong to this block
2281 if(y < node_min.Y || y > node_max.Y)
2286 u32 i = data->vmanip->m_area.index(v3s16(p));
2287 MapNode *n = &data->vmanip->m_data[i];
2288 if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS"))
2291 // Will be placed one lower
2294 make_largestone(data->vmanip, p);
2301 BlockMakeData::BlockMakeData():
2308 BlockMakeData::~BlockMakeData()
2313 }; // namespace mapgen