657 lines
23 KiB
Lua
657 lines
23 KiB
Lua
|
|
||
|
trees_lib = {}
|
||
|
|
||
|
-- place this node if a sapling does not like the environment and refuses
|
||
|
-- to grow into a tree there
|
||
|
trees_lib.place_when_tree_cant_grow = {name="default:dry_shrub"};
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- compatibility functions so that trees_lib can work without default mod
|
||
|
-----------------------------------------------------------------------------
|
||
|
trees_lib.sound_leaves = function()
|
||
|
if( default and default.node_sound_leaves_defaults) then
|
||
|
return default.node_sound_leaves_defaults(table)
|
||
|
else
|
||
|
return nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
trees_lib.sound_wood = function()
|
||
|
if( default and default.node_sound_wood_defaults) then
|
||
|
return default.node_sound_wood_defaults(table)
|
||
|
else
|
||
|
return nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- copy of default.after_place_leaves
|
||
|
trees_lib.after_place_leaves = function(pos, placer, itemstack, pointed_thing)
|
||
|
local node = minetest.get_node(pos)
|
||
|
node.param2 = 1
|
||
|
minetest.set_node(pos, node)
|
||
|
end
|
||
|
|
||
|
-- generalized function called after placing fruits
|
||
|
trees_lib.after_place_fruit = function(pos, placer, itemstack, pointed_thing)
|
||
|
if placer:is_player() then
|
||
|
-- find out the node name (this function is for all fruits that do not override it)
|
||
|
local node = minetest.get_node( pos );
|
||
|
if( node and node.name) then
|
||
|
minetest.set_node(pos, {name = node.name, param2 = 1})
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- the various node definitions that are common to all nodes of that type
|
||
|
-- (unless overriden)
|
||
|
-----------------------------------------------------------------------------
|
||
|
trees_lib.node_def_tree = {
|
||
|
--description = "TREENAME Tree",
|
||
|
--tiles = nodes.tree.tiles,
|
||
|
paramtype2 = "facedir",
|
||
|
is_ground_content = false,
|
||
|
-- moretrees uses snappy=1 here as well
|
||
|
groups = {tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||
|
sounds = trees_lib.sound_wood,
|
||
|
on_place = minetest.rotate_node
|
||
|
}
|
||
|
|
||
|
trees_lib.node_def_wood = {
|
||
|
--description = "TREENAME Wood Planks",
|
||
|
--tiles = nodes.wood.tiles,
|
||
|
is_ground_content = false,
|
||
|
-- moretrees uses snappy=1 here
|
||
|
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, wood = 1},
|
||
|
sounds = trees_lib.sound_wood,
|
||
|
}
|
||
|
|
||
|
trees_lib.node_def_leaves = {
|
||
|
--description = "TREENAME Leaves",
|
||
|
--tiles = nodes[k].tiles,
|
||
|
--special_tiles = nodes[k].special_tiles,
|
||
|
|
||
|
-- moretrees has some options for this
|
||
|
drawtype = "allfaces_optional",
|
||
|
waving = 1,
|
||
|
visual_scale = 1.3,
|
||
|
paramtype = "light",
|
||
|
is_ground_content = false,
|
||
|
-- moretrees sets moretrees_leaves=1, leafdecay = decay
|
||
|
groups = {snappy = 3, leafdecay = 3, flammable = 2, leaves = 1},
|
||
|
sounds = trees_lib.sound_leaves,
|
||
|
after_place_node = trees_lib.after_place_leaves,
|
||
|
-- the drop part of the node definition needs to be constructed
|
||
|
-- for each leaf individually
|
||
|
}
|
||
|
|
||
|
|
||
|
trees_lib.node_def_fruit = {
|
||
|
--description = "TREENAME Fruit",
|
||
|
drawtype = "plantlike",
|
||
|
visual_scale = 1.0,
|
||
|
--tiles = nodes.fruit.tiles,
|
||
|
--inventory_image = nodes.fruit.tiles[1],
|
||
|
paramtype = "light",
|
||
|
sunlight_propagates = true,
|
||
|
walkable = false,
|
||
|
is_ground_content = false,
|
||
|
selection_box = {
|
||
|
type = "fixed",
|
||
|
fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2}
|
||
|
},
|
||
|
groups = {fleshy = 3, dig_immediate = 3, flammable = 2,
|
||
|
leafdecay = 3, leafdecay_drop = 1},
|
||
|
sounds = trees_lib.sound_leaves,
|
||
|
-- store that this fruit has been placed manually
|
||
|
after_place_node = trees_lib.after_place_fruit,
|
||
|
-- a fruit that wants to be eatable ought to supply the following line in
|
||
|
-- its fruit definition:
|
||
|
--on_use = minetest.item_eat(food_points),
|
||
|
}
|
||
|
|
||
|
trees_lib.node_def_sapling = {
|
||
|
--description = "TREENAME sapling",
|
||
|
drawtype = "plantlike",
|
||
|
visual_scale = 1.0,
|
||
|
--tiles = nodes.sapling.tiles,
|
||
|
--inventory_image = nodes.sapling.tiles[1],
|
||
|
--wield_image = nodes.sapling.tiles[1],
|
||
|
paramtype = "light",
|
||
|
sunlight_propagates = true,
|
||
|
walkable = false,
|
||
|
selection_box = {
|
||
|
type = "fixed",
|
||
|
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||
|
},
|
||
|
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
||
|
attached_node = 1, sapling = 1},
|
||
|
sounds = trees_lib.sound_leaves,
|
||
|
}
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- internal functions for handling identification of nodes (i.e. what is a
|
||
|
-- trunk, what is a leaf, which nodes can be replaced by new trees)
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- those are helpful for fast lookup (either by name or content id)
|
||
|
trees_lib.is_tree = {}
|
||
|
trees_lib.is_wood = {}
|
||
|
trees_lib.is_leaf = {}
|
||
|
trees_lib.is_sapling = {}
|
||
|
trees_lib.is_fruit = {}
|
||
|
trees_lib.ignore = {}
|
||
|
|
||
|
-- trees are allowed to replace these nodes when growing
|
||
|
-- (in addition to leaves, saplings and fruits from other trees)
|
||
|
trees_lib.ignore_list = {
|
||
|
"air","ignore",
|
||
|
"default:water_source","default:water_flowing",
|
||
|
"default:snow","default:ice"}
|
||
|
|
||
|
trees_lib.build_lookup_table = function( node_name, node_type, value, allow_removal_by_other_saplings )
|
||
|
if( not( node_name )
|
||
|
or node_name == ""
|
||
|
or not( minetest.registered_nodes[ node_name ])
|
||
|
or not( trees_lib[ node_type ])) then
|
||
|
return;
|
||
|
end
|
||
|
local id = minetest.get_content_id( node_name );
|
||
|
-- we store by id and nodename both for faster lookup
|
||
|
trees_lib[ node_type ][ id ] = value;
|
||
|
trees_lib[ node_type ][ node_name ] = value;
|
||
|
-- if this is set, then other saplings can overwrite these nodes during
|
||
|
-- their growth (i.e. replacing leaves with tree trunks)
|
||
|
if( allow_removal_by_other_saplings ) then
|
||
|
trees_lib.ignore[ id ] = value;
|
||
|
trees_lib.ignore[ node_name ] = value;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- actually store the information from the ignore list
|
||
|
for _,v in ipairs( trees_lib.ignore_list ) do
|
||
|
trees_lib.build_lookup_table( v,"ignore", v, 1 );
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- allow to call a function whenever a new tree has been registered
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- contains a list of all functions that need to be called whenever a new tree
|
||
|
-- type is registered using trees_lib.register_tree(..)
|
||
|
trees_lib.register_on_new_tree_type_function_list = {}
|
||
|
|
||
|
-- the function new_tree_type_function will be called once for each tree type;
|
||
|
-- use this for adding the 1 tree -> 4 wood craft receipe
|
||
|
trees_lib.register_on_new_tree_type = function( new_tree_type_function )
|
||
|
|
||
|
-- call the function for all tree types that have been registered up
|
||
|
-- until now
|
||
|
for k,v in pairs( trees_lib.is_sapling) do
|
||
|
new_tree_type_function( v.tree_name, v.mod_prefix, v.nodes );
|
||
|
end
|
||
|
|
||
|
-- store the function so that it will get called at all subsequent
|
||
|
-- registrations of new trees
|
||
|
table.insert( trees_lib.register_on_new_tree_type_function_list,
|
||
|
new_tree_type_function );
|
||
|
|
||
|
end
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- mix basic node definition (see below), default constructed values (which
|
||
|
-- are derived from modname and treename) as fallback and user (=user of the
|
||
|
-- trees_lib) specified node defintion up into one node definition and
|
||
|
-- register the node (provided it does not exist yet)
|
||
|
-----------------------------------------------------------------------------
|
||
|
trees_lib.register_one_node = function( def_common, def_default, def_user, node_type, sapling_node_name, cid )
|
||
|
if( not( def_user)) then
|
||
|
def_user = {};
|
||
|
end
|
||
|
-- find out which node we are supposed to register
|
||
|
local node_name = def_user.node_name;
|
||
|
if( not( node_name )) then
|
||
|
node_name = def_default.node_name;
|
||
|
end
|
||
|
-- if the node is alrady registered, then abort
|
||
|
if( minetest.registered_nodes[ node_name ]) then
|
||
|
-- store the content id of this node for this type
|
||
|
cid[ node_type ] = minetest.get_content_id( node_name );
|
||
|
def_user.node_name = node_name;
|
||
|
return def_user;
|
||
|
end
|
||
|
|
||
|
-- create the new node definition
|
||
|
local node_def = {};
|
||
|
-- first, add all entries from def_common
|
||
|
for k,v in pairs( def_common ) do
|
||
|
node_def[ k ] = v;
|
||
|
end
|
||
|
-- then try the default values
|
||
|
for k,v in pairs( def_default) do
|
||
|
node_def[ k ] = v;
|
||
|
end
|
||
|
-- last, apply all user supplied node definitions and thus overwrite
|
||
|
-- common and default definitions
|
||
|
for k,v in pairs( def_user ) do
|
||
|
node_def[ k ] = v;
|
||
|
end
|
||
|
|
||
|
-- set inventory_image and wield_image for plantlike nodes
|
||
|
if( node_def.drawtype
|
||
|
and node_def.drawtype=="plantlike"
|
||
|
and not( node_def.inventory_image )) then
|
||
|
node_def.inventory_image = node_def.tiles[1];
|
||
|
node_def.wield_image = node_def.tiles[1];
|
||
|
end
|
||
|
|
||
|
-- the node name does not belong into the node definition
|
||
|
node_def.node_name = nil;
|
||
|
|
||
|
-- actually register the new node
|
||
|
minetest.register_node( node_name, node_def );
|
||
|
|
||
|
|
||
|
-- make sure the node name gets saved
|
||
|
def_user.node_name = node_name;
|
||
|
|
||
|
-- can this node (in theory) be overwritten by other trees?
|
||
|
local allow_overwrite = nil;
|
||
|
if( node_type=="leaf" or node_type=="fruit" or node_type=="sapling") then
|
||
|
allow_overwrite = 1;
|
||
|
end
|
||
|
-- enter all these node names into a table for fast lookup
|
||
|
-- (without having to resort to checking the group)
|
||
|
-- the trees_lib.is_sapling field will later on contain more helpful information;
|
||
|
-- the sapling needs to be the first node registered for this to work reliably
|
||
|
trees_lib.build_lookup_table( node_name, "is_"..node_type, sapling_node_name, allow_overwrite );
|
||
|
|
||
|
-- store the content id of the newly registered node
|
||
|
cid[ node_type ] = minetest.get_content_id( node_name );
|
||
|
return def_user;
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- nodes for the trees: trunk, planks, leaves, sapling and fruit
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- (internal function)
|
||
|
-- * there can be up to 5 diffrent leaves types
|
||
|
-- * Note: craft receipes for fuel (tree, wood, leaves) do not need to be
|
||
|
-- added because default already contains general craft receipes
|
||
|
-- based on the respective groups.
|
||
|
-- * Note: The craft receipe for 1 tree -> 4 wood can be done via
|
||
|
-- trees_lib.register_on_new_tree_type
|
||
|
trees_lib.register_tree_nodes = function( tree_name, mod_prefix, nodes )
|
||
|
|
||
|
-- gather all the relevant content ids
|
||
|
local cid = {};
|
||
|
|
||
|
local tree_name_upcase = tree_name:gsub("^%l", string.upper);
|
||
|
local texture_prefix = mod_prefix.."_"..tree_name;
|
||
|
|
||
|
if( not( nodes )) then
|
||
|
nodes = {};
|
||
|
end
|
||
|
|
||
|
-- the sapling node name will act as a reference in the lookup table later on;
|
||
|
-- therefore, we need to determine how the node will be called early enough
|
||
|
local sapling_node_name = mod_prefix..':'..tree_name..'_sapling';
|
||
|
if( nodes.sapling and nodes.sapling.node_name ) then
|
||
|
sapling_node_name = nodes.sapling.node_name;
|
||
|
end
|
||
|
|
||
|
-- register the sapling
|
||
|
nodes.sapling = trees_lib.register_one_node( trees_lib.node_def_sapling,
|
||
|
{
|
||
|
node_name = sapling_node_name,
|
||
|
description = tree_name_upcase.." Sapling",
|
||
|
tiles = { texture_prefix.."_sapling.png",
|
||
|
},
|
||
|
}, nodes.sapling, "sapling", sapling_node_name, cid );
|
||
|
|
||
|
|
||
|
-- register the tree trunk
|
||
|
nodes.tree = trees_lib.register_one_node( trees_lib.node_def_tree,
|
||
|
{
|
||
|
node_name = mod_prefix..':'..tree_name..'_tree',
|
||
|
description = tree_name_upcase.." Tree",
|
||
|
tiles = { texture_prefix.."_tree_top.png",
|
||
|
texture_prefix.."_tree_top.png",
|
||
|
texture_prefix.."_tree.png",
|
||
|
},
|
||
|
}, nodes.tree, "tree", sapling_node_name, cid );
|
||
|
|
||
|
-- register the wood that belongs to the tree
|
||
|
nodes.wood = trees_lib.register_one_node( trees_lib.node_def_wood,
|
||
|
{
|
||
|
node_name = mod_prefix..':'..tree_name..'_wood',
|
||
|
description = tree_name_upcase.." Planks",
|
||
|
tiles = { texture_prefix.."_wood.png",
|
||
|
},
|
||
|
}, nodes.wood, "wood", sapling_node_name, cid );
|
||
|
|
||
|
|
||
|
-- default drop rate for the sapling (1/20)
|
||
|
local sapling_rarity = 20;
|
||
|
if( nodes.sapling and nodes.sapling.rarity ) then
|
||
|
sapling_rarity = nodes.sapling.rarity;
|
||
|
end
|
||
|
|
||
|
-- register the leaves; some trees may have more than one type of leaves (i.e. moretrees jungletrees)
|
||
|
local leaves_id = {'leaves','leaves2','leaves3','leaves4','leaves5'};
|
||
|
for _,k in ipairs( leaves_id ) do
|
||
|
-- not all leaf types need to exist; we just expect at least one type of leaves to be there
|
||
|
if( nodes[ k ] or k=='leaves') then
|
||
|
-- we need to determine the node name now as leaves tend to drop themshelves sometimes
|
||
|
local leaves_node_name = mod_prefix..':'..tree_name..'_'..k;
|
||
|
if( nodes[ k ] and nodes[ k ].node_name ) then
|
||
|
leaves_node_name = nodes[ k ].node_name;
|
||
|
end
|
||
|
nodes[ k ] = trees_lib.register_one_node( trees_lib.node_def_leaves,
|
||
|
{
|
||
|
node_name = leaves_node_name,
|
||
|
description = tree_name_upcase.." Leaves",
|
||
|
tiles = { texture_prefix.."_"..k..".png",
|
||
|
},
|
||
|
-- special_tiles = { texture_prefix.."_"..k.."_simple.png", },
|
||
|
drop = {
|
||
|
max_items = 1,
|
||
|
items = {
|
||
|
{
|
||
|
-- player will get sapling with 1/20 chance
|
||
|
items = { sapling_node_name},
|
||
|
rarity = sapling_rarity,
|
||
|
},
|
||
|
{
|
||
|
-- player will get leaves only if he get no saplings,
|
||
|
-- this is because max_items is 1
|
||
|
items = { leaves_node_name},
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
}, nodes[ k ], "leaf", sapling_node_name, cid);
|
||
|
|
||
|
-- also store the content ids of all leaf types
|
||
|
cid[ k ] = cid[ "leaf" ];
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- register the fruit
|
||
|
nodes.fruit = trees_lib.register_one_node( trees_lib.node_def_fruit,
|
||
|
{
|
||
|
node_name = mod_prefix..':'..tree_name..'_fruit',
|
||
|
description = tree_name_upcase.." Fruit",
|
||
|
tiles = { texture_prefix.."_fruit.png",
|
||
|
},
|
||
|
}, nodes.fruit, "fruit", sapling_node_name, cid );
|
||
|
|
||
|
-- return the ids we've gathered
|
||
|
return cid;
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- growing of the trees from saplings
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- turn saplings that failed to grow (because they don't like the ground or
|
||
|
-- environment) into dry shrub, thus allowing dry shrub farming;
|
||
|
-- override this function if you don't like this feature
|
||
|
trees_lib.failed_to_grow = function( pos, node )
|
||
|
minetest.set_node( pos, trees_lib.place_when_tree_cant_grow);
|
||
|
end
|
||
|
|
||
|
-- this function is called just before a tree actually grows;
|
||
|
-- the function ought to return how_to_grow for normal tree growth;
|
||
|
-- returning another way of growing is also possible (i.e. diffrent
|
||
|
-- model when growing in flower pots/on stone)
|
||
|
trees_lib.change_tree_growth = function( pos, node, how_to_grow )
|
||
|
return how_to_grow;
|
||
|
end
|
||
|
|
||
|
|
||
|
-- this function is called whenever a sapling of type node has grown
|
||
|
-- into a tree using how_to_grow at position pos
|
||
|
trees_lib.a_tree_has_grown = function( pos, node, how_to_grow )
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
-- called by the abm running on the saplings;
|
||
|
-- if force is set, the tree will grow even if it usually wouldn't in that
|
||
|
-- environment
|
||
|
trees_lib.tree_abm_called = function( pos, node, active_object_count, active_object_count_wider, force_grow)
|
||
|
-- if we don't have further information about that sapling, then abort
|
||
|
if( not( node )
|
||
|
or not( node.name )
|
||
|
or not( trees_lib.is_sapling[ node.name ])) then
|
||
|
-- turn into dry shrub (because we don't know what to do with
|
||
|
-- this sapling)
|
||
|
trees_lib.failed_to_grow( pos, node );
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
-- get information about what we're supposed to do with that sapling
|
||
|
local sapling_data = trees_lib.is_sapling[ node.name ];
|
||
|
|
||
|
-- the type of ground might be of intrest for further functions (i.e. can_grow, select_how_to_grow)
|
||
|
local ground_found = nil;
|
||
|
-- a quick check of the ground; sapling_data.grows_on has to be a list of all
|
||
|
-- ground types acceptable for the tree
|
||
|
if( not(force_grow) and sapling_data.grows_on and type( sapling_data.grows_on )=="table") then
|
||
|
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z});
|
||
|
-- abort if this check cannot be done
|
||
|
if( not(node_under) or node_under.name=="ignore") then
|
||
|
return;
|
||
|
end
|
||
|
-- search all acceptable ground names
|
||
|
for _,g in ipairs( sapling_data.grows_on ) do
|
||
|
if( g==node_under.name ) then
|
||
|
ground_found = g;
|
||
|
elseif( not( ground_found)
|
||
|
and string.sub(g,1,6)=="group:"
|
||
|
and minetest.get_item_group( node_under.name, string.sub(g,7))~=0 ) then
|
||
|
ground_found = g;
|
||
|
end
|
||
|
end
|
||
|
-- abort if the tree does not like this type of ground
|
||
|
if( not( ground_found )) then
|
||
|
-- trun into dry shrub
|
||
|
trees_lib.failed_to_grow( pos, node );
|
||
|
return;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- the tree may come with a more complex function that checks if it can grow there
|
||
|
if( not(force_grow) and sapling_data.can_grow and type( sapling_data.can_grow)=="function" ) then
|
||
|
-- the parameter ground_found is nil if the tree did not specify any demands for a particular ground
|
||
|
local ret = sapling_data.can_grow( pos, node, ground_found );
|
||
|
if( ret < 1 ) then
|
||
|
-- trun into dry shrub if growing failed finally (and was not just delayed)
|
||
|
if( ret==0 ) then
|
||
|
trees_lib.failed_to_grow( pos, node, ground_found );
|
||
|
end
|
||
|
return;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- each tree can have several ways of growing
|
||
|
local how_to_grow = nil;
|
||
|
-- the sapling may - depending on the circumstances - choose a specific growth function
|
||
|
-- instead of a random one
|
||
|
if( sapling_data.select_how_to_grow and type( sapling_data.select_how_to_grow)=="function") then
|
||
|
-- ground_found is nil if the tree did not specify any demands for a particular ground
|
||
|
how_to_grow = sapling_data.select_how_to_grow( pos, node, sapling_data.how_to_grow, ground_found );
|
||
|
-- the select_how_to_grow function may either return a table or a number indicating which
|
||
|
-- growth method to select
|
||
|
if( how_to_grow and type(how_to_grow)=="number" and sapling_data.how_to_grow[ how_to_grow ]) then
|
||
|
how_to_grow = sapling_data.how_to_grow[ how_to_grow ];
|
||
|
end
|
||
|
else -- else select a random one
|
||
|
how_to_grow = sapling_data.how_to_grow[ math.random( 1, #sapling_data.how_to_grow )];
|
||
|
end
|
||
|
|
||
|
-- this function may change the way the tree grows (i.e. select a special method for trees growing in flower pots or on stone ground)
|
||
|
how_to_grow = trees_lib.change_tree_growth( pos, node, how_to_grow );
|
||
|
|
||
|
-- actually grow the tree in a seperate function
|
||
|
trees_lib.tree_abm_grow_tree( pos, node, sapling_data, how_to_grow, force_grow );
|
||
|
end
|
||
|
|
||
|
|
||
|
-- actually grow the tree from a sapling
|
||
|
trees_lib.tree_abm_grow_tree = function( pos, node, sapling_data, how_to_grow, force_grow )
|
||
|
-- abort if no way was found to grow the tree
|
||
|
if( not( how_to_grow ) or type(how_to_grow)~="table") then
|
||
|
trees_lib.failed_to_grow( pos, node );
|
||
|
return;
|
||
|
|
||
|
-- grow the tree using a function (like the old apple trees did)
|
||
|
elseif( how_to_grow.use_function and type(how_to_grow.use_function)=="function") then
|
||
|
|
||
|
-- get the voxelmanip data
|
||
|
local vm = minetest.get_voxel_manip()
|
||
|
local minp, maxp = vm:read_from_map(
|
||
|
{x = pos.x - how_to_grow.xoff, y = pos.y - how_to_grow.yoff, z = pos.z - how_to_grow.zoff},
|
||
|
{x = pos.x + how_to_grow.xoff, y = pos.y + how_to_grow.height, z = pos.z + how_to_grow.zoff}
|
||
|
)
|
||
|
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
|
||
|
local data = vm:get_data()
|
||
|
|
||
|
how_to_grow.use_function( data, a, pos, sapling_data, how_to_grow.extra_params );
|
||
|
|
||
|
-- write the data back
|
||
|
vm:set_data(data)
|
||
|
vm:write_to_map()
|
||
|
vm:update_map()
|
||
|
|
||
|
|
||
|
-- grow the tree using a schematic
|
||
|
elseif( how_to_grow.use_schematic
|
||
|
and (type(how_to_grow.use_schematic)=="string"
|
||
|
or type(how_to_grow.use_schematic)=="table")) then
|
||
|
-- TODO: use voxelmanip
|
||
|
-- remove the sapling
|
||
|
minetest.set_node( pos, {name="air"});
|
||
|
-- TODO: determine xoff, yoff and zoff when registering the tree
|
||
|
-- (if yoff is not given, then use 0)
|
||
|
minetest.place_schematic(
|
||
|
{x = pos.x - how_to_grow.xoff,
|
||
|
y = pos.y - how_to_grow.yoff,
|
||
|
z = pos.z - how_to_grow.zoff},
|
||
|
how_to_grow.use_schematic, -- full path to the .mts file
|
||
|
"random", -- rotation
|
||
|
how_to_grow.use_replacements, -- use the same schematic for diffrent trees
|
||
|
false -- no overwriting of existing nodes
|
||
|
);
|
||
|
|
||
|
-- grow the tree using L-system
|
||
|
elseif( how_to_grow.use_lsystem and type(how_to_grow.use_lsystem)=="table") then
|
||
|
-- remove the sapling
|
||
|
minetest.set_node( pos, {name="air"});
|
||
|
-- spawn the l-system tree
|
||
|
minetest.spawn_tree(pos, how_to_grow.use_lsystem );
|
||
|
|
||
|
-- else prevent call of success function below
|
||
|
else
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
trees_lib.a_tree_has_grown( pos, node, how_to_grow );
|
||
|
end
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
-- register a new tree
|
||
|
-----------------------------------------------------------------------------
|
||
|
trees_lib.register_tree = function( tree_name, nodes, growing_methods, grows_on_node_type_list, can_grow_function, select_how_to_grow_function, interval, chance )
|
||
|
-- the tree name is the minimum needed in order to register a new tree
|
||
|
if( not( tree_name )) then
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
-- we may have to register nodes - and those have to be registered under the name of whichever mod called this function and is the "current" mod
|
||
|
local mod_prefix = "";
|
||
|
-- set it to the current mod - this cannot be done in the line above as that would set mod_prefix to trees_lib and not to the calling mod
|
||
|
mod_prefix = minetest.get_current_modname();
|
||
|
|
||
|
|
||
|
-- register tree trunk, wood, leaves and fruit (provided they are not defined yet)
|
||
|
local cid_list = trees_lib.register_tree_nodes( tree_name, mod_prefix, nodes );
|
||
|
|
||
|
-- a sapling will be needed for growing the tree
|
||
|
if( not( nodes.sapling )
|
||
|
or not( nodes.sapling.node_name )
|
||
|
or not( growing_methods )) then
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
-- store information about the new tree type in the sapling table
|
||
|
trees_lib.is_sapling[ nodes.sapling.node_name ] = {
|
||
|
|
||
|
-- minetest.get_content_id for tree, wood, leaves1..n, sapling, fruit
|
||
|
cid = cid_list,
|
||
|
|
||
|
-- node name of the sapling
|
||
|
sapling = nodes.sapling.node_name,
|
||
|
|
||
|
-- values passed on to all functions registered via
|
||
|
-- trees_lib.register_on_new_tree_type = function( new_tree_type_function )
|
||
|
tree_name = tree_name,
|
||
|
mod_prefix = mod_prefix,
|
||
|
nodes = nodes,
|
||
|
|
||
|
-- list of node names (can contain groups, i.e. "group:soil")
|
||
|
-- on which the sapling will grow;
|
||
|
-- note: the parameter ground_found to the functions below can only be
|
||
|
-- passed on if grows_on has been specified (else the sapling does
|
||
|
-- not do any ground checks on its own)
|
||
|
grows_on = grows_on_node_type_list,
|
||
|
|
||
|
-- are all the requirements met for growing at pos?
|
||
|
-- sapling will only grow if
|
||
|
-- growing.can_grow( pos, node, ground_found )
|
||
|
-- returns a value >0; if 0 is returned, the sapling will fail to grow
|
||
|
-- and be turned into dry shrub; if a value <0 is returned, nothing will
|
||
|
-- happen (the sapling can try again later on)
|
||
|
-- (usful for i.e. requiring water nearby, or other
|
||
|
-- more complex requirements)
|
||
|
can_grow = can_grow_function,
|
||
|
|
||
|
-- has to be either nil (for selecting a random way)
|
||
|
-- or return a specific growth function like the ones in
|
||
|
-- the list how_to_grow (see below) when called with
|
||
|
-- growing.select_how_to_grow( pos, node, growing.how_to_grow, ground_found )
|
||
|
select_how_to_grow = select_how_to_grow_function,
|
||
|
|
||
|
-- list of all methods that can turn the sapling into a
|
||
|
-- tree; can be a function, a file name containing a schematic
|
||
|
-- or a table for L-system trees;
|
||
|
-- this table/list is REQUIRED
|
||
|
how_to_grow = growing_methods,
|
||
|
};
|
||
|
|
||
|
-- a new tree was registered - call all functions that want to be told about new trees
|
||
|
for i,new_tree_type_function in ipairs( trees_lib.register_on_new_tree_type_function_list ) do
|
||
|
new_tree_type_function( tree_name, mod_prefix, nodes );
|
||
|
end
|
||
|
|
||
|
-- set default values for the tree-growing abm if none are set
|
||
|
if( not( interval)) then
|
||
|
interval = 10;
|
||
|
end
|
||
|
if( not( chance )) then
|
||
|
chance = 50;
|
||
|
end
|
||
|
-- now add the abm that lets the tree grow
|
||
|
minetest.register_abm({
|
||
|
nodenames = { nodes.sapling.node_name },
|
||
|
interval = interval,
|
||
|
chance = chance,
|
||
|
action = trees_lib.tree_abm_called,
|
||
|
});
|
||
|
end
|