diff --git a/mods/bg_api/leveled_node.lua b/mods/bg_api/leveled_node.lua index ce8752a..b0e378b 100644 --- a/mods/bg_api/leveled_node.lua +++ b/mods/bg_api/leveled_node.lua @@ -4,6 +4,12 @@ local function is_same_kind (pos, kindname) return kindname and node_kindname and kindname == node_kindname end +local function transfer_levels (source, target, max) + local max_diff = max - target + local diff = math.min(max_diff, source) + return source - diff, target + diff +end + local function stack_attempt (pos, source_level) local node = minetest.get_node(pos) local def = minetest.registered_nodes[node.name] @@ -12,11 +18,10 @@ local function stack_attempt (pos, source_level) local level_max = def.level_max local kindname = def.kindname - local max_diff = level_max - def.level - local diff = math.min(max_diff, source_level) + local source_level, target_level = transfer_levels(source_level, def.level, level_max) - minetest.swap_node(pos, {name = kindname .. "_" .. (def.level + diff)}) - return source_level - diff + minetest.swap_node(pos, {name = kindname .. "_" .. (target_level)}) + return source_level end function blockgame.check_for_stacking (pos) @@ -43,6 +48,40 @@ end +local function on_place (itemstack, placer, pointed) + local function fallback_to_default () + return minetest.item_place(itemstack, placer, pointed) + end + + local placed_def = minetest.registered_items[itemstack:get_name()] + if not placed_def.level_max then return fallback_to_default() end + + if not is_same_kind(pointed.under, placed_def.kindname) then return fallback_to_default() end + + local above = pointed.under + vector.new(0, 1, 0) + local is_top = above == pointed.above + if not is_top then return fallback_to_default() end + + local above_node = minetest.get_node(above) + + local target_node = minetest.get_node(pointed.under) + local target_def = minetest.registered_items[target_node.name] + if target_def.level_max == target_def.level then return fallback_to_default() end + + local source_level, target_level = transfer_levels(placed_def.level, target_def.level, placed_def.level_max) + if source_level > 0 and above_node.name ~= "air" then return fallback_to_default() end + + local left_over = stack_attempt(pointed.under, placed_def.level) + if above_node.name == "air" then + minetest.set_node(pointed.above, {name = target_def.kindname .. "_" .. left_over}) + end + itemstack:set_count(itemstack:get_count() - 1) + + return itemstack +end + + + local function register_layer (kindname, def, level, modname) local def = blockgame.naive_deep_copy(def) def.level = level @@ -60,6 +99,7 @@ local function register_layer (kindname, def, level, modname) end def.on_construct = blockgame.check_for_stacking + def.on_place = on_place def.after_place_node = blockgame.check_for_stacking def.after_land = blockgame.check_for_stacking