Merge pull request 'mcl_hoppers fixes' (#2983) from mcl-hoppers-fixes into master

Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/2983
Reviewed-by: ancientmarinerdev <ancientmariner_dev@proton.me>
ancientmarinerdev 2022-12-11 20:55:59 +00:00
commit 38e49a4b80
2 changed files with 226 additions and 181 deletions

@ -1,4 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_hoppers", false)
local function mcl_log(message)
@ -9,21 +11,23 @@ end
--[[ BEGIN OF NODE DEFINITIONS ]]
local mcl_hoppers_formspec =
"size[9,7]"..
"label[2,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Hopper"))).."]"..
"list[context;main;2,0.5;5,1;]"..
mcl_formspec.get_itemslot_bg(2,0.5,5,1)..
"label[0,2;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,2.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,2.5,9,3)..
"list[current_player;main;0,5.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,5.74,9,1)..
"listring[context;main]"..
"listring[current_player;main]"
local mcl_hoppers_formspec = table.concat({
"size[9,7]",
"label[2,0;" .. F(C("#313131", S("Hopper"))) .. "]",
"list[context;main;2,0.5;5,1;]",
mcl_formspec.get_itemslot_bg(2, 0.5, 5, 1),
"label[0,2;" .. F(C("#313131", S("Inventory"))) .. "]",
"list[current_player;main;0,2.5;9,3;9]",
mcl_formspec.get_itemslot_bg(0, 2.5, 9, 3),
"list[current_player;main;0,5.74;9,1;]",
mcl_formspec.get_itemslot_bg(0, 5.74, 9, 1),
"listring[context;main]",
"listring[current_player;main]",
})
-- Downwards hopper (base definition)
---@type node_definition
local def_hopper = {
inventory_image = "mcl_hoppers_item.png",
wield_image = "mcl_hoppers_item.png",
@ -31,7 +35,14 @@ local def_hopper = {
drawtype = "nodebox",
paramtype = "light",
-- FIXME: mcl_hoppers_hopper_inside.png is unused by hoppers.
tiles = {"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png"},
tiles = {
"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
},
node_box = {
type = "fixed",
fixed = {
@ -74,7 +85,7 @@ local def_hopper = {
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
local p = vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5)
minetest.add_item(p, stack)
end
end
@ -131,11 +142,15 @@ local def_hopper = {
-- Enabled downwards hopper
local def_hopper_enabled = table.copy(def_hopper)
def_hopper_enabled.description = S("Hopper")
def_hopper_enabled._tt_help = S("5 inventory slots").."\n"..S("Collects items from above, moves items to container below").."\n"..S("Can be disabled with redstone power")
def_hopper_enabled._doc_items_longdesc = S("Hoppers are containers with 5 inventory slots. They collect dropped items from above, take items from a container above and attempt to put its items it into an adjacent container. Hoppers can go either downwards or sideways. Hoppers interact with chests, droppers, dispensers, shulker boxes, furnaces and hoppers.").."\n\n"..
def_hopper_enabled._tt_help = S("5 inventory slots") ..
"\n" .. S("Collects items from above, moves items to container below") .. "\n" ..
S("Can be disabled with redstone power")
def_hopper_enabled._doc_items_longdesc = S("Hoppers are containers with 5 inventory slots. They collect dropped items from above, take items from a container above and attempt to put its items it into an adjacent container. Hoppers can go either downwards or sideways. Hoppers interact with chests, droppers, dispensers, shulker boxes, furnaces and hoppers.")
.. "\n\n" ..
S("Hoppers interact with containers the following way:") .. "\n" ..
S("• Furnaces: Hoppers from above will put items into the source slot. Hoppers from below take items from the output slot. They also take items from the fuel slot when they can't be used as a fuel. Sideway hoppers that point to the furnace put items into the fuel slot").."\n"..
S("• Furnaces: Hoppers from above will put items into the source slot. Hoppers from below take items from the output slot. They also take items from the fuel slot when they can't be used as a fuel. Sideway hoppers that point to the furnace put items into the fuel slot")
.. "\n" ..
S("• Ender chests: No interaction.") .. "\n" ..
S("• Other containers: Normal interaction.") .. "\n\n" ..
@ -187,7 +202,8 @@ def_hopper_enabled.mesecons = {
minetest.register_node("mcl_hoppers:hopper", def_hopper_enabled)
-- Disabled downwards hopper
---Disabled downwards hopper
---@type node_definition
local def_hopper_disabled = table.copy(def_hopper)
def_hopper_disabled.description = S("Disabled Hopper")
def_hopper_disabled.inventory_image = nil
@ -211,7 +227,8 @@ if minetest.get_modpath("screwdriver") then
on_rotate = screwdriver.rotate_simple
end
-- Sidewars hopper (base definition)
---Sidewars hopper (base definition)
---@type node_definition
local def_hopper_side = {
_doc_items_create_entry = false,
drop = "mcl_hoppers:hopper",
@ -219,7 +236,14 @@ local def_hopper_side = {
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
tiles = {"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png"},
tiles = {
"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
"mcl_hoppers_hopper_outside.png",
},
node_box = {
type = "fixed",
fixed = {
@ -262,7 +286,7 @@ local def_hopper_side = {
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
local p = vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5)
minetest.add_item(p, stack)
end
end
@ -314,6 +338,7 @@ local def_hopper_side = {
_mcl_hardness = 3,
}
---@type node_definition
local def_hopper_side_enabled = table.copy(def_hopper_side)
def_hopper_side_enabled.description = S("Side Hopper")
def_hopper_side_enabled.mesecons = {
@ -325,6 +350,7 @@ def_hopper_side_enabled.mesecons = {
}
minetest.register_node("mcl_hoppers:hopper_side", def_hopper_side_enabled)
---@type node_definition
local def_hopper_side_disabled = table.copy(def_hopper_side)
def_hopper_side_disabled.description = S("Disabled Side Hopper")
def_hopper_side_disabled.mesecons = {
@ -382,7 +408,7 @@ end
--[[ BEGIN OF ABM DEFINITONS ]]
minetest.register_abm({
label = "Hoppers pull from minecart",
label = "Hoppers pull from minecart hoppers",
nodenames = {"mcl_hoppers:hopper", "mcl_hoppers:hopper_side"},
interval = 0.5,
chance = 1,
@ -433,7 +459,7 @@ minetest.register_abm({
interval = 1.0,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local abovenode = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
local abovenode = minetest.get_node(vector.offset(pos, 0, 1, 0))
if not minetest.registered_items[abovenode.name] then return end
-- Don't bother checking item enties if node above is a container (should save some CPU)
if minetest.get_item_group(abovenode.name, "container") ~= 0 then
@ -443,7 +469,8 @@ minetest.register_abm({
local inv = meta:get_inventory()
for _, object in pairs(minetest.get_objects_inside_radius(pos, 2)) do
if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and not object:get_luaentity()._removed then
if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and
not object:get_luaentity()._removed then
if inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
-- Item must get sucked in when the item just TOUCHES the block above the hopper
-- This is the reason for the Y calculation.
@ -461,8 +488,14 @@ minetest.register_abm({
end,
})
-- Returns true if itemstack is fuel, but not for lava bucket if destination already has one
local is_transferrable_fuel = function(itemstack, src_inventory, src_list, dst_inventory, dst_list)
---Returns true if itemstack is fuel, but not for lava bucket if destination already has one
---@param itemstack ItemStack
---@param src_inventory InvRef
---@param src_list string
---@param dst_inventory InvRef
---@param dst_list string
---@return boolean
local function is_transferrable_fuel(itemstack, src_inventory, src_list, dst_inventory, dst_list)
if mcl_util.is_fuel(itemstack) then
if itemstack:get_name() == "mcl_buckets:bucket_lava" then
return dst_inventory:is_empty(dst_list)
@ -474,8 +507,6 @@ local is_transferrable_fuel = function(itemstack, src_inventory, src_list, dst_i
end
end
minetest.register_abm({
label = "Hopper/container item exchange",
nodenames = {"mcl_hoppers:hopper"},
@ -484,8 +515,8 @@ minetest.register_abm({
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
-- Get node pos' for item transfer
local uppos = {x=pos.x,y=pos.y+1,z=pos.z}
local downpos = {x=pos.x,y=pos.y-1,z=pos.z}
local uppos = vector.offset(pos, 0, 1, 0)
local downpos = vector.offset(pos, 0, -1, 0)
-- Suck an item from the container above into the hopper
local upnode = minetest.get_node(uppos)
@ -519,15 +550,15 @@ minetest.register_abm({
local face = minetest.get_node(pos).param2
local front = {}
if face == 0 then
front = {x=pos.x-1,y=pos.y,z=pos.z}
front = vector.offset(pos, -1, 0, 0)
elseif face == 1 then
front = {x=pos.x,y=pos.y,z=pos.z+1}
front = vector.offset(pos, 0, 0, 1)
elseif face == 2 then
front = {x=pos.x+1,y=pos.y,z=pos.z}
front = vector.offset(pos, 1, 0, 0)
elseif face == 3 then
front = {x=pos.x,y=pos.y,z=pos.z-1}
front = vector.offset(pos, 0, 0, -1)
end
local above = {x=pos.x,y=pos.y+1,z=pos.z}
local above = vector.offset(pos, 0, 1, 0)
local frontnode = minetest.get_node(front)
if not minetest.registered_nodes[frontnode.name] then return end
@ -562,6 +593,7 @@ minetest.register_abm({
end
})
if minetest.get_modpath("mcl_composters") then
minetest.register_abm({
label = "Bonemeal extraction from composter",
nodenames = {"mcl_hoppers:hopper", "mcl_hoppers:hopper_side"},
@ -569,83 +601,93 @@ minetest.register_abm({
interval = 1.0,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local uppos = {x=pos.x,y=pos.y+1,z=pos.z}
local downpos = {x=pos.x,y=pos.y-1,z=pos.z}
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local uppos = vector.offset(pos, 0, 1, 0)
--local downpos = vector.offset(pos, 0, -1, 0)
-- Get bonemeal from composter above
local upnode = minetest.get_node(uppos)
if upnode.name == "mcl_composters:composter_ready" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
minetest.swap_node(uppos, {name = "mcl_composters:composter"})
inv:add_item("main", "mcl_dye:white")
end
end,
})
---@param node node
---@return integer?
---@nodiscard
local function composter_level(node)
local nn = node.name
if nn == "mcl_composters:composter" then
return 0
elseif nn == "mcl_composters:composter_1" then
return 1
elseif nn == "mcl_composters:composter_2" then
return 2
elseif nn == "mcl_composters:composter_3" then
return 3
elseif nn == "mcl_composters:composter_4" then
return 4
elseif nn == "mcl_composters:composter_5" then
return 5
elseif nn == "mcl_composters:composter_6" then
return 6
elseif nn == "mcl_composters:composter_7" then
return 7
else
return nil
end
end
for i = 1, 7 do
assert(composter_level({name = "mcl_composters:composter_" .. i}) == i)
end
assert(composter_level({name = "mcl_composters:composter"}) == 0)
assert(composter_level({name = "mcl_composters:some_other_node"}) == nil)
minetest.register_abm({
label = "Add compostable items on composter",
nodenames = {"mcl_hoppers:hopper"},
neighbors = {"mcl_composters:composter", "mcl_composters:composter_1", "mcl_composters:composter_2",
"mcl_composters:composter_3", "mcl_composters:composter_4", "mcl_composters:composter_5",
"mcl_composters:composter_6", "mcl_composters:composter_7",},
neighbors = {
"mcl_composters:composter",
"mcl_composters:composter_1",
"mcl_composters:composter_2",
"mcl_composters:composter_3",
"mcl_composters:composter_4",
"mcl_composters:composter_5",
"mcl_composters:composter_6",
"mcl_composters:composter_7",
},
interval = 1.0,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local uppos = {x=pos.x,y=pos.y+1,z=pos.z}
local downpos = {x=pos.x,y=pos.y-1,z=pos.z}
--local uppos = vector.offset(pos, 0, 1, 0)
local downpos = vector.offset(pos, 0, -1, 0)
local downnode = minetest.get_node(downpos)
---@type integer|string|nil
local level = composter_level(downnode)
--Consume compostable items and update composter below
if level then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
--Consume compostable items and update composter below
local downnode = minetest.get_node(downpos)
if downnode.name == "mcl_composters:composter" or downnode.name == "mcl_composters:composter_1"
or downnode.name == "mcl_composters:composter_2" or downnode.name == "mcl_composters:composter_3"
or downnode.name == "mcl_composters:composter_4" or downnode.name == "mcl_composters:composter_5"
or downnode.name == "mcl_composters:composter_6" or downnode.name == "mcl_composters:composter_7" then
local itemcomp = inv:get_list("main")
local hslot = mcl_util.get_first_occupied_inventory_slot(minetest.get_inventory({type="node", pos = pos}), "main")
if hslot == nil then return end
local compchance = minetest.get_item_group(itemcomp[hslot]:get_name(), "compostability")
if compchance == 0 then
hslot = hslot+1
if hslot == 6 then return end
compchance = minetest.get_item_group(itemcomp[hslot]:get_name(), "compostability")
if compchance == 0 then
hslot = hslot+1
if hslot == 6 then return end
compchance = minetest.get_item_group(itemcomp[hslot]:get_name(), "compostability")
if compchance == 0 then
hslot = hslot+1
if hslot == 6 then return end
compchance = minetest.get_item_group(itemcomp[hslot]:get_name(), "compostability")
if compchance == 0 then
hslot = hslot+1
if hslot == 6 then return end
compchance = minetest.get_item_group(itemcomp[hslot]:get_name(), "compostability")
end
end
end
end
for i = 1, 5 do
local stack = inv:get_stack("main", i)
local compchance = minetest.get_item_group(stack:get_name(), "compostability")
if compchance > 0 then
itemcomp[hslot]:take_item()
inv:set_list("main", itemcomp)
local rand = math.random(0,100)
if compchance >= rand then
local level = 0
if downnode.name == "mcl_composters:composter_1" then
level = 1
elseif downnode.name == "mcl_composters:composter_2" then
level = 2
elseif downnode.name == "mcl_composters:composter_3" then
level = 3
elseif downnode.name == "mcl_composters:composter_4" then
level = 4
elseif downnode.name == "mcl_composters:composter_5" then
level = 5
elseif downnode.name == "mcl_composters:composter_6" then
level = 6
elseif downnode.name == "mcl_composters:composter_7" then
level = 7
end
stack:take_item()
inv:set_stack("main", i, stack)
if compchance >= math.random(0, 100) then
mcl_dye.add_bone_meal_particle(vector.offset(downpos, 0, level / 8, 0))
if level < 7 then
level = level + 1
@ -654,10 +696,13 @@ minetest.register_abm({
end
minetest.swap_node(downpos, {name = "mcl_composters:composter_" .. level})
end
break
end
end
end
end,
})
end
minetest.register_craft({
output = "mcl_hoppers:hopper",
@ -665,7 +710,7 @@ minetest.register_craft({
{"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"},
{"mcl_core:iron_ingot", "mcl_chests:chest", "mcl_core:iron_ingot"},
{"", "mcl_core:iron_ingot", ""},
}
},
})
-- Add entry aliases for the Help

@ -1,4 +1,4 @@
name = mcl_hoppers
description = It's just a clone of Minecraft hoppers, functions nearly identical to them minus mesecons making them stop and the way they're placed.
depends = mcl_core, mcl_formspec, mcl_sounds, mcl_util
depends = mcl_core, mcl_formspec, mcl_sounds, mcl_util, mcl_dye
optional_depends = doc, screwdriver