From f2c26e20147cf586b5b4ffa761303b670689ab40 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 25 Jun 2011 18:12:41 +0300 Subject: moved map generator to separate source files --- src/mapgen.cpp | 1936 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1936 insertions(+) create mode 100644 src/mapgen.cpp (limited to 'src/mapgen.cpp') diff --git a/src/mapgen.cpp b/src/mapgen.cpp new file mode 100644 index 000000000..a739ceaeb --- /dev/null +++ b/src/mapgen.cpp @@ -0,0 +1,1936 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "mapgen.h" +#include "voxel.h" +#include "content_mapnode.h" +#include "noise.h" +#include "mapblock.h" +#include "map.h" +#include "serverobject.h" +#include "mineral.h" + +namespace mapgen +{ + +/* + Some helper functions for the map generator +*/ + +#if 0 +static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d) +{ + v3s16 em = vmanip.m_area.getExtent(); + s16 y_nodes_max = vmanip.m_area.MaxEdge.Y; + 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; + for(y=y_nodes_max; y>=y_nodes_min; y--) + { + MapNode &n = vmanip.m_data[i]; + if(content_walkable(n.d)) + break; + + vmanip.m_area.add_y(em, i, -1); + } + if(y >= y_nodes_min) + return y; + else + return y_nodes_min; +} + +static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d) +{ + v3s16 em = vmanip.m_area.getExtent(); + s16 y_nodes_max = vmanip.m_area.MaxEdge.Y; + 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; + for(y=y_nodes_max; y>=y_nodes_min; y--) + { + MapNode &n = vmanip.m_data[i]; + if(content_walkable(n.d) + && n.d != CONTENT_TREE + && n.d != CONTENT_LEAVES) + break; + + vmanip.m_area.add_y(em, i, -1); + } + if(y >= y_nodes_min) + return y; + else + return y_nodes_min; +} +#endif + +static void make_tree(VoxelManipulator &vmanip, v3s16 p0) +{ + MapNode treenode(CONTENT_TREE); + MapNode leavesnode(CONTENT_LEAVES); + + s16 trunk_h = myrand_range(3, 6); + v3s16 p1 = p0; + for(s16 ii=0; ii leaves_d(new u8[leaves_a.getVolume()]); + Buffer leaves_d(leaves_a.getVolume()); + for(s32 i=0; i stone_d(stone_a.getVolume()); + for(s32 i=0; i 0.0) + { + u32 vi = stone_a.index(v3s16(x,y,z)); + stone_d[vi] = 1; + } + } + + /*// Add stone randomly + for(u32 iii=0; iii<7; iii++) + { + s16 d = 1; + + v3s16 p( + myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d), + myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d), + myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d) + ); + + for(s16 z=0; z<=d; z++) + for(s16 y=0; y<=d; y++) + for(s16 x=0; x<=d; x++) + { + stone_d[stone_a.index(p+v3s16(x,y,z))] = 1; + } + }*/ + + // Blit stone to vmanip + for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++) + for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++) + for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++) + { + v3s16 p(x,y,z); + p += p0; + if(vmanip.m_area.contains(p) == false) + continue; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].d != CONTENT_AIR + && vmanip.m_data[vi].d != CONTENT_IGNORE) + continue; + u32 i = stone_a.index(x,y,z); + if(stone_d[i] == 1) + vmanip.m_data[vi] = stonenode; + } +} +#endif + +#if 0 +static void make_largestone(VoxelManipulator &vmanip, v3s16 p0) +{ + MapNode stonenode(CONTENT_STONE); + + s16 size = myrand_range(8, 16); + + VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2)); + Buffer stone_d(stone_a.getVolume()); + for(s32 i=0; i 1.0) + { + u32 vi = stone_a.index(v3s16(x,y,z)); + stone_d[vi] = 1; + } + } + + /*// Add stone randomly + for(u32 iii=0; iii<7; iii++) + { + s16 d = 1; + + v3s16 p( + myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d), + myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d), + myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d) + ); + + for(s16 z=0; z<=d; z++) + for(s16 y=0; y<=d; y++) + for(s16 x=0; x<=d; x++) + { + stone_d[stone_a.index(p+v3s16(x,y,z))] = 1; + } + }*/ + + // Blit stone to vmanip + for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++) + for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++) + for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++) + { + v3s16 p(x,y,z); + p += p0; + if(vmanip.m_area.contains(p) == false) + continue; + u32 vi = vmanip.m_area.index(p); + /*if(vmanip.m_data[vi].d != CONTENT_AIR + && vmanip.m_data[vi].d != CONTENT_IGNORE) + continue;*/ + u32 i = stone_a.index(x,y,z); + if(stone_d[i] == 1) + vmanip.m_data[vi] = stonenode; + } +} +#endif + +/* + Dungeon making routines +*/ + +#define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1 +#define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2 +#define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\ + VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE) + +static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace) +{ + // Make +-X walls + for(s16 z=0; z= 3) + make_stairs = random.next()%2 ? 1 : -1; + for(u32 i=0; i= partlength) + { + partcount = 0; + + dir = random_turn(random, dir); + + partlength = random.range(1,length); + + make_stairs = 0; + if(random.next()%2 == 0 && partlength >= 3) + make_stairs = random.next()%2 ? 1 : -1; + } + } + result_place = p0; + result_dir = dir; +} + +class RoomWalker +{ +public: + + RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random): + vmanip(vmanip_), + m_pos(pos), + m_random(random) + { + randomizeDir(); + } + + void randomizeDir() + { + m_dir = rand_ortho_dir(m_random); + } + + void setPos(v3s16 pos) + { + m_pos = pos; + } + + void setDir(v3s16 dir) + { + m_dir = dir; + } + + bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir) + { + for(u32 i=0; i<100; i++) + { + v3s16 p = m_pos + m_dir; + v3s16 p1 = p + v3s16(0,1,0); + if(vmanip.m_area.contains(p) == false + || vmanip.m_area.contains(p1) == false + || i % 4 == 0) + { + randomizeDir(); + continue; + } + if(vmanip.getNodeNoExNoEmerge(p).d + == CONTENT_COBBLE + && vmanip.getNodeNoExNoEmerge(p1).d + == CONTENT_COBBLE) + { + // Found wall, this is a good place! + result_place = p; + result_dir = m_dir; + // Randomize next direction + randomizeDir(); + return true; + } + /* + Determine where to move next + */ + // Jump one up if the actual space is there + if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d + == CONTENT_COBBLE + && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d + == CONTENT_AIR + && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d + == CONTENT_AIR) + p += v3s16(0,1,0); + // Jump one down if the actual space is there + if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d + == CONTENT_COBBLE + && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d + == CONTENT_AIR + && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d + == CONTENT_AIR) + p += v3s16(0,-1,0); + // Check if walking is now possible + if(vmanip.getNodeNoExNoEmerge(p).d + != CONTENT_AIR + || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d + != CONTENT_AIR) + { + // Cannot continue walking here + randomizeDir(); + continue; + } + // Move there + m_pos = p; + } + return false; + } + + bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace, + v3s16 &result_doordir, v3s16 &result_roomplace) + { + for(s16 trycount=0; trycount<30; trycount++) + { + v3s16 doorplace; + v3s16 doordir; + bool r = findPlaceForDoor(doorplace, doordir); + if(r == false) + continue; + v3s16 roomplace; + // X east, Z north, Y up + if(doordir == v3s16(1,0,0)) // X+ + roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1)); + if(doordir == v3s16(-1,0,0)) // X- + roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1)); + if(doordir == v3s16(0,0,1)) // Z+ + roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0); + if(doordir == v3s16(0,0,-1)) // Z- + roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,-roomsize.Z+1); + + // Check fit + bool fits = true; + for(s16 z=1; z CAVE_NOISE_THRESHOLD; +} + +/* + Ground density noise shall be interpreted by using this. + + TODO: No perlin noises here, they should be outsourced + and buffered +*/ +bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed) +{ + //return ((double)p.Y < ground_noise1_val); + + double f = 0.8 + noise2d_perlin( + 0.5+(float)p.X/250, 0.5+(float)p.Z/250, + seed+920381, 3, 0.5); + if(f < 0.01) + f = 0.01; + else if(f >= 1.0) + f *= 2.0; + double h = WATER_LEVEL + 10 * noise2d_perlin( + 0.5+(float)p.X/250, 0.5+(float)p.Z/250, + seed+84174, 4, 0.5); + return ((double)p.Y - h < ground_noise1_val * f); +} + +/* + Queries whether a position is ground or not. +*/ +bool is_ground(u64 seed, v3s16 p) +{ + double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z); + return val_is_ground(val1, p, seed); +} + +// Amount of trees per area in nodes +double tree_amount_2d(u64 seed, v2s16 p) +{ + /*double noise = noise2d_perlin( + 0.5+(float)p.X/250, 0.5+(float)p.Y/250, + seed+2, 5, 0.66);*/ + double noise = noise2d_perlin( + 0.5+(float)p.X/125, 0.5+(float)p.Y/125, + seed+2, 4, 0.66); + double zeroval = -0.35; + if(noise < zeroval) + return 0; + else + return 0.04 * (noise-zeroval) / (1.0-zeroval); +} + +#if 0 +double randomstone_amount_2d(u64 seed, v2s16 p) +{ + double noise = noise2d_perlin( + 0.5+(float)p.X/250, 0.5+(float)p.Y/250, + seed+3829434, 5, 0.66); + double zeroval = 0.1; + if(noise < zeroval) + return 0; + else + return 0.01 * (noise-zeroval) / (1.0-zeroval); +} +#endif + +double largestone_amount_2d(u64 seed, v2s16 p) +{ + double noise = noise2d_perlin( + 0.5+(float)p.X/250, 0.5+(float)p.Y/250, + seed+14143242, 5, 0.66); + double zeroval = 0.3; + if(noise < zeroval) + return 0; + else + return 0.005 * (noise-zeroval) / (1.0-zeroval); +} + +/* + Incrementally find ground level from 3d noise +*/ +s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) +{ + // Start a bit fuzzy to make averaging lower precision values + // more useful + s16 level = myrand_range(-precision/2, precision/2); + s16 dec[] = {31000, 100, 20, 4, 1, 0}; + s16 i; + for(i = 1; dec[i] != 0 && precision <= dec[i]; i++) + { + // First find non-ground by going upwards + // Don't stop in caves. + { + s16 max = level+dec[i-1]*2; + v3s16 p(p2d.X, level, p2d.Y); + for(; p.Y < max; p.Y += dec[i]) + { + if(!is_ground(seed, p)) + { + level = p.Y; + break; + } + } + } + // Then find ground by going downwards from there. + // Go in caves, too, when precision is 1. + { + s16 min = level-dec[i-1]*2; + v3s16 p(p2d.X, level, p2d.Y); + for(; p.Y>min; p.Y-=dec[i]) + { + bool ground = is_ground(seed, p); + /*if(dec[i] == 1 && is_cave(seed, p)) + ground = false;*/ + if(ground) + { + level = p.Y; + break; + } + } + } + } + + // This is more like the actual ground level + level += dec[i-1]/2; + + return level; +} + +double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4); + +double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p) +{ + v2s16 node_min = sectorpos*MAP_BLOCKSIZE; + v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1); + double a = 0; + a += find_ground_level_from_noise(seed, + v2s16(node_min.X, node_min.Y), p); + a += find_ground_level_from_noise(seed, + v2s16(node_min.X, node_max.Y), p); + a += find_ground_level_from_noise(seed, + v2s16(node_max.X, node_max.Y), p); + a += find_ground_level_from_noise(seed, + v2s16(node_max.X, node_min.Y), p); + a += find_ground_level_from_noise(seed, + v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p); + a /= 5; + return a; +} + +double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4); + +double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p) +{ + v2s16 node_min = sectorpos*MAP_BLOCKSIZE; + v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1); + double a = -31000; + a = MYMAX(a, find_ground_level_from_noise(seed, + v2s16(node_min.X, node_min.Y), p)); + a = MYMAX(a, find_ground_level_from_noise(seed, + v2s16(node_min.X, node_max.Y), p)); + a = MYMAX(a, find_ground_level_from_noise(seed, + v2s16(node_max.X, node_max.Y), p)); + a = MYMAX(a, find_ground_level_from_noise(seed, + v2s16(node_min.X, node_min.Y), p)); + a = MYMAX(a, find_ground_level_from_noise(seed, + v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p)); + return a; +} + +double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4); + +double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p) +{ + v2s16 node_min = sectorpos*MAP_BLOCKSIZE; + v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1); + double a = 31000; + a = MYMIN(a, find_ground_level_from_noise(seed, + v2s16(node_min.X, node_min.Y), p)); + a = MYMIN(a, find_ground_level_from_noise(seed, + v2s16(node_min.X, node_max.Y), p)); + a = MYMIN(a, find_ground_level_from_noise(seed, + v2s16(node_max.X, node_max.Y), p)); + a = MYMIN(a, find_ground_level_from_noise(seed, + v2s16(node_min.X, node_min.Y), p)); + a = MYMIN(a, find_ground_level_from_noise(seed, + v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p)); + return a; +} + +bool block_is_underground(u64 seed, v3s16 blockpos) +{ + s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level( + seed, v2s16(blockpos.X, blockpos.Z)); + + if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel) + return true; + else + return false; +} + +#if 0 +#define AVERAGE_MUD_AMOUNT 4 + +double base_rock_level_2d(u64 seed, v2s16 p) +{ + // The base ground level + double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT + + 20. * noise2d_perlin( + 0.5+(float)p.X/500., 0.5+(float)p.Y/500., + (seed>>32)+654879876, 6, 0.6); + + /*// A bit hillier one + double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin( + 0.5+(float)p.X/250., 0.5+(float)p.Y/250., + (seed>>27)+90340, 6, 0.69); + if(base2 > base) + base = base2;*/ +#if 1 + // Higher ground level + double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin( + 0.5+(float)p.X/250., 0.5+(float)p.Y/250., + seed+85039, 5, 0.69); + //higher = 30; // For debugging + + // Limit higher to at least base + if(higher < base) + higher = base; + + // Steepness factor of cliffs + double b = 1.0 + 1.0 * noise2d_perlin( + 0.5+(float)p.X/250., 0.5+(float)p.Y/250., + seed-932, 7, 0.7); + b = rangelim(b, 0.0, 1000.0); + b = pow(b, 5); + b *= 7; + b = rangelim(b, 3.0, 1000.0); + //dstream<<"b="<blockpos; + + /*dstream<<"makeBlock(): ("<vmanip; + v3s16 blockpos_min = blockpos - v3s16(1,1,1); + v3s16 blockpos_max = blockpos + v3s16(1,1,1); + // Area of center block + v3s16 node_min = blockpos*MAP_BLOCKSIZE; + v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1); + // Full allocated area + v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE; + v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1); + // Area of a block + double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE; + + v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2); + + /* + Get average ground level from noise + */ + + s16 approx_groundlevel = (s16)get_sector_average_ground_level( + data->seed, v2s16(blockpos.X, blockpos.Z)); + //dstream<<"approx_groundlevel="<seed, v2s16(blockpos.X, blockpos.Z)); + // Minimum amount of ground above the top of the central block + s16 minimum_ground_depth = minimum_groundlevel - node_max.Y; + + s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level( + data->seed, v2s16(blockpos.X, blockpos.Z), 1); + // Maximum amount of ground above the bottom of the central block + s16 maximum_ground_depth = maximum_groundlevel - node_min.Y; + + /* + Special case for high air or water: Just fill with air and water. + */ + if(maximum_ground_depth < -20) + { + for(s16 x=node_min.X; x<=node_max.X; x++) + for(s16 z=node_min.Z; z<=node_max.Z; z++) + { + // Node position + v2s16 p2d(x,z); + { + // Use fast index incrementing + v3s16 em = vmanip.m_area.getExtent(); + 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++) + { + // Only modify places that have no content + if(vmanip.m_data[i].d == CONTENT_IGNORE) + { + if(y <= WATER_LEVEL) + vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE); + else + vmanip.m_data[i] = MapNode(CONTENT_AIR); + } + + data->vmanip.m_area.add_y(em, i, 1); + } + } + } + + // We're done + return; + } + + /* + If block is deep underground, this is set to true and ground + density noise is not generated, for speed optimization. + */ + bool all_is_ground_except_caves = (minimum_ground_depth > 16); + + /* + Create a block-specific seed + */ + u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234 + + full_node_min.Y*42123 + full_node_min.X*23; + + /* + Make some 3D noise + */ + + //NoiseBuffer noisebuf1; + //NoiseBuffer noisebuf2; + NoiseBuffer noisebuf_cave; + NoiseBuffer noisebuf_ground; + NoiseBuffer noisebuf_ground_crumbleness; + NoiseBuffer noisebuf_ground_wetness; + { + v3f minpos_f(node_min.X, node_min.Y, node_min.Z); + v3f maxpos_f(node_max.X, node_max.Y, node_max.Z); + + //TimeTaker timer("noisebuf.create"); + + /* + Cave noise + */ + + noisebuf_cave.create(get_cave_noise1_params(data->seed), + minpos_f.X, minpos_f.Y, minpos_f.Z, + maxpos_f.X, maxpos_f.Y, maxpos_f.Z, + 4, 3, 4); + + noisebuf_cave.multiply(get_cave_noise2_params(data->seed)); + + /* + Ground noise + */ + + // Sample length + v3f sl = v3f(4.0, 4.0, 4.0); + + /* + Density noise + */ + if(all_is_ground_except_caves == false) + //noisebuf_ground.create(data->seed+983240, 6, 0.60, false, + noisebuf_ground.create(get_ground_noise1_params(data->seed), + minpos_f.X, minpos_f.Y, minpos_f.Z, + maxpos_f.X, maxpos_f.Y, maxpos_f.Z, + sl.X, sl.Y, sl.Z); + + /* + Ground property noise + */ + sl = v3f(2.5, 2.5, 2.5); + noisebuf_ground_crumbleness.create( + get_ground_crumbleness_params(data->seed), + minpos_f.X, minpos_f.Y, minpos_f.Z, + maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z, + sl.X, sl.Y, sl.Z); + noisebuf_ground_wetness.create( + get_ground_wetness_params(data->seed), + minpos_f.X, minpos_f.Y, minpos_f.Z, + maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z, + sl.X, sl.Y, sl.Z); + } + + /* + Make base ground level + */ + + for(s16 x=node_min.X; x<=node_max.X; x++) + for(s16 z=node_min.Z; z<=node_max.Z; z++) + { + // Node position + v2s16 p2d(x,z); + { + // Use fast index incrementing + v3s16 em = vmanip.m_area.getExtent(); + 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++) + { + // Only modify places that have no content + if(vmanip.m_data[i].d == CONTENT_IGNORE) + { + // First priority: make air and water. + // This avoids caves inside water. + if(all_is_ground_except_caves == false + && val_is_ground(noisebuf_ground.get(x,y,z), + v3s16(x,y,z), data->seed) == false) + { + if(y <= WATER_LEVEL) + vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE); + else + vmanip.m_data[i] = MapNode(CONTENT_AIR); + } + else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD) + vmanip.m_data[i] = MapNode(CONTENT_AIR); + else + vmanip.m_data[i] = MapNode(CONTENT_STONE); + } + + data->vmanip.m_area.add_y(em, i, 1); + } + } + } + + /* + Add minerals + */ + + { + PseudoRandom mineralrandom(blockseed); + + /* + Add meseblocks + */ + for(s16 i=0; i 0.0) + new_content = MapNode(CONTENT_STONE, MINERAL_IRON); + /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0) + vmanip.m_data[i] = MapNode(CONTENT_MUD); + else + vmanip.m_data[i] = MapNode(CONTENT_SAND);*/ + } + /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1) + { + }*/ + + if(new_content.d != CONTENT_IGNORE) + { + for(u16 i=0; i<27; i++) + { + v3s16 p = v3s16(x,y,z) + g_27dirs[i]; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].d == base_content) + { + if(mineralrandom.next()%sparseness == 0) + vmanip.m_data[vi] = new_content; + } + } + } + } + } + /* + Add coal + */ + //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++) + //for(s16 i=0; i<50; i++) + u16 coal_amount = 30; + u16 coal_rareness = 60 / coal_amount; + if(coal_rareness == 0) + coal_rareness = 1; + if(mineralrandom.next()%coal_rareness == 0) + { + u16 a = mineralrandom.next() % 16; + u16 amount = coal_amount * a*a*a / 1000; + for(s16 i=0; i=node_min.Y; y--) + { + if(vmanip.m_data[i].d == CONTENT_STONE) + { + if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3) + { + if(noisebuf_ground_wetness.get(x,y,z) > 0.0) + vmanip.m_data[i] = MapNode(CONTENT_MUD); + else + vmanip.m_data[i] = MapNode(CONTENT_SAND); + } + else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7) + { + if(noisebuf_ground_wetness.get(x,y,z) < -0.6) + vmanip.m_data[i] = MapNode(CONTENT_GRAVEL); + } + } + + data->vmanip.m_area.add_y(em, i, -1); + } + } + } + + /* + Add dungeons + */ + + //if(node_min.Y < approx_groundlevel) + //if(myrand() % 3 == 0) + //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel) + //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel) + //float dungeon_rarity = g_settings.getFloat("dungeon_rarity"); + float dungeon_rarity = 0.02; + if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0) + < dungeon_rarity + && node_min.Y < approx_groundlevel) + { + // Dungeon generator doesn't modify places which have this set + data->vmanip.clearFlag(VMANIP_FLAG_DUNGEON_INSIDE + | VMANIP_FLAG_DUNGEON_PRESERVE); + + // Set all air and water to be untouchable to make dungeons open + // to caves and open air + for(s16 x=full_node_min.X; x<=full_node_max.X; x++) + for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++) + { + // Node position + v2s16 p2d(x,z); + { + // Use fast index incrementing + v3s16 em = vmanip.m_area.getExtent(); + u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y)); + for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--) + { + if(vmanip.m_data[i].d == CONTENT_AIR) + vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE; + else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE) + vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE; + data->vmanip.m_area.add_y(em, i, -1); + } + } + } + + PseudoRandom random(blockseed+2); + + // Add it + make_dungeon1(data->vmanip, random); + + // Convert some cobble to mossy cobble + for(s16 x=full_node_min.X; x<=full_node_max.X; x++) + for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++) + { + // Node position + v2s16 p2d(x,z); + { + // Use fast index incrementing + v3s16 em = vmanip.m_area.getExtent(); + u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y)); + for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--) + { + // (noisebuf not used because it doesn't contain the + // full area) + double wetness = noise3d_param( + get_ground_wetness_params(data->seed), x,y,z); + double d = noise3d_perlin((float)x/2.5, + (float)y/2.5,(float)z/2.5, + blockseed, 2, 1.4); + if(vmanip.m_data[i].d == CONTENT_COBBLE) + { + if(d < wetness/3.0) + { + vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE; + } + } + /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE) + { + if(wetness > 1.2) + vmanip.m_data[i].d = CONTENT_MUD; + }*/ + data->vmanip.m_area.add_y(em, i, -1); + } + } + } + } + + /* + Add top and bottom side of water to transforming_liquid queue + */ + + for(s16 x=node_min.X; x<=node_max.X; x++) + for(s16 z=node_min.Z; z<=node_max.Z; z++) + { + // Node position + v2s16 p2d(x,z); + { + bool water_found = false; + // Use fast index incrementing + v3s16 em = vmanip.m_area.getExtent(); + u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y)); + for(s16 y=node_max.Y; y>=node_min.Y; y--) + { + if(water_found == false) + { + if(vmanip.m_data[i].d == CONTENT_WATERSOURCE) + { + v3s16 p = v3s16(p2d.X, y, p2d.Y); + data->transforming_liquid.push_back(p); + water_found = true; + } + } + else + { + // This can be done because water_found can only + // turn to true and end up here after going through + // a single block. + if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE) + { + v3s16 p = v3s16(p2d.X, y+1, p2d.Y); + data->transforming_liquid.push_back(p); + water_found = false; + } + } + + data->vmanip.m_area.add_y(em, i, -1); + } + } + } + + /* + If close to ground level + */ + + //if(abs(approx_ground_depth) < 30) + if(minimum_ground_depth < 5 && maximum_ground_depth > -5) + { + /* + Add grass and mud + */ + + for(s16 x=node_min.X; x<=node_max.X; x++) + for(s16 z=node_min.Z; z<=node_max.Z; z++) + { + // Node position + v2s16 p2d(x,z); + { + bool possibly_have_sand = get_have_sand(data->seed, p2d); + bool have_sand = false; + u32 current_depth = 0; + bool air_detected = false; + bool water_detected = false; + // Use fast index incrementing + s16 start_y = node_max.Y+2; + v3s16 em = vmanip.m_area.getExtent(); + u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y)); + for(s16 y=start_y; y>=node_min.Y-3; y--) + { + if(vmanip.m_data[i].d == CONTENT_WATERSOURCE) + water_detected = true; + if(vmanip.m_data[i].d == CONTENT_AIR) + air_detected = true; + + if((vmanip.m_data[i].d == CONTENT_STONE + || vmanip.m_data[i].d == CONTENT_GRASS + || vmanip.m_data[i].d == CONTENT_MUD + || vmanip.m_data[i].d == CONTENT_SAND + || vmanip.m_data[i].d == CONTENT_GRAVEL + ) && (air_detected || water_detected)) + { + if(current_depth == 0 && y <= WATER_LEVEL+2 + && possibly_have_sand) + have_sand = true; + + if(current_depth < 4) + { + if(have_sand) + { + vmanip.m_data[i] = MapNode(CONTENT_SAND); + } + #if 1 + else if(current_depth==0 && !water_detected + && y >= WATER_LEVEL && air_detected) + vmanip.m_data[i] = MapNode(CONTENT_GRASS); + #endif + else + vmanip.m_data[i] = MapNode(CONTENT_MUD); + } + else + { + if(vmanip.m_data[i].d == CONTENT_MUD + || vmanip.m_data[i].d == CONTENT_GRASS) + vmanip.m_data[i] = MapNode(CONTENT_STONE); + } + + current_depth++; + + if(current_depth >= 8) + break; + } + else if(current_depth != 0) + break; + + data->vmanip.m_area.add_y(em, i, -1); + } + } + } + + /* + Add trees + */ + + // Amount of trees + u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center); + PseudoRandom treerandom(blockseed); + // Put trees in random places on part of division + for(u32 i=0; ivmanip, v2s16(x,z)); + s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4); + // Don't make a tree under water level + if(y < WATER_LEVEL) + continue; + // Make sure tree fits (only trees whose starting point is + // at this block are added) + if(y < node_min.Y || y > node_max.Y) + continue; + /* + Find exact ground level + */ + v3s16 p(x,y+6,z); + bool found = false; + for(; p.Y >= y-6; p.Y--) + { + u32 i = data->vmanip.m_area.index(p); + MapNode *n = &data->vmanip.m_data[i]; + if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE) + { + found = true; + break; + } + } + // If not found, handle next one + if(found == false) + continue; + /* + Trees grow only on mud and grass + */ + { + u32 i = data->vmanip.m_area.index(p); + MapNode *n = &data->vmanip.m_data[i]; + if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) + continue; + } + // Tree will be placed one higher + p.Y++; + // Make a tree + make_tree(data->vmanip, p); + } + +#if 0 + /* + Add some kind of random stones + */ + + u32 random_stone_count = block_area_nodes * + randomstone_amount_2d(data->seed, p2d_center); + // Put in random places on part of division + for(u32 i=0; iseed, v2s16(x,z), 1); + // Don't add under water level + /*if(y < WATER_LEVEL) + continue;*/ + // Don't add if doesn't belong to this block + if(y < node_min.Y || y > node_max.Y) + continue; + v3s16 p(x,y,z); + // Filter placement + /*{ + u32 i = data->vmanip.m_area.index(v3s16(p)); + MapNode *n = &data->vmanip.m_data[i]; + if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) + continue; + }*/ + // Will be placed one higher + p.Y++; + // Add it + make_randomstone(data->vmanip, p); + } +#endif + +#if 0 + /* + Add larger stones + */ + + u32 large_stone_count = block_area_nodes * + largestone_amount_2d(data->seed, p2d_center); + //u32 large_stone_count = 1; + // Put in random places on part of division + for(u32 i=0; iseed, v2s16(x,z), 1); + // Don't add under water level + /*if(y < WATER_LEVEL) + continue;*/ + // Don't add if doesn't belong to this block + if(y < node_min.Y || y > node_max.Y) + continue; + v3s16 p(x,y,z); + // Filter placement + /*{ + u32 i = data->vmanip.m_area.index(v3s16(p)); + MapNode *n = &data->vmanip.m_data[i]; + if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) + continue; + }*/ + // Will be placed one lower + p.Y--; + // Add it + make_largestone(data->vmanip, p); + } +#endif + } + +} + +}; // namespace mapgen + + -- cgit v1.2.3 From a80025c352fb91ff295423940b3ded22755b70f0 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 25 Jun 2011 18:35:32 +0300 Subject: moved mapgen stuff around abit --- src/mapgen.cpp | 52 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'src/mapgen.cpp') diff --git a/src/mapgen.cpp b/src/mapgen.cpp index a739ceaeb..801dd72b1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -903,6 +903,7 @@ bool is_cave(u64 seed, v3s16 p) TODO: No perlin noises here, they should be outsourced and buffered + NOTE: The speed of these actually isn't terrible */ bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed) { @@ -918,6 +919,8 @@ bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed) double h = WATER_LEVEL + 10 * noise2d_perlin( 0.5+(float)p.X/250, 0.5+(float)p.Z/250, seed+84174, 4, 0.5); + /*double f = 1; + double h = 0;*/ return ((double)p.Y - h < ground_noise1_val * f); } @@ -1253,7 +1256,7 @@ void make_block(BlockMakeData *data) /*dstream<<"makeBlock(): ("<vmanip; + ManualMapVoxelManipulator &vmanip = *(data->vmanip); v3s16 blockpos_min = blockpos - v3s16(1,1,1); v3s16 blockpos_max = blockpos + v3s16(1,1,1); // Area of center block @@ -1312,7 +1315,7 @@ void make_block(BlockMakeData *data) vmanip.m_data[i] = MapNode(CONTENT_AIR); } - data->vmanip.m_area.add_y(em, i, 1); + data->vmanip->m_area.add_y(em, i, 1); } } } @@ -1428,7 +1431,7 @@ void make_block(BlockMakeData *data) vmanip.m_data[i] = MapNode(CONTENT_STONE); } - data->vmanip.m_area.add_y(em, i, 1); + data->vmanip->m_area.add_y(em, i, 1); } } } @@ -1597,7 +1600,7 @@ void make_block(BlockMakeData *data) } } - data->vmanip.m_area.add_y(em, i, -1); + data->vmanip->m_area.add_y(em, i, -1); } } } @@ -1617,7 +1620,7 @@ void make_block(BlockMakeData *data) && node_min.Y < approx_groundlevel) { // Dungeon generator doesn't modify places which have this set - data->vmanip.clearFlag(VMANIP_FLAG_DUNGEON_INSIDE + data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE); // Set all air and water to be untouchable to make dungeons open @@ -1637,7 +1640,7 @@ void make_block(BlockMakeData *data) vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE; else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE) vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE; - data->vmanip.m_area.add_y(em, i, -1); + data->vmanip->m_area.add_y(em, i, -1); } } } @@ -1645,7 +1648,7 @@ void make_block(BlockMakeData *data) PseudoRandom random(blockseed+2); // Add it - make_dungeon1(data->vmanip, random); + make_dungeon1(vmanip, random); // Convert some cobble to mossy cobble for(s16 x=full_node_min.X; x<=full_node_max.X; x++) @@ -1678,7 +1681,7 @@ void make_block(BlockMakeData *data) if(wetness > 1.2) vmanip.m_data[i].d = CONTENT_MUD; }*/ - data->vmanip.m_area.add_y(em, i, -1); + data->vmanip->m_area.add_y(em, i, -1); } } } @@ -1722,7 +1725,7 @@ void make_block(BlockMakeData *data) } } - data->vmanip.m_area.add_y(em, i, -1); + data->vmanip->m_area.add_y(em, i, -1); } } } @@ -1800,7 +1803,7 @@ void make_block(BlockMakeData *data) else if(current_depth != 0) break; - data->vmanip.m_area.add_y(em, i, -1); + data->vmanip->m_area.add_y(em, i, -1); } } } @@ -1833,8 +1836,8 @@ void make_block(BlockMakeData *data) bool found = false; for(; p.Y >= y-6; p.Y--) { - u32 i = data->vmanip.m_area.index(p); - MapNode *n = &data->vmanip.m_data[i]; + u32 i = data->vmanip->m_area.index(p); + MapNode *n = &data->vmanip->m_data[i]; if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE) { found = true; @@ -1848,15 +1851,15 @@ void make_block(BlockMakeData *data) Trees grow only on mud and grass */ { - u32 i = data->vmanip.m_area.index(p); - MapNode *n = &data->vmanip.m_data[i]; + u32 i = data->vmanip->m_area.index(p); + MapNode *n = &data->vmanip->m_data[i]; if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) continue; } // Tree will be placed one higher p.Y++; // Make a tree - make_tree(data->vmanip, p); + make_tree(vmanip, p); } #if 0 @@ -1881,8 +1884,8 @@ void make_block(BlockMakeData *data) v3s16 p(x,y,z); // Filter placement /*{ - u32 i = data->vmanip.m_area.index(v3s16(p)); - MapNode *n = &data->vmanip.m_data[i]; + u32 i = data->vmanip->m_area.index(v3s16(p)); + MapNode *n = &data->vmanip->m_data[i]; if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) continue; }*/ @@ -1916,8 +1919,8 @@ void make_block(BlockMakeData *data) v3s16 p(x,y,z); // Filter placement /*{ - u32 i = data->vmanip.m_area.index(v3s16(p)); - MapNode *n = &data->vmanip.m_data[i]; + u32 i = data->vmanip->m_area.index(v3s16(p)); + MapNode *n = &data->vmanip->m_data[i]; if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) continue; }*/ @@ -1931,6 +1934,17 @@ void make_block(BlockMakeData *data) } +BlockMakeData::BlockMakeData(): + no_op(false), + vmanip(NULL), + seed(0) +{} + +BlockMakeData::~BlockMakeData() +{ + delete vmanip; +} + }; // namespace mapgen -- cgit v1.2.3 From 7efe89ff584b2c0338dcede4c1e08504d0158780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20R=C3=BChl?= Date: Sun, 26 Jun 2011 13:47:21 +0200 Subject: backported cactus, papyrus and clay --- src/mapgen.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 10 deletions(-) (limited to 'src/mapgen.cpp') diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 801dd72b1..71696a349 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -151,6 +151,34 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0) } } +void make_papyrus(VoxelManipulator &vmanip, v3s16 p0) +{ + MapNode papyrusnode(CONTENT_PAPYRUS); + + s16 trunk_h = myrand_range(2, 3); + v3s16 p1 = p0; + for(s16 ii=0; iiseed+4321, 6, 0.95); + + have_clay = have_sand && (claynoise > 1.25); + // Use fast index incrementing s16 start_y = node_max.Y+2; v3s16 em = vmanip.m_area.getExtent(); @@ -1778,7 +1815,10 @@ void make_block(BlockMakeData *data) { if(have_sand) { - vmanip.m_data[i] = MapNode(CONTENT_SAND); + if (have_clay) + vmanip.m_data[i] = MapNode(CONTENT_CLAY); + else + vmanip.m_data[i] = MapNode(CONTENT_SAND); } #if 1 else if(current_depth==0 && !water_detected @@ -1823,7 +1863,7 @@ void make_block(BlockMakeData *data) //s16 y = find_ground_level(data->vmanip, v2s16(x,z)); s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4); // Don't make a tree under water level - if(y < WATER_LEVEL) + if(y < WATER_LEVEL - 1) continue; // Make sure tree fits (only trees whose starting point is // at this block are added) @@ -1847,19 +1887,36 @@ void make_block(BlockMakeData *data) // If not found, handle next one if(found == false) continue; - /* - Trees grow only on mud and grass - */ + { u32 i = data->vmanip->m_area.index(p); MapNode *n = &data->vmanip->m_data[i]; - if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS) + + if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS && n->d != CONTENT_SAND) + continue; + + // Papyrus grows only on mud and in water + if(n->d == CONTENT_MUD && y == WATER_LEVEL - 1) + { + p.Y++; + make_papyrus(vmanip, p); + } + // Don't make a tree under water level + if(y < WATER_LEVEL) continue; + // Trees grow only on mud and grass + if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS) + { + p.Y++; + make_tree(vmanip, p); + } + // Cactii grow only on sand + else if(n->d == CONTENT_SAND) + { + p.Y++; + make_cactus(vmanip, p); + } } - // Tree will be placed one higher - p.Y++; - // Make a tree - make_tree(vmanip, p); } #if 0 -- cgit v1.2.3