Generate beaches
[oweals/minetest.git] / src / mapgen.cpp
index 74521d3a1d873fbc86fb639dddb2844c5515ea8b..3212b693289921012b1be52d3b7c7d920ecdf404 100644 (file)
@@ -70,13 +70,14 @@ static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
        s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
        u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
        s16 y;
+       content_t c_tree = ndef->getId("mapgen_tree");
+       content_t c_leaves = ndef->getId("mapgen_leaves");
        for(y=y_nodes_max; y>=y_nodes_min; y--)
        {
                MapNode &n = vmanip.m_data[i];
                if(ndef->get(n).walkable
-                               // TODO: Cache LEGN values
-                               && n.getContent() != LEGN(ndef, "CONTENT_TREE")
-                               && n.getContent() != LEGN(ndef, "CONTENT_LEAVES"))
+                               && n.getContent() != c_tree
+                               && n.getContent() != c_leaves)
                        break;
 
                vmanip.m_area.add_y(em, i, -1);
@@ -96,7 +97,7 @@ static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
        s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
        u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
        s16 y;
-       content_t c_stone = LEGN(ndef, "CONTENT_STONE");
+       content_t c_stone = ndef->getId("mapgen_stone");
        for(y=y_nodes_max; y>=y_nodes_min; y--)
        {
                MapNode &n = vmanip.m_data[i];
@@ -115,9 +116,9 @@ static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
                bool is_apple_tree, INodeDefManager *ndef)
 {
-       MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
-       MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
-       MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
+       MapNode treenode(ndef->getId("mapgen_tree"));
+       MapNode leavesnode(ndef->getId("mapgen_leaves"));
+       MapNode applenode(ndef->getId("mapgen_apple"));
        
        s16 trunk_h = myrand_range(4, 5);
        v3s16 p1 = p0;
@@ -192,11 +193,12 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
        }
 }
 
+#if 0
 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
                INodeDefManager *ndef)
 {
-       MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
-       MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
+       MapNode treenode(ndef->getId("mapgen_jungletree"));
+       MapNode leavesnode(ndef->getId("mapgen_leaves"));
 
        for(s16 x=-1; x<=1; x++)
        for(s16 z=-1; z<=1; z++)
@@ -279,10 +281,10 @@ static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
        }
 }
 
-void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
+static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
                INodeDefManager *ndef)
 {
-       MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
+       MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
 
        s16 trunk_h = myrand_range(2, 3);
        v3s16 p1 = p0;
@@ -294,10 +296,10 @@ void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
        }
 }
 
-void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
+static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
                INodeDefManager *ndef)
 {
-       MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
+       MapNode cactusnode(ndef->getId("mapgen_cactus"));
 
        s16 trunk_h = 3;
        v3s16 p1 = p0;
@@ -308,7 +310,9 @@ void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
                p1.Y++;
        }
 }
+#endif
 
+#if 0
 /*
        Dungeon making routines
 */
@@ -332,7 +336,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace
                        u32 vi = vmanip.m_area.index(p);
                        if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
+                       vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
                }
                {
                        v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
@@ -341,7 +345,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace
                        u32 vi = vmanip.m_area.index(p);
                        if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
+                       vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
                }
        }
        
@@ -356,7 +360,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace
                        u32 vi = vmanip.m_area.index(p);
                        if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
+                       vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
                }
                {
                        v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
@@ -365,7 +369,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace
                        u32 vi = vmanip.m_area.index(p);
                        if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
+                       vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
                }
        }
        
@@ -380,7 +384,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace
                        u32 vi = vmanip.m_area.index(p);
                        if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
+                       vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
                }
                {
                        v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
@@ -389,7 +393,7 @@ static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace
                        u32 vi = vmanip.m_area.index(p);
                        if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
+                       vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
                }
        }
        
@@ -437,7 +441,7 @@ static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
 {
        make_hole1(vmanip, doorplace, ndef);
        // Place torch (for testing)
-       //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
+       //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
 }
 
 static v3s16 rand_ortho_dir(PseudoRandom &random)
@@ -524,7 +528,7 @@ static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
                        if(make_stairs)
                        {
                                make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
-                                               VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
+                                               VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
                                make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
                                                VMANIP_FLAG_DUNGEON_INSIDE);
                                make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
@@ -533,7 +537,7 @@ static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
                        else
                        {
                                make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
-                                               VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
+                                               VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
                                make_hole1(vmanip, p, ndef);
                                /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
                                                VMANIP_FLAG_DUNGEON_INSIDE);*/
@@ -612,9 +616,9 @@ public:
                                continue;
                        }
                        if(vmanip.getNodeNoExNoEmerge(p).getContent()
-                                       == LEGN(m_ndef, "CONTENT_COBBLE")
+                                       == m_ndef->getId("mapgen_cobble")
                        && vmanip.getNodeNoExNoEmerge(p1).getContent()
-                                       == LEGN(m_ndef, "CONTENT_COBBLE"))
+                                       == m_ndef->getId("mapgen_cobble"))
                        {
                                // Found wall, this is a good place!
                                result_place = p;
@@ -628,25 +632,25 @@ public:
                        */
                        // Jump one up if the actual space is there
                        if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
-                                       == LEGN(m_ndef, "CONTENT_COBBLE")
+                                       == m_ndef->getId("mapgen_cobble")
                        && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
-                                       == LEGN(m_ndef, "CONTENT_AIR")
+                                       == CONTENT_AIR
                        && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
-                                       == LEGN(m_ndef, "CONTENT_AIR"))
+                                       == CONTENT_AIR)
                                p += v3s16(0,1,0);
                        // Jump one down if the actual space is there
                        if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
-                                       == LEGN(m_ndef, "CONTENT_COBBLE")
+                                       == m_ndef->getId("mapgen_cobble")
                        && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
-                                       == LEGN(m_ndef, "CONTENT_AIR")
+                                       == CONTENT_AIR
                        && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
-                                       == LEGN(m_ndef, "CONTENT_AIR"))
+                                       == CONTENT_AIR)
                                p += v3s16(0,-1,0);
                        // Check if walking is now possible
                        if(vmanip.getNodeNoExNoEmerge(p).getContent()
-                                       != LEGN(m_ndef, "CONTENT_AIR")
+                                       != CONTENT_AIR
                        || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
-                                       != LEGN(m_ndef, "CONTENT_AIR"))
+                                       != CONTENT_AIR)
                        {
                                // Cannot continue walking here
                                randomizeDir();
@@ -798,7 +802,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
                v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
 
                // Place torch at room center (for testing)
-               //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
+               //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
 
                // Quit if last room
                if(i == room_count-1)
@@ -860,7 +864,9 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
                
        }
 }
+#endif
 
+#if 0
 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
                INodeDefManager *ndef)
 {
@@ -887,14 +893,15 @@ static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
                        16+random.range(0,15),
                        16+random.range(0,15),
                        16+random.range(0,15));
-       vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC"), facedir_i);
+       vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
        u32 length = random.range(3,15);
        for(u32 j=0; j<length; j++)
        {
                p -= dir;
-               vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
+               vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
        }
 }
+#endif
 
 /*
        Noise functions. Make sure seed is mangled differently in each one.
@@ -1200,9 +1207,9 @@ double base_rock_level_2d(u64 seed, v2s16 p)
                base = base2;*/
 #if 1
        // Higher ground level
-       double higher = (double)WATER_LEVEL + 20. + 10. * noise2d_perlin(
-                       0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
-                       seed+85039, 4, 0.6);
+       double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
+                       0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
+                       seed+85039, 5, 0.6);
        //higher = 30; // For debugging
 
        // Limit higher to at least base
@@ -1214,11 +1221,19 @@ double base_rock_level_2d(u64 seed, v2s16 p)
                        0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
                        seed-932, 5, 0.7);
        b = rangelim(b, 0.0, 1000.0);
-       b = pow(b, 8);
+       b = pow(b, 7);
        b *= 5;
-       b = rangelim(b, 3.0, 1000.0);
+       b = rangelim(b, 0.5, 1000.0);
+       // Values 1.5...100 give quite horrible looking slopes
+       if(b > 1.5 && b < 100.0){
+               if(b < 10.0)
+                       b = 1.5;
+               else
+                       b = 100.0;
+       }
        //dstream<<"b="<<b<<std::endl;
        //double b = 20;
+       //b = 0.25;
 
        // Offset to more low
        double a_off = -0.20;
@@ -1253,14 +1268,20 @@ double get_mud_add_amount(u64 seed, v2s16 p)
                        seed+91013, 3, 0.55));
 }
 
-bool get_have_sand(u64 seed, v2s16 p2d)
+bool get_have_beach(u64 seed, v2s16 p2d)
 {
        // Determine whether to have sand here
        double sandnoise = noise2d_perlin(
                        0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
                        seed+59420, 3, 0.50);
 
-       return (sandnoise > -0.15);
+       return (sandnoise > 0.15);
+}
+
+u32 get_blockseed(u64 seed, v3s16 p)
+{
+       s32 x=p.X, y=p.Y, z=p.Z;
+       return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
 }
 
 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
@@ -1319,15 +1340,12 @@ void make_block(BlockMakeData *data)
        //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
 
        // Horribly wrong heuristic, but better than nothing
-       bool block_is_underground = (WATER_LEVEL /* local minimum ground level */ > 
-                       MAP_BLOCKSIZE * (data->blockpos_max.X
-                                       - data->blockpos_min.X + 1) / 2);
+       bool block_is_underground = (WATER_LEVEL > node_max.Y);
 
        /*
                Create a block-specific seed
        */
-       /*u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
-                       + full_node_min.Y*42123 + full_node_min.X*23;*/
+       u32 blockseed = get_blockseed(data->seed, full_node_min);
        
        /*
                Cache some ground type values for speed
@@ -1335,7 +1353,7 @@ void make_block(BlockMakeData *data)
 
 // Creates variables c_name=id and n_name=node
 #define CONTENT_VARIABLE(ndef, name)\
-       content_t c_##name = ndef->getId(#name);\
+       content_t c_##name = ndef->getId("mapgen_" #name);\
        MapNode n_##name(c_##name);
 
        CONTENT_VARIABLE(ndef, stone);
@@ -1409,12 +1427,14 @@ void make_block(BlockMakeData *data)
                        u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
                        for(s16 y=node_min.Y; y<=node_max.Y; y++)
                        {
-                               if(y <= surface_y)
-                                       vmanip.m_data[i] = MapNode(c_stone);
-                               else if(y <= WATER_LEVEL)
+                               if(y <= surface_y){
+                                       if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
+                                               vmanip.m_data[i] = MapNode(c_stone);
+                               } else if(y <= WATER_LEVEL){
                                        vmanip.m_data[i] = MapNode(c_water_source);
-                               else
+                               } else {
                                        vmanip.m_data[i] = MapNode(c_air);
+                               }
 
                                vmanip.m_area.add_y(em, i, 1);
                        }
@@ -1423,6 +1443,42 @@ void make_block(BlockMakeData *data)
 #endif
        
        }//timer1
+       
+       /*
+               Add blobs of dirt and gravel underground
+       */
+       {
+       PseudoRandom pr(blockseed+983);
+       for(int i=0; i<volume_nodes/12/12/12; i++){
+               v3s16 size(
+                       pr.range(1, 6),
+                       pr.range(1, 6),
+                       pr.range(1, 6)
+               );
+               v3s16 p0(
+                       pr.range(node_min.X, node_max.X)-size.X/2,
+                       pr.range(node_min.Y, node_max.Y)-size.Y/2,
+                       pr.range(node_min.Z, node_max.Z)-size.Z/2
+               );
+               MapNode n1;
+               if(p0.Y > -32 && pr.range(0,1) == 0)
+                       n1 = MapNode(c_dirt);
+               else
+                       n1 = MapNode(c_gravel);
+               for(int x1=0; x1<size.X; x1++)
+               for(int y1=0; y1<size.Y; y1++)
+               for(int z1=0; z1<size.Z; z1++)
+               {
+                       v3s16 p = p0 + v3s16(x1,y1,z1);
+                       u32 i = vmanip.m_area.index(p);
+                       if(!vmanip.m_area.contains(i))
+                               continue;
+                       if(vmanip.m_data[i].getContent() != c_stone)
+                               continue;
+                       vmanip.m_data[i] = n1;
+               }
+       }
+       }
 
        // Limit dirt flow area by 1 because mud is flown into neighbors.
        assert(central_area_size.X == central_area_size.Z);
@@ -1452,12 +1508,10 @@ void make_block(BlockMakeData *data)
        u32 bruises_count = volume_nodes * stone_surface_max_y / 40000000;
        if(stone_surface_max_y < WATER_LEVEL - 20)
                bruises_count = 0;
-       /*u32 caves_count = 0;
-       u32 bruises_count = 0;*/
        for(u32 jj=0; jj<caves_count+bruises_count; jj++)
        {
                s16 min_tunnel_diameter = 2;
-               s16 max_tunnel_diameter = 5;
+               s16 max_tunnel_diameter = myrand_range(4,5);
                u16 tunnel_routepoints = 20;
                
                v3f main_direction(0,0,0);
@@ -1542,6 +1596,7 @@ void make_block(BlockMakeData *data)
                );
 
                MapNode airnode(CONTENT_AIR);
+               MapNode waternode(c_water_source);
                
                /*
                        Generate some tunnel starting from orp
@@ -1567,7 +1622,7 @@ void make_block(BlockMakeData *data)
                        v3s16 maxlen;
                        if(bruise_surface)
                        {
-                               maxlen = v3s16(rs*7,rs*7,rs*7);
+                               maxlen = v3s16(rs*7,rs*2,rs*7);
                        }
                        else
                        {
@@ -1593,6 +1648,14 @@ void make_block(BlockMakeData *data)
                                );
                        }
                        
+                       if(bruise_surface){
+                               v3f p = orp + vec;
+                               s16 h = find_ground_level_clever(vmanip,
+                                               v2s16(p.X, p.Z), ndef);
+                               route_y_min = h - rs/3;
+                               route_y_max = h + rs;
+                       }
+
                        vec += main_direction;
 
                        v3f rp = orp + vec;
@@ -1613,14 +1676,16 @@ void make_block(BlockMakeData *data)
                        for(float f=0; f<1.0; f+=1.0/vec.getLength())
                        {
                                v3f fp = orp + vec * f;
+                               fp.X += 0.1*myrand_range(-10,10);
+                               fp.Z += 0.1*myrand_range(-10,10);
                                v3s16 cp(fp.X, fp.Y, fp.Z);
 
                                s16 d0 = -rs/2;
                                s16 d1 = d0 + rs - 1;
                                for(s16 z0=d0; z0<=d1; z0++)
                                {
-                                       //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
-                                       s16 si = rs - MYMAX(0, abs(z0)-rs/7);
+                                       s16 si = rs - MYMAX(0, abs(z0)-rs/4);
+                                       //s16 si = rs - MYMAX(0, abs(z0)-rs/7);
                                        for(s16 x0=-si; x0<=si-1; x0++)
                                        {
                                                s16 maxabsxz = MYMAX(abs(x0), abs(z0));
@@ -1657,7 +1722,14 @@ void make_block(BlockMakeData *data)
                                                        // Just set it to air, it will be changed to
                                                        // water afterwards
                                                        u32 i = vmanip.m_area.index(p);
-                                                       vmanip.m_data[i] = airnode;
+                                                       if(bruise_surface){
+                                                               if(p.Y <= WATER_LEVEL)
+                                                                       vmanip.m_data[i] = waternode;
+                                                               else
+                                                                       vmanip.m_data[i] = airnode;
+                                                       } else {
+                                                               vmanip.m_data[i] = airnode;
+                                                       }
 
                                                        if(bruise_surface == false)
                                                        {
@@ -1692,6 +1764,8 @@ void make_block(BlockMakeData *data)
                // Node position in 2d
                v2s16 p2d = v2s16(x,z);
                
+               MapNode addnode(c_dirt);
+
                // Randomize mud amount
                s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0;
 
@@ -1701,6 +1775,14 @@ void make_block(BlockMakeData *data)
                if(surface_y == vmanip.m_area.MinEdge.Y - 1)
                        continue;
 
+               if(mud_add_amount <= 0){
+                       mud_add_amount = 1 - mud_add_amount;
+                       addnode = MapNode(c_gravel);
+               } else if(get_have_beach(data->seed, p2d) &&
+                               surface_y + mud_add_amount <= WATER_LEVEL+2){
+                       addnode = MapNode(c_sand);
+               }
+
                /*
                        If topmost node is grass, change it to mud.
                        It might be if it was flown to there from a neighboring
@@ -1727,7 +1809,7 @@ void make_block(BlockMakeData *data)
                                        break;
                                        
                                MapNode &n = vmanip.m_data[i];
-                               n = MapNode(c_dirt);
+                               n = addnode;
                                mudcount++;
 
                                vmanip.m_area.add_y(em, i, 1);
@@ -2288,7 +2370,7 @@ void make_block(BlockMakeData *data)
                        // Node position
                        v2s16 p2d(x,z);
                        {
-                               bool possibly_have_sand = get_have_sand(data->seed, p2d);
+                               bool possibly_have_sand = get_have_beach(data->seed, p2d);
                                bool have_sand = false;
                                u32 current_depth = 0;
                                bool air_detected = false;