Compare commits

...

16 Commits

Author SHA1 Message Date
trans_soup 9c28941a6a fix error in decomposing leaves placement code.
make sure that the node at the placed position is actually a decomposing
leaves variant before doing anything else. (this may not be the case,
since a node may start falling immediately after being placed.)
2023-10-19 14:15:17 +02:00
trans_soup a4f121ac24 make some leaves non-walkable.
make leaves and decomposing_leaves non-walkable, and make them support
falling nodes.
2023-10-19 14:14:05 +02:00
trans_soup 6bb71aa341 add opt-in falling_node collision for non-walkable nodes.
make falling_node entities land on nodes with `supports_falling = true`
in their definitions.
2023-10-19 14:07:47 +02:00
trans_soup c0ef9c3677 tweak grass growth rate.
it now grows twice as slowly.
2023-10-19 13:20:36 +02:00
trans_soup b22827952c add a comment. 2023-10-19 13:14:50 +02:00
trans_soup c4a70e45ce decomposition fix.
make decomposing leaves no longer traverse nodes that don't affect their
decomposition rate, when determining said rate. this means that they're
only affected by nodes that either touch them directly, or touch nodes
that affect them.
2023-10-19 13:12:10 +02:00
trans_soup a3319cf9ea decomposition tweak.
make leaves that have started to decompose continue to do so regardless
of their surrounding nodes.
2023-10-19 13:11:41 +02:00
trans_soup 72a8666a86 leaves decomposition tweaks.
make decomposing leaves account for the pile size of nearby decomposing
leaves when determining their decomposition rate.
2023-10-19 13:10:49 +02:00
trans_soup 5014254c91 tweak decomposition rng.
leaves now have a higher chance of turning into dirt, the higher they're
piled within the node. full stacks (taking up an entire node) always
turn into dirt.
2023-10-19 12:58:31 +02:00
trans_soup 4b408d9943 make decomposing leaves have layers.
decomposing leaves now stack in layers, each one 1/4 of a node in
height.

currently this doesn't affect their behaviour, beyond making them stack
when placed or landing.
2023-10-19 12:54:09 +02:00
trans_soup 8d94fb9c70 minor rename.
look for `after_land` instead of `after_landing` in node defs when
handling falling nodes landing.
2023-10-19 12:46:38 +02:00
trans_soup 87fba22f3b add temporary "crushing" recipe variants.
using the new falling node hooks provided by `bg_api`, add alternative
versions of existing stoneworking recipes, where instead of pummeling, a
stoney node must fall onto the input nodes with sufficient force.

note that since the only currently existing stoney node that can fall,
loose cobblestone, is unobtainable without cheats, so are these recipes.
2023-10-19 11:30:45 +02:00
trans_soup 96ebbe8e0e improve `fall_fix`.
make the position passed to callbacks be the position where the
falling_node entity landed, rather than the position it tries to land
on/in.

note that if the node it lands on has its `paramtype2` set to
`"leveled"` then this new position might be empty after a landing.
2023-10-19 11:25:12 +02:00
trans_soup a09dc62101 add hook for falling_node stepping.
and use this to keep track of their falling velocity.
2023-10-19 11:21:27 +02:00
trans_soup becfb37402 provide more data to landing node callbacks.
specifically, give them the falling_node entity that landed as third
argument.
2023-10-19 11:19:32 +02:00
trans_soup e1103a07e4 create `fall_fix`.
modify the builtin `falling_node` entity to make it possible for mods to
register callbacks to be called when they land and turn into a node.

also register such a callback that checks if the landed node has an
entry `after_landing`, and if so calls that.
2023-10-18 23:30:00 +02:00
7 changed files with 233 additions and 29 deletions

103
mods/bg_api/fall_fix.lua Normal file
View File

@ -0,0 +1,103 @@
local entity = minetest.registered_entities["__builtin:falling_node"]
local old_try_place = entity.try_place
local after_land_callbacks = {}
entity.try_place = function (self, bcp, bcn)
local result = old_try_place(self, bcp, bcn)
-- `result` will be true if the falling node landed successfully (afaict from reading `/builtin/game/falling.lua` in the minetest source).
if result then
-- `bcp` is actually the node 0.7 nodes (rounded) below the falling_node entity.
-- the vector addition here makes it be the position where the entity itself landed.
-- if it landed on something layered, this new position might be air when the callbacks are called.
local pos = bcp + vector.new(0, 1, 0)
for _, callback in pairs(after_land_callbacks) do
callback(pos, bcn, self)
end
end
return result
end
function blockgame.register_after_falling_node_lands (callback)
table.insert(after_land_callbacks, callback)
end
blockgame.register_after_falling_node_lands(function (pos, node)
local def = minetest.registered_nodes[node.name]
if type(def.after_land) == "function" then
def.after_land(pos, node)
end
end)
local old_on_step = entity.on_step
local on_step_callbacks = {}
entity.on_step = function (self, dtime, moveresult)
local result = old_on_step(self, dtime, moveresult)
for _, callback in pairs(on_step_callbacks) do
callback(self, dtime, moveresult)
end
return result
end
function blockgame.register_on_falling_node_step (callback)
table.insert(on_step_callbacks, callback)
end
-- keep track of velocity a falling_node had before landing
-- so that code hooked into the landing can check "how fast was this moving?"
blockgame.register_on_falling_node_step(function (entity, delta_time, move_result)
local velocity = entity.object:get_velocity()
-- let `previous_velocity` be (0, 0, 0) at the very first step
if not entity.fall_velocity then
entity.fall_velocity = vector.new(0, 0, 0)
end
-- keep track of moving velocity, not still velocity
if velocity and (vector.length(velocity) ~= 0) then
entity.fall_velocity = vector.copy(velocity)
end
end)
-- make falling nodes collide with `walkable = false` nodes if they are also `supports_falling = true`.
blockgame.register_on_falling_node_step(function (entity, delta_time, move_result)
local pos = entity.object:get_pos()
if not pos then return end
local below = pos:offset(0, -0.7, 0) -- same offset as in `/builtin/game/falling.lua`
local node = minetest.get_node(below)
if node == "air" then return end
local def = minetest.registered_nodes[node.name]
if not def then return end
if def.walkable or not def.supports_falling then return end
local success = entity:try_place(below, node)
if not success then
local drops = minetest.get_node_drops(entity.node, "")
for _, item in pairs(drops) do
minetest.add_item(pos, item)
end
end
entity.object:remove()
end)
local old_check = minetest.check_single_for_falling
function minetest.check_single_for_falling (pos, ...)
local node = minetest.get_node(pos:offset(0, -1, 0))
local def = minetest.registered_nodes[node.name]
if def and def.supports_falling then return false end
return old_check(pos, ...)
end

View File

@ -22,5 +22,6 @@ load_file("wrappers")
load_file("random_tick")
load_file("increasing_abm")
load_file("loose_node")
load_file("fall_fix")
load_file("cleanup")

View File

@ -30,3 +30,37 @@ blockgame.crafting.register_pummel_recipe({
minetest.set_node(pos, {name = modname .. ":bricks"})
end,
})
local crush_recipes = {
{
input = {"bg_terrain:cobblestone", "bg_terrain:cobblestone_loose"},
output = modname .. ":tile",
},
{
input = {modname .. ":tile"},
output = modname .. ":bricks",
},
}
blockgame.register_after_falling_node_lands(function (pos, node, entity)
if not blockgame.item_matches(node.name, {"group:stoney"}) then return end
local def = minetest.registered_nodes[node.name]
local mass = def.mass or 1
local force = math.abs(entity.fall_velocity.y) * mass
if force < 5 then return end
local below = pos + blockgame.vector.dirs.down
local target = minetest.get_node(below).name
if not blockgame.item_matches(target, {"group:stoney"}) then return end
for _, recipe in pairs(crush_recipes) do
local input = recipe.input
local output = recipe.output
if blockgame.item_matches(target, input) then
minetest.set_node(below, {name = output})
return
end
end
end)

View File

@ -24,7 +24,7 @@ end
blockgame.register_abm({
nodenames = {"bg_terrain:grass"},
neighbors = {"bg_terrain:dirt"},
interval = 15,
interval = 30,
chance = 8,
action = function (pos, node)
local sides = listify_table(blockgame.vector.sides)

View File

@ -27,22 +27,18 @@ blockgame.register_increasing_abm({
end,
})
local decompose_node_scores = {
[leaves_decomposing] = 30,
}
local decompose_group_scores = {
local decompose_scores = {
dirty = 50,
leaves_decomposing = 30,
}
local decompose_cost = 2000
local average_leaves_per_dirt = 4
blockgame.register_increasing_abm({
id = modname .. ":decompose",
label = "decompose leaves",
nodenames = {leaves_decomposing},
neighbors = {"group:dirty", leaves_decomposing},
nodenames = {"group:leaves_decomposing"},
-- neighbors = {"group:dirty", "group:leaves_decomposing"},
interval = 30,
chance = 10,
rate = function (pos, node, data)
@ -55,9 +51,10 @@ blockgame.register_increasing_abm({
local name = minetest.get_node(pos).name
local gain = 0
for group, value in pairs(decompose_group_scores) do
if minetest.get_item_group(name, group) > 0 then
gain = math.max(gain, value)
for group, value in pairs(decompose_scores) do
local group = minetest.get_item_group(name, group)
if group > 0 then
gain = math.max(gain, value * group)
end
end
@ -68,10 +65,7 @@ blockgame.register_increasing_abm({
return true
end
if decompose_node_scores[name] then
score = score + math.floor(decompose_node_scores[name] / distance)
return true
end
return false
end, 4)
return data.value + score
@ -80,7 +74,12 @@ blockgame.register_increasing_abm({
return data.value >= decompose_cost
end,
action = function (pos, node, data)
if blockgame.chance(average_leaves_per_dirt) then
-- currently, larger leaf piles have a greater chance of turning into dirt instead of disappearing.
-- might wanna make it so that instead, dirt is layered as well?
local def = minetest.registered_nodes[node.name]
local dirt_chance = def.level_max - def.level + 1
if blockgame.chance(dirt_chance) then
minetest.set_node(pos, {name = "bg_terrain:dirt"})
else
minetest.remove_node(pos)

View File

@ -25,6 +25,7 @@ blockgame.register_abm({
end, 3)
if not is_supported then
-- TODO: become randomly-sized leaves pile when layered leaves is added.
minetest.set_node(pos, {name = modname .. ":leaves"})
minetest.check_for_falling(pos)
-- TODO: send out event here that makes nearby leaves check if they're unsupported as well?

View File

@ -1,13 +1,18 @@
local modname = minetest.get_current_modname()
local function reg_leaves (name, def)
def.description = def.description or name
def.texture = def.texture or name
def.tiles = {modname .. "_" .. def.texture .. ".png"}
local texture = def.texture or name
def.drawtype = "glasslike"
def.paramtype = "light"
def.sunlight_propagates = true
def = blockgame.underride(def, {
description = name,
texture = texture,
tiles = {modname .. "_" .. texture .. ".png"},
drawtype = "allfaces_optional",
paramtype = "light",
sunlight_propagates = true,
})
def.groups = blockgame.underride(def.groups, {
planty = 1,
@ -39,6 +44,8 @@ local nutty_drops = {
reg_leaves("leaves", {
description = "Leaves",
walkable = false,
supports_falling = true,
})
reg_leaves("leaves_growing", {
description = "Growing Leaves",
@ -55,9 +62,68 @@ reg_leaves("leaves_alive", {
falling_node = 0,
},
})
reg_leaves("leaves_decomposing", {
description = "Decomposing Leaves",
groups = {
supports_leaves = 0,
},
})
-- TODO: generalize stacking node registration and put into API.
local decomposing_leaves_layers = 4
local after_place_stack = function (pos)
local node = minetest.get_node(pos)
if not blockgame.starts_with(node.name, modname .. ":leaves_decomposing") then return end
local below = pos + blockgame.vector.dirs.down
local below_node = minetest.get_node(below)
if not blockgame.starts_with(below_node.name, modname .. ":leaves_decomposing") then return end
local def = minetest.registered_nodes[node.name]
local below_def = minetest.registered_nodes[below_node.name]
if below_def.level == decomposing_leaves_layers then return end
local max_diff = decomposing_leaves_layers - below_def.level
local diff = math.min(max_diff, def.level)
minetest.swap_node(below, {name = modname .. ":leaves_decomposing_" .. (below_def.level + diff)})
if diff == def.level then
minetest.remove_node(pos)
else
minetest.swap_node(pos, {name = modname .. ":leaves_decomposing_" .. (def.level - diff)})
end
end
local function reg_decomposing (level)
local height = level / decomposing_leaves_layers
local description = "Decomposing Leaves (" .. level .. "/" .. decomposing_leaves_layers .. ")"
if level == decomposing_leaves_layers then description = "Decomposing Leaves" end
local drawtype = "nodebox"
local node_box = {
["type"] = "fixed",
fixed = { -0.5, -0.5, -0.5, 0.5, -0.5 + height, 0.5 },
}
if level == decomposing_leaves_layers then
drawtype = "allfaces_optional"
node_box = nil
end
reg_leaves("leaves_decomposing_" .. level, {
description = description,
level = level,
level_max = decomposing_leaves_layers,
texture = "leaves_decomposing",
drawtype = drawtype,
node_box = node_box,
after_place_node = after_place_stack,
after_land = after_place_stack,
drop = modname .. ":leaves_decomposing_1 " .. level,
groups = {
leaves_decomposing = level,
},
walkable = false,
supports_falling = true,
})
end
for level=1, decomposing_leaves_layers do
reg_decomposing(level)
end
minetest.register_alias(modname .. ":leaves_decomposing", modname .. ":leaves_decomposing_" .. decomposing_leaves_layers)