Move trees generation into Lua mod

This commit is contained in:
Kotolegokot 2012-11-05 22:54:00 +06:00
parent 8c3ffa3907
commit 757b5963f6
5 changed files with 93 additions and 271 deletions

View File

@ -22,6 +22,28 @@ minetest.register_on_joinplayer(function(player)
minetest.after(2.0, cb, player)
end)
minetest.register_abm({
nodenames = {"default:sapling"},
interval = 10,
chance = 50,
action = function(pos, node)
if not minetest.env:get_node_light(pos) then
return
end
if minetest.env:get_node_light(pos) < 8 then
return
end
for dy=1,5 do
pos.y = pos.y+dy
if not minetest.registered_nodes[minetest.env:get_node(pos).name].buildable_to then
return
end
pos.y = pos.y-dy
end
make_tree(pos, math.random(1,4)==1)
end
})
--
-- Tool definition
--

View File

@ -66,6 +66,77 @@ local function generate_ore(name, wherein, minp, maxp, seed, chunks_per_volume,
end
end
--print("generate_ore done")
--Generate trees
local perlin1 = minetest.env:get_perlin(200, 3, 0.6, 100)
-- Assume X and Z lengths are equal
local divlen = 16
local divs = (maxp.x-minp.x)/divlen+1;
for divx=0,divs-1 do
for divz=0,divs-1 do
local x0 = minp.x + math.floor((divx+0)*divlen)
local z0 = minp.z + math.floor((divz+0)*divlen)
local x1 = minp.x + math.floor((divx+1)*divlen)
local z1 = minp.z + math.floor((divz+1)*divlen)
local cobbles_amount = math.floor(perlin1:get2d({x=x0, y=z0}) * 5 + 0)
local pr = PseudoRandom(seed+1)
for i=0,cobbles_amount do
local x = pr:next(x0, x1)
local z = pr:next(z0, z1)
-- Find ground level (0...15)
local ground_y = nil
for y=30,0,-1 do
if minetest.env:get_node({x=x,y=y,z=z}).name ~= "air" then
ground_y = y
break
end
end
if ground_y and minetest.env:get_node({x=x,y=ground_y,z=z}).name == "default:dirt_with_grass" then
make_tree({x=x,y=ground_y+1,z=z}, false)
end
end
end
end
end
function make_tree(pos, is_apple_tree)
for _=1,math.random(4,5) do
minetest.env:set_node(pos, {name="default:tree"})
pos.y = pos.y+1
end
pos.y = pos.y-1
local function set_leaves(pos)
if minetest.registered_nodes[minetest.env:get_node(pos).name].buildable_to then
if is_apple_tree and math.random(1, 10)==1 then
minetest.env:set_node(pos, {name="default:apple"})
else
minetest.env:set_node(pos, {name="default:leaves"})
end
end
end
for dx=-1,1 do
for dy=-1,1 do
for dz=-1,1 do
set_leaves({x=pos.x+dx,y=pos.y+dy,z=pos.z+dz})
end
end
end
for _=1,8 do
local p = {x=math.random(-2, 1),y=math.random(-1, 1),z=math.random(-2, 1),}
p.x = p.x+pos.x
p.y = p.y+pos.y
p.z = p.z+pos.z
for dx=0,1 do
for dy=0,1 do
for dz=0,1 do
set_leaves({x=p.x+dx,y=p.y+dy,z=p.z+dz})
end
end
end
end
end
minetest.register_on_generated(function(minp, maxp, seed)

View File

@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "settings.h"
#include "mapblock.h" // For getNodeBlockPos
#include "mapgen.h" // For mapgen::make_tree
#include "map.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@ -89,67 +88,10 @@ public:
}
};
class MakeTreesFromSaplingsABM : public ActiveBlockModifier
{
private:
public:
virtual std::set<std::string> getTriggerContents()
{
std::set<std::string> s;
s.insert("sapling");
return s;
}
virtual float getTriggerInterval()
{ return 10.0; }
virtual u32 getTriggerChance()
{ return 50; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
u32 active_object_count, u32 active_object_count_wider)
{
INodeDefManager *ndef = env->getGameDef()->ndef();
ServerMap *map = &env->getServerMap();
actionstream<<"A sapling grows into a tree at "
<<PP(p)<<std::endl;
core::map<v3s16, MapBlock*> modified_blocks;
v3s16 tree_p = p;
ManualMapVoxelManipulator vmanip(map);
v3s16 tree_blockp = getNodeBlockPos(tree_p);
vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
bool is_apple_tree = myrand()%4 == 0;
mapgen::make_tree(vmanip, tree_p, is_apple_tree, ndef);
vmanip.blitBackAll(&modified_blocks);
// update lighting
core::map<v3s16, MapBlock*> lighting_modified_blocks;
for(core::map<v3s16, MapBlock*>::Iterator
i = modified_blocks.getIterator();
i.atEnd() == false; i++)
{
lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
}
map->updateLighting(lighting_modified_blocks, modified_blocks);
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
for(core::map<v3s16, MapBlock*>::Iterator
i = modified_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
event.modified_blocks.insert(p, true);
}
map->dispatchEvent(&event);
}
};
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
{
env->addActiveBlockModifier(new GrowGrassABM());
env->addActiveBlockModifier(new RemoveGrassABM());
env->addActiveBlockModifier(new MakeTreesFromSaplingsABM());
}

View File

@ -110,7 +110,6 @@ struct HeightPoint
float gh; // ground height
float ma; // mud amount
float have_sand;
float tree_amount;
};
core::map<v2s16, HeightPoint> g_heights;
@ -126,10 +125,6 @@ HeightPoint ground_height(u64 seed, v2s16 p2d)
/*hp.gh = BS*base_rock_level_2d(seed, p2d);
hp.ma = BS*get_mud_add_amount(seed, p2d);*/
hp.have_sand = mapgen::get_have_beach(seed, p2d);
if(hp.gh > BS*WATER_LEVEL)
hp.tree_amount = mapgen::tree_amount_2d(seed, p2d);
else
hp.tree_amount = 0;
// No mud has been added if mud amount is less than 1
if(hp.ma < 1.0*BS)
hp.ma = 0.0;
@ -244,7 +239,6 @@ void FarMesh::render()
float ma_avg = 0;
float h_avg = 0;
u32 have_sand_count = 0;
float tree_amount_avg = 0;
for(u32 i=0; i<5; i++)
{
noise[i] = hps[i].gh + hps[i].ma;
@ -256,11 +250,9 @@ void FarMesh::render()
h_avg += noise[i];
if(hps[i].have_sand)
have_sand_count++;
tree_amount_avg += hps[i].tree_amount;
}
ma_avg /= 5.0;
h_avg /= 5.0;
tree_amount_avg /= 5.0;
float steepness = (h_max - h_min)/grid_size;
@ -315,11 +307,6 @@ void FarMesh::render()
}
else
{
/*// Trees if there are over 0.01 trees per MapNode
if(tree_amount_avg > 0.01)
c = video::SColor(255,50,128,50);
else
c = video::SColor(255,107,134,51);*/
c = video::SColor(255,107,134,51);
ground_is_mud = true;
}
@ -351,51 +338,6 @@ void FarMesh::render()
u16 indices[] = {0,1,2,2,3,0};
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
// Add some trees if appropriate
if(tree_amount_avg >= 0.0065 && steepness < 1.4
&& ground_is_mud == true)
{
driver->setMaterial(m_materials[1]);
float b = m_brightness;
c = video::SColor(255, b*255, b*255, b*255);
{
video::S3DVertex vertices[4] =
{
video::S3DVertex(p0.X,noise[0],p0.Y,
0,0,0, c, 0,1),
video::S3DVertex(p0.X,noise[0]+BS*MAP_BLOCKSIZE,p0.Y,
0,0,0, c, 0,0),
video::S3DVertex(p1.X,noise[2]+BS*MAP_BLOCKSIZE,p1.Y,
0,0,0, c, 1,0),
video::S3DVertex(p1.X,noise[2],p1.Y,
0,0,0, c, 1,1),
};
u16 indices[] = {0,1,2,2,3,0};
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
video::EVT_STANDARD, scene::EPT_TRIANGLES,
video::EIT_16BIT);
}
{
video::S3DVertex vertices[4] =
{
video::S3DVertex(p1.X,noise[3],p0.Y,
0,0,0, c, 0,1),
video::S3DVertex(p1.X,noise[3]+BS*MAP_BLOCKSIZE,p0.Y,
0,0,0, c, 0,0),
video::S3DVertex(p0.X,noise[1]+BS*MAP_BLOCKSIZE,p1.Y,
0,0,0, c, 1,0),
video::S3DVertex(p0.X,noise[1],p1.Y,
0,0,0, c, 1,1),
};
u16 indices[] = {0,1,2,2,3,0};
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
video::EVT_STANDARD, scene::EPT_TRIANGLES,
video::EIT_16BIT);
}
}
}
//driver->clearZBuffer();

View File

@ -120,86 +120,6 @@ static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
}
#endif
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
bool is_apple_tree, INodeDefManager *ndef)
{
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;
for(s16 ii=0; ii<trunk_h; ii++)
{
if(vmanip.m_area.contains(p1))
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
p1.Y++;
}
// p1 is now the last piece of the trunk
p1.Y -= 1;
VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
//SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
Buffer<u8> leaves_d(leaves_a.getVolume());
for(s32 i=0; i<leaves_a.getVolume(); i++)
leaves_d[i] = 0;
// Force leaves at near the end of the trunk
{
s16 d = 1;
for(s16 z=-d; z<=d; z++)
for(s16 y=-d; y<=d; y++)
for(s16 x=-d; x<=d; x++)
{
leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
}
}
// Add leaves randomly
for(u32 iii=0; iii<7; iii++)
{
s16 d = 1;
v3s16 p(
myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
myrand_range(leaves_a.MinEdge.Z, leaves_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++)
{
leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
}
}
// Blit leaves to vmanip
for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
{
v3s16 p(x,y,z);
p += p1;
if(vmanip.m_area.contains(p) == false)
continue;
u32 vi = vmanip.m_area.index(p);
if(vmanip.m_data[vi].getContent() != CONTENT_AIR
&& vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
continue;
u32 i = leaves_a.index(x,y,z);
if(leaves_d[i] == 1) {
bool is_apple = myrand_range(0,99) < 10;
if(is_apple_tree && is_apple) {
vmanip.m_data[vi] = applenode;
} else {
vmanip.m_data[vi] = leavesnode;
}
}
}
}
#if 0
static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
INodeDefManager *ndef)
@ -1017,22 +937,6 @@ bool is_ground(u64 seed, v3s16 p)
}
#endif
// 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.39;
if(noise < zeroval)
return 0;
else
return 0.04 * (noise-zeroval) / (1.0-zeroval);
}
#if 0
double surface_humidity_2d(u64 seed, v2s16 p)
{
@ -2184,65 +2088,6 @@ void make_block(BlockMakeData *data)
}
}
/*
Generate some trees
*/
assert(central_area_size.X == central_area_size.Z);
{
// Divide area into parts
s16 div = 8;
s16 sidelen = central_area_size.X / div;
double area = sidelen * sidelen;
for(s16 x0=0; x0<div; x0++)
for(s16 z0=0; z0<div; z0++)
{
// Center position of part of division
v2s16 p2d_center(
node_min.X + sidelen/2 + sidelen*x0,
node_min.Z + sidelen/2 + sidelen*z0
);
// Minimum edge of part of division
v2s16 p2d_min(
node_min.X + sidelen*x0,
node_min.Z + sidelen*z0
);
// Maximum edge of part of division
v2s16 p2d_max(
node_min.X + sidelen + sidelen*x0 - 1,
node_min.Z + sidelen + sidelen*z0 - 1
);
// Amount of trees
u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
// Put trees in random places on part of division
for(u32 i=0; i<tree_count; i++)
{
s16 x = myrand_range(p2d_min.X, p2d_max.X);
s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
// Don't make a tree under water level
if(y < WATER_LEVEL)
continue;
// Don't make a tree so high that it doesn't fit
if(y > node_max.Y - 6)
continue;
v3s16 p(x,y,z);
/*
Trees grow only on mud and grass
*/
{
u32 i = vmanip.m_area.index(v3s16(p));
MapNode *n = &vmanip.m_data[i];
if(n->getContent() != c_dirt
&& n->getContent() != c_dirt_with_grass)
continue;
}
p.Y++;
// Make a tree
make_tree(vmanip, p, false, ndef);
}
}
}
#if 0
/*
Make base ground level