From b8f4ee3f8b4cab2acb8161a2ba421e4779b2717e Mon Sep 17 00:00:00 2001 From: FaceDeer Date: Fri, 31 Mar 2017 00:58:28 -0600 Subject: [PATCH] Sorter, splitting up giant init.lua Adding a sorter, and splitting up the overly-large init.lua in the process. --- abms.lua | 124 +++++ api.lua | 117 ++++ config.lua | 17 + crafts.lua | 48 ++ depends.txt | 2 + doc.lua | 24 + init.lua | 805 +--------------------------- locale/de.po | 114 ++-- locale/template.pot | 108 ++-- locale/update.bat | 6 + nodes/chute.lua | 115 ++++ nodes/hoppers.lua | 227 ++++++++ nodes/sorter.lua | 186 +++++++ textures/hopper_back_16.png | Bin 305 -> 293 bytes textures/hopper_back_32.png | Bin 500 -> 550 bytes textures/hopper_sorter_arrow_16.png | Bin 0 -> 260 bytes textures/hopper_sorter_arrow_32.png | Bin 0 -> 385 bytes utility.lua | 146 +++++ 18 files changed, 1171 insertions(+), 868 deletions(-) create mode 100644 abms.lua create mode 100644 api.lua create mode 100644 config.lua create mode 100644 crafts.lua create mode 100644 doc.lua create mode 100644 locale/update.bat create mode 100644 nodes/chute.lua create mode 100644 nodes/hoppers.lua create mode 100644 nodes/sorter.lua create mode 100644 textures/hopper_sorter_arrow_16.png create mode 100644 textures/hopper_sorter_arrow_32.png create mode 100644 utility.lua diff --git a/abms.lua b/abms.lua new file mode 100644 index 0000000..edef8ed --- /dev/null +++ b/abms.lua @@ -0,0 +1,124 @@ + +-- suck in items on top of hopper +minetest.register_abm({ + label = "Hopper suction", + nodenames = {"hopper:hopper", "hopper:hopper_side"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + if active_object_count_wider == 0 then + return + end + + local inv = minetest.get_meta(pos):get_inventory() + local posob + + for _,object in pairs(minetest.get_objects_inside_radius(pos, 1)) do + if not object:is_player() + and object:get_luaentity() + and object:get_luaentity().name == "__builtin:item" + and inv + and inv:room_for_item("main", + ItemStack(object:get_luaentity().itemstring)) then + + posob = object:getpos() + + if math.abs(posob.x - pos.x) <= 0.5 + and posob.y - pos.y <= 0.85 + and posob.y - pos.y >= 0.3 then + + inv:add_item("main", + ItemStack(object:get_luaentity().itemstring)) + + object:get_luaentity().itemstring = "" + object:remove() + end + end + end + end, +}) + +-- Used to convert side hopper facing into source and destination relative coordinates +-- This was tedious to populate and test +local directions = { + [0]={["src"]={x=0, y=1, z=0},["dst"]={x=-1, y=0, z=0}}, + [1]={["src"]={x=0, y=1, z=0},["dst"]={x=0, y=0, z=1}}, + [2]={["src"]={x=0, y=1, z=0},["dst"]={x=1, y=0, z=0}}, + [3]={["src"]={x=0, y=1, z=0},["dst"]={x=0, y=0, z=-1}}, + [4]={["src"]={x=0, y=0, z=1},["dst"]={x=-1, y=0, z=0}}, + [5]={["src"]={x=0, y=0, z=1},["dst"]={x=0, y=-1, z=0}}, + [6]={["src"]={x=0, y=0, z=1},["dst"]={x=1, y=0, z=0}}, + [7]={["src"]={x=0, y=0, z=1},["dst"]={x=0, y=1, z=0}}, + [8]={["src"]={x=0, y=0, z=-1},["dst"]={x=-1, y=0, z=0}}, + [9]={["src"]={x=0, y=0, z=-1},["dst"]={x=0, y=1, z=0}}, + [10]={["src"]={x=0, y=0, z=-1},["dst"]={x=1, y=0, z=0}}, + [11]={["src"]={x=0, y=0, z=-1},["dst"]={x=0, y=-1, z=0}}, + [12]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=1, z=0}}, + [13]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=0, z=1}}, + [14]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=-1, z=0}}, + [15]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=0, z=-1}}, + [16]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=-1, z=0}}, + [17]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=0, z=1}}, + [18]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=1, z=0}}, + [19]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=0, z=-1}}, + [20]={["src"]={x=0, y=-1, z=0},["dst"]={x=1, y=0, z=0}}, + [21]={["src"]={x=0, y=-1, z=0},["dst"]={x=0, y=0, z=1}}, + [22]={["src"]={x=0, y=-1, z=0},["dst"]={x=-1, y=0, z=0}}, + [23]={["src"]={x=0, y=-1, z=0},["dst"]={x=0, y=0, z=-1}}, +} + +local bottomdir = function(facedir) + return ({[0]={x=0, y=-1, z=0}, + {x=0, y=0, z=-1}, + {x=0, y=0, z=1}, + {x=-1, y=0, z=0}, + {x=1, y=0, z=0}, + {x=0, y=1, z=0}})[math.floor(facedir/4)] +end + +-- hopper workings +minetest.register_abm({ + label = "Hopper transfer", + nodenames = {"hopper:hopper", "hopper:hopper_side"}, + neighbors = hopper.neighbors, + interval = 1.0, + chance = 1, + catch_up = false, + + action = function(pos, node, active_object_count, active_object_count_wider) + local source_pos, destination_pos, destination_dir + if node.name == "hopper:hopper_side" then + source_pos = vector.add(pos, directions[node.param2].src) + destination_dir = directions[node.param2].dst + destination_pos = vector.add(pos, destination_dir) + else + destination_dir = bottomdir(node.param2) + source_pos = vector.subtract(pos, destination_dir) + destination_pos = vector.add(pos, destination_dir) + end + + local output_direction + if destination_dir.y == 0 then + output_direction = "horizontal" + end + + local source_node = minetest.get_node(source_pos) + local destination_node = minetest.get_node(destination_pos) + + local registered_source_inventories = hopper.get_registered_inventories_for(source_node.name) + if registered_source_inventories ~= nil then + hopper.take_item_from(pos, source_pos, source_node, registered_source_inventories["top"]) + end + + local registered_destination_inventories = hopper.get_registered_inventories_for(destination_node.name) + if registered_destination_inventories ~= nil then + if output_direction == "horizontal" then + hopper.send_item_to(pos, destination_pos, destination_node, registered_destination_inventories["side"]) + else + hopper.send_item_to(pos, destination_pos, destination_node, registered_destination_inventories["bottom"]) + end + else + hopper.send_item_to(pos, destination_pos, destination_node) -- for handling ejection + end + end, +}) diff --git a/api.lua b/api.lua new file mode 100644 index 0000000..4eb6282 --- /dev/null +++ b/api.lua @@ -0,0 +1,117 @@ +hopper.containers = {} +hopper.groups = {} +hopper.neighbors = {} + +-- global function to add new containers +function hopper:add_container(list) + for _, entry in pairs(list) do + + local target_node = entry[2] + local neighbor_node + + if string.sub(target_node, 1, 6) == "group:" then + local group_identifier, group_number + local equals_index = string.find(target_node, "=") + if equals_index ~= nil then + group_identifier = string.sub(target_node, 7, equals_index-1) + -- it's possible that the string was of the form "group:blah = 1", in which case we want to trim spaces off the end of the group identifier + local space_index = string.find(group_identifier, " ") + if space_index ~= nil then + group_identifier = string.sub(group_identifier, 1, space_index-1) + end + group_number = tonumber(string.sub(target_node, equals_index+1, -1)) + else + group_identifier = string.sub(target_node, 7, -1) + group_number = "all" -- special value to indicate no number was provided + end + + local group_info = hopper.groups[group_identifier] + if group_info == nil then + group_info = {} + end + if group_info[group_number] == nil then + group_info[group_number] = {} + end + group_info[group_number][entry[1]] = entry[3] + hopper.groups[group_identifier] = group_info + neighbor_node = "group:"..group_identifier + -- result is a table of the form groups[group_identifier][group_number][relative_position][inventory_name] + else + local node_info = hopper.containers[target_node] + if node_info == nil then + node_info = {} + end + node_info[entry[1]] = entry[3] + hopper.containers[target_node] = node_info + neighbor_node = target_node + -- result is a table of the form containers[target_node_name][relative_position][inventory_name] + end + + local already_in_neighbors = false + for _, value in pairs(hopper.neighbors) do + if value == neighbor_node then + already_in_neighbors = true + break + end + end + if not already_in_neighbors then + table.insert(hopper.neighbors, neighbor_node) + end + end +end + +-- "top" indicates what inventory the hopper will take items from if this node is located at the hopper's wide end +-- "side" indicates what inventory the hopper will put items into if this node is located at the hopper's narrow end and at the same height as the hopper +-- "bottom" indicates what inventory the hopper will put items into if this node is located at the hopper's narrow end and either above or below the hopper. + +hopper:add_container({ + {"top", "hopper:hopper", "main"}, + {"bottom", "hopper:hopper", "main"}, + {"side", "hopper:hopper", "main"}, + {"side", "hopper:hopper_side", "main"}, + + {"bottom", "hopper:chute", "main"}, + {"side", "hopper:chute", "main"}, + + {"bottom", "hopper:sorter", "main"}, + {"side", "hopper:sorter", "main"}, +}) + +if minetest.get_modpath("default") then + hopper:add_container({ + {"top", "default:chest", "main"}, + {"bottom", "default:chest", "main"}, + {"side", "default:chest", "main"}, + + {"top", "default:furnace", "dst"}, + {"bottom", "default:furnace", "src"}, + {"side", "default:furnace", "fuel"}, + + {"top", "default:furnace_active", "dst"}, + {"bottom", "default:furnace_active", "src"}, + {"side", "default:furnace_active", "fuel"}, + + {"top", "default:chest_locked", "main"}, + {"bottom", "default:chest_locked", "main"}, + {"side", "default:chest_locked", "main"}, + }) +end + +-- protector redo mod support +if minetest.get_modpath("protector") then + hopper:add_container({ + {"top", "protector:chest", "main"}, + {"bottom", "protector:chest", "main"}, + {"side", "protector:chest", "main"}, + }) +end + +-- wine mod support +if minetest.get_modpath("wine") then + hopper:add_container({ + {"top", "wine:wine_barrel", "dst"}, + {"bottom", "wine:wine_barrel", "src"}, + {"side", "wine:wine_barrel", "src"}, + }) +end + diff --git a/config.lua b/config.lua new file mode 100644 index 0000000..5ca395d --- /dev/null +++ b/config.lua @@ -0,0 +1,17 @@ +hopper.config = {} + +-- settings +hopper.config.texture_resolution = minetest.setting_get("hopper_texture_size") +if hopper.config.texture_resolution == nil then + hopper.config.texture_resolution = "16" +end + +hopper.config.single_craftable_item = minetest.setting_getbool("hopper_single_craftable_item") +if hopper.config.single_craftable_item == nil then + hopper.config.single_craftable_item = true +end + +hopper.config.eject_button_enabled = minetest.setting_getbool("hopper_eject_button") +if hopper.config.eject_button_enabled == nil then + hopper.config.eject_button_enabled = true +end diff --git a/crafts.lua b/crafts.lua new file mode 100644 index 0000000..065c04f --- /dev/null +++ b/crafts.lua @@ -0,0 +1,48 @@ + +if minetest.get_modpath("default") then + minetest.register_craft({ + output = "hopper:hopper", + recipe = { + {"default:steel_ingot","default:chest","default:steel_ingot"}, + {"","default:steel_ingot",""}, + } + }) + + minetest.register_craft({ + output = "hopper:chute", + recipe = { + {"default:steel_ingot","default:chest","default:steel_ingot"}, + } + }) + + minetest.register_craft({ + output = "hopper:sorter", + recipe = { + {"","default:mese_crystal",""}, + {"default:steel_ingot","default:chest","default:steel_ingot"}, + {"","default:steel_ingot",""}, + } + }) + + if not hopper.config.single_craftable_item then + minetest.register_craft({ + output = "hopper:hopper_side", + recipe = { + {"default:steel_ingot","default:chest","default:steel_ingot"}, + {"","","default:steel_ingot"}, + } + }) + + minetest.register_craft({ + output = "hopper:hopper_side", + type="shapeless", + recipe = {"hopper:hopper"}, + }) + + minetest.register_craft({ + output = "hopper:hopper", + type="shapeless", + recipe = {"hopper:hopper_side"}, + }) + end +end \ No newline at end of file diff --git a/depends.txt b/depends.txt index 74aec35..79d95ba 100644 --- a/depends.txt +++ b/depends.txt @@ -2,3 +2,5 @@ default? lucky_block? doc? intllib? +protector? +wine? \ No newline at end of file diff --git a/doc.lua b/doc.lua new file mode 100644 index 0000000..d7fee24 --- /dev/null +++ b/doc.lua @@ -0,0 +1,24 @@ +hopper.doc = {} + +if not minetest.get_modpath("doc") then + return +end + +-- internationalization boilerplate +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +hopper.doc.hopper_long_desc = S("Hopper to transfer items between neighboring blocks' inventories.") +hopper.doc.hopper_usage = S("Items are transfered from the block at the wide end of the hopper to the block at the narrow end of the hopper at a rate of one per second. Items can also be placed directly into the hopper's inventory, or they can be dropped into the space above a hopper and will be sucked into the hopper's inventory automatically.\n\n") +if hopper.config.single_craftable_item then + hopper.doc.hopper_usage = hopper.doc.hopper_usage .. S("Hopper blocks come in both 'vertical' and 'side' forms, but when in a player's inventory both are represented by a single generic item. The type of hopper block that will be placed when the player uses this item depends on what is pointed at - when the hopper item is pointed at the top or bottom face of a block a vertical hopper is placed, when aimed at the side of a block a side hopper is produced that connects to the clicked-on side.\n\n") +else + hopper.doc.hopper_usage = hopper.doc.hopper_usage .. S("Hopper blocks come in both 'vertical' and 'side' forms. They can be interconverted between the two forms via the crafting grid.\n\n") +end +hopper.doc.hopper_usage = hopper.doc.hopper_usage .. S("When used with furnaces, hoppers inject items into the furnace's \"raw material\" inventory slot when the narrow end is attached to the top or bottom and inject items into the furnace's \"fuel\" inventory slot when attached to the furnace's side.\n\nItems that cannot be placed in a target block's inventory will remain in the hopper.\n\nHoppers have the same permissions as the player that placed them. Hoppers placed by you are allowed to take items from or put items into locked chests that you own, but hoppers placed by other players will be unable to do so. A hopper's own inventory is not not owner-locked, though, so you can use this as a way to allow other players to deposit items into your locked chests.") + +hopper.doc.chute_long_desc = S("A chute to transfer items over longer distances.") +hopper.doc.chute_usage = S("Chutes operate much like hoppers but do not have their own intake capability. Items can only be inserted into a chute manually or by a hopper connected to a chute. They transfer items in the direction indicated by the arrow on their narrow segment at a rate of one item per second. They have a small buffer capacity, and any items that can't be placed into the target block's inventory will remain lodged in the chute's buffer until manually removed or their destination becomes available.") + +hopper.doc.sorter_long_desc = S("A sorter to redirect certain items to an alternate target.") +hopper.doc.sorter_usage = S("This is similar to a chute but has a secondary output that is used to shunt specific items to an alternate destination. There is a set of inventory slots labeled \"Filter\" at the top of this block's inventory display, if you place an item into one of these slots the sorter will record the item's type (without actually taking it from you). Then when items come through the sorter's inventory that match one of the items in the filter list it will first attempt to send it in the direction marked with an arrow on the sorter's sides.\n\nIf the item doesn't match the filter list, or the secondary output is unable to take the item for whatever reason, the sorter will try to send the item out the other output instead.") \ No newline at end of file diff --git a/init.lua b/init.lua index f1ef970..f2c7cfc 100644 --- a/init.lua +++ b/init.lua @@ -5,635 +5,22 @@ hopper = {} local MP = minetest.get_modpath(minetest.get_current_modname()) local S, NS = dofile(MP.."/intllib.lua") --- settings -local texture_resolution = minetest.setting_get("hopper_texture_size") -if texture_resolution == nil then - texture_resolution = "16" -end - -local single_craftable_item = minetest.setting_getbool("hopper_single_craftable_item") -if single_craftable_item == nil then - single_craftable_item = true -end - -local eject_button_enabled = minetest.setting_getbool("hopper_eject_button") -if eject_button_enabled == nil then - eject_button_enabled = true -end - -------------------------------------------------------------------------------------------- --- API - -local containers = {} -local groups = {} -local neighbors = {} - --- global function to add new containers -function hopper:add_container(list) - for _, entry in pairs(list) do - - local target_node = entry[2] - local neighbor_node - - if string.sub(target_node, 1, 6) == "group:" then - local group_identifier, group_number - local equals_index = string.find(target_node, "=") - if equals_index ~= nil then - group_identifier = string.sub(target_node, 7, equals_index-1) - -- it's possible that the string was of the form "group:blah = 1", in which case we want to trim spaces off the end of the group identifier - local space_index = string.find(group_identifier, " ") - if space_index ~= nil then - group_identifier = string.sub(group_identifier, 1, space_index-1) - end - group_number = tonumber(string.sub(target_node, equals_index+1, -1)) - else - group_identifier = string.sub(target_node, 7, -1) - group_number = "all" -- special value to indicate no number was provided - end - - local group_info = groups[group_identifier] - if group_info == nil then - group_info = {} - end - if group_info[group_number] == nil then - group_info[group_number] = {} - end - group_info[group_number][entry[1]] = entry[3] - groups[group_identifier] = group_info - neighbor_node = "group:"..group_identifier - -- result is a table of the form groups[group_identifier][group_number][relative_position][inventory_name] - else - local node_info = containers[target_node] - if node_info == nil then - node_info = {} - end - node_info[entry[1]] = entry[3] - containers[target_node] = node_info - neighbor_node = target_node - -- result is a table of the form containers[target_node_name][relative_position][inventory_name] - end - - local already_in_neighbors = false - for _, value in pairs(neighbors) do - if value == neighbor_node then - already_in_neighbors = true - break - end - end - if not already_in_neighbors then - table.insert(neighbors, neighbor_node) - end - end -end - --- "top" indicates what inventory the hopper will take items from if this node is located at the hopper's wide end --- "side" indicates what inventory the hopper will put items into if this node is located at the hopper's narrow end and at the same height as the hopper --- "bottom" indicates what inventory the hopper will put items into if this node is located at the hopper's narrow end and either above or below the hopper. - -hopper:add_container({ - {"top", "hopper:hopper", "main"}, - {"bottom", "hopper:hopper", "main"}, - {"side", "hopper:hopper", "main"}, - {"side", "hopper:hopper_side", "main"}, - - {"bottom", "hopper:chute", "main"}, - {"side", "hopper:chute", "main"}, -}) - if minetest.get_modpath("default") then - hopper:add_container({ - {"top", "default:chest", "main"}, - {"bottom", "default:chest", "main"}, - {"side", "default:chest", "main"}, - - {"top", "default:furnace", "dst"}, - {"bottom", "default:furnace", "src"}, - {"side", "default:furnace", "fuel"}, - - {"top", "default:furnace_active", "dst"}, - {"bottom", "default:furnace_active", "src"}, - {"side", "default:furnace_active", "fuel"}, - - {"top", "default:chest_locked", "main"}, - {"bottom", "default:chest_locked", "main"}, - {"side", "default:chest_locked", "main"}, - }) -end - --- protector redo mod support -if minetest.get_modpath("protector") then - hopper:add_container({ - {"top", "protector:chest", "main"}, - {"bottom", "protector:chest", "main"}, - {"side", "protector:chest", "main"}, - }) -end - --- wine mod support -if minetest.get_modpath("wine") then - hopper:add_container({ - {"top", "wine:wine_barrel", "dst"}, - {"bottom", "wine:wine_barrel", "src"}, - {"side", "wine:wine_barrel", "src"}, - }) -end - -------------------------------------------------------------------------------------------- --- Documentation - -local hopper_long_desc = S("Hopper to transfer items between neighboring blocks' inventories.") -local hopper_usage = S("Items are transfered from the block at the wide end of the hopper to the block at the narrow end of the hopper at a rate of one per second. Items can also be placed directly into the hopper's inventory, or they can be dropped into the space above a hopper and will be sucked into the hopper's inventory automatically.\n\n") -if single_craftable_item then - hopper_usage = hopper_usage .. S("Hopper blocks come in both 'vertical' and 'side' forms, but when in a player's inventory both are represented by a single generic item. The type of hopper block that will be placed when the player uses this item depends on what is pointed at - when the hopper item is pointed at the top or bottom face of a block a vertical hopper is placed, when aimed at the side of a block a side hopper is produced that connects to the clicked-on side.\n\n") + hopper.formspec_bg = default.gui_bg .. default.gui_bg_img .. default.gui_slots else - hopper_usage = hopper_usage .. S("Hopper blocks come in both 'vertical' and 'side' forms. They can be interconverted between the two forms via the crafting grid.\n\n") -end -hopper_usage = hopper_usage .. S("When used with furnaces, hoppers inject items into the furnace's \"raw material\" inventory slot when the narrow end is attached to the top or bottom and inject items into the furnace's \"fuel\" inventory slot when attached to the furnace's side.\n\nItems that cannot be placed in a target block's inventory will remain in the hopper.\n\nHoppers have the same permissions as the player that placed them. Hoppers placed by you are allowed to take items from or put items into locked chests that you own, but hoppers placed by other players will be unable to do so. A hopper's own inventory is not not owner-locked, though, so you can use this as a way to allow other players to deposit items into your locked chests.") - -local chute_long_desc = S("A chute to transfer items over longer distances.") -local chute_usage = S("Chutes operate much like hoppers but do not have their own intake capability. Items can only be inserted into a chute manually or by a hopper connected to a chute. They transfer items in the direction indicated by the arrow on their narrow segment at a rate of one item per second. They have a small buffer capacity, and any items that can't be placed into the target block's inventory will remain lodged in the chute's buffer until manually removed or their destination becomes available.") - -------------------------------------------------------------------------------------------- --- Target inventory retrieval - --- looks first for a registration matching the specific node name, then for a registration --- matching group and value, then for a registration matching a group and *any* value -local get_registered_inventories_for = function(target_node_name) - local output = containers[target_node_name] - if output ~= nil then return output end - - local target_def = minetest.registered_nodes[target_node_name] - if target_def.groups == nil then return nil end - - for group, value in pairs(target_def.groups) do - local registered_group = groups[group] - if registered_group ~= nil then - output = registered_group[value] - if output ~= nil then return output end - output = registered_group["all"] - if output ~= nil then return output end - end - end - - return nil + hopper.formspec_bg = "bgcolor[#080808BB;true]" .. "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" end -------------------------------------------------------------------------------------------- --- Inventory transfer functions +dofile(MP.."/config.lua") +dofile(MP.."/api.lua") +dofile(MP.."/utility.lua") +dofile(MP.."/doc.lua") +dofile(MP.."/nodes/hoppers.lua") +dofile(MP.."/nodes/chute.lua") +dofile(MP.."/nodes/sorter.lua") +dofile(MP.."/crafts.lua") +dofile(MP.."/abms.lua") --- Used to remove items from the target block and put it into the hopper's inventory -local function take_item_from(hopper_pos, target_pos, target_node, target_inventory_name) - if target_inventory_name == nil then - return - end - - --hopper inventory - local hopper_meta = minetest.get_meta(hopper_pos); - local hopper_inv = hopper_meta:get_inventory() - local placer = minetest.get_player_by_name(hopper_meta:get_string("placer")) - - --source inventory - local target_inv = minetest.get_meta(target_pos):get_inventory() - local target_inv_size = target_inv:get_size(target_inventory_name) - local target_def = minetest.registered_nodes[target_node.name] - if target_inv:is_empty(target_inventory_name) == false then - for i = 1,target_inv_size do - local stack = target_inv:get_stack(target_inventory_name, i) - local item = stack:get_name() - if item ~= "" then - if hopper_inv:room_for_item("main", item) then - local stack_to_take = stack:take_item(1) - if target_def.allow_metadata_inventory_take == nil - or placer == nil -- backwards compatibility, older versions of this mod didn't record who placed the hopper - or target_def.allow_metadata_inventory_take(target_pos, target_inventory_name, i, stack_to_take, placer) > 0 then - target_inv:set_stack(target_inventory_name, i, stack) - --add to hopper - hopper_inv:add_item("main", item) - if target_def.on_metadata_inventory_take ~= nil and placer ~= nil then - target_def.on_metadata_inventory_take(target_pos, target_inventory_name, i, stack_to_take, placer) - end - break - end - end - end - end - end -end - --- Used to put items from the hopper inventory into the target block -local function send_item_to(hopper_pos, target_pos, target_node, target_inventory_name) - local hopper_meta = minetest.get_meta(hopper_pos) - local target_def = minetest.registered_nodes[target_node.name] - local eject_item = eject_button_enabled and hopper_meta:get_string("eject") == "true" and target_def.buildable_to - - if not eject_item and not target_inventory_name then - return - end - - --hopper inventory - local hopper_meta = minetest.get_meta(hopper_pos); - local hopper_inv = hopper_meta:get_inventory() - if hopper_inv:is_empty("main") == true then - return - end - local hopper_inv_size = hopper_inv:get_size("main") - local placer = minetest.get_player_by_name(hopper_meta:get_string("placer")) - - --target inventory - local target_inv = minetest.get_meta(target_pos):get_inventory() - - for i = 1,hopper_inv_size do - local stack = hopper_inv:get_stack("main", i) - local item = stack:get_name() - if item ~= "" then - if target_inventory_name then - if target_inv:room_for_item(target_inventory_name, item) then - local stack_to_put = stack:take_item(1) - if target_def.allow_metadata_inventory_put == nil - or placer == nil -- backwards compatibility, older versions of this mod didn't record who placed the hopper - or target_def.allow_metadata_inventory_put(target_pos, target_inventory_name, i, stack_to_put, placer) > 0 then - hopper_inv:set_stack("main", i, stack) - --add to target node - target_inv:add_item(target_inventory_name, stack_to_put) - if target_def.on_metadata_inventory_put ~= nil and placer ~= nil then - target_def.on_metadata_inventory_put(target_pos, target_inventory_name, i, stack_to_put, placer) - end - break - end - end - elseif eject_item then - local stack_to_put = stack:take_item(1) - minetest.add_item(target_pos, stack_to_put) - hopper_inv:set_stack("main", i, stack) - end - end - end -end - -------------------------------------------------------------------------------------------- --- Nodes - -local function get_eject_button_texts(pos, loc_X, loc_Y) - if not eject_button_enabled then return "" end - - local eject_button_text, eject_button_tooltip - if minetest.get_meta(pos):get_string("eject") == "true" then - eject_button_text = S("Don't\nEject") - eject_button_tooltip = S("This hopper is currently set to eject items from its output\neven if there isn't a compatible block positioned to receive it.\nClick this button to disable this feature.") - else - eject_button_text = S("Eject\nItems") - eject_button_tooltip = S("This hopper is currently set to hold on to item if there\nisn't a compatible block positioned to receive it.\nClick this button to have it eject items instead.") - end - return string.format("button_exit[%i,%i;1,1;eject;%s]tooltip[eject;%s]", loc_X, loc_Y, eject_button_text, eject_button_tooltip) -end - -local function get_string_pos(pos) - return pos.x .. "," .. pos.y .. "," ..pos.z -end - -local formspec_bg -if minetest.get_modpath("default") then - formspec_bg = default.gui_bg .. default.gui_bg_img .. default.gui_slots -else - formspec_bg = "bgcolor[#080808BB;true]" .. "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" -end - --- formspec -local function get_hopper_formspec(pos) - local spos = get_string_pos(pos) - local formspec = - "size[8,9]" - .. formspec_bg - .. "list[nodemeta:" .. spos .. ";main;2,0.3;4,4;]" - .. get_eject_button_texts(pos, 7, 2) - .. "list[current_player;main;0,4.85;8,1;]" - .. "list[current_player;main;0,6.08;8,3;8]" - .. "listring[nodemeta:" .. spos .. ";main]" - .. "listring[current_player;main]" - return formspec -end - -local hopper_on_place = function(itemstack, placer, pointed_thing, node_name) - local pos = pointed_thing.under - local pos2 = pointed_thing.above - local x = pos.x - pos2.x - local z = pos.z - pos2.z - - local returned_stack, success - -- unfortunately param2 overrides are needed for side hoppers even in the non-single-craftable-item case - -- because they are literally *side* hoppers - their spouts point to the side rather than to the front, so - -- the default item_place_node orientation code will not orient them pointing toward the selected surface. - if x == -1 and (single_craftable_item or node_name == "hopper:hopper_side") then - returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 0) - elseif x == 1 and (single_craftable_item or node_name == "hopper:hopper_side") then - returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 2) - elseif z == -1 and (single_craftable_item or node_name == "hopper:hopper_side") then - returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 3) - elseif z == 1 and (single_craftable_item or node_name == "hopper:hopper_side") then - returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 1) - else - if single_craftable_item then - node_name = "hopper:hopper" -- For cases where single_craftable_item was set on an existing world and there are still side hoppers in player inventories - end - returned_stack, success = minetest.item_place_node(ItemStack(node_name), placer, pointed_thing) - end - - if success then - local meta = minetest.get_meta(pos2) - meta:set_string("placer", placer:get_player_name()) - if not minetest.setting_getbool("creative_mode") then - itemstack:take_item() - end - end - return itemstack -end - -------------------------------------------------------------------------------------------- --- Hoppers - -minetest.register_node("hopper:hopper", { - drop = "hopper:hopper", - description = S("Hopper"), - _doc_items_longdesc = hopper_long_desc, - _doc_items_usagehelp = hopper_usage, - groups = {cracky = 3}, - drawtype = "nodebox", - paramtype = "light", - paramtype2 = "facedir", - tiles = { - "hopper_top_" .. texture_resolution .. ".png", - "hopper_top_" .. texture_resolution .. ".png", - "hopper_front_" .. texture_resolution .. ".png" - }, - node_box = { - type = "fixed", - fixed = { - --funnel walls - {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5}, - {0.4, 0.0, -0.5, 0.5, 0.5, 0.5}, - {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5}, - {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4}, - --funnel base - {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5}, - --spout - {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, - {-0.15, -0.3, -0.15, 0.15, -0.7, 0.15}, - }, - }, - selection_box = { - type = "fixed", - fixed = { - --funnel - {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5}, - --spout - {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, - {-0.15, -0.3, -0.15, 0.15, -0.7, 0.15}, - }, - }, - - on_construct = function(pos) - local inv = minetest.get_meta(pos):get_inventory() - inv:set_size("main", 4*4) - end, - - on_place = function(itemstack, placer, pointed_thing) - return hopper_on_place(itemstack, placer, pointed_thing, "hopper:hopper") - end, - - can_dig = function(pos, player) - local inv = minetest.get_meta(pos):get_inventory() - return inv:is_empty("main") - end, - - on_rightclick = function(pos, node, clicker, itemstack) - if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then - return - end - minetest.show_formspec(clicker:get_player_name(), - "hopper_formspec:"..minetest.pos_to_string(pos), get_hopper_formspec(pos)) - end, - - on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - minetest.log("action", S("@1 moves stuff in hopper at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - end, - - on_metadata_inventory_put = function(pos, listname, index, stack, player) - minetest.log("action", S("@1 moves stuff to hopper at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - end, - - on_metadata_inventory_take = function(pos, listname, index, stack, player) - minetest.log("action", S("@1 moves stuff from hopper at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - end, -}) - -local hopper_side_drop -local hopper_groups -if single_craftable_item then - hopper_side_drop = "hopper:hopper" - hopper_groups = {cracky=3, not_in_creative_inventory = 1} -else - hopper_side_drop = "hopper:hopper_side" - hopper_groups = {cracky=3} -end - -minetest.register_node("hopper:hopper_side", { - description = S("Side Hopper"), - _doc_items_longdesc = hopper_long_desc, - _doc_items_usagehelp = hopper_usage, - drop = hopper_side_drop, - groups = hopper_groups, - drawtype = "nodebox", - paramtype = "light", - paramtype2 = "facedir", - tiles = { - "hopper_top_" .. texture_resolution .. ".png", - "hopper_bottom_" .. texture_resolution .. ".png", - "hopper_back_" .. texture_resolution .. ".png", - "hopper_side_" .. texture_resolution .. ".png", - "hopper_back_" .. texture_resolution .. ".png", - "hopper_back_" .. texture_resolution .. ".png" - }, - node_box = { - type = "fixed", - fixed = { - --funnel walls - {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5}, - {0.4, 0.0, -0.5, 0.5, 0.5, 0.5}, - {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5}, - {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4}, - --funnel base - {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5}, - --spout - {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, - {-0.7, -0.3, -0.15, 0.15, 0.0, 0.15}, - }, - }, - selection_box = { - type = "fixed", - fixed = { - --funnel - {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5}, - --spout - {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, - {-0.7, -0.3, -0.15, 0.15, 0.0, 0.15}, - }, - }, - - on_construct = function(pos) - local inv = minetest.get_meta(pos):get_inventory() - inv:set_size("main", 4*4) - end, - - on_place = function(itemstack, placer, pointed_thing) - return hopper_on_place(itemstack, placer, pointed_thing, "hopper:hopper_side") - end, - - can_dig = function(pos,player) - local inv = minetest.get_meta(pos):get_inventory() - return inv:is_empty("main") - end, - - on_rightclick = function(pos, node, clicker, itemstack) - if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then - return - end - minetest.show_formspec(clicker:get_player_name(), - "hopper_formspec:"..minetest.pos_to_string(pos), get_hopper_formspec(pos)) - end, - - on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - minetest.log("action", S("@1 moves stuff in hopper at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - end, - - on_metadata_inventory_put = function(pos, listname, index, stack, player) - minetest.log("action", S("@1 moves stuff to hopper at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - end, - - on_metadata_inventory_take = function(pos, listname, index, stack, player) - minetest.log("action", S("@1 moves stuff from hopper at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - end, -}) - -local function get_chute_formspec(pos) - local spos = pos.x .. "," .. pos.y .. "," ..pos.z - local formspec = - "size[8,7]" - .. formspec_bg - .. "list[nodemeta:" .. spos .. ";main;3,0.3;2,2;]" - .. get_eject_button_texts(pos, 7, 1) - .. "list[current_player;main;0,2.85;8,1;]" - .. "list[current_player;main;0,4.08;8,3;8]" - .. "listring[nodemeta:" .. spos .. ";main]" - .. "listring[current_player;main]" - return formspec -end - -------------------------------------------------------------------------------------------- --- Chute - -minetest.register_node("hopper:chute", { - description = S("Hopper Chute"), - _doc_items_longdesc = chute_long_desc, - _doc_items_usagehelp = chute_usage, - drop = "hopper:chute", - groups = {cracky = 3}, - drawtype = "nodebox", - paramtype = "light", - paramtype2 = "facedir", - tiles = { - "hopper_bottom_" .. texture_resolution .. ".png^hopper_chute_arrow_" .. texture_resolution .. ".png", - "hopper_bottom_" .. texture_resolution .. ".png^(hopper_chute_arrow_" .. texture_resolution .. ".png^[transformR180)", - "hopper_bottom_" .. texture_resolution .. ".png^(hopper_chute_arrow_" .. texture_resolution .. ".png^[transformR270)", - "hopper_bottom_" .. texture_resolution .. ".png^(hopper_chute_arrow_" .. texture_resolution .. ".png^[transformR90)", - "hopper_top_" .. texture_resolution .. ".png", - "hopper_bottom_" .. texture_resolution .. ".png" - }, - node_box = { - type = "fixed", - fixed = { - {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}, - {-0.2, -0.2, 0.3, 0.2, 0.2, 0.7}, - }, - }, - - on_construct = function(pos) - local inv = minetest.get_meta(pos):get_inventory() - inv:set_size("main", 2*2) - end, - - on_place = function(itemstack, placer, pointed_thing, node_name) - local pos = pointed_thing.under - local pos2 = pointed_thing.above - local x = pos.x - pos2.x - local z = pos.z - pos2.z - - local returned_stack, success = minetest.item_place_node(itemstack, placer, pointed_thing) - if success then - local meta = minetest.get_meta(pos2) - meta:set_string("placer", placer:get_player_name()) - end - return returned_stack - end, - - can_dig = function(pos,player) - local inv = minetest.get_meta(pos):get_inventory() - return inv:is_empty("main") - end, - - on_rightclick = function(pos, node, clicker, itemstack) - if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then - return - end - minetest.show_formspec(clicker:get_player_name(), - "hopper_formspec:"..minetest.pos_to_string(pos), get_chute_formspec(pos)) - end, - - on_metadata_inventory_put = function(pos, listname, index, stack, player) - minetest.log("action", S("@1 moves stuff to chute at @2", - player:get_player_name(), minetest.pos_to_string(pos))) - - local timer = minetest.get_node_timer(pos) - if not timer:is_started() then - timer:start(1) - end - end, - - on_timer = function(pos, elapsed) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory() - local eject_item = meta:get_string("eject") == "true" - - local node = minetest.get_node(pos) - local dir = minetest.facedir_to_dir(node.param2) - local destination_pos = vector.add(pos, dir) - local output_direction - if dir.y == 0 then - output_direction = "horizontal" - end - - local destination_node = minetest.get_node(destination_pos) - local registered_inventories = get_registered_inventories_for(destination_node.name) - if registered_inventories ~= nil then - if output_direction == "horizontal" then - send_item_to(pos, destination_pos, destination_node, registered_inventories["side"]) - else - send_item_to(pos, destination_pos, destination_node, registered_inventories["bottom"]) - end - else - send_item_to(pos, destination_pos, destination_node) - end - - if not inv:is_empty("main") then - minetest.get_node_timer(pos):start(1) - end - end, -}) ------------------------------------------------------------------------------------------- -- Formspec handling @@ -654,174 +41,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end) -------------------------------------------------------------------------------------------- --- ABMs - --- suck in items on top of hopper -minetest.register_abm({ - label = "Hopper suction", - nodenames = {"hopper:hopper", "hopper:hopper_side"}, - interval = 1.0, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - if active_object_count_wider == 0 then - return - end - - local inv = minetest.get_meta(pos):get_inventory() - local posob - - for _,object in pairs(minetest.get_objects_inside_radius(pos, 1)) do - if not object:is_player() - and object:get_luaentity() - and object:get_luaentity().name == "__builtin:item" - and inv - and inv:room_for_item("main", - ItemStack(object:get_luaentity().itemstring)) then - - posob = object:getpos() - - if math.abs(posob.x - pos.x) <= 0.5 - and posob.y - pos.y <= 0.85 - and posob.y - pos.y >= 0.3 then - - inv:add_item("main", - ItemStack(object:get_luaentity().itemstring)) - - object:get_luaentity().itemstring = "" - object:remove() - end - end - end - end, -}) - --- Used to convert side hopper facing into source and destination relative coordinates --- This was tedious to populate and test -local directions = { - [0]={["src"]={x=0, y=1, z=0},["dst"]={x=-1, y=0, z=0}}, - [1]={["src"]={x=0, y=1, z=0},["dst"]={x=0, y=0, z=1}}, - [2]={["src"]={x=0, y=1, z=0},["dst"]={x=1, y=0, z=0}}, - [3]={["src"]={x=0, y=1, z=0},["dst"]={x=0, y=0, z=-1}}, - [4]={["src"]={x=0, y=0, z=1},["dst"]={x=-1, y=0, z=0}}, - [5]={["src"]={x=0, y=0, z=1},["dst"]={x=0, y=-1, z=0}}, - [6]={["src"]={x=0, y=0, z=1},["dst"]={x=1, y=0, z=0}}, - [7]={["src"]={x=0, y=0, z=1},["dst"]={x=0, y=1, z=0}}, - [8]={["src"]={x=0, y=0, z=-1},["dst"]={x=-1, y=0, z=0}}, - [9]={["src"]={x=0, y=0, z=-1},["dst"]={x=0, y=1, z=0}}, - [10]={["src"]={x=0, y=0, z=-1},["dst"]={x=1, y=0, z=0}}, - [11]={["src"]={x=0, y=0, z=-1},["dst"]={x=0, y=-1, z=0}}, - [12]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=1, z=0}}, - [13]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=0, z=1}}, - [14]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=-1, z=0}}, - [15]={["src"]={x=1, y=0, z=0},["dst"]={x=0, y=0, z=-1}}, - [16]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=-1, z=0}}, - [17]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=0, z=1}}, - [18]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=1, z=0}}, - [19]={["src"]={x=-1, y=0, z=0},["dst"]={x=0, y=0, z=-1}}, - [20]={["src"]={x=0, y=-1, z=0},["dst"]={x=1, y=0, z=0}}, - [21]={["src"]={x=0, y=-1, z=0},["dst"]={x=0, y=0, z=1}}, - [22]={["src"]={x=0, y=-1, z=0},["dst"]={x=-1, y=0, z=0}}, - [23]={["src"]={x=0, y=-1, z=0},["dst"]={x=0, y=0, z=-1}}, -} - -local bottomdir = function(facedir) - return ({[0]={x=0, y=-1, z=0}, - {x=0, y=0, z=-1}, - {x=0, y=0, z=1}, - {x=-1, y=0, z=0}, - {x=1, y=0, z=0}, - {x=0, y=1, z=0}})[math.floor(facedir/4)] -end - --- hopper workings -minetest.register_abm({ - label = "Hopper transfer", - nodenames = {"hopper:hopper", "hopper:hopper_side"}, - neighbors = neighbors, - interval = 1.0, - chance = 1, - catch_up = false, - - action = function(pos, node, active_object_count, active_object_count_wider) - local source_pos, destination_pos, destination_dir - if node.name == "hopper:hopper_side" then - source_pos = vector.add(pos, directions[node.param2].src) - destination_dir = directions[node.param2].dst - destination_pos = vector.add(pos, destination_dir) - else - destination_dir = bottomdir(node.param2) - source_pos = vector.subtract(pos, destination_dir) - destination_pos = vector.add(pos, destination_dir) - end - - local output_direction - if destination_dir.y == 0 then - output_direction = "horizontal" - end - - local source_node = minetest.get_node(source_pos) - local destination_node = minetest.get_node(destination_pos) - - local registered_source_inventories = get_registered_inventories_for(source_node.name) - if registered_source_inventories ~= nil then - take_item_from(pos, source_pos, source_node, registered_source_inventories["top"]) - end - - local registered_destination_inventories = get_registered_inventories_for(destination_node.name) - if registered_destination_inventories ~= nil then - if output_direction == "horizontal" then - send_item_to(pos, destination_pos, destination_node, registered_destination_inventories["side"]) - else - send_item_to(pos, destination_pos, destination_node, registered_destination_inventories["bottom"]) - end - else - send_item_to(pos, destination_pos, destination_node) -- for handling ejection - end - end, -}) - -------------------------------------------------------------------------------------------- --- Crafts - -if minetest.get_modpath("default") then - minetest.register_craft({ - output = "hopper:hopper", - recipe = { - {"default:steel_ingot","default:chest","default:steel_ingot"}, - {"","default:steel_ingot",""}, - } - }) - - minetest.register_craft({ - output = "hopper:chute", - recipe = { - {"default:steel_ingot","default:chest","default:steel_ingot"}, - } - }) - - if not single_craftable_item then - minetest.register_craft({ - output = "hopper:hopper_side", - recipe = { - {"default:steel_ingot","default:chest","default:steel_ingot"}, - {"","","default:steel_ingot"}, - } - }) - - minetest.register_craft({ - output = "hopper:hopper_side", - type="shapeless", - recipe = {"hopper:hopper"}, - }) - - minetest.register_craft({ - output = "hopper:hopper", - type="shapeless", - recipe = {"hopper:hopper_side"}, - }) - end -end -- add lucky blocks if minetest.get_modpath("lucky_block") then @@ -831,4 +50,4 @@ if minetest.get_modpath("lucky_block") then }) end -print (S("[MOD] Hopper loaded")) +print (S("[MOD] Hopper loaded")) \ No newline at end of file diff --git a/locale/de.po b/locale/de.po index c6a2c52..b6d91b4 100644 --- a/locale/de.po +++ b/locale/de.po @@ -8,19 +8,20 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-02-25 06:31-0700\n" +"POT-Creation-Date: 2017-03-31 00:35-0600\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: init.lua:135 +#: hopper\doc.lua:11 msgid "Hopper to transfer items between neighboring blocks' inventories." msgstr "" -#: init.lua:136 +#: hopper\doc.lua:12 msgid "" "Items are transfered from the block at the wide end of the hopper to the " "block at the narrow end of the hopper at a rate of one per second. Items can " @@ -30,7 +31,7 @@ msgid "" "\n" msgstr "" -#: init.lua:138 +#: hopper\doc.lua:14 msgid "" "Hopper blocks come in both 'vertical' and 'side' forms, but when in a " "player's inventory both are represented by a single generic item. The type " @@ -41,14 +42,14 @@ msgid "" "\n" msgstr "" -#: init.lua:140 +#: hopper\doc.lua:16 msgid "" "Hopper blocks come in both 'vertical' and 'side' forms. They can be " "interconverted between the two forms via the crafting grid.\n" "\n" msgstr "" -#: init.lua:142 +#: hopper\doc.lua:18 msgid "" "When used with furnaces, hoppers inject items into the furnace's \"raw " "material\" inventory slot when the narrow end is attached to the top or " @@ -65,11 +66,11 @@ msgid "" "as a way to allow other players to deposit items into your locked chests." msgstr "" -#: init.lua:144 +#: hopper\doc.lua:20 msgid "A chute to transfer items over longer distances." msgstr "" -#: init.lua:145 +#: hopper\doc.lua:21 msgid "" "Chutes operate much like hoppers but do not have their own intake " "capability. Items can only be inserted into a chute manually or by a hopper " @@ -80,62 +81,97 @@ msgid "" "removed or their destination becomes available." msgstr "" -#: init.lua:270 +#: hopper\doc.lua:23 +msgid "A sorter to redirect certain items to an alternate target." +msgstr "" + +#: hopper\doc.lua:24 +msgid "" +"This is similar to a chute but has a secondary output that is used to shunt " +"specific items to an alternate destination. There is a set of inventory " +"slots labeled \"Filter\" at the top of this block's inventory display, if " +"you place an item into one of these slots the sorter will record the item's " +"type (without actually taking it from you). Then when items come through the " +"sorter's inventory that match one of the items in the filter list it will " +"first attempt to send it in the direction marked with an arrow on the " +"sorter's sides.\n" +"\n" +"If the item doesn't match the filter list, or the secondary output is unable " +"to take the item for whatever reason, the sorter will try to send the item " +"out the other output instead." +msgstr "" + +#: hopper\init.lua:53 +msgid "[MOD] Hopper loaded" +msgstr "[MOD] Trichter geladen" + +#: hopper\utility.lua:34 msgid "" "Don't\n" "Eject" msgstr "" -#: init.lua:270 +#: hopper\utility.lua:35 msgid "" "This hopper is currently set to eject items from its output\n" "even if there isn't a compatible block positioned to receive it.\n" "Click this button to disable this feature." msgstr "" -#: init.lua:272 +#: hopper\utility.lua:37 msgid "" "Eject\n" "Items" msgstr "" -#: init.lua:272 +#: hopper\utility.lua:38 msgid "" "This hopper is currently set to hold on to item if there\n" "isn't a compatible block positioned to receive it.\n" "Click this button to have it eject items instead." msgstr "" -#: init.lua:339 -msgid "Hopper" -msgstr "Trichter" - -#: init.lua:400 init.lua:491 -msgid "@1 moves stuff in hopper at @2" -msgstr "@1 bewegt Dinge in einem Trichter bei @2" - -#: init.lua:405 init.lua:496 -msgid "@1 moves stuff to hopper at @2" -msgstr "@1 verlagert Dinge in einen Trichter bei @2" - -#: init.lua:410 init.lua:501 -msgid "@1 moves stuff from hopper at @2" -msgstr "@1 nimmt Dinge aus einem Trichter bei @2" - -#: init.lua:426 -msgid "Side Hopper" -msgstr "Seitentrichter" - -#: init.lua:528 -#, fuzzy +#: hopper\nodes\chute.lua:20 msgid "Hopper Chute" -msgstr "Trichter" +msgstr "" -#: init.lua:585 +#: hopper\nodes\chute.lua:77 #, fuzzy msgid "@1 moves stuff to chute at @2" msgstr "@1 verlagert Dinge in einen Trichter bei @2" -#: init.lua:819 -msgid "[MOD] Hopper loaded" -msgstr "[MOD] Trichter geladen" +#: hopper\nodes\hoppers.lua:60 +msgid "Hopper" +msgstr "Trichter" + +#: hopper\nodes\hoppers.lua:121 +#: hopper\nodes\hoppers.lua:212 +msgid "@1 moves stuff in hopper at @2" +msgstr "@1 bewegt Dinge in einem Trichter bei @2" + +#: hopper\nodes\hoppers.lua:126 +#: hopper\nodes\hoppers.lua:217 +msgid "@1 moves stuff to hopper at @2" +msgstr "@1 verlagert Dinge in einen Trichter bei @2" + +#: hopper\nodes\hoppers.lua:131 +#: hopper\nodes\hoppers.lua:222 +msgid "@1 moves stuff from hopper at @2" +msgstr "@1 nimmt Dinge aus einem Trichter bei @2" + +#: hopper\nodes\hoppers.lua:147 +msgid "Side Hopper" +msgstr "Seitentrichter" + +#: hopper\nodes\sorter.lua:23 +msgid "Filter" +msgstr "" + +#: hopper\nodes\sorter.lua:36 +msgid "Sorter" +msgstr "" + +#: hopper\nodes\sorter.lua:115 +#, fuzzy +msgid "@1 moves stuff to sorter at @2" +msgstr "@1 verlagert Dinge in einen Trichter bei @2" diff --git a/locale/template.pot b/locale/template.pot index 962c5d5..1c28eeb 100644 --- a/locale/template.pot +++ b/locale/template.pot @@ -8,19 +8,20 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-02-25 06:31-0700\n" +"POT-Creation-Date: 2017-03-31 00:35-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: init.lua:135 +#: hopper\doc.lua:11 msgid "Hopper to transfer items between neighboring blocks' inventories." msgstr "" -#: init.lua:136 +#: hopper\doc.lua:12 msgid "" "Items are transfered from the block at the wide end of the hopper to the " "block at the narrow end of the hopper at a rate of one per second. Items can " @@ -30,7 +31,7 @@ msgid "" "\n" msgstr "" -#: init.lua:138 +#: hopper\doc.lua:14 msgid "" "Hopper blocks come in both 'vertical' and 'side' forms, but when in a " "player's inventory both are represented by a single generic item. The type " @@ -41,14 +42,14 @@ msgid "" "\n" msgstr "" -#: init.lua:140 +#: hopper\doc.lua:16 msgid "" "Hopper blocks come in both 'vertical' and 'side' forms. They can be " "interconverted between the two forms via the crafting grid.\n" "\n" msgstr "" -#: init.lua:142 +#: hopper\doc.lua:18 msgid "" "When used with furnaces, hoppers inject items into the furnace's \"raw " "material\" inventory slot when the narrow end is attached to the top or " @@ -65,11 +66,11 @@ msgid "" "as a way to allow other players to deposit items into your locked chests." msgstr "" -#: init.lua:144 +#: hopper\doc.lua:20 msgid "A chute to transfer items over longer distances." msgstr "" -#: init.lua:145 +#: hopper\doc.lua:21 msgid "" "Chutes operate much like hoppers but do not have their own intake " "capability. Items can only be inserted into a chute manually or by a hopper " @@ -80,60 +81,95 @@ msgid "" "removed or their destination becomes available." msgstr "" -#: init.lua:270 +#: hopper\doc.lua:23 +msgid "A sorter to redirect certain items to an alternate target." +msgstr "" + +#: hopper\doc.lua:24 +msgid "" +"This is similar to a chute but has a secondary output that is used to shunt " +"specific items to an alternate destination. There is a set of inventory " +"slots labeled \"Filter\" at the top of this block's inventory display, if " +"you place an item into one of these slots the sorter will record the item's " +"type (without actually taking it from you). Then when items come through the " +"sorter's inventory that match one of the items in the filter list it will " +"first attempt to send it in the direction marked with an arrow on the " +"sorter's sides.\n" +"\n" +"If the item doesn't match the filter list, or the secondary output is unable " +"to take the item for whatever reason, the sorter will try to send the item " +"out the other output instead." +msgstr "" + +#: hopper\init.lua:53 +msgid "[MOD] Hopper loaded" +msgstr "" + +#: hopper\utility.lua:34 msgid "" "Don't\n" "Eject" msgstr "" -#: init.lua:270 +#: hopper\utility.lua:35 msgid "" "This hopper is currently set to eject items from its output\n" "even if there isn't a compatible block positioned to receive it.\n" "Click this button to disable this feature." msgstr "" -#: init.lua:272 +#: hopper\utility.lua:37 msgid "" "Eject\n" "Items" msgstr "" -#: init.lua:272 +#: hopper\utility.lua:38 msgid "" "This hopper is currently set to hold on to item if there\n" "isn't a compatible block positioned to receive it.\n" "Click this button to have it eject items instead." msgstr "" -#: init.lua:339 -msgid "Hopper" -msgstr "" - -#: init.lua:400 init.lua:491 -msgid "@1 moves stuff in hopper at @2" -msgstr "" - -#: init.lua:405 init.lua:496 -msgid "@1 moves stuff to hopper at @2" -msgstr "" - -#: init.lua:410 init.lua:501 -msgid "@1 moves stuff from hopper at @2" -msgstr "" - -#: init.lua:426 -msgid "Side Hopper" -msgstr "" - -#: init.lua:528 +#: hopper\nodes\chute.lua:20 msgid "Hopper Chute" msgstr "" -#: init.lua:585 +#: hopper\nodes\chute.lua:77 msgid "@1 moves stuff to chute at @2" msgstr "" -#: init.lua:819 -msgid "[MOD] Hopper loaded" +#: hopper\nodes\hoppers.lua:60 +msgid "Hopper" +msgstr "" + +#: hopper\nodes\hoppers.lua:121 +#: hopper\nodes\hoppers.lua:212 +msgid "@1 moves stuff in hopper at @2" +msgstr "" + +#: hopper\nodes\hoppers.lua:126 +#: hopper\nodes\hoppers.lua:217 +msgid "@1 moves stuff to hopper at @2" +msgstr "" + +#: hopper\nodes\hoppers.lua:131 +#: hopper\nodes\hoppers.lua:222 +msgid "@1 moves stuff from hopper at @2" +msgstr "" + +#: hopper\nodes\hoppers.lua:147 +msgid "Side Hopper" +msgstr "" + +#: hopper\nodes\sorter.lua:23 +msgid "Filter" +msgstr "" + +#: hopper\nodes\sorter.lua:36 +msgid "Sorter" +msgstr "" + +#: hopper\nodes\sorter.lua:115 +msgid "@1 moves stuff to sorter at @2" msgstr "" diff --git a/locale/update.bat b/locale/update.bat new file mode 100644 index 0000000..e87d44c --- /dev/null +++ b/locale/update.bat @@ -0,0 +1,6 @@ +@echo off +setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION +cd .. +set LIST= +for /r %%X in (*.lua) do set LIST=!LIST! %%X +..\intllib\tools\xgettext.bat %LIST% \ No newline at end of file diff --git a/nodes/chute.lua b/nodes/chute.lua new file mode 100644 index 0000000..c354318 --- /dev/null +++ b/nodes/chute.lua @@ -0,0 +1,115 @@ +-- internationalization boilerplate +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +local function get_chute_formspec(pos) + local spos = hopper.get_string_pos(pos) + local formspec = + "size[8,7]" + .. hopper.formspec_bg + .. "list[nodemeta:" .. spos .. ";main;3,0.3;2,2;]" + .. hopper.get_eject_button_texts(pos, 7, 1) + .. "list[current_player;main;0,2.85;8,1;]" + .. "list[current_player;main;0,4.08;8,3;8]" + .. "listring[nodemeta:" .. spos .. ";main]" + .. "listring[current_player;main]" + return formspec +end + +minetest.register_node("hopper:chute", { + description = S("Hopper Chute"), + _doc_items_longdesc = hopper.doc.chute_long_desc, + _doc_items_usagehelp = hopper.doc.chute_usage, + drop = "hopper:chute", + groups = {cracky = 3}, + sounds = hopper.metal_sounds, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + tiles = { + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^hopper_chute_arrow_" .. hopper.config.texture_resolution .. ".png", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^(hopper_chute_arrow_" .. hopper.config.texture_resolution .. ".png^[transformR180)", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^(hopper_chute_arrow_" .. hopper.config.texture_resolution .. ".png^[transformR270)", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^(hopper_chute_arrow_" .. hopper.config.texture_resolution .. ".png^[transformR90)", + "hopper_top_" .. hopper.config.texture_resolution .. ".png", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png" + }, + node_box = { + type = "fixed", + fixed = { + {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}, + {-0.2, -0.2, 0.3, 0.2, 0.2, 0.7}, + }, + }, + + on_construct = function(pos) + local inv = minetest.get_meta(pos):get_inventory() + inv:set_size("main", 2*2) + end, + + on_place = function(itemstack, placer, pointed_thing, node_name) + local pos = pointed_thing.under + local pos2 = pointed_thing.above + local x = pos.x - pos2.x + local z = pos.z - pos2.z + + local returned_stack, success = minetest.item_place_node(itemstack, placer, pointed_thing) + if success then + local meta = minetest.get_meta(pos2) + meta:set_string("placer", placer:get_player_name()) + end + return returned_stack + end, + + can_dig = function(pos,player) + local inv = minetest.get_meta(pos):get_inventory() + return inv:is_empty("main") + end, + + on_rightclick = function(pos, node, clicker, itemstack) + if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then + return + end + minetest.show_formspec(clicker:get_player_name(), + "hopper_formspec:"..minetest.pos_to_string(pos), get_chute_formspec(pos)) + end, + + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", S("@1 moves stuff to chute at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + + local timer = minetest.get_node_timer(pos) + if not timer:is_started() then + timer:start(1) + end + end, + + on_timer = function(pos, elapsed) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + local destination_pos = vector.add(pos, dir) + local output_direction + if dir.y == 0 then + output_direction = "horizontal" + end + + local destination_node = minetest.get_node(destination_pos) + local registered_inventories = hopper.get_registered_inventories_for(destination_node.name) + if registered_inventories ~= nil then + if output_direction == "horizontal" then + hopper.send_item_to(pos, destination_pos, destination_node, registered_inventories["side"]) + else + hopper.send_item_to(pos, destination_pos, destination_node, registered_inventories["bottom"]) + end + else + hopper.send_item_to(pos, destination_pos, destination_node) + end + + if not inv:is_empty("main") then + minetest.get_node_timer(pos):start(1) + end + end, +}) \ No newline at end of file diff --git a/nodes/hoppers.lua b/nodes/hoppers.lua new file mode 100644 index 0000000..2c40696 --- /dev/null +++ b/nodes/hoppers.lua @@ -0,0 +1,227 @@ +-- internationalization boilerplate +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +-- formspec +local function get_hopper_formspec(pos) + local spos = hopper.get_string_pos(pos) + local formspec = + "size[8,9]" + .. hopper.formspec_bg + .. "list[nodemeta:" .. spos .. ";main;2,0.3;4,4;]" + .. hopper.get_eject_button_texts(pos, 7, 2) + .. "list[current_player;main;0,4.85;8,1;]" + .. "list[current_player;main;0,6.08;8,3;8]" + .. "listring[nodemeta:" .. spos .. ";main]" + .. "listring[current_player;main]" + return formspec +end + +local hopper_on_place = function(itemstack, placer, pointed_thing, node_name) + local pos = pointed_thing.under + local pos2 = pointed_thing.above + local x = pos.x - pos2.x + local z = pos.z - pos2.z + + local returned_stack, success + -- unfortunately param2 overrides are needed for side hoppers even in the non-single-craftable-item case + -- because they are literally *side* hoppers - their spouts point to the side rather than to the front, so + -- the default item_place_node orientation code will not orient them pointing toward the selected surface. + if x == -1 and (hopper.config.single_craftable_item or node_name == "hopper:hopper_side") then + returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 0) + elseif x == 1 and (hopper.config.single_craftable_item or node_name == "hopper:hopper_side") then + returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 2) + elseif z == -1 and (hopper.config.single_craftable_item or node_name == "hopper:hopper_side") then + returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 3) + elseif z == 1 and (hopper.config.single_craftable_item or node_name == "hopper:hopper_side") then + returned_stack, success = minetest.item_place_node(ItemStack("hopper:hopper_side"), placer, pointed_thing, 1) + else + if hopper.config.single_craftable_item then + node_name = "hopper:hopper" -- For cases where single_craftable_item was set on an existing world and there are still side hoppers in player inventories + end + returned_stack, success = minetest.item_place_node(ItemStack(node_name), placer, pointed_thing) + end + + if success then + local meta = minetest.get_meta(pos2) + meta:set_string("placer", placer:get_player_name()) + if not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + end + return itemstack +end + +------------------------------------------------------------------------------------------- +-- Hoppers + +minetest.register_node("hopper:hopper", { + drop = "hopper:hopper", + description = S("Hopper"), + _doc_items_longdesc = hopper.doc.hopper_long_desc, + _doc_items_usagehelp = hopper.doc.hopper_usage, + groups = {cracky = 3}, + sounds = hopper.metal_sounds, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + tiles = { + "hopper_top_" .. hopper.config.texture_resolution .. ".png", + "hopper_top_" .. hopper.config.texture_resolution .. ".png", + "hopper_front_" .. hopper.config.texture_resolution .. ".png" + }, + node_box = { + type = "fixed", + fixed = { + --funnel walls + {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5}, + {0.4, 0.0, -0.5, 0.5, 0.5, 0.5}, + {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5}, + {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4}, + --funnel base + {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5}, + --spout + {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, + {-0.15, -0.3, -0.15, 0.15, -0.7, 0.15}, + }, + }, + selection_box = { + type = "fixed", + fixed = { + --funnel + {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5}, + --spout + {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, + {-0.15, -0.3, -0.15, 0.15, -0.7, 0.15}, + }, + }, + + on_construct = function(pos) + local inv = minetest.get_meta(pos):get_inventory() + inv:set_size("main", 4*4) + end, + + on_place = function(itemstack, placer, pointed_thing) + return hopper_on_place(itemstack, placer, pointed_thing, "hopper:hopper") + end, + + can_dig = function(pos, player) + local inv = minetest.get_meta(pos):get_inventory() + return inv:is_empty("main") + end, + + on_rightclick = function(pos, node, clicker, itemstack) + if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then + return + end + minetest.show_formspec(clicker:get_player_name(), + "hopper_formspec:"..minetest.pos_to_string(pos), get_hopper_formspec(pos)) + end, + + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + minetest.log("action", S("@1 moves stuff in hopper at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + end, + + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", S("@1 moves stuff to hopper at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + end, + + on_metadata_inventory_take = function(pos, listname, index, stack, player) + minetest.log("action", S("@1 moves stuff from hopper at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + end, +}) + +local hopper_side_drop +local hopper_groups +if hopper.config.single_craftable_item then + hopper_side_drop = "hopper:hopper" + hopper_groups = {cracky=3, not_in_creative_inventory = 1} +else + hopper_side_drop = "hopper:hopper_side" + hopper_groups = {cracky=3} +end + +minetest.register_node("hopper:hopper_side", { + description = S("Side Hopper"), + _doc_items_longdesc = hopper.doc.hopper_long_desc, + _doc_items_usagehelp = hopper.doc.hopper_usage, + drop = hopper_side_drop, + groups = hopper_groups, + sounds = hopper.metal_sounds, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + tiles = { + "hopper_top_" .. hopper.config.texture_resolution .. ".png", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png", + "hopper_back_" .. hopper.config.texture_resolution .. ".png", + "hopper_side_" .. hopper.config.texture_resolution .. ".png", + "hopper_back_" .. hopper.config.texture_resolution .. ".png", + "hopper_back_" .. hopper.config.texture_resolution .. ".png" + }, + node_box = { + type = "fixed", + fixed = { + --funnel walls + {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5}, + {0.4, 0.0, -0.5, 0.5, 0.5, 0.5}, + {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5}, + {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4}, + --funnel base + {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5}, + --spout + {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, + {-0.7, -0.3, -0.15, 0.15, 0.0, 0.15}, + }, + }, + selection_box = { + type = "fixed", + fixed = { + --funnel + {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5}, + --spout + {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3}, + {-0.7, -0.3, -0.15, 0.15, 0.0, 0.15}, + }, + }, + + on_construct = function(pos) + local inv = minetest.get_meta(pos):get_inventory() + inv:set_size("main", 4*4) + end, + + on_place = function(itemstack, placer, pointed_thing) + return hopper_on_place(itemstack, placer, pointed_thing, "hopper:hopper_side") + end, + + can_dig = function(pos,player) + local inv = minetest.get_meta(pos):get_inventory() + return inv:is_empty("main") + end, + + on_rightclick = function(pos, node, clicker, itemstack) + if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then + return + end + minetest.show_formspec(clicker:get_player_name(), + "hopper_formspec:"..minetest.pos_to_string(pos), get_hopper_formspec(pos)) + end, + + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + minetest.log("action", S("@1 moves stuff in hopper at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + end, + + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", S("@1 moves stuff to hopper at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + end, + + on_metadata_inventory_take = function(pos, listname, index, stack, player) + minetest.log("action", S("@1 moves stuff from hopper at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + end, +}) \ No newline at end of file diff --git a/nodes/sorter.lua b/nodes/sorter.lua new file mode 100644 index 0000000..e678bb1 --- /dev/null +++ b/nodes/sorter.lua @@ -0,0 +1,186 @@ +-- internationalization boilerplate +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +local facedir_to_bottomdir = { + [0]={x=0, y=-1, z=0}, + {x=0, y=0, z=-1}, + {x=0, y=0, z=1}, + {x=-1, y=0, z=0}, + {x=1, y=0, z=0}, + {x=0, y=1, z=0}, +} + +local bottomdir = function(facedir) + return facedir_to_bottomdir[math.floor(facedir/4)] +end + +local function get_sorter_formspec(pos) + local spos = hopper.get_string_pos(pos) + local formspec = + "size[8,8.4]" + .. hopper.formspec_bg + .. "label[3.7,0;"..S("Filter").."]" + .. "list[nodemeta:" .. spos .. ";filter;0,0.5;8,1;]" + .. "list[nodemeta:" .. spos .. ";main;3,2.1;2,2;]" + .. hopper.get_eject_button_texts(pos, 7, 3) + .. "list[current_player;main;0,4.5;8,1;]" + .. "list[current_player;main;0,5.7;8,3;8]" + .. "listring[nodemeta:" .. spos .. ";main]" + .. "listring[current_player;main]" + return formspec +end + + +minetest.register_node("hopper:sorter", { + description = S("Sorter"), + _doc_items_longdesc = hopper.doc.sorter_long_desc, + _doc_items_usagehelp = hopper.doc.sorter_usage, + groups = {cracky = 3}, + sounds = hopper.metal_sounds, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + tiles = { + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png", + "hopper_top_" .. hopper.config.texture_resolution .. ".png", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^hopper_sorter_arrow_" .. hopper.config.texture_resolution .. ".png^[transformFX", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^hopper_sorter_arrow_" .. hopper.config.texture_resolution .. ".png", + "hopper_top_" .. hopper.config.texture_resolution .. ".png", + "hopper_bottom_" .. hopper.config.texture_resolution .. ".png^hopper_sorter_arrow_" .. hopper.config.texture_resolution .. ".png", + }, + node_box = { + type = "fixed", + fixed = { + {-0.3, -0.3, -0.4, 0.3, 0.4, 0.4}, + {-0.2, -0.2, 0.4, 0.2, 0.2, 0.7}, + {-0.2, -0.3, -0.2, 0.2, -0.7, 0.2}, + }, + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size("main", 2*2) + inv:set_size("filter", 8) + end, + + on_place = function(itemstack, placer, pointed_thing, node_name) + local pos = pointed_thing.under + local pos2 = pointed_thing.above + local x = pos.x - pos2.x + local z = pos.z - pos2.z + + local returned_stack, success = minetest.item_place_node(itemstack, placer, pointed_thing) + if success then + local meta = minetest.get_meta(pos2) + meta:set_string("placer", placer:get_player_name()) + end + return returned_stack + end, + + can_dig = function(pos,player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("main") + end, + + on_rightclick = function(pos, node, clicker, itemstack) + if minetest.is_protected(pos, clicker:get_player_name()) and not minetest.check_player_privs(clicker, "protection_bypass") then + return + end + minetest.show_formspec(clicker:get_player_name(), + "hopper_formspec:"..minetest.pos_to_string(pos), get_sorter_formspec(pos)) + end, + + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + if listname == "filter" then + local inv = minetest.get_inventory({type="node", pos=pos}) + inv:set_stack(listname, index, stack:take_item(1)) + return 0 + end + return stack:get_count() + end, + + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + if listname == "filter" then + local inv = minetest.get_inventory({type="node", pos=pos}) + inv:set_stack(listname, index, ItemStack("")) + return 0 + end + return stack:get_count() + end, + + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", S("@1 moves stuff to sorter at @2", + player:get_player_name(), minetest.pos_to_string(pos))) + + local timer = minetest.get_node_timer(pos) + if not timer:is_started() then + timer:start(1) + end + end, + + on_timer = function(pos, elapsed) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + + -- build a filter list + local filter_items = {} + local filter_inv_size = inv:get_size("filter") + for i = 1, filter_inv_size do + local stack = inv:get_stack("filter", i) + local item = stack:get_name() + if item ~= "" then + filter_items[item] = true + end + end + + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + local default_destination_pos = vector.add(pos, dir) + local default_output_direction + if dir.y == 0 then + default_output_direction = "horizontal" + end + + dir = bottomdir(node.param2) + local filter_destination_pos = vector.add(pos, dir) + local filter_output_direction + if dir.y == 0 then + filter_output_direction = "horizontal" + end + + local success = false + + local filter_destination_node = minetest.get_node(filter_destination_pos) + local registered_inventories = hopper.get_registered_inventories_for(filter_destination_node.name) + if registered_inventories ~= nil then + if filter_output_direction == "horizontal" then + success = hopper.send_item_to(pos, filter_destination_pos, filter_destination_node, registered_inventories["side"], filter_items) + else + success = hopper.send_item_to(pos, filter_destination_pos, filter_destination_node, registered_inventories["bottom"], filter_items) + end + else + success = hopper.send_item_to(pos, filter_destination_pos, filter_destination_node, nil, filter_items) + end + + if not success then -- weren't able to put something in the filter destination, for whatever reason. Now we can start moving stuff forward to the default. + local default_destination_node = minetest.get_node(default_destination_pos) + local registered_inventories = hopper.get_registered_inventories_for(default_destination_node.name) + if registered_inventories ~= nil then + if default_output_direction == "horizontal" then + hopper.send_item_to(pos, default_destination_pos, default_destination_node, registered_inventories["side"]) + else + hopper.send_item_to(pos, default_destination_pos, default_destination_node, registered_inventories["bottom"]) + end + else + hopper.send_item_to(pos, default_destination_pos, default_destination_node) + end + end + + if not inv:is_empty("main") then + minetest.get_node_timer(pos):start(1) + end + end, +}) \ No newline at end of file diff --git a/textures/hopper_back_16.png b/textures/hopper_back_16.png index 666f113d8cc6fe3be550f49505c429cc04ced4d5..f0de151d49766b02e3b2f69496d25821396a3680 100644 GIT binary patch delta 184 zcmV;p07w6^0;K|wBn2%{OjJdYEG-1&>6r47YAk;P90mjnyO5Ah0001fNklcx0Eth zx9JS4%2&2~l`Naa0M~Amz{tSBz$V1tyipJcq{SE}Z&ETcQnt2aC_iSbY-Y74ogw_0 mYvv&A>GRweW^sLUuRUP^0000?# diff --git a/textures/hopper_back_32.png b/textures/hopper_back_32.png index 75b8eae237dafbf4b84d2a35050be0953387f8d9..14f3a59e4b6add63b4c946043b5a28cc05b82d1a 100644 GIT binary patch delta 492 zcmVm0001iRAh9>0004eNklsZrG}-Ei}UThrPM zsMB^^Jl}TnCAVb{Y`Cn5plO&QxabB0CfdNvd*sX%Xm-Os6JB1K0>?&AF1zn z=y3EnhFAg9EIIu~0#?F)9D>001*kOjJcc005CGFn=5#{oVio00DGTPE!Ct z=GbNc00D1FL_t(I%iWSua^x@wM2Um|BRk{!pLQS2W+tgh)&4KGp&Mi*wItVdKW^;v zy3Qwh^L_3uyTi_`(C8Z{BkJxe>>w@$9fxLlS0zLU^@JZm&_)bs?y(OKIn0b!9!8%i zbS#2z{@yzdiGNB*W=10>w|IxOCCg}#`GuI`mLc}zDAgd(RdwRE!PtT zKAW>f6J5%pvo>qGjFOl4R3)A9)FG*{twNzMzG|VZ135GP^dxNwM~dRiCrHbRN`S06 zeU&DOha^4a`sCqY&I*mbaZLVsnkQq={^f<zL>G#m+gnAd=1`;8E}7Z8&u@U?K>osjA>I)&AO()f@0gg!ird#RqgD2G=Sl!>3U1t}73ei z!=mV?s(YH*E?#=dZu4}Ph~~lv>X{Q37+w<0QP&Mxw(EBE+BdEH(~U({SQVJ~jjN|^ z;rCTDVKQG(8Z~>1h3S8m88>Am8qb}SHCT3AeBpvA(I1_ilD7`|-R{H3K@1!PC{xWt~$(69Cc* BUZVg2 literal 0 HcmV?d00001 diff --git a/textures/hopper_sorter_arrow_32.png b/textures/hopper_sorter_arrow_32.png new file mode 100644 index 0000000000000000000000000000000000000000..1dedc2652c5de0c9d92f1b986f83043daa5f8e1c GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&pI+S)Nr*@_)v*i3|*ke4Z|jArXh)PBHXjHWYA`KN+-8 zMuAo6I){n#d~26EDvK5_UhFZ``3++ovt|*emDQ>#A|}jIYh_NBnO*qdsa=`2Z;gF& z^}>r8e~iT~m5g^Yo^kf9vUe4KY1AvVf$!rtm%I9tn=;QfWGAGieRla?obYs3&uLaz1gdfid@E^Mpbd>pn(Lsh-l> z6y57-7e(!EAOCPh$LAp1tiu1y&A0z?-Ko0K&du>b?d7_Z{p%h*-^$DOPI#-5nkZY< zgUi>$|2^FK?+u$uEyHY=%*R_d`!hUXwP^YA!1CXbhVot9D`S1XZ=L?3UHyU48tGoQ b#eql7LtlCsR?2CBf|kM4)z4*}Q$iB}$jX-J literal 0 HcmV?d00001 diff --git a/utility.lua b/utility.lua new file mode 100644 index 0000000..2d9c2c9 --- /dev/null +++ b/utility.lua @@ -0,0 +1,146 @@ +-- internationalization boilerplate +local MP = minetest.get_modpath(minetest.get_current_modname()) +local S, NS = dofile(MP.."/intllib.lua") + +-- Target inventory retrieval + +-- looks first for a registration matching the specific node name, then for a registration +-- matching group and value, then for a registration matching a group and *any* value +hopper.get_registered_inventories_for = function(target_node_name) + local output = hopper.containers[target_node_name] + if output ~= nil then return output end + + local target_def = minetest.registered_nodes[target_node_name] + if target_def.groups == nil then return nil end + + for group, value in pairs(target_def.groups) do + local registered_group = hopper.groups[group] + if registered_group ~= nil then + output = registered_group[value] + if output ~= nil then return output end + output = registered_group["all"] + if output ~= nil then return output end + end + end + + return nil +end + +hopper.get_eject_button_texts = function(pos, loc_X, loc_Y) + if not hopper.config.eject_button_enabled then return "" end + + local eject_button_text, eject_button_tooltip + if minetest.get_meta(pos):get_string("eject") == "true" then + eject_button_text = S("Don't\nEject") + eject_button_tooltip = S("This hopper is currently set to eject items from its output\neven if there isn't a compatible block positioned to receive it.\nClick this button to disable this feature.") + else + eject_button_text = S("Eject\nItems") + eject_button_tooltip = S("This hopper is currently set to hold on to item if there\nisn't a compatible block positioned to receive it.\nClick this button to have it eject items instead.") + end + return string.format("button_exit[%i,%i;1,1;eject;%s]tooltip[eject;%s]", loc_X, loc_Y, eject_button_text, eject_button_tooltip) +end + +hopper.get_string_pos = function(pos) + return pos.x .. "," .. pos.y .. "," ..pos.z +end + +-- Apparently node_sound_metal_defaults is a newer thing, I ran into games using an older version of the default mod without it. +if default.node_sound_metal_defaults ~= nil then + hopper.metal_sounds = default.node_sound_metal_defaults() +else + hopper.metal_sounds = default.node_sound_stone_defaults() +end + +------------------------------------------------------------------------------------------- +-- Inventory transfer functions + +-- Used to remove items from the target block and put it into the hopper's inventory +hopper.take_item_from = function(hopper_pos, target_pos, target_node, target_inventory_name) + if target_inventory_name == nil then + return + end + + --hopper inventory + local hopper_meta = minetest.get_meta(hopper_pos); + local hopper_inv = hopper_meta:get_inventory() + local placer = minetest.get_player_by_name(hopper_meta:get_string("placer")) + + --source inventory + local target_inv = minetest.get_meta(target_pos):get_inventory() + local target_inv_size = target_inv:get_size(target_inventory_name) + local target_def = minetest.registered_nodes[target_node.name] + if target_inv:is_empty(target_inventory_name) == false then + for i = 1,target_inv_size do + local stack = target_inv:get_stack(target_inventory_name, i) + local item = stack:get_name() + if item ~= "" then + if hopper_inv:room_for_item("main", item) then + local stack_to_take = stack:take_item(1) + if target_def.allow_metadata_inventory_take == nil + or placer == nil -- backwards compatibility, older versions of this mod didn't record who placed the hopper + or target_def.allow_metadata_inventory_take(target_pos, target_inventory_name, i, stack_to_take, placer) > 0 then + target_inv:set_stack(target_inventory_name, i, stack) + --add to hopper + hopper_inv:add_item("main", item) + if target_def.on_metadata_inventory_take ~= nil and placer ~= nil then + target_def.on_metadata_inventory_take(target_pos, target_inventory_name, i, stack_to_take, placer) + end + break + end + end + end + end + end +end + +-- Used to put items from the hopper inventory into the target block +hopper.send_item_to = function(hopper_pos, target_pos, target_node, target_inventory_name, filtered_items) + local hopper_meta = minetest.get_meta(hopper_pos) + local target_def = minetest.registered_nodes[target_node.name] + local eject_item = hopper.config.eject_button_enabled and hopper_meta:get_string("eject") == "true" and target_def.buildable_to + + if not eject_item and not target_inventory_name then + return false + end + + --hopper inventory + local hopper_meta = minetest.get_meta(hopper_pos); + local hopper_inv = hopper_meta:get_inventory() + if hopper_inv:is_empty("main") == true then + return false + end + local hopper_inv_size = hopper_inv:get_size("main") + local placer = minetest.get_player_by_name(hopper_meta:get_string("placer")) + + --target inventory + local target_inv = minetest.get_meta(target_pos):get_inventory() + + for i = 1,hopper_inv_size do + local stack = hopper_inv:get_stack("main", i) + local item = stack:get_name() + if item ~= "" and (filtered_items == nil or filtered_items[item]) then + if target_inventory_name then + if target_inv:room_for_item(target_inventory_name, item) then + local stack_to_put = stack:take_item(1) + if target_def.allow_metadata_inventory_put == nil + or placer == nil -- backwards compatibility, older versions of this mod didn't record who placed the hopper + or target_def.allow_metadata_inventory_put(target_pos, target_inventory_name, i, stack_to_put, placer) > 0 then + hopper_inv:set_stack("main", i, stack) + --add to target node + target_inv:add_item(target_inventory_name, stack_to_put) + if target_def.on_metadata_inventory_put ~= nil and placer ~= nil then + target_def.on_metadata_inventory_put(target_pos, target_inventory_name, i, stack_to_put, placer) + end + return true + end + end + elseif eject_item then + local stack_to_put = stack:take_item(1) + minetest.add_item(target_pos, stack_to_put) + hopper_inv:set_stack("main", i, stack) + return true + end + end + end + return false +end