zegaton_game/mods/conifers/init.lua

525 lines
14 KiB
Lua

--------------------------------------------------------------------------------
--
-- CONIFERS MOD 0.3
-- For Minetest-c55
-- Created by Cisoun (cysoun[at]gmail.com).
--
-- This mod adds some conifers randomly at a certain altitude.
-- There are two types of conifers: regular and narrow.
-- You can define the altitude at which they spawn and their structure and
-- choose if you want to keep normal trees above this altitude.
--
--------------------------------------------------------------------------------
-- Structure definitions.
local TRUNK_MINHEIGHT = 7
local TRUNK_MAXHEIGHT = 25
local LEAVES_MINHEIGHT = 2
local LEAVES_MAXHEIGHT = 6
local LEAVES_MAXRADIUS = 5
local LEAVES_NARROWRADIUS = 3 -- For narrow typed conifers.
local CONIFERS_DISTANCE = 4
local CONIFERS_ALTITUDE = 30
local REMOVE_TREES = false -- Remove trees above CONIFERS_ALTITUDE?
local SAPLING_CHANCE = 100 -- 1/x chances to grow a sapling.
local INTERVAL = 1800
-- End of structure definitions.
conifers = {}
--------------------------------------------------------------------------------
--
-- Definitions
--
--------------------------------------------------------------------------------
--
-- Node definitions
--
minetest.register_node("conifers:trunk", {
description = "Conifer trunk",
tile_images = {
"conifers_trunktop.png",
"conifers_trunktop.png",
"conifers_trunk.png",
"conifers_trunk.png",
"conifers_trunk.png",
"conifers_trunk.png"
},
--inventory_image = minetest.inventorycube(
--"conifers_trunktop.png",
--"conifers_trunk.png",
--"conifers_trunk.png"
--),
paramtype = "facedir_simple",
material = minetest.digprop_woodlike(1.0),
is_ground_content = true,
groups = {
tree = 1,
snappy = 2,
choppy = 2,
oddly_breakable_by_hand = 1,
flammable = 2
},
sounds = default.node_sound_wood_defaults()
})
minetest.register_node("conifers:trunk_reversed", {
description = "Conifer reversed trunk",
tile_images = {
"conifers_trunk_reversed.png",
"conifers_trunk_reversed.png",
"conifers_trunktop.png",
"conifers_trunktop.png",
"conifers_trunk_reversed.png",
"conifers_trunk_reversed.png"
},
--inventory_image = minetest.inventorycube(
--"conifers_trunk.png",
--"conifers_trunktop.png",
--"conifers_trunk.png"
--),
paramtype = "facedir_simple",
material = minetest.digprop_woodlike(1.0),
legacy_facedir_simple = true,
is_ground_content = true,
groups = {
tree = 1,
snappy = 2,
choppy = 2,
oddly_breakable_by_hand = 1,
flammable = 2
},
sounds = default.node_sound_wood_defaults()
})
minetest.register_node("conifers:leaves", {
description = "Conifer leaves",
drawtype = "allfaces_optional",
visual_scale = 1.3,
tile_images = { "conifers_leaves.png" },
--inventory_image = "conifers_leaves.png",
paramtype = "light",
groups = {
snappy = 3,
leafdecay = 3,
flammable = 2
},
drop = {
max_items = 1,
items = {
{
-- player will get sapling with 1/20 chance
items = {'conifers:sapling'},
rarity = 20,
},
{
-- player will get leaves only if he get no saplings,
-- this is because max_items is 1
items = {'conifers:leaves'},
}
}
},
sounds = default.node_sound_leaves_defaults()
})
minetest.register_node("conifers:leaves_special", {
description = "Bright conifer leaves",
drawtype = "allfaces_optional",
visual_scale = 1.3,
tile_images = { "conifers_leaves_special.png" },
--inventory_image = "conifers_leaves_special.png",
paramtype = "light",
groups = {
snappy = 3,
leafdecay = 3,
flammable = 2
},
drop = {
max_items = 1,
items = {
{
-- player will get sapling with 1/20 chance
items = {'conifers:sapling'},
rarity = 20,
},
{
-- player will get leaves only if he get no saplings,
-- this is because max_items is 1
items = {'conifers:leaves'},
}
}
},
sounds = default.node_sound_leaves_defaults()
})
minetest.register_node("conifers:sapling", {
description = "Conifer sapling",
drawtype = "plantlike",
visual_scale = 1.0,
tile_images = {"conifers_sapling.png"},
inventory_image = "conifers_sapling.png",
wield_image = "conifers_sapling.png",
paramtype = "light",
walkable = false,
groups = {
snappy = 2,
dig_immediate = 3,
flammable = 2
},
sounds = default.node_sound_defaults(),
})
--
-- Craft definitions
--
minetest.register_craft({
output = 'node "conifers:trunk_reversed" 2',
recipe = {
{'node "conifers:trunk"', 'node "conifers:trunk"'},
}
})
minetest.register_craft({
output = 'node "conifers:trunk" 2',
recipe = {
{'node "conifers:trunk_reversed"'},
{'node "conifers:trunk_reversed"'}
}
})
minetest.register_craft({
output = 'default:wood 4',
recipe = {
{'conifers:trunk'}
}
})
minetest.register_craft({
output = 'default:wood 4',
recipe = {
{'conifers:trunk_reversed'}
}
})
--
-- ABM definitions
--
-- Spawn random conifers.
minetest.register_abm({
nodenames = "default:dirt_with_grass",
interval = INTERVAL,
chance = 1,
action = function(pos, node, _, _)
if minetest.env:get_node({x = pos.x, y = pos.y + 1, z = pos.z}).name == "air"
and pos.y >= CONIFERS_ALTITUDE
and conifers:is_node_in_cube({"conifers:trunk"}, pos, CONIFERS_DISTANCE) == false
then
if math.random(0,1000) == 5 then
conifers:make_conifer({x = pos.x, y = pos.y + 1, z = pos.z}, math.random(0, 1))
end
end
end
})
-- Saplings.
minetest.register_abm({
nodenames = "conifers:sapling",
interval = INTERVAL,
chance = SAPLING_CHANCE,
action = function(pos, node, _, _)
if minetest.env:get_node({x = pos.x, y = pos.y + 1, z = pos.z}).name == "air" then
conifers:make_conifer({x = pos.x, y = pos.y, z = pos.z}, math.random(0, 1))
end
end
})
-- Should we remove all the trees above the conifers altitude?
if REMOVE_TREES == true then
minetest.register_abm({
nodenames = {
"default:tree",
"default:leaves"
},
interval = INTERVAL/100,
chance = 1,
action = function(pos, node, _, _)
if minetest.env:get_node({x = pos.x, y = pos.y + 1, z = pos.z}).name == "air"
and pos.y >= CONIFERS_ALTITUDE
then
minetest.env:add_node(pos , {name = "air"})
end
end
})
end
--------------------------------------------------------------------------------
--
-- Functions
--
--------------------------------------------------------------------------------
--
-- table_contains(t, v)
--
-- Taken from the Flowers mod by erlehmann.
--
function conifers:table_contains(t, v)
for _, i in ipairs(t) do
if (i == v) then
return true
end
end
return false
end
--
-- is_node_in_cube(nodenames, node_pos, radius)
--
-- Taken from the Flowers mod by erlehmann.
--
function conifers:is_node_in_cube(nodenames, node_pos, radius)
for x = node_pos.x - radius, node_pos.x + radius do
for y = node_pos.y - math.floor(radius / 2), node_pos.y + math.floor(radius / 2) do
for z = node_pos.z - radius, node_pos.z + radius do
n = minetest.env:get_node_or_nil({x = x, y = y, z = z})
if (n == nil)
or (n.name == 'ignore')
or (conifers:table_contains(nodenames, n.name) == true) then
return true
end
end
end
end
return false
end
--
-- are_leaves_surrounded(position)
--
-- Return a boolean value set to 'true' if a leaves block is surrounded
-- by something else than
-- - air
-- - leaves
-- - special leaves
--
-- If a leaves block is surrounded by the blocks above,
-- it can be placed.
-- Otherwise, it will replace blocks we want to keep.
--
function conifers:are_leaves_surrounded(pos)
--
-- Check if a leaves block does not interfer with something else than the air or another leaves block.
--
local node1 = minetest.env:get_node({x = pos.x + 1, y = pos.y, z = pos.z}).name
local node2 = minetest.env:get_node({x = pos.x - 1, y = pos.y, z = pos.z}).name
local node3 = minetest.env:get_node({x = pos.x, y = pos.y, z = pos.z + 1}).name
local node4 = minetest.env:get_node({x = pos.x, y = pos.y, z = pos.z - 1}).name
local replacable_nodes = {
"air",
"conifers:leaves",
"conifers:leaves_special"
}
-- Let's check if the neighboring node is a replacable node.
if (conifers:table_contains(replacable_nodes, node1) == true)
and (conifers:table_contains(replacable_nodes, node2) == true)
and (conifers:table_contains(replacable_nodes, node3) == true)
and (conifers:table_contains(replacable_nodes, node4) == true)
then
return false
else
return true
end
end
--
-- add_leaves_block(position, type of leaves, near trunk?)
--
-- Put a simple leaves block.
-- Leaves must be positioned near a trunk or surrounded by air.
-- Types of leaves are:
-- 0: dark leaves
-- 1: bright leaves (special)
--
function conifers:add_leaves_block(pos, special, near_trunk)
if conifers:are_leaves_surrounded(pos) == false or near_trunk == true then
if special == 0 then
minetest.env:add_node(pos , { name = "conifers:leaves" })
else
minetest.env:add_node(pos , { name = "conifers:leaves_special" })
end
end
end
--
-- make_leaves(middle point, min radius, max radius, type of leaves)
--
-- Make a circle of leaves with a center given by 'middle point'.
-- Types of leaves are:
-- 0: dark leaves
-- 1: bright leaves (special)
--
function conifers:make_leaves(c, radius_min, radius_max, special)
--
-- Using the midpoint circle algorithm from Bresenham we can trace a circle of leaves.
--
for r = radius_min, radius_max do
local m_x = 0
local m_z = r
local m_m = 5 - 4 * r
while m_x <= m_z do
if radius_max > 1 then
if r == 1 then
-- Add a square of leaves (fixing holes near the trunk).
-- [ ] [ ]
-- [#]
-- [ ] [ ]
conifers:add_leaves_block({x = -1 + c.x, y = c.y, z = 1 + c.z}, special)
conifers:add_leaves_block({x = 1 + c.x, y = c.y, z = 1 + c.z}, special)
conifers:add_leaves_block({x = -1 + c.x, y = c.y, z = -1 + c.z}, special)
conifers:add_leaves_block({x = 1 + c.x, y = c.y, z = -1 + c.z}, special)
-- [ ]
-- [ ][#][ ]
-- [ ]
conifers:add_leaves_block({x = c.x, y = c.y, z = -1 + c.z}, special, true)
conifers:add_leaves_block({x = c.x, y = c.y, z = 1 + c.z}, special, true)
conifers:add_leaves_block({x = -1 + c.x, y = c.y, z = c.z}, special, true)
conifers:add_leaves_block({x = 1 + c.x, y = c.y, z = c.z}, special, true)
else
conifers:add_leaves_block({x = m_x + c.x, y = c.y, z = m_z + c.z}, special)
conifers:add_leaves_block({x = m_z + c.x, y = c.y, z = m_x + c.z}, special)
conifers:add_leaves_block({x = -m_x + c.x, y = c.y, z = m_z + c.z}, special)
conifers:add_leaves_block({x = -m_z + c.x, y = c.y, z = m_x + c.z}, special)
conifers:add_leaves_block({x = m_x + c.x, y = c.y, z = -m_z + c.z}, special)
conifers:add_leaves_block({x = m_z + c.x, y = c.y, z = -m_x + c.z}, special)
conifers:add_leaves_block({x = -m_x + c.x, y = c.y, z = -m_z + c.z}, special)
conifers:add_leaves_block({x = -m_z + c.x, y = c.y, z = -m_x + c.z}, special)
end
else
-- Put a small circle of leaves around the trunk.
-- [ ]
-- [ ][#][ ]
-- [ ]
conifers:add_leaves_block({x = c.x, y = c.y, z = -1 + c.z}, special, true)
conifers:add_leaves_block({x = c.x, y = c.y, z = 1 + c.z}, special, true)
conifers:add_leaves_block({x = -1 + c.x, y = c.y, z = c.z}, special, true)
conifers:add_leaves_block({x = 1 + c.x, y = c.y, z = c.z}, special, true)
end
-- Stuff...
if m_m > 0 then
m_z = m_z - 1
m_m = m_m - 8 * m_z
end
m_x = m_x + 1
m_m = m_m + 8 * m_x + 4
end
end
end
--
-- make_conifer(position, type)
--
-- Make a conifer at a given position.
-- Types are:
-- 0: regular pine
-- 1: narrow pine
--
function conifers:make_conifer(pos, conifer_type)
-- Check if we can gros a conifer at this place.
if minetest.env:get_node({x = pos.x, y = pos.y - 1, z = pos.z}).name ~= "default:dirt_with_grass"
and (minetest.env:get_node({x = pos.x, y = pos.y, z = pos.z}).name ~= "air"
or minetest.env:get_node({x = pos.x, y = pos.y, z = pos.z}).name ~= "conifers:sapling"
)
then
return false
--else
--if minetest.env:get_node({x = pos.x, y = pos.y, z = pos.z}).name == "conifers:sapling" then
--minetest.env:add_node(pos , {name = "air"})
--end
end
local height = math.random(TRUNK_MINHEIGHT, TRUNK_MAXHEIGHT) -- Random height of the conifer.
local leaves_height = math.random(LEAVES_MINHEIGHT, LEAVES_MAXHEIGHT) -- Level from where the leaves grow.
local current_block = {} -- Duh...
local leaves_radius = 1
local leaves_max_radius = 2
local special = math.random(0, 1)
-- Let's check if we can grow a tree here.
-- That means, we must have a column of 'height' high which contains
-- only air.
for j = 1, height - 1 do -- Start from 1 so we can grow a sapling.
if minetest.env:get_node({x = pos.x, y = pos.y + j, z = pos.z}).name ~= "air" then
-- Abort
return false
end
end
-- Create the trunk and add the leaves.
for i = 0, height - 1 do
current_block = {
x = pos.x,
y = pos.y + i,
z = pos.z
}
-- Put a trunk block.
minetest.env:add_node(current_block , {name = "conifers:trunk"})
-- Put some leaves.
if i >= leaves_height then
-- Put some leaves.
conifers:make_leaves({x = pos.x, y = pos.y + leaves_height + (height - 1) - i, z = pos.z}, 1, leaves_radius, special)
--
-- TYPE OF CONIFER
--
if conifer_type == 1 then -- Regular type
-- Prepare the next circle of leaves.
leaves_radius = leaves_radius + 1
-- Check if the current radius is the maximum radius at this level.
if leaves_radius > leaves_max_radius then
leaves_radius = 1
leaves_max_radius = leaves_max_radius + 1
-- Does it exceeds the maximum radius?
if leaves_max_radius > LEAVES_MAXRADIUS then
leaves_max_radius = LEAVES_MAXRADIUS
end
end
else -- Narrow type
if i % 2 == 0 then
leaves_radius = LEAVES_NARROWRADIUS - math.random(0, 1)
else
leaves_radius = math.floor(LEAVES_NARROWRADIUS / 2)
end
end
end
end
-- Put a top leaves block.
current_block.y = current_block.y + 1
conifers:add_leaves_block(current_block, special)
-- Blahblahblah
print ('[conifers] A conifer has grown at (' .. pos.x .. ',' .. pos.y .. ',' .. pos.z .. ') with a height of ' .. (height))
return true
end