mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-22 02:21:06 +01:00
Add mcl_util.trace_node(), rewrite bamboo growth code to fix bone meal growth
This commit is contained in:
parent
4eda77acd1
commit
66b5a369f1
2 changed files with 84 additions and 150 deletions
|
@ -1131,3 +1131,25 @@ if not vector.in_area then
|
|||
(pos.z >= min.z) and (pos.z <= max.z)
|
||||
end
|
||||
end
|
||||
|
||||
-- Traces along a line of nodes vertically to find the next possition that isn't an allowed node
|
||||
---@param pos The position to start tracing from
|
||||
---@param dir The direction to trace in (1 is up, -1 is down)
|
||||
---@param allowed_nodes A table of node names to trace along
|
||||
---@param limit The maximum number of steps to make. Defaults to 16 if nil or missing
|
||||
---@return Three return values:
|
||||
--- the position of the next node that isn't allowed or nil if no such node was found,
|
||||
--- the distance from the start where that node was found,
|
||||
--- the node table if a node was found
|
||||
function mcl_util.trace_nodes(pos, dir, allowed_nodes, limit)
|
||||
if not dir or dir == 0 or #allowed_nodes == 0 then return nil, 0, nil end
|
||||
limit = limit or 16
|
||||
|
||||
for i = 1,limit do
|
||||
pos = vector.offset(pos, 0, dir, 0)
|
||||
local node = minetest.get_node(pos)
|
||||
if table.indexof(allowed_nodes, node.name) == -1 then return pos, i, node end
|
||||
end
|
||||
|
||||
return nil, limit, nil
|
||||
end
|
||||
|
|
|
@ -94,172 +94,84 @@ end
|
|||
--]]
|
||||
|
||||
function mcl_bamboo.grow_bamboo(pos, bonemeal_applied)
|
||||
local log = mcl_bamboo.mcl_log
|
||||
local node_above = minetest.get_node(vector.offset(pos, 0, 1, 0))
|
||||
mcl_bamboo.mcl_log("Grow bamboo called; bonemeal: " .. tostring(bonemeal_applied))
|
||||
log("Grow bamboo called; bonemeal: " .. tostring(bonemeal_applied))
|
||||
|
||||
if not bonemeal_applied and mcl_bamboo.is_bamboo(node_above.name) ~= false then
|
||||
return false -- short circuit this function if we're trying to grow (std) the bamboo and it's not the top shoot.
|
||||
if not bonemeal_applied then
|
||||
-- Only allow natural growth at the top of the bamboo
|
||||
if mcl_bamboo.is_bamboo(node_above.name) ~= false then return false end
|
||||
|
||||
-- Don't perform natual growth in low light
|
||||
if minetest.get_node_light(pos) < 8 then return false end
|
||||
end
|
||||
if minetest.get_node_light(pos) < 8 then
|
||||
|
||||
-- Determine the location of soil
|
||||
local soil_pos
|
||||
soil_pos,a,b = mcl_util.trace_nodes(pos, -1, mcl_bamboo.bamboo_index, BAMBOO_MAX_HEIGHT - 1)
|
||||
|
||||
-- No soil found, return false so that bonemeal isn't used
|
||||
if not soil_pos then return false end
|
||||
log("Grow bamboo; soil found. ")
|
||||
|
||||
-- Find the first bamboo shoot and retrieve data about it
|
||||
local first_shoot = vector.offset(soil_pos, 0, 1, 0)
|
||||
local first_shoot_meta = minetest.get_meta(first_shoot)
|
||||
|
||||
-- Get or initialize bamboo height
|
||||
local height = (first_shoot_meta and first_shoot_meta:get_int("height", -1)) or -1
|
||||
if height == -1 then
|
||||
height = rand(BAM_MAX_HEIGHT_STPCHK + 1, BAM_MAX_HEIGHT_TOP + 1)
|
||||
first_shoot_meta:set_int("height", height)
|
||||
end
|
||||
log("Grow bamboo; height: " .. height)
|
||||
|
||||
-- Locate the bamboo tip
|
||||
local bamboo_tip,actual_height,bamboo_tip_node = mcl_util.trace_nodes(first_shoot, 1, mcl_bamboo.bamboo_index, height - 1)
|
||||
log("Current height: "..tostring(actual_height))
|
||||
|
||||
-- Short circuit growth if the bamboo is already finished growing
|
||||
if not bamboo_tip or not actual_height or actual_height >= height then
|
||||
log("Bamboo is already as large as it can grow")
|
||||
return false
|
||||
end
|
||||
|
||||
-- variables used in more than one spot.
|
||||
local first_shoot
|
||||
local chk_pos
|
||||
local soil_pos
|
||||
local node_name = ""
|
||||
local dist = 0
|
||||
local node_below
|
||||
-- -------------------
|
||||
-- Now that we are actually going to add nodes, initialize some more information
|
||||
local first_shoot_node_name = minetest.get_node(first_shoot).name
|
||||
|
||||
mcl_bamboo.mcl_log("Grow bamboo; checking for soil: ")
|
||||
-- the soil node below the bamboo.
|
||||
for py = -1, BAMBOO_SOIL_DIST, -1 do
|
||||
chk_pos = vector.offset(pos, 0, py, 0)
|
||||
node_name = minetest.get_node(chk_pos).name
|
||||
if mcl_bamboo.is_dirt(node_name) then
|
||||
soil_pos = chk_pos
|
||||
break
|
||||
end
|
||||
if mcl_bamboo.is_bamboo(node_name) == false then
|
||||
break
|
||||
end
|
||||
end
|
||||
-- requires knowing where the soil node is.
|
||||
if soil_pos == nil then
|
||||
return false -- returning false means don't use up the bonemeal.
|
||||
end
|
||||
|
||||
mcl_bamboo.mcl_log("Grow bamboo; soil found. ")
|
||||
local grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE) -- because yeah, not truly random, or even a good prng.
|
||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
||||
local init_height = rand(BAM_MAX_HEIGHT_STPCHK + 1, BAM_MAX_HEIGHT_TOP + 1)
|
||||
mcl_bamboo.mcl_log("Grow bamboo; random height: " .. init_height)
|
||||
|
||||
node_name = ""
|
||||
|
||||
-- update: add randomized max height to first node's meta data.
|
||||
first_shoot = vector.offset(soil_pos, 0, 1, 0)
|
||||
local meta = minetest.get_meta(first_shoot)
|
||||
node_below = minetest.get_node(first_shoot).name
|
||||
|
||||
mcl_bamboo.mcl_log("Grow bamboo; checking height meta ")
|
||||
-- check the meta data for the first node, to see how high to make the stalk.
|
||||
if not meta then
|
||||
-- if no metadata, set the metadata!!!
|
||||
meta:set_int("height", init_height)
|
||||
end
|
||||
local height = meta:get_int("height", -1)
|
||||
mcl_bamboo.mcl_log("Grow bamboo; meta-height: " .. height)
|
||||
if height <= 10 then
|
||||
height = init_height
|
||||
meta:set_int("height", init_height)
|
||||
end
|
||||
|
||||
mcl_bamboo.mcl_log("Grow bamboo; height: " .. height)
|
||||
|
||||
-- Bonemeal: Grows the bamboo by 1-2 stems. (per the minecraft wiki.)
|
||||
-- If applying bonemeal, randomly grow two segments instead of one
|
||||
local grow_amount = 1
|
||||
if bonemeal_applied then
|
||||
-- handle applying bonemeal.
|
||||
for py = 1, BAM_MAX_HEIGHT_TOP do
|
||||
-- find the top node of bamboo.
|
||||
chk_pos = vector.offset(pos, 0, py, 0)
|
||||
node_name = minetest.get_node(chk_pos).name
|
||||
dist = vector.distance(soil_pos, chk_pos)
|
||||
if mcl_bamboo.is_bamboo(node_name) == false or node_name == BAMBOO_ENDCAP_NAME then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
mcl_bamboo.mcl_log("Grow bamboo; dist: " .. dist)
|
||||
|
||||
if node_name == BAMBOO_ENDCAP_NAME then
|
||||
-- prevent overgrowth
|
||||
return false
|
||||
end
|
||||
|
||||
-- check to see if we have a full stalk of bamboo.
|
||||
if dist >= height - 1 then
|
||||
if dist == height - 1 then
|
||||
-- equals top of the stalk before the cap
|
||||
if node_name == "air" then
|
||||
mcl_bamboo.mcl_log("Grow bamboo; Placing endcap")
|
||||
minetest.set_node(vector.offset(chk_pos, 0, 1, 0), { name = BAMBOO_ENDCAP_NAME })
|
||||
return true -- returning true means use up the bonemeal.
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
-- okay, we're higher than the end cap, fail out.
|
||||
return false -- returning false means don't use up the bonemeal.
|
||||
end
|
||||
end
|
||||
|
||||
-- and now, the meat of the section... add bamboo to the stalk.
|
||||
-- at this point, we should be lower than the generated maximum height. ~ about height -2 or lower.
|
||||
if dist <= height - 2 then
|
||||
if node_name == "air" then
|
||||
-- here we can check to see if we can do up to 2 bamboo shoots onto the stalk
|
||||
mcl_bamboo.mcl_log("Grow bamboo; Placing bamboo.")
|
||||
minetest.set_node(chk_pos, { name = node_below })
|
||||
-- handle growing a second node.
|
||||
if grow_amount == 2 then
|
||||
chk_pos = vector.offset(chk_pos, 0, 1, 0)
|
||||
if minetest.get_node(chk_pos).name == "air" then
|
||||
mcl_bamboo.mcl_log("Grow bamboo; OOOH! It's twofer day!")
|
||||
minetest.set_node(chk_pos, { name = node_below })
|
||||
end
|
||||
end
|
||||
return true -- exit out with a success. We've added 1-2 nodes, per the wiki.
|
||||
end
|
||||
local rng = PcgRandom(minetest.hash_node_position(pos) + minetest.get_us_time())
|
||||
if rng:next(1, GROW_DOUBLE_CHANGE) == 1 then
|
||||
grow_amount = 2
|
||||
end
|
||||
end
|
||||
log("Growing up to "..grow_amount.." segments")
|
||||
|
||||
-- Non-Bonemeal growth.
|
||||
for py = 1, BAM_MAX_HEIGHT_TOP do
|
||||
-- Find the topmost node above the stalk, and check it for "air"
|
||||
chk_pos = vector.offset(pos, 0, py, 0)
|
||||
node_below = minetest.get_node(pos).name
|
||||
node_name = minetest.get_node(chk_pos).name
|
||||
dist = vector.distance(soil_pos, chk_pos)
|
||||
|
||||
if node_name ~= "air" and mcl_bamboo.is_bamboo(node_name) == false then
|
||||
break
|
||||
-- Perform bamboo growth
|
||||
for i = 1,grow_amount do
|
||||
-- Check for air to grow into
|
||||
local bamboo_tip_node = minetest.get_node(bamboo_tip)
|
||||
if not bamboo_tip_node or bamboo_tip_node.name ~= "air" then
|
||||
-- Something is blocking growth, stop and signal that use bonemeal has been used if at least on segment has grown
|
||||
return i ~= 1
|
||||
end
|
||||
|
||||
-- stop growing check. ie, handle endcap placement.
|
||||
if dist >= height - 1 then
|
||||
local above_node_name = minetest.get_node(vector.offset(chk_pos, 0, 1, 0)).name
|
||||
if node_name == "air" and above_node_name == "air" then
|
||||
if height - 1 == dist then
|
||||
mcl_bamboo.mcl_log("Grow bamboo; Placing endcap")
|
||||
minetest.set_node(chk_pos, { name = BAMBOO_ENDCAP_NAME })
|
||||
end
|
||||
end
|
||||
break
|
||||
if actual_height + 1 == height then
|
||||
-- This is the end cap
|
||||
minetest.set_node(bamboo_tip, { name = BAMBOO_ENDCAP_NAME })
|
||||
return true
|
||||
else
|
||||
-- This isn't the end cap, add a bamboo segment
|
||||
minetest.set_node(bamboo_tip, { name = first_shoot_node_name })
|
||||
actual_height = actual_height + 1
|
||||
end
|
||||
|
||||
-- handle regular node placement.
|
||||
-- find the air node above the top shoot. place a node. And then, if short enough,
|
||||
-- check for second node placement.
|
||||
if node_name == "air" then
|
||||
mcl_bamboo.mcl_log("Grow bamboo; dist: " .. dist)
|
||||
mcl_bamboo.mcl_log("Grow bamboo; Placing bamboo.")
|
||||
minetest.set_node(chk_pos, { name = node_below })
|
||||
-- handle growing a second node. (1 in 32 chance.)
|
||||
if grow_amount == 2 and dist <= height - 2 then
|
||||
chk_pos = vector.offset(chk_pos, 0, 1, 0)
|
||||
if minetest.get_node(chk_pos).name == "air" then
|
||||
mcl_bamboo.mcl_log("Grow bamboo; OOOH! It's twofer day!")
|
||||
minetest.set_node(chk_pos, { name = node_below })
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
bamboo_tip = vector.offset(bamboo_tip, 0, 1, 0)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Add Groups function, courtesy of Warr1024.
|
||||
|
|
Loading…
Reference in a new issue