1
0
mirror of https://github.com/minetest/minetest_game.git synced 2024-12-23 15:20:19 +01:00
minetest_game/mods/default/trees.lua

536 lines
14 KiB
Lua
Raw Normal View History

local random = math.random
2014-06-13 20:03:14 +02:00
--
-- Grow trees from saplings
2014-06-13 20:03:14 +02:00
--
-- 'can grow' function
2014-06-13 20:03:14 +02:00
function default.can_grow(pos)
2014-06-13 20:03:14 +02:00
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
if not node_under then
return false
end
local name_under = node_under.name
local is_soil = minetest.get_item_group(name_under, "soil")
if is_soil == 0 then
return false
end
local light_level = minetest.get_node_light(pos)
if not light_level or light_level < 13 then
return false
end
2014-06-13 20:03:14 +02:00
return true
end
-- 'is snow nearby' function
local function is_snow_nearby(pos)
return minetest.find_node_near(pos, 1, {"group:snowy"})
end
-- Grow sapling
2014-06-13 20:03:14 +02:00
function default.grow_sapling(pos)
if not default.can_grow(pos) then
-- try again 5 min later
minetest.get_node_timer(pos):start(300)
return
end
local mg_name = minetest.get_mapgen_setting("mg_name")
local node = minetest.get_node(pos)
if node.name == "default:sapling" then
minetest.log("action", "A sapling grows into a tree at "..
minetest.pos_to_string(pos))
if mg_name == "v6" then
default.grow_tree(pos, random(1, 4) == 1)
else
default.grow_new_apple_tree(pos)
end
elseif node.name == "default:junglesapling" then
minetest.log("action", "A jungle sapling grows into a tree at "..
minetest.pos_to_string(pos))
if mg_name == "v6" then
default.grow_jungle_tree(pos)
else
default.grow_new_jungle_tree(pos)
end
elseif node.name == "default:pine_sapling" then
minetest.log("action", "A pine sapling grows into a tree at "..
minetest.pos_to_string(pos))
local snow = is_snow_nearby(pos)
if mg_name == "v6" then
default.grow_pine_tree(pos, snow)
elseif snow then
default.grow_new_snowy_pine_tree(pos)
else
default.grow_new_pine_tree(pos)
end
elseif node.name == "default:acacia_sapling" then
minetest.log("action", "An acacia sapling grows into a tree at "..
minetest.pos_to_string(pos))
default.grow_new_acacia_tree(pos)
elseif node.name == "default:aspen_sapling" then
minetest.log("action", "An aspen sapling grows into a tree at "..
minetest.pos_to_string(pos))
default.grow_new_aspen_tree(pos)
elseif node.name == "default:bush_sapling" then
minetest.log("action", "A bush sapling grows into a bush at "..
minetest.pos_to_string(pos))
default.grow_bush(pos)
elseif node.name == "default:acacia_bush_sapling" then
minetest.log("action", "An acacia bush sapling grows into a bush at "..
minetest.pos_to_string(pos))
default.grow_acacia_bush(pos)
end
end
minetest.register_lbm({
name = "default:convert_saplings_to_node_timer",
nodenames = {"default:sapling", "default:junglesapling",
"default:pine_sapling", "default:acacia_sapling",
"default:aspen_sapling"},
action = function(pos)
minetest.get_node_timer(pos):start(math.random(300, 1500))
end
})
--
-- Tree generation
--
2014-06-13 20:03:14 +02:00
-- Apple tree and jungle tree trunk and leaves function
2014-06-13 20:03:14 +02:00
local function add_trunk_and_leaves(data, a, pos, tree_cid, leaves_cid,
height, size, iters, is_apple_tree)
local x, y, z = pos.x, pos.y, pos.z
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_apple = minetest.get_content_id("default:apple")
2014-06-13 20:03:14 +02:00
-- Trunk
data[a:index(x, y, z)] = tree_cid -- Force-place lowest trunk node to replace sapling
for yy = y + 1, y + height - 1 do
local vi = a:index(x, yy, z)
local node_id = data[vi]
if node_id == c_air or node_id == c_ignore or node_id == leaves_cid then
2014-06-13 20:03:14 +02:00
data[vi] = tree_cid
end
end
-- Force leaves near the trunk
for z_dist = -1, 1 do
for y_dist = -size, 1 do
local vi = a:index(x - 1, y + height + y_dist, z + z_dist)
for x_dist = -1, 1 do
if data[vi] == c_air or data[vi] == c_ignore then
2014-06-13 20:03:14 +02:00
if is_apple_tree and random(1, 8) == 1 then
data[vi] = c_apple
else
data[vi] = leaves_cid
end
end
vi = vi + 1
end
end
end
-- Randomly add leaves in 2x2x2 clusters.
for i = 1, iters do
local clust_x = x + random(-size, size - 1)
local clust_y = y + height + random(-size, 0)
local clust_z = z + random(-size, size - 1)
for xi = 0, 1 do
for yi = 0, 1 do
for zi = 0, 1 do
local vi = a:index(clust_x + xi, clust_y + yi, clust_z + zi)
if data[vi] == c_air or data[vi] == c_ignore then
2014-06-13 20:03:14 +02:00
if is_apple_tree and random(1, 8) == 1 then
data[vi] = c_apple
else
data[vi] = leaves_cid
end
end
end
end
end
end
end
-- Apple tree
2014-06-13 20:03:14 +02:00
function default.grow_tree(pos, is_apple_tree, bad)
--[[
NOTE: Tree-placing code is currently duplicated in the engine
and in games that have saplings; both are deprecated but not
replaced yet
--]]
if bad then
error("Deprecated use of default.grow_tree")
end
local x, y, z = pos.x, pos.y, pos.z
local height = random(4, 5)
local c_tree = minetest.get_content_id("default:tree")
local c_leaves = minetest.get_content_id("default:leaves")
2014-06-13 20:03:14 +02:00
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map(
{x = x - 2, y = y, z = z - 2},
{x = x + 2, y = y + height + 1, z = z + 2}
2014-06-13 20:03:14 +02:00
)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
add_trunk_and_leaves(data, a, pos, c_tree, c_leaves, height, 2, 8, is_apple_tree)
vm:set_data(data)
vm:write_to_map()
vm:update_map()
end
-- Jungle tree
function default.grow_jungle_tree(pos, bad)
2014-06-13 20:03:14 +02:00
--[[
NOTE: Jungletree-placing code is currently duplicated in the engine
2014-06-13 20:03:14 +02:00
and in games that have saplings; both are deprecated but not
replaced yet
--]]
if bad then
error("Deprecated use of default.grow_jungle_tree")
2014-06-13 20:03:14 +02:00
end
local x, y, z = pos.x, pos.y, pos.z
local height = random(8, 12)
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_jungletree = minetest.get_content_id("default:jungletree")
local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
2014-06-13 20:03:14 +02:00
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map(
{x = x - 3, y = y - 1, z = z - 3},
{x = x + 3, y = y + height + 1, z = z + 3}
)
2014-06-13 20:03:14 +02:00
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
add_trunk_and_leaves(data, a, pos, c_jungletree, c_jungleleaves,
height, 3, 30, false)
2014-06-13 20:03:14 +02:00
-- Roots
for z_dist = -1, 1 do
local vi_1 = a:index(x - 1, y - 1, z + z_dist)
local vi_2 = a:index(x - 1, y, z + z_dist)
2014-06-13 20:03:14 +02:00
for x_dist = -1, 1 do
if random(1, 3) >= 2 then
if data[vi_1] == c_air or data[vi_1] == c_ignore then
2014-06-13 20:03:14 +02:00
data[vi_1] = c_jungletree
elseif data[vi_2] == c_air or data[vi_2] == c_ignore then
2014-06-13 20:03:14 +02:00
data[vi_2] = c_jungletree
end
end
vi_1 = vi_1 + 1
vi_2 = vi_2 + 1
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
end
2014-06-13 20:03:14 +02:00
-- Pine tree from mg mapgen mod, design by sfan5, pointy top added by paramat
local function add_pine_needles(data, vi, c_air, c_ignore, c_snow, c_pine_needles)
local node_id = data[vi]
if node_id == c_air or node_id == c_ignore or node_id == c_snow then
data[vi] = c_pine_needles
end
end
local function add_snow(data, vi, c_air, c_ignore, c_snow)
local node_id = data[vi]
if node_id == c_air or node_id == c_ignore then
data[vi] = c_snow
end
end
function default.grow_pine_tree(pos, snow)
local x, y, z = pos.x, pos.y, pos.z
local maxy = y + random(9, 13) -- Trunk top
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_pine_tree = minetest.get_content_id("default:pine_tree")
local c_pine_needles = minetest.get_content_id("default:pine_needles")
local c_snow = minetest.get_content_id("default:snow")
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map(
{x = x - 3, y = y, z = z - 3},
{x = x + 3, y = maxy + 3, z = z + 3}
)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
-- Upper branches layer
local dev = 3
for yy = maxy - 1, maxy + 1 do
for zz = z - dev, z + dev do
local vi = a:index(x - dev, yy, zz)
local via = a:index(x - dev, yy + 1, zz)
for xx = x - dev, x + dev do
if random() < 0.95 - dev * 0.05 then
add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
if snow then
add_snow(data, via, c_air, c_ignore, c_snow)
end
end
vi = vi + 1
via = via + 1
end
end
dev = dev - 1
end
-- Centre top nodes
add_pine_needles(data, a:index(x, maxy + 1, z), c_air, c_ignore, c_snow,
c_pine_needles)
add_pine_needles(data, a:index(x, maxy + 2, z), c_air, c_ignore, c_snow,
c_pine_needles) -- Paramat added a pointy top node
if snow then
add_snow(data, a:index(x, maxy + 3, z), c_air, c_ignore, c_snow)
end
-- Lower branches layer
local my = 0
for i = 1, 20 do -- Random 2x2 squares of needles
local xi = x + random(-3, 2)
local yy = maxy + random(-6, -5)
local zi = z + random(-3, 2)
if yy > my then
my = yy
end
for zz = zi, zi+1 do
local vi = a:index(xi, yy, zz)
local via = a:index(xi, yy + 1, zz)
for xx = xi, xi + 1 do
add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
if snow then
add_snow(data, via, c_air, c_ignore, c_snow)
end
vi = vi + 1
via = via + 1
end
end
end
dev = 2
for yy = my + 1, my + 2 do
for zz = z - dev, z + dev do
local vi = a:index(x - dev, yy, zz)
local via = a:index(x - dev, yy + 1, zz)
for xx = x - dev, x + dev do
if random() < 0.95 - dev * 0.05 then
add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
if snow then
add_snow(data, via, c_air, c_ignore, c_snow)
end
end
vi = vi + 1
via = via + 1
end
end
dev = dev - 1
end
-- Trunk
-- Force-place lowest trunk node to replace sapling
data[a:index(x, y, z)] = c_pine_tree
for yy = y + 1, maxy do
local vi = a:index(x, yy, z)
local node_id = data[vi]
if node_id == c_air or node_id == c_ignore or
node_id == c_pine_needles or node_id == c_snow then
data[vi] = c_pine_tree
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
end
-- New apple tree
function default.grow_new_apple_tree(pos)
local path = minetest.get_modpath("default") ..
"/schematics/apple_tree_from_sapling.mts"
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
path, "random", nil, false)
end
-- New jungle tree
function default.grow_new_jungle_tree(pos)
local path = minetest.get_modpath("default") ..
"/schematics/jungle_tree_from_sapling.mts"
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
path, "random", nil, false)
end
-- New pine tree
function default.grow_new_pine_tree(pos)
local path = minetest.get_modpath("default") ..
"/schematics/pine_tree_from_sapling.mts"
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
path, "0", nil, false)
end
-- New snowy pine tree
function default.grow_new_snowy_pine_tree(pos)
local path = minetest.get_modpath("default") ..
"/schematics/snowy_pine_tree_from_sapling.mts"
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
path, "random", nil, false)
end
-- New acacia tree
function default.grow_new_acacia_tree(pos)
local path = minetest.get_modpath("default") ..
"/schematics/acacia_tree_from_sapling.mts"
minetest.place_schematic({x = pos.x - 4, y = pos.y - 1, z = pos.z - 4},
path, "random", nil, false)
end
Aspen trees. Adds a birch-like tree to the default_game. Aspen was chosen on purpose instead of birch, as several birch tree mods already exist and choosing a different name avoids any conflicts. Schematics were made for both normal and sapling version, assuring saplings will not be able to grief. The shape of the Aspen is "fanning out at the top" and provides an easy tree to walk under, but still a somewhat thick cover. The Aspen trunk is 4 to 6 blocks tall, with up to three layers of leaves on top, making it slightly taller than an Apple tree, but shorter than a Pine tree, which provides a good blend. Textures were painted from scratch, except tree_top and _wood variants, which are color modified versions of the pine_wood variants. Appropriate licenses have been chosen for the new textures. The leaf texture is light enough to contrast other trees, but dark enough to offset against our light default grass color. The leaves are drawn in the typical minetest default fashion with plenty of transparancy, but enough definition to suggest that you're seeing something that looks like leaves. The placement of leaves in the schematic also suggests the top of the tree is sparse and you can see the sky through the leaves. Sapling texture is both traditional and different, with lush green leaves and a well-defined stem, but slightly stick-like and skinny, as these plants tend to grow up first, then out. Add fallen Aspen logs. We make these logs a minimum of 2 blocks long, and up to 3. This allows us to make these logs a place where both red and brown mushrooms can be found, to these may be attractive to players. However, the spawn rate for these has been reduced a lot compared to the other logs, to account for the scarcity of Aspen. Add stairs, slabs for these wood types as well. Mapgen will place these trees in deciduous forests only, but in a way that the biome is a range between entirely Apple trees, and mostly entirely Aspen trees, with a bias to Apple trees. To make fallen logs somewhat correlated with trees, we modify the planting of Apple trees and logs to use perlin noise and not fill ratio, otherwise you'd always end up with Apple logs in Aspen tree areas, which would be suspicious. There still is a bit of a mix.
2016-01-05 02:56:20 +01:00
Aspen trees. Adds a birch-like tree to the default_game. Aspen was chosen on purpose instead of birch, as several birch tree mods already exist and choosing a different name avoids any conflicts. Schematics were made for both normal and sapling version, assuring saplings will not be able to grief. The shape of the Aspen is "fanning out at the top" and provides an easy tree to walk under, but still a somewhat thick cover. The Aspen trunk is 4 to 6 blocks tall, with up to three layers of leaves on top, making it slightly taller than an Apple tree, but shorter than a Pine tree, which provides a good blend. Textures were painted from scratch, except tree_top and _wood variants, which are color modified versions of the pine_wood variants. Appropriate licenses have been chosen for the new textures. The leaf texture is light enough to contrast other trees, but dark enough to offset against our light default grass color. The leaves are drawn in the typical minetest default fashion with plenty of transparancy, but enough definition to suggest that you're seeing something that looks like leaves. The placement of leaves in the schematic also suggests the top of the tree is sparse and you can see the sky through the leaves. Sapling texture is both traditional and different, with lush green leaves and a well-defined stem, but slightly stick-like and skinny, as these plants tend to grow up first, then out. Add fallen Aspen logs. We make these logs a minimum of 2 blocks long, and up to 3. This allows us to make these logs a place where both red and brown mushrooms can be found, to these may be attractive to players. However, the spawn rate for these has been reduced a lot compared to the other logs, to account for the scarcity of Aspen. Add stairs, slabs for these wood types as well. Mapgen will place these trees in deciduous forests only, but in a way that the biome is a range between entirely Apple trees, and mostly entirely Aspen trees, with a bias to Apple trees. To make fallen logs somewhat correlated with trees, we modify the planting of Apple trees and logs to use perlin noise and not fill ratio, otherwise you'd always end up with Apple logs in Aspen tree areas, which would be suspicious. There still is a bit of a mix.
2016-01-05 02:56:20 +01:00
-- New aspen tree
function default.grow_new_aspen_tree(pos)
local path = minetest.get_modpath("default") ..
"/schematics/aspen_tree_from_sapling.mts"
Aspen trees. Adds a birch-like tree to the default_game. Aspen was chosen on purpose instead of birch, as several birch tree mods already exist and choosing a different name avoids any conflicts. Schematics were made for both normal and sapling version, assuring saplings will not be able to grief. The shape of the Aspen is "fanning out at the top" and provides an easy tree to walk under, but still a somewhat thick cover. The Aspen trunk is 4 to 6 blocks tall, with up to three layers of leaves on top, making it slightly taller than an Apple tree, but shorter than a Pine tree, which provides a good blend. Textures were painted from scratch, except tree_top and _wood variants, which are color modified versions of the pine_wood variants. Appropriate licenses have been chosen for the new textures. The leaf texture is light enough to contrast other trees, but dark enough to offset against our light default grass color. The leaves are drawn in the typical minetest default fashion with plenty of transparancy, but enough definition to suggest that you're seeing something that looks like leaves. The placement of leaves in the schematic also suggests the top of the tree is sparse and you can see the sky through the leaves. Sapling texture is both traditional and different, with lush green leaves and a well-defined stem, but slightly stick-like and skinny, as these plants tend to grow up first, then out. Add fallen Aspen logs. We make these logs a minimum of 2 blocks long, and up to 3. This allows us to make these logs a place where both red and brown mushrooms can be found, to these may be attractive to players. However, the spawn rate for these has been reduced a lot compared to the other logs, to account for the scarcity of Aspen. Add stairs, slabs for these wood types as well. Mapgen will place these trees in deciduous forests only, but in a way that the biome is a range between entirely Apple trees, and mostly entirely Aspen trees, with a bias to Apple trees. To make fallen logs somewhat correlated with trees, we modify the planting of Apple trees and logs to use perlin noise and not fill ratio, otherwise you'd always end up with Apple logs in Aspen tree areas, which would be suspicious. There still is a bit of a mix.
2016-01-05 02:56:20 +01:00
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
path, "0", nil, false)
Aspen trees. Adds a birch-like tree to the default_game. Aspen was chosen on purpose instead of birch, as several birch tree mods already exist and choosing a different name avoids any conflicts. Schematics were made for both normal and sapling version, assuring saplings will not be able to grief. The shape of the Aspen is "fanning out at the top" and provides an easy tree to walk under, but still a somewhat thick cover. The Aspen trunk is 4 to 6 blocks tall, with up to three layers of leaves on top, making it slightly taller than an Apple tree, but shorter than a Pine tree, which provides a good blend. Textures were painted from scratch, except tree_top and _wood variants, which are color modified versions of the pine_wood variants. Appropriate licenses have been chosen for the new textures. The leaf texture is light enough to contrast other trees, but dark enough to offset against our light default grass color. The leaves are drawn in the typical minetest default fashion with plenty of transparancy, but enough definition to suggest that you're seeing something that looks like leaves. The placement of leaves in the schematic also suggests the top of the tree is sparse and you can see the sky through the leaves. Sapling texture is both traditional and different, with lush green leaves and a well-defined stem, but slightly stick-like and skinny, as these plants tend to grow up first, then out. Add fallen Aspen logs. We make these logs a minimum of 2 blocks long, and up to 3. This allows us to make these logs a place where both red and brown mushrooms can be found, to these may be attractive to players. However, the spawn rate for these has been reduced a lot compared to the other logs, to account for the scarcity of Aspen. Add stairs, slabs for these wood types as well. Mapgen will place these trees in deciduous forests only, but in a way that the biome is a range between entirely Apple trees, and mostly entirely Aspen trees, with a bias to Apple trees. To make fallen logs somewhat correlated with trees, we modify the planting of Apple trees and logs to use perlin noise and not fill ratio, otherwise you'd always end up with Apple logs in Aspen tree areas, which would be suspicious. There still is a bit of a mix.
2016-01-05 02:56:20 +01:00
end
-- Bushes do not need 'from sapling' schematic variants because
-- only the stem node is force-placed in the schematic.
-- Bush
function default.grow_bush(pos)
local path = minetest.get_modpath("default") ..
"/schematics/bush.mts"
minetest.place_schematic({x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
path, "0", nil, false)
end
-- Acacia bush
function default.grow_acacia_bush(pos)
local path = minetest.get_modpath("default") ..
"/schematics/acacia_bush.mts"
minetest.place_schematic({x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
path, "0", nil, false)
end
--
-- Sapling 'on place' function to check protection of node and resulting tree volume
--
function default.sapling_on_place(itemstack, placer, pointed_thing,
sapling_name, minp_relative, maxp_relative, interval)
-- Position of sapling
local pos = pointed_thing.under
local node = minetest.get_node_or_nil(pos)
local pdef = node and minetest.registered_nodes[node.name]
if pdef and pdef.on_rightclick and not placer:get_player_control().sneak then
return pdef.on_rightclick(pos, node, placer, itemstack, pointed_thing)
end
if not pdef or not pdef.buildable_to then
pos = pointed_thing.above
node = minetest.get_node_or_nil(pos)
pdef = node and minetest.registered_nodes[node.name]
if not pdef or not pdef.buildable_to then
return itemstack
end
end
local player_name = placer:get_player_name()
-- Check sapling position for protection
if minetest.is_protected(pos, player_name) then
minetest.record_protection_violation(pos, player_name)
return itemstack
end
-- Check tree volume for protection
if default.intersects_protection(
vector.add(pos, minp_relative),
vector.add(pos, maxp_relative),
player_name,
interval) then
minetest.record_protection_violation(pos, player_name)
-- Print extra information to explain
minetest.chat_send_player(player_name, "Tree will intersect protection")
return itemstack
end
minetest.log("action", player_name .. " places node "
.. sapling_name .. " at " .. minetest.pos_to_string(pos))
local take_item = not (creative and creative.is_enabled_for
and creative.is_enabled_for(player_name))
local newnode = {name = sapling_name}
local ndef = minetest.registered_nodes[sapling_name]
minetest.set_node(pos, newnode)
-- Run callback
if ndef and ndef.after_place_node then
-- Deepcopy place_to and pointed_thing because callback can modify it
if ndef.after_place_node(table.copy(pos), placer,
itemstack, table.copy(pointed_thing)) then
take_item = false
end
end
-- Run script hook
for _, callback in ipairs(minetest.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
if callback(table.copy(pos), table.copy(newnode),
placer, table.copy(node or {}),
itemstack, table.copy(pointed_thing)) then
take_item = false
end
end
if take_item then
itemstack:take_item()
end
return itemstack
end