From 1da7bb0bdcf438276faadae17ac1426ec8c68612 Mon Sep 17 00:00:00 2001 From: Kostinatyn Tsiupa Date: Fri, 27 Oct 2023 01:15:57 +0300 Subject: [PATCH] hopper reimplementation Reimplemented hoppers and all (blast_furnace, furnace, smoker, composters, double chaets, shulker_boxes, droppers, bookshelvs and brewing_stands) connected nodes --- GROUPS.md | 12 +- mods/CORE/mcl_util/init.lua | 229 +++++----------- mods/ITEMS/REDSTONE/mcl_droppers/init.lua | 37 ++- mods/ITEMS/mcl_blast_furnace/init.lua | 11 +- mods/ITEMS/mcl_books/init.lua | 8 +- mods/ITEMS/mcl_brewing/init.lua | 108 +++++++- mods/ITEMS/mcl_chests/init.lua | 79 +++++- mods/ITEMS/mcl_composters/init.lua | 147 ++++++++--- mods/ITEMS/mcl_composters/mod.conf | 2 +- mods/ITEMS/mcl_furnaces/init.lua | 38 ++- mods/ITEMS/mcl_hoppers/init.lua | 244 ++++-------------- mods/ITEMS/mcl_itemframes/item_frames_API.lua | 2 +- mods/ITEMS/mcl_jukebox/init.lua | 2 +- mods/ITEMS/mcl_potions/init.lua | 4 +- mods/ITEMS/mcl_potions/lingering.lua | 2 +- mods/ITEMS/mcl_potions/potions.lua | 10 +- mods/ITEMS/mcl_potions/splash.lua | 2 +- mods/ITEMS/mcl_smoker/init.lua | 11 +- 18 files changed, 504 insertions(+), 444 deletions(-) diff --git a/GROUPS.md b/GROUPS.md index e6d878990..0eb2d2d7c 100644 --- a/GROUPS.md +++ b/GROUPS.md @@ -170,16 +170,8 @@ These groups are used mostly for informational purposes * `ammo_bow=1`: Item is used as ammo for bows * `non_combat_armor=1`: Item can be equipped as armor, but is not made for combat (e.g. zombie head, pumpkin) * `container`: Node is a container which physically stores items within and has at least 1 inventory - * `container=2`: Has one inventory with list name `"main"`. Items can be placed and taken freely - * `container=3`: Same as `container=2`, but shulker boxes can not be inserted - * `container=4`: Furnace-like, has lists `"src"`, `"fuel"` and `"dst"`. - It is expected that this also reacts on `on_timer`; - the node timer must be started from other mods when they add into `"src"` or `"fuel"` - * `container=5`: Left part of a 2-part horizontal connected container. Both parts have a `"main"` inventory - list. Both inventories are considered to belong together. This is used for large chests. - * `container=6`: Same as above, but for the right part. - * `container=7`: Has inventory list "`main`", no movement allowed - * `container=1`: Other/unspecified container type + * `container=1`: Container type, which does not allow hoppers to transfer items + * `container=2`: Items can be placed and taken freely. Can have inventory with list name `"main"` or define `_mcl_hoppers_on_try_pull`, `_mcl_hoppers_on_try_push`, `_mcl_hoppers_on_after_pull`, `_mcl_hoppers_on_after_push` to play along hoppers nicely. * `spawn_egg=1`: Spawn egg * `pressure_plate=1`: Pressure plate (off) diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index e894eebd7..5d44bb29f 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -241,34 +241,25 @@ function mcl_util.get_double_container_neighbor_pos(pos, param2, side) end end --- Iterates through all items in the given inventory and --- returns the slot of the first item which matches a condition. --- Returns nil if no item was found. ---- source_inventory: Inventory to take the item from ---- source_list: List name of the source inventory from which to take the item ---- destination_inventory: Put item into this inventory ---- destination_list: List name of the destination inventory to which to put the item into ---- condition: Function which takes an itemstack and returns true if it matches the desired item condition. ---- If set to nil, the slot of the first item stack will be taken unconditionally. --- dst_inventory and dst_list can also be nil if condition is nil. -function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_inventory, dst_list, condition) - local size = src_inventory:get_size(src_list) +--- Selects item stack to transfer from +---@param src_inventory InvRef Source innentory to pull from +---@param src_list string Name of source inventory list to pull from +---@param dst_inventory InvRef Destination inventory to push to +---@param dst_list string Name of destination inventory list to push to +---@param condition? fun(stack: ItemStack) Condition which items are allowed to be transfered. +---@return integer Item stack number to be transfered +function mcl_util.select_stack(src_inventory, src_list, dst_inventory, dst_list, condition) + local src_size = src_inventory:get_size(src_list) local stack - for i = 1, size do + for i = 1, src_size do stack = src_inventory:get_stack(src_list, i) - if not stack:is_empty() and (condition == nil or condition(stack, src_inventory, src_list, dst_inventory, dst_list)) then + if not stack:is_empty() and dst_inventory:room_for_item(dst_list, stack) and ((condition == nil or condition(stack))) then return i end end return nil end --- Returns true if itemstack is a shulker box -local function is_not_shulker_box(itemstack) - local g = minetest.get_item_group(itemstack:get_name(), "shulker_box") - return g == 0 or g == nil -end - -- Moves a single item from one inventory to another. --- source_inventory: Inventory to take the item from --- source_list: List name of the source inventory from which to take the item @@ -279,13 +270,6 @@ end -- Returns true on success and false on failure -- Possible failures: No item in source slot, destination inventory full function mcl_util.move_item(source_inventory, source_list, source_stack_id, destination_inventory, destination_list) - if source_stack_id == -1 then - source_stack_id = mcl_util.get_first_occupied_inventory_slot(source_inventory, source_list) - if source_stack_id == nil then - return false - end - end - if not source_inventory:is_empty(source_list) then local stack = source_inventory:get_stack(source_list, source_stack_id) if not stack:is_empty() then @@ -303,150 +287,75 @@ function mcl_util.move_item(source_inventory, source_list, source_stack_id, dest return false end --- Moves a single item from one container node into another. Performs a variety of high-level --- checks to prevent invalid transfers such as shulker boxes into shulker boxes ---- source_pos: Position ({x,y,z}) of the node to take the item from ---- destination_pos: Position ({x,y,z}) of the node to put the item into ---- source_list (optional): List name of the source inventory from which to take the item. Default is normally "main"; "dst" for furnace ---- source_stack_id (optional): The inventory position ID of the source inventory to take the item from (-1 for slot of the first valid item; -1 is default) ---- destination_list (optional): List name of the destination inventory. Default is normally "main"; "src" for furnace --- Returns true on success and false on failure. -function mcl_util.move_item_container(source_pos, destination_pos, source_list, source_stack_id, destination_list) - local dpos = table.copy(destination_pos) - local spos = table.copy(source_pos) - local snode = minetest.get_node(spos) - local dnode = minetest.get_node(dpos) +--- Try pushing item from hopper inventory to destination inventory +---@param pos Vector +---@param dst_pos Vector +function mcl_util.hopper_push(pos, dst_pos) + local hop_inv = minetest.get_meta(pos):get_inventory() + local hop_list = 'main' - local dctype = minetest.get_item_group(dnode.name, "container") - local sctype = minetest.get_item_group(snode.name, "container") + -- Get node pos' for item transfer + local dst = minetest.get_node(dst_pos) + if not minetest.registered_nodes[dst.name] then return end + local dst_type = minetest.get_item_group(dst.name, "container") + if dst_type ~= 2 then return end + local dst_def = minetest.registered_nodes[dst.name] - -- Container type 7 does not allow any movement - if sctype == 7 then - return false + local dst_list = 'main' + local dst_inv, stack_id + + if dst_def._mcl_hoppers_on_try_push then + dst_inv, dst_list, stack_id = dst_def._mcl_hoppers_on_try_push(dst_pos, pos, hop_inv, hop_list) + else + local dst_meta = minetest.get_meta(dst_pos) + dst_inv = dst_meta:get_inventory() + stack_id = mcl_util.select_stack(hop_inv, hop_list, dst_inv, dst_list) end - -- Normalize double container by forcing to always use the left segment first - local function normalize_double_container(pos, node, ctype) - if ctype == 6 then - pos = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") - if not pos then - return false - end - node = minetest.get_node(pos) - ctype = minetest.get_item_group(node.name, "container") - -- The left segment seems incorrect? We better bail out! - if ctype ~= 5 then - return false - end + if stack_id ~= nil then + local ok = mcl_util.move_item(hop_inv, hop_list, stack_id, dst_inv, dst_list) + if dst_def._mcl_hoppers_on_after_push then + dst_def._mcl_hoppers_on_after_push(dst_pos) end - return pos, node, ctype - end - - spos, snode, sctype = normalize_double_container(spos, snode, sctype) - dpos, dnode, dctype = normalize_double_container(dpos, dnode, dctype) - if not spos or not dpos then return false end - - local smeta = minetest.get_meta(spos) - local dmeta = minetest.get_meta(dpos) - - local sinv = smeta:get_inventory() - local dinv = dmeta:get_inventory() - - -- Default source lists - if not source_list then - -- Main inventory for most container types - if sctype == 2 or sctype == 3 or sctype == 5 or sctype == 6 or sctype == 7 then - source_list = "main" - -- Furnace: output - elseif sctype == 4 then - source_list = "dst" - -- Unknown source container type. Bail out - else - return false + if ok then + return true end end - -- Automatically select stack slot ID if set to automatic - if not source_stack_id then - source_stack_id = -1 - end - if source_stack_id == -1 then - local cond = nil - -- Prevent shulker box inception - if dctype == 3 then - cond = is_not_shulker_box - end - source_stack_id = mcl_util.get_eligible_transfer_item_slot(sinv, source_list, dinv, dpos, cond) - if not source_stack_id then - -- Try again if source is a double container - if sctype == 5 then - spos = mcl_util.get_double_container_neighbor_pos(spos, snode.param2, "left") - smeta = minetest.get_meta(spos) - sinv = smeta:get_inventory() - - source_stack_id = mcl_util.get_eligible_transfer_item_slot(sinv, source_list, dinv, dpos, cond) - if not source_stack_id then - return false - end - else - return false - end - end - end - - -- Abort transfer if shulker box wants to go into shulker box - if dctype == 3 then - local stack = sinv:get_stack(source_list, source_stack_id) - if stack and minetest.get_item_group(stack:get_name(), "shulker_box") == 1 then - return false - end - end - -- Container type 7 does not allow any placement - if dctype == 7 then - return false - end - - -- If it's a container, put it into the container - if dctype ~= 0 then - -- Automatically select a destination list if omitted - if not destination_list then - -- Main inventory for most container types - if dctype == 2 or dctype == 3 or dctype == 5 or dctype == 6 or dctype == 7 then - destination_list = "main" - -- Furnace source slot - elseif dctype == 4 then - destination_list = "src" - end - end - if destination_list then - -- Move item - local ok = mcl_util.move_item(sinv, source_list, source_stack_id, dinv, destination_list) - - -- Try transfer to neighbor node if transfer failed and double container - if not ok and dctype == 5 then - dpos = mcl_util.get_double_container_neighbor_pos(dpos, dnode.param2, "left") - dmeta = minetest.get_meta(dpos) - dinv = dmeta:get_inventory() - - ok = mcl_util.move_item(sinv, source_list, source_stack_id, dinv, destination_list) - end - - -- Update furnace - if ok and dctype == 4 then - -- Start furnace's timer function, it will sort out whether furnace can burn or not. - minetest.get_node_timer(dpos):start(1.0) - end - - return ok - end - end return false end --- Returns the ID of the first non-empty slot in the given inventory list --- or nil, if inventory is empty. -function mcl_util.get_first_occupied_inventory_slot(inventory, listname) - return mcl_util.get_eligible_transfer_item_slot(inventory, listname) +-- Try pulling from source inventory to hopper inventory +---@param pos Vector +---@param src_pos Vector +function mcl_util.hopper_pull(pos, src_pos) + local hop_inv = minetest.get_meta(pos):get_inventory() + local hop_list = 'main' + + -- Get node pos' for item transfer + local src = minetest.get_node(src_pos) + if not minetest.registered_nodes[src.name] then return end + local src_type = minetest.get_item_group(src.name, "container") + if src_type ~= 2 then return end + local src_def = minetest.registered_nodes[src.name] + + local src_list = 'main' + local src_inv, stack_id + + if src_def._mcl_hoppers_on_try_pull then + src_inv, src_list, stack_id = src_def._mcl_hoppers_on_try_pull(src_pos, pos, hop_inv, hop_list) + else + local src_meta = minetest.get_meta(src_pos) + src_inv = src_meta:get_inventory() + stack_id = mcl_util.select_stack(src_inv, src_list, hop_inv, hop_list) + end + + if stack_id ~= nil then + local ok = mcl_util.move_item(src_inv, src_list, stack_id, hop_inv, hop_list) + if src_def._mcl_hoppers_on_after_pull then + src_def._mcl_hoppers_on_after_pull(src_pos) + end + end end local function drop_item_stack(pos, stack) diff --git a/mods/ITEMS/REDSTONE/mcl_droppers/init.lua b/mods/ITEMS/REDSTONE/mcl_droppers/init.lua index 09e221a4d..e47371bc9 100644 --- a/mods/ITEMS/REDSTONE/mcl_droppers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_droppers/init.lua @@ -125,7 +125,11 @@ local dropperdef = { local dropnode = minetest.get_node(droppos) -- Do not drop into solid nodes, unless they are containers local dropnodedef = minetest.registered_nodes[dropnode.name] - if dropnodedef.walkable and not dropnodedef.groups.container then + if dropnodedef.groups.container == 2 then + -- If they are containers - double down as hopper + mcl_util.hopper_push(pos, droppos) + end + if dropnodedef.walkable then return end local stacks = {} @@ -141,25 +145,18 @@ local dropperdef = { local dropitem = ItemStack(stack) dropitem:set_count(1) local stack_id = stacks[r].stackpos - - -- If it's a container, attempt to put it into the container - local dropped = mcl_util.move_item_container(pos, droppos, nil, stack_id) - -- No container? - if not dropped and not dropnodedef.groups.container then - -- Drop item normally - local pos_variation = 100 - droppos = vector.offset(droppos, - math.random(-pos_variation, pos_variation) / 1000, - math.random(-pos_variation, pos_variation) / 1000, - math.random(-pos_variation, pos_variation) / 1000 - ) - local item_entity = minetest.add_item(droppos, dropitem) - local drop_vel = vector.subtract(droppos, pos) - local speed = 3 - item_entity:set_velocity(vector.multiply(drop_vel, speed)) - stack:take_item() - inv:set_stack("main", stack_id, stack) - end + local pos_variation = 100 + droppos = vector.offset(droppos, + math.random(-pos_variation, pos_variation) / 1000, + math.random(-pos_variation, pos_variation) / 1000, + math.random(-pos_variation, pos_variation) / 1000 + ) + local item_entity = minetest.add_item(droppos, dropitem) + local drop_vel = vector.subtract(droppos, pos) + local speed = 3 + item_entity:set_velocity(vector.multiply(drop_vel, speed)) + stack:take_item() + inv:set_stack("main", stack_id, stack) end end, rules = mesecon.rules.alldirs, diff --git a/mods/ITEMS/mcl_blast_furnace/init.lua b/mods/ITEMS/mcl_blast_furnace/init.lua index 51a8f193a..7d0f091d9 100644 --- a/mods/ITEMS/mcl_blast_furnace/init.lua +++ b/mods/ITEMS/mcl_blast_furnace/init.lua @@ -453,7 +453,7 @@ minetest.register_node("mcl_blast_furnace:blast_furnace", { "blast_furnace_side.png", "blast_furnace_front.png" }, paramtype2 = "facedir", - groups = { pickaxey = 1, container = 4, deco_block = 1, material_stone = 1 }, + groups = { pickaxey = 1, container = 2, deco_block = 1, material_stone = 1 }, is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), @@ -514,6 +514,11 @@ minetest.register_node("mcl_blast_furnace:blast_furnace", { _mcl_blast_resistance = 3.5, _mcl_hardness = 3.5, on_rotate = on_rotate, + _mcl_hoppers_on_try_pull = mcl_furnaces.hoppers_on_try_pull, + _mcl_hoppers_on_try_push = mcl_furnaces.hoppers_on_try_push, + _mcl_hoppers_on_after_push = function(pos) + minetest.get_node_timer(pos):start(1.0) + end, }) minetest.register_node("mcl_blast_furnace:blast_furnace_active", { @@ -531,7 +536,7 @@ minetest.register_node("mcl_blast_furnace:blast_furnace_active", { paramtype = "light", light_source = LIGHT_ACTIVE_FURNACE, drop = "mcl_blast_furnace:blast_furnace", - groups = { pickaxey = 1, container = 4, deco_block = 1, not_in_creative_inventory = 1, material_stone = 1 }, + groups = { pickaxey = 1, container = 2, deco_block = 1, not_in_creative_inventory = 1, material_stone = 1 }, is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), on_timer = blast_furnace_node_timer, @@ -574,6 +579,8 @@ minetest.register_node("mcl_blast_furnace:blast_furnace_active", { _mcl_hardness = 3.5, on_rotate = on_rotate, after_rotate = after_rotate_active, + _mcl_hoppers_on_try_pull = mcl_furnaces.hoppers_on_try_pull, + _mcl_hoppers_on_try_push = mcl_furnaces.hoppers_on_try_push, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_books/init.lua b/mods/ITEMS/mcl_books/init.lua index e2f391b17..25d93b854 100644 --- a/mods/ITEMS/mcl_books/init.lua +++ b/mods/ITEMS/mcl_books/init.lua @@ -438,7 +438,7 @@ minetest.register_node("mcl_books:bookshelf", { flammable = 3, fire_encouragement = 30, fire_flammability = 20, - container = 1 + container = 2 }, drop = "mcl_books:book 3", sounds = wood_sound, @@ -472,6 +472,12 @@ minetest.register_node("mcl_books:bookshelf", { on_blast = on_blast, on_rightclick = bookshelf_gui, on_destruct = close_forms, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", + function(stack) return minetest.get_item_group(stack:get_name(), "book") == 1 or stack:get_name() == "mcl_enchanting:book_enchanted" end) + end, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_brewing/init.lua b/mods/ITEMS/mcl_brewing/init.lua index 9c6879430..cb5374d81 100644 --- a/mods/ITEMS/mcl_brewing/init.lua +++ b/mods/ITEMS/mcl_brewing/init.lua @@ -376,13 +376,41 @@ local function allow_take(pos, listname, index, stack, player) end end +local function hoppers_on_try_push(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z) then + return inv, "input", mcl_util.select_stack(hop_inv, hop_list, inv, "input", + function(stack) return minetest.get_item_group(stack:get_name(), "brewitem") == 1 and minetest.get_item_group(stack:get_name(), "bottle") == 0 end) + else + local stack = mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", function(stack) return stack:get_name() == "mcl_mobitems:blaze_powder" end) + if stack then + return inv, "fuel", stack + else + return inv, "stand", mcl_util.select_stack(hop_inv, hop_list, inv, "stand", + function(stack) return minetest.get_item_group(stack:get_name(), "bottle") == 1 end) + end + end +end + +local function hoppers_on_try_pull(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local stand_timer = meta:get_float("stand_timer") or 0 + if stand_timer > 0 then + return nil, nil, nil + end + + local inv = meta:get_inventory() + local stack = mcl_util.select_stack(inv, "stand", hop_inv, hop_list) + return inv, "stand", stack +end minetest.register_node("mcl_brewing:stand_000", { description = S("Brewing Stand"), _doc_items_longdesc = S("The stand allows you to brew potions!"), _doc_items_usagehelp = doc_string, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, brewitem=1 }, + groups = {pickaxey=1, container = 2, brewitem=1 }, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -444,12 +472,20 @@ minetest.register_node("mcl_brewing:stand_000", { on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_100", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = { pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1 }, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -514,13 +550,21 @@ minetest.register_node("mcl_brewing:stand_100", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_010", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = {pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1}, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -586,13 +630,21 @@ minetest.register_node("mcl_brewing:stand_010", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_001", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = {pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1}, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -653,13 +705,21 @@ minetest.register_node("mcl_brewing:stand_001", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_110", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = {pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1}, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -730,13 +790,21 @@ minetest.register_node("mcl_brewing:stand_110", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_101", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = {pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1}, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -803,13 +871,21 @@ minetest.register_node("mcl_brewing:stand_101", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_011", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = {pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1}, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -876,13 +952,21 @@ minetest.register_node("mcl_brewing:stand_011", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_node("mcl_brewing:stand_111", { description = S("Brewing Stand"), _doc_items_create_entry = false, _tt_help = S("Brew Potions"), - groups = {pickaxey=1, not_in_creative_inventory = 1, not_in_craft_guide = 1}, + groups = {pickaxey=1, container = 2, not_in_creative_inventory = 1, not_in_craft_guide = 1}, tiles = tiles, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, drop = "mcl_brewing:stand", @@ -956,6 +1040,14 @@ minetest.register_node("mcl_brewing:stand_111", { end, on_timer = brewing_stand_timer, on_rotate = on_rotate, + _mcl_hoppers_on_try_push = hoppers_on_try_push, + _mcl_hoppers_on_try_pull = hoppers_on_try_pull, + _mcl_hoppers_on_after_push = function(pos) + on_put(pos, nil, nil, nil, nil) + end, + _mcl_hoppers_on_after_pull = function(pos) + on_put(pos, nil, nil, nil, nil) + end, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index 6f3272149..38b1102a3 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -10,6 +10,8 @@ local sf = string.format local mod_doc = minetest.get_modpath("doc") +mcl_chests = {} + -- Christmas chest setup local it_is_christmas = false local date = os.date("*t") @@ -596,7 +598,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile groups = { handy = 1, axey = 1, - container = 5, + container = 2, not_in_creative_inventory = 1, material_wood = 1, flammable = -1, @@ -751,6 +753,34 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile end, mesecons = mesecons, on_rotate = no_rotate, + _mcl_hoppers_on_try_pull = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack_id = mcl_util.select_stack(inv, "main", hop_inv, hop_list) + if stack_id ~= nil then + return inv, "main", stack_id + end + local node = minetest.get_node(pos) + local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") + local meta_other = minetest.get_meta(pos_other) + local inv_other = meta_other:get_inventory() + stack_id = mcl_util.select_stack(inv_other, "main", hop_inv, hop_list) + return inv_other, "main", stack_id + end, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main") + if stack_id ~= nil then + return inv, "main", stack_id + end + local node = minetest.get_node(pos) + local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") + local meta_other = minetest.get_meta(pos_other) + local inv_other = meta_other:get_inventory() + stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main") + return inv_other, "main", stack_id + end, }) minetest.register_node("mcl_chests:" .. basename .. "_right", { @@ -766,7 +796,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile groups = { handy = 1, axey = 1, - container = 6, + container = 2, not_in_creative_inventory = 1, material_wood = 1, flammable = -1, @@ -916,6 +946,34 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile end, mesecons = mesecons, on_rotate = no_rotate, + _mcl_hoppers_on_try_pull = function(pos, hop_pos, hop_inv, hop_list) + local node = minetest.get_node(pos) + local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") + local meta_other = minetest.get_meta(pos_other) + local inv_other = meta_other:get_inventory() + local stack_id = mcl_util.select_stack(inv_other, "main", hop_inv, hop_list) + if stack_id ~= nil then + return inv_other, "main", stack_id + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + stack_id = mcl_util.select_stack(inv, "main", hop_inv, hop_list) + return inv, "main", stack_id + end, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + local node = minetest.get_node(pos) + local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") + local meta_other = minetest.get_meta(pos_other) + local inv_other = meta_other:get_inventory() + local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main") + if stack_id ~= nil then + return inv_other, "main", stack_id + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main") + return inv, "main", stack_id + end, }) if mod_doc then @@ -1305,7 +1363,7 @@ for color, desc in pairs(boxtypes) do groups = { handy = 1, pickaxey = 1, - container = 3, + container = 2, deco_block = 1, dig_by_piston = 1, shulker_box = 1, @@ -1378,7 +1436,7 @@ for color, desc in pairs(boxtypes) do groups = { handy = 1, pickaxey = 1, - container = 3, + container = 2, deco_block = 1, dig_by_piston = 1, shulker_box = 1, @@ -1471,6 +1529,11 @@ for color, desc in pairs(boxtypes) do end, _mcl_blast_resistance = 6, _mcl_hardness = 2, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box) + end, }) if mod_doc and not is_canonical then @@ -1487,6 +1550,14 @@ for color, desc in pairs(boxtypes) do }) end +--- Returns false if itemstack is a shulker box +---@param itemstack ItemStack +---@return boolean +function mcl_chests.is_not_shulker_box(stack) + local g = minetest.get_item_group(stack:get_name(), "shulker_box") + return g == 0 or g == nil +end + minetest.register_craft({ output = "mcl_chests:violet_shulker_box", recipe = { diff --git a/mods/ITEMS/mcl_composters/init.lua b/mods/ITEMS/mcl_composters/init.lua index d60422afd..5a67ef92b 100644 --- a/mods/ITEMS/mcl_composters/init.lua +++ b/mods/ITEMS/mcl_composters/init.lua @@ -81,34 +81,44 @@ local function composter_add_item(pos, node, player, itemstack, pointed_thing) max_hear_distance = 16, }, true) end - -- calculate leveling up chance - local rand = math.random(0,100) - if chance >= rand then - -- get current compost level - local level = registered_nodes[node.name]["_mcl_compost_level"] - -- spawn green particles above new layer - mcl_dye.add_bone_meal_particle(vector_offset(pos, 0, level/8, 0)) - -- update composter block - if level < 7 then - level = level + 1 - else - level = "ready" - end - swap_node(pos, {name = "mcl_composters:composter_" .. level}) - minetest.sound_play({name="default_grass_footstep", gain=0.4}, { - pos = pos, - gain= 0.4, - max_hear_distance = 16, - }, true) - -- a full composter becomes ready for harvest after one second - -- the block will get updated by the node timer callback set in node reg def - if level == 7 then - local timer = get_node_timer(pos) + composter_progress_chance(pos, node, chance) + end + return itemstack +end + +--- Math and node swap during compost progression +---@param pos Vector Position of the node +---@param node node +---@param chance integer Value of "compostability" group of inserted item +function composter_progress_chance(pos, node, chance) + -- calculate leveling up chance + local rand = math.random(0,100) + if chance >= rand then + -- get current compost level + local level = registered_nodes[node.name]["_mcl_compost_level"] + -- spawn green particles above new layer + mcl_dye.add_bone_meal_particle(vector_offset(pos, 0, level/8, 0)) + -- update composter block + if level < 7 then + level = level + 1 + else + level = "ready" + end + swap_node(pos, {name = "mcl_composters:composter_" .. level}) + minetest.sound_play({name="default_grass_footstep", gain=0.4}, { + pos = pos, + gain= 0.4, + max_hear_distance = 16, + }, true) + -- a full composter becomes ready for harvest after one second + -- the block will get updated by the node timer callback set in node reg def + if level == 7 then + local timer = get_node_timer(pos) + if not timer:is_started() then timer:start(1) end end end - return itemstack end --- Update a full composter block to ready for harvesting. @@ -147,6 +157,10 @@ local function composter_harvest(pos, node, player, itemstack, pointed_thing) record_protection_violation(pos, name) return itemstack end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + --remove bone meal from internal inventory + inv:set_stack("dst", 1, ItemStack()) -- reset ready type composter to empty type swap_node(pos, {name="mcl_composters:composter"}) -- spawn bone meal item @@ -175,6 +189,14 @@ local function composter_get_nodeboxes(level) } end +local function hopper_push_condition(stack) + local chance = get_item_group(stack:get_name(), "compostability") + if chance > 0 then + return true + end + return false +end + --- Register empty composter node. -- -- This is the craftable base model that can be placed in an inventory. @@ -197,12 +219,40 @@ minetest.register_node("mcl_composters:composter", { groups = { handy=1, material_wood=1, deco_block=1, dirtifier=1, flammable=2, fire_encouragement=3, fire_flammability=4, + container = 2 }, sounds = mcl_sounds.node_sound_wood_defaults(), _mcl_hardness = 0.6, _mcl_blast_resistance = 0.6, _mcl_compost_level = 0, - on_rightclick = composter_add_item + on_rightclick = composter_add_item, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size("src", 1) + inv:set_size("dst", 1) + end, + _mcl_hoppers_on_try_pull = function(pos, hop_pos, hop_inv, hop_list) + return nil, nil, nil + end, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition) + end, + _mcl_hoppers_on_after_push = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack("src", 1) + if not stack:is_empty() then + local chance = get_item_group(stack:get_name(), "compostability") + if chance > 0 then + local node = minetest.get_node(pos) + composter_progress_chance(pos, node, chance) + end + end + inv:remove_item("src", stack) + end, }) --- Template function for composters with compost. @@ -228,7 +278,7 @@ local function register_filled_composter(level) handy=1, material_wood=1, deco_block=1, dirtifier=1, not_in_creative_inventory=1, not_in_craft_guide=1, flammable=2, fire_encouragement=3, fire_flammability=4, - comparator_signal=level + comparator_signal=level, container = 2 }, sounds = mcl_sounds.node_sound_wood_defaults(), drop = "mcl_composters:composter", @@ -236,7 +286,28 @@ local function register_filled_composter(level) _mcl_blast_resistance = 0.6, _mcl_compost_level = level, on_rightclick = composter_add_item, - on_timer = composter_ready + on_timer = composter_ready, + _mcl_hoppers_on_try_pull = function(pos, hop_pos, hop_inv, hop_list) + return nil, nil, nil + end, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition) + end, + _mcl_hoppers_on_after_push = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack("src", 1) + if not stack:is_empty() then + local chance = get_item_group(stack:get_name(), "compostability") + if chance > 0 then + local node = minetest.get_node(pos) + composter_progress_chance(pos, node, chance) + end + end + inv:remove_item("src", stack) + end, }) -- Add entry aliases for the Help @@ -270,14 +341,32 @@ minetest.register_node("mcl_composters:composter_ready", { handy=1, material_wood=1, deco_block=1, dirtifier=1, not_in_creative_inventory=1, not_in_craft_guide=1, flammable=2, fire_encouragement=3, fire_flammability=4, - comparator_signal=8 + comparator_signal=8, container = 2 }, sounds = mcl_sounds.node_sound_wood_defaults(), drop = "mcl_composters:composter", _mcl_hardness = 0.6, _mcl_blast_resistance = 0.6, _mcl_compost_level = 7, - on_rightclick = composter_harvest + on_rightclick = composter_harvest, + _mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list) + return nil, nil, nil + end, + _mcl_hoppers_on_try_pull = function(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + --remove bone meal from internal inventory + inv:set_stack("dst", 1, ItemStack()) + inv:add_item("dst", "mcl_bone_meal:bone_meal") + local stack = inv:get_stack("dst", 1) + if not stack:is_empty() and hop_inv:room_for_item(hop_list, stack) then + return inv, "dst", 1 + end + return nil, nil, nil + end, + _mcl_hoppers_on_after_pull = function(pos) + minetest.swap_node(pos, {name = "mcl_composters:composter"}) + end, }) -- Add entry aliases for the Help diff --git a/mods/ITEMS/mcl_composters/mod.conf b/mods/ITEMS/mcl_composters/mod.conf index 86d729887..ed6119d3a 100644 --- a/mods/ITEMS/mcl_composters/mod.conf +++ b/mods/ITEMS/mcl_composters/mod.conf @@ -1,5 +1,5 @@ name = mcl_composters author = kabou description = Composters can convert various organic items into bonemeal. -depends = mcl_core, mcl_sounds, mcl_dye +depends = mcl_core, mcl_sounds, mcl_dye, mcl_hoppers optional_depends = doc diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index 9cb8ffb16..74e2efecb 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -4,6 +4,8 @@ local F = minetest.formspec_escape local LIGHT_ACTIVE_FURNACE = 13 +mcl_furnaces = {} + -- -- Formspecs -- @@ -445,6 +447,31 @@ local function furnace_node_timer(pos, elapsed) return result end +function mcl_furnaces.hoppers_on_try_pull(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack("dst", 1) + if not stack:is_empty() and hop_inv:room_for_item(hop_list, stack) then + return inv, "dst", 1 + end + -- Allow empty bucket extraction + stack = inv:get_stack("fuel", 1) + if not stack:is_empty() and not mcl_util.is_fuel(stack) and hop_inv:room_for_item(hop_list, stack) then + return inv, "fuel", 1 + end + return nil, nil, nil +end + +function mcl_furnaces.hoppers_on_try_push(pos, hop_pos, hop_inv, hop_list) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z) then + return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src") + else + return inv, "fuel", mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", mcl_util.is_fuel) + end +end + local on_rotate, after_rotate_active if minetest.get_modpath("screwdriver") then on_rotate = screwdriver.rotate_simple @@ -475,7 +502,7 @@ minetest.register_node("mcl_furnaces:furnace", { "default_furnace_side.png", "default_furnace_front.png" }, paramtype2 = "facedir", - groups = { pickaxey = 1, container = 4, deco_block = 1, material_stone = 1 }, + groups = { pickaxey = 1, container = 2, deco_block = 1, material_stone = 1 }, is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), @@ -538,6 +565,11 @@ minetest.register_node("mcl_furnaces:furnace", { _mcl_blast_resistance = 3.5, _mcl_hardness = 3.5, on_rotate = on_rotate, + _mcl_hoppers_on_try_pull = mcl_furnaces.hoppers_on_try_pull, + _mcl_hoppers_on_try_push = mcl_furnaces.hoppers_on_try_push, + _mcl_hoppers_on_after_push = function(pos) + minetest.get_node_timer(pos):start(1.0) + end, }) minetest.register_node("mcl_furnaces:furnace_active", { @@ -552,7 +584,7 @@ minetest.register_node("mcl_furnaces:furnace_active", { paramtype = "light", light_source = LIGHT_ACTIVE_FURNACE, drop = "mcl_furnaces:furnace", - groups = { pickaxey = 1, container = 4, deco_block = 1, not_in_creative_inventory = 1, material_stone = 1 }, + groups = { pickaxey = 1, container = 2, deco_block = 1, not_in_creative_inventory = 1, material_stone = 1 }, is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), on_timer = furnace_node_timer, @@ -592,6 +624,8 @@ minetest.register_node("mcl_furnaces:furnace_active", { _mcl_hardness = 3.5, on_rotate = on_rotate, after_rotate = after_rotate_active, + _mcl_hoppers_on_try_pull = mcl_furnaces.hoppers_on_try_pull, + _mcl_hoppers_on_try_push = mcl_furnaces.hoppers_on_try_push, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index b4378b21b..23a511ce5 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -470,31 +470,38 @@ minetest.register_abm({ if entity and entity.name then --mcl_log("Name of object near: " .. tostring(entity.name)) - if entity.name == "mcl_minecarts:hopper_minecart" or entity.name == "mcl_minecarts:chest_minecart" then + if entity.name == "mcl_minecarts:hopper_minecart" or entity.name == "mcl_minecarts:chest_minecart" or entity.name == "mcl_boats:chest_boat" then local hm_pos = entity.object:get_pos() mcl_log("We have a minecart with inventory close: " .. minetest.pos_to_string(hm_pos)) - --if hm_pos.y == pos.y + 1 then mcl_log("y is correct") end + local ent_pos_y + if entity.name == "mcl_minecarts:hopper_minecart" or entity.name == "mcl_minecarts:chest_minecart" then + ent_pos_y = hm_pos.y + elseif entity.name == "mcl_boats:chest_boat" then + ent_pos_y = math.floor(hm_pos.y + 0.8) + end + + local DIST_FROM_MC = 1.5 + --if ent_pos_y == pos.y - 1 then mcl_log("y is correct") end --if (hm_pos.x >= pos.x - DIST_FROM_MC and hm_pos.x <= pos.x + DIST_FROM_MC) then mcl_log("x is within range") end --if (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then mcl_log("z is within range") end - local DIST_FROM_MC = 1.5 - if (hm_pos.y == pos.y + 1) + if (ent_pos_y == pos.y + 1) and (hm_pos.x >= pos.x - DIST_FROM_MC and hm_pos.x <= pos.x + DIST_FROM_MC) and (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then mcl_log("Minecart close enough") if entity.name == "mcl_minecarts:hopper_minecart" then hopper_pull_from_mc(entity, pos, 5) - elseif entity.name == "mcl_minecarts:chest_minecart" then + elseif entity.name == "mcl_minecarts:chest_minecart" or entity.name == "mcl_boats:chest_boat" then hopper_pull_from_mc(entity, pos, 27) end - elseif (hm_pos.y == pos.y - 1) + elseif (ent_pos_y == pos.y - 1) and (hm_pos.x >= pos.x - DIST_FROM_MC and hm_pos.x <= pos.x + DIST_FROM_MC) and (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then mcl_log("Minecart close enough") if entity.name == "mcl_minecarts:hopper_minecart" then hopper_push_to_mc(entity, pos, 5) - elseif entity.name == "mcl_minecarts:chest_minecart" then + elseif entity.name == "mcl_minecarts:chest_minecart" or entity.name == "mcl_boats:chest_boat" then hopper_push_to_mc(entity, pos, 27) end end @@ -545,25 +552,7 @@ minetest.register_abm({ end, }) ----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) - else - return true - end - else - return false - end -end - +-- Register push/pull for "straight" hopper minetest.register_abm({ label = "Hopper/container item exchange", nodenames = { "mcl_hoppers:hopper" }, @@ -571,31 +560,26 @@ minetest.register_abm({ interval = 1.0, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) - -- Get node pos' for item transfer - 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) - if not minetest.registered_nodes[upnode.name] then return end - local g = minetest.get_item_group(upnode.name, "container") - local sucked = mcl_util.move_item_container(uppos, pos) - - -- Also suck in non-fuel items from furnace fuel slot - if not sucked and g == 4 then - local finv = minetest.get_inventory({type = "node", pos = uppos}) - if finv and not mcl_util.is_fuel(finv:get_stack("fuel", 1)) then - mcl_util.move_item_container(uppos, pos, "fuel") - end + if minetest.get_node_timer(pos):is_started() then + return end - -- Move an item from the hopper into container below - local downnode = minetest.get_node(downpos) - if not minetest.registered_nodes[downnode.name] then return end - mcl_util.move_item_container(pos, downpos) + -- Move from internal inventory to dst first + local dst_pos = vector.offset(pos, 0, -1, 0) + local pushed = mcl_util.hopper_push(pos, dst_pos) + + local src_pos = vector.offset(pos, 0, 1, 0) + mcl_util.hopper_pull(pos, src_pos) + + local dst_node = minetest.get_node(dst_pos) + if pushed and (dst_node.name == "mcl_hoppers:hopper" or dst_node.name == "mcl_hoppers:hopper_side") then + --Pause destination hopper + minetest.get_node_timer(dst_pos):start(1.0) + end end, }) +-- Register push/pull for "bent" hopper minetest.register_abm({ label = "Side-hopper/container item exchange", nodenames = { "mcl_hoppers:hopper_side" }, @@ -603,164 +587,36 @@ minetest.register_abm({ interval = 1.0, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) + if minetest.get_node_timer(pos):is_started() then + --Pause if already recived item this tick + return + end + -- Determine to which side the hopper is facing, get nodes local face = minetest.get_node(pos).param2 - local front = {} + local dst_pos = {} if face == 0 then - front = vector.offset(pos, -1, 0, 0) + dst_pos = vector.offset(pos, -1, 0, 0) elseif face == 1 then - front = vector.offset(pos, 0, 0, 1) + dst_pos = vector.offset(pos, 0, 0, 1) elseif face == 2 then - front = vector.offset(pos, 1, 0, 0) + dst_pos = vector.offset(pos, 1, 0, 0) elseif face == 3 then - front = vector.offset(pos, 0, 0, -1) + dst_pos = vector.offset(pos, 0, 0, -1) end - local above = vector.offset(pos, 0, 1, 0) - - local frontnode = minetest.get_node(front) - if not minetest.registered_nodes[frontnode.name] then return end - - -- Suck an item from the container above into the hopper - local abovenode = minetest.get_node(above) - if not minetest.registered_nodes[abovenode.name] then return end - local g = minetest.get_item_group(abovenode.name, "container") - local sucked = mcl_util.move_item_container(above, pos) - - -- Also suck in non-fuel items from furnace fuel slot - if not sucked and g == 4 then - local finv = minetest.get_inventory({type = "node", pos = above}) - if finv and not mcl_util.is_fuel(finv:get_stack("fuel", 1)) then - mcl_util.move_item_container(above, pos, "fuel") - end + local pushed = mcl_util.hopper_push(pos, dst_pos) + + local src_pos = vector.offset(pos, 0, 1, 0) + mcl_util.hopper_pull(pos, src_pos) + + local dst_node = minetest.get_node(dst_pos) + if pushed and (dst_node.name == "mcl_hoppers:hopper" or dst_node.name == "mcl_hoppers:hopper_side") then + --Pause destination hopper + minetest.get_node_timer(dst_pos):start(1.0) end - - -- Move an item from the hopper into the container to which the hopper points to - local g = minetest.get_item_group(frontnode.name, "container") - if g == 2 or g == 3 or g == 5 or g == 6 then - mcl_util.move_item_container(pos, front) - elseif g == 4 then - -- Put fuel into fuel slot - local sinv = minetest.get_inventory({type = "node", pos = pos}) - local dinv = minetest.get_inventory({type = "node", pos = front}) - local slot_id, _ = mcl_util.get_eligible_transfer_item_slot(sinv, "main", dinv, "fuel", is_transferrable_fuel) - if slot_id then - mcl_util.move_item_container(pos, front, nil, slot_id, "fuel") - end - end - end + end, }) -if minetest.get_modpath("mcl_composters") then - minetest.register_abm({ - label = "Bonemeal extraction from composter", - nodenames = {"mcl_hoppers:hopper", "mcl_hoppers:hopper_side"}, - neighbors = {"mcl_composters:composter_ready"}, - interval = 1.0, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - 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_bone_meal:bone_meal") - 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", - }, - interval = 1.0, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - --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() - - 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 - 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 - else - level = "ready" - end - minetest.swap_node(downpos, {name = "mcl_composters:composter_" .. level}) - end - break - end - end - end - end, - }) -end - minetest.register_craft({ output = "mcl_hoppers:hopper", recipe = { diff --git a/mods/ITEMS/mcl_itemframes/item_frames_API.lua b/mods/ITEMS/mcl_itemframes/item_frames_API.lua index 999becf05..dbdaa313d 100644 --- a/mods/ITEMS/mcl_itemframes/item_frames_API.lua +++ b/mods/ITEMS/mcl_itemframes/item_frames_API.lua @@ -638,7 +638,7 @@ function mcl_itemframes.create_base_definitions() paramtype = "light", paramtype2 = "facedir", sunlight_propagates = true, - groups = { dig_immediate = 3, deco_block = 1, dig_by_piston = 1, container = 7, }, -- attached_node_facedir = 1 }, -- allows for more placement options. + groups = { dig_immediate = 3, deco_block = 1, dig_by_piston = 1, container = 1, }, -- attached_node_facedir = 1 }, -- allows for more placement options. sounds = mcl_sounds.node_sound_defaults(), node_placement_prediction = "", diff --git a/mods/ITEMS/mcl_jukebox/init.lua b/mods/ITEMS/mcl_jukebox/init.lua index d817bdac7..e64bc52c7 100644 --- a/mods/ITEMS/mcl_jukebox/init.lua +++ b/mods/ITEMS/mcl_jukebox/init.lua @@ -121,7 +121,7 @@ minetest.register_node("mcl_jukebox:jukebox", { _doc_items_usagehelp = S("Place a music disc into an empty jukebox to insert the music disc and play music. If the jukebox already has a music disc, you will retrieve this music disc first. The music can only be heard by you, not by other players."), tiles = {"mcl_jukebox_top.png", "mcl_jukebox_side.png", "mcl_jukebox_side.png"}, sounds = mcl_sounds.node_sound_wood_defaults(), - groups = {handy=1,axey=1, container=7, deco_block=1, material_wood=1, flammable=-1}, + groups = {handy=1,axey=1, container=1, deco_block=1, material_wood=1, flammable=-1}, is_ground_content = false, on_construct = function(pos) local meta = minetest.get_meta(pos) diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index 73fcdae16..8e4c53cad 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -256,7 +256,7 @@ minetest.register_craftitem("mcl_potions:water", { stack_max = 1, inventory_image = potion_image("#0022FF"), wield_image = potion_image("#0022FF"), - groups = {brewitem=1, food=3, can_eat_when_full=1, water_bottle=1}, + groups = {brewitem=1, food=3, can_eat_when_full=1, water_bottle=1, bottle=1}, on_place = water_bottle_on_place, _on_dispense = dispense_water_bottle, _dispense_into_walkable = true, @@ -273,7 +273,7 @@ minetest.register_craftitem("mcl_potions:river_water", { stack_max = 1, inventory_image = potion_image("#0044FF"), wield_image = potion_image("#0044FF"), - groups = {brewitem=1, food=3, can_eat_when_full=1, water_bottle=1}, + groups = {brewitem=1, food=3, can_eat_when_full=1, water_bottle=1, bottle=1}, on_place = water_bottle_on_place, _on_dispense = dispense_water_bottle, _dispense_into_walkable = true, diff --git a/mods/ITEMS/mcl_potions/lingering.lua b/mods/ITEMS/mcl_potions/lingering.lua index 17088ad13..46d94cad3 100644 --- a/mods/ITEMS/mcl_potions/lingering.lua +++ b/mods/ITEMS/mcl_potions/lingering.lua @@ -102,7 +102,7 @@ function mcl_potions.register_lingering(name, descr, color, def) _doc_items_longdesc = longdesc, _doc_items_usagehelp = S("Use the “Punch” key to throw it."), inventory_image = lingering_image(color), - groups = {brewitem=1, not_in_creative_inventory=0}, + groups = {brewitem=1, not_in_creative_inventory=0, bottle=1}, on_use = function(item, placer, pointed_thing) local velocity = 10 local dir = placer:get_look_dir(); diff --git a/mods/ITEMS/mcl_potions/potions.lua b/mods/ITEMS/mcl_potions/potions.lua index 57c06c29d..225fffed2 100644 --- a/mods/ITEMS/mcl_potions/potions.lua +++ b/mods/ITEMS/mcl_potions/potions.lua @@ -163,7 +163,7 @@ local function register_potion(def) stack_max = def.stack_max or 1, inventory_image = def.image or potion_image(def.color), wield_image = def.image or potion_image(def.color), - groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1 }, + groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, on_place = on_use, on_secondary_use = on_use, }) @@ -260,7 +260,7 @@ local function register_potion(def) stack_max = def.stack_max or 1, inventory_image = def.image or potion_image(def.color), wield_image = def.image or potion_image(def.color), - groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1}, + groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, on_place = on_use, on_secondary_use = on_use, }) @@ -343,7 +343,7 @@ local function register_potion(def) stack_max = 1, inventory_image = def.image or potion_image(def.color), wield_image = def.image or potion_image(def.color), - groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1}, + groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, on_place = on_use, on_secondary_use = on_use, }) @@ -411,7 +411,7 @@ local awkward_def = { _tt = S("No effect"), _longdesc = S("Has an awkward taste and is used for brewing potions."), color = "#0000FF", - groups = {brewitem=1, food=3, can_eat_when_full=1}, + groups = {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, on_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), } @@ -450,7 +450,7 @@ local dragon_breath_def = { no_effect = true, _longdesc = S("This item is used in brewing and can be combined with splash potions to create lingering potions."), image = "mcl_potions_dragon_breath.png", - groups = { brewitem = 1 }, + groups = { brewitem = 1, bottle = 1 }, on_use = nil, stack_max = 64, } diff --git a/mods/ITEMS/mcl_potions/splash.lua b/mods/ITEMS/mcl_potions/splash.lua index 6b6238dbf..0b8aedeab 100644 --- a/mods/ITEMS/mcl_potions/splash.lua +++ b/mods/ITEMS/mcl_potions/splash.lua @@ -26,7 +26,7 @@ function mcl_potions.register_splash(name, descr, color, def) _doc_items_longdesc = longdesc, _doc_items_usagehelp = S("Use the “Punch” key to throw it."), inventory_image = splash_image(color), - groups = {brewitem=1, not_in_creative_inventory=0}, + groups = {brewitem=1, not_in_creative_inventory=0, bottle=1}, on_use = function(item, placer, pointed_thing) local velocity = 10 local dir = placer:get_look_dir(); diff --git a/mods/ITEMS/mcl_smoker/init.lua b/mods/ITEMS/mcl_smoker/init.lua index 757f13054..787d0c429 100644 --- a/mods/ITEMS/mcl_smoker/init.lua +++ b/mods/ITEMS/mcl_smoker/init.lua @@ -453,7 +453,7 @@ minetest.register_node("mcl_smoker:smoker", { "smoker_side.png", "smoker_front.png" }, paramtype2 = "facedir", - groups = { pickaxey = 1, container = 4, deco_block = 1, material_stone = 1 }, + groups = { pickaxey = 1, container = 2, deco_block = 1, material_stone = 1 }, is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), @@ -519,6 +519,11 @@ minetest.register_node("mcl_smoker:smoker", { _mcl_blast_resistance = 3.5, _mcl_hardness = 3.5, on_rotate = on_rotate, + _mcl_hoppers_on_try_pull = mcl_furnaces.hoppers_on_try_pull, + _mcl_hoppers_on_try_push = mcl_furnaces.hoppers_on_try_push, + _mcl_hoppers_on_after_push = function(pos) + minetest.get_node_timer(pos):start(1.0) + end, }) minetest.register_node("mcl_smoker:smoker_active", { @@ -536,7 +541,7 @@ minetest.register_node("mcl_smoker:smoker_active", { paramtype = "light", light_source = LIGHT_ACTIVE_FURNACE, drop = "mcl_smoker:smoker", - groups = { pickaxey = 1, container = 4, deco_block = 1, not_in_creative_inventory = 1, material_stone = 1 }, + groups = { pickaxey = 1, container = 2, deco_block = 1, not_in_creative_inventory = 1, material_stone = 1 }, is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), on_timer = smoker_node_timer, @@ -579,6 +584,8 @@ minetest.register_node("mcl_smoker:smoker_active", { _mcl_hardness = 3.5, on_rotate = on_rotate, after_rotate = after_rotate_active, + _mcl_hoppers_on_try_pull = mcl_furnaces.hoppers_on_try_pull, + _mcl_hoppers_on_try_push = mcl_furnaces.hoppers_on_try_push, }) minetest.register_craft({