code:
--[[
	Hidden Doors - Adds various wood, stone, etc. doors.
	Copyright © 2017, 2019 Hamlet <hamlatmesehub@riseup.net> and contributors.

	Licensed under the EUPL, Version 1.2 or – as soon they will be
	approved by the European Commission – subsequent versions of the
	EUPL (the "Licence");
	You may not use this work except in compliance with the Licence.
	You may obtain a copy of the Licence at:

	https://joinup.ec.europa.eu/software/page/eupl
	https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017D0863

	Unless required by applicable law or agreed to in writing,
	software distributed under the Licence is distributed on an
	"AS IS" basis,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
	implied.
	See the Licence for the specific language governing permissions
	and limitations under the Licence.

--]]

--
-- Variables
--

-- Used for localization, choose either built-in or intllib.

local s_ModPath, S, NS = nil

if (minetest.get_modpath("intllib") == nil) then
	S = minetest.get_translator("hidden_doors")

else
	-- internationalization boilerplate
	s_ModPath = minetest.get_modpath(minetest.get_current_modname())
	S, NS = dofile(s_ModPath.."/intllib.lua")

end

--
-- Moreblocks module support
--

hidden_doors.RegisterHiddenDoors("default", "jungletree_top",
	s_RecipeItem1, "moreblocks:slab_all_faces_jungle_tree",
	"moreblocks:slab_all_faces_jungle_tree", S("All-faces Jungle Tree"),
	t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("default", "tree_top",
	s_RecipeItem1, "moreblocks:slab_all_faces_tree",
	"moreblocks:slab_all_faces_tree", S("All-faces Tree"),
	t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "cactus_brick",
	s_RecipeItem1, "moreblocks:slab_cactus_brick",
	"moreblocks:slab_cactus_brick", S("Cactus Brick"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

--[[ Disabled due to additional texture manipulation required

hidden_doors.RegisterHiddenDoors("moreblocks", "cactus_checker",
	s_RecipeItem1, "moreblocks:slab_cactus_checker",
	"moreblocks:slab_cactus_checker", S("Cactus Checker"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

]]--

hidden_doors.RegisterHiddenDoors("moreblocks", "circle_stone_bricks",
	s_RecipeItem1, "moreblocks:slab_circle_stone_bricks",
	"moreblocks:slab_circle_stone_bricks", S("Circle Stone Bricks"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

--[[ Disabled due to additional texture manipulation required

hidden_doors.RegisterHiddenDoors("moreblocks", "coal_checker",
	s_RecipeItem1, "moreblocks:slab_coal_checker",
	"moreblocks:slab_coal_checker", S("Coal Checker"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

]]--

hidden_doors.RegisterHiddenDoors("moreblocks", "coal_stone",
	s_RecipeItem1, "moreblocks:slab_coal_stone",
	"moreblocks:slab_coal_stone", S("Coal Stone"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "cobble_compressed",
	s_RecipeItem1, "moreblocks:slab_cobble_compressed",
	"moreblocks:slab_cobble_compressed", S("Cobble Compressed"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "copperpatina",
	s_RecipeItem1, "moreblocks:slab_copperpatina",
	"moreblocks:slab_copperpatina", S("Copper Patina"),
	t_MetalDefault, s_MetalOpen, s_MetalClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "empty_shelf",
	s_RecipeItem1, "moreblocks:empty_shelf", nil, S("Empty Shelf"),
	t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "grey_bricks",
	s_RecipeItem1, "moreblocks:slab_grey_bricks",
	"moreblocks:slab_grey_bricks", S("Stone Bricks"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

--[[ Disabled due to additional texture manipulation required

hidden_doors.RegisterHiddenDoors("moreblocks", "iron_checker",
	s_RecipeItem1, "moreblocks:slab_iron_checker",
	"moreblocks:slab_iron_checker", S("Iron Checker"),
	t_MetalDefault, s_MetalOpen, s_MetalClose)

]]--

hidden_doors.RegisterHiddenDoors("moreblocks", "iron_stone",
	s_RecipeItem1, "moreblocks:slab_iron_stone",
	"moreblocks:slab_iron_stone", S("Iron Stone"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "iron_stone_bricks",
	s_RecipeItem1, "moreblocks:slab_iron_stone_bricks",
	"moreblocks:slab_iron_stone_bricks", S("Iron Stone Bricks"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "plankstone",
	s_RecipeItem1, "moreblocks:slab_plankstone", "moreblocks:slab_plankstone",
	S("Plankstone"), t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "split_stone_tile",
	s_RecipeItem1, "moreblocks:slab_split_stone_tile",
	"moreblocks:slab_split_stone_tile", S("Split Stone Tile"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "stone_tile",
	s_RecipeItem1, "moreblocks:slab_stone_tile",
	"moreblocks:slab_stone_tile", S("Stone Tile"),
	t_StoneDefault, t_StoneOpen, t_StoneClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "tar",
	s_RecipeItem1, "moreblocks:slab_tar", "moreblocks:slab_tar",
	S("Tar"), t_StoneDefault, t_StoneOpen, t_StoneClose)

--[[ Disabled due to additional texture manipulation required

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile",
	s_RecipeItem1, "moreblocks:slab_wood_tile", "moreblocks:slab_wood_tile",
	S("Wooden Tile"), t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile_center",
	s_RecipeItem1, "moreblocks:slab_wood_tile_center",
	"moreblocks:slab_wood_tile_center", S("Centered Wooden Tile"),
	t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile_down",
	s_RecipeItem1, "moreblocks:wood_tile_down", nil,
	S("Downwards Wooden Tile"), t_WoodDefault, s_WoodOpen, s_WoodClose)

]]--

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile_full",
	s_RecipeItem1, "moreblocks:slab_wood_tile_full",
	"moreblocks:slab_wood_tile_full", S("Full Wooden Tile"),
	t_WoodDefault, s_WoodOpen, s_WoodClose)

--[[ Disabled due to additional texture manipulation required

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile_left",
	s_RecipeItem1, "moreblocks:wood_tile_left", nil,
	S("Leftwards Wooden Tile"), t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile_right",
	s_RecipeItem1, "moreblocks:wood_tile_right", nil,
	S("Rightwards Wooden Tile"), t_WoodDefault, s_WoodOpen, s_WoodClose)

hidden_doors.RegisterHiddenDoors("moreblocks", "wood_tile_up",
	s_RecipeItem1, "moreblocks:wood_tile_up", nil,
	S("Upwards Wooden Tile"), t_WoodDefault, s_WoodOpen, s_WoodClose)

]]--


code:
--[[

   Hidden Doors - Adds various wood, stone, etc. doors.

   Copyright (C) 2017-2018  Hamlet

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.

]]--

--
-- Minetest Game's based hidden doors
--

minetest.register_lbm({
   name = ":standard_remover_a",
   nodenames = {"doors:hidden_door_stone_a", "doors:hidden_door_cobble_a",
                "doors:hidden_door_stone_brick_a",
                "doors:hidden_door_stone_block_a",
                "doors:hidden_door_mossycobble_a",
                "doors:hidden_door_desert_stone_a",
                "doors:hidden_door_desert_cobble_a",
                "doors:hidden_door_desert_stone_brick_a",
                "doors:hidden_door_desert_stone_block_a",
                "doors:hidden_door_sandstone_a",
                "doors:hidden_door_sandstone_brick_a",
                "doors:hidden_door_sandstone_block_a",
                "doors:hidden_door_desert_sandstone_a",
                "doors:hidden_door_desert_sandstone_brick_a",
                "doors:hidden_door_desert_sandstone_block_a",
                "doors:hidden_door_silver_sandstone_a",
                "doors:hidden_door_silver_sandstone_brick_a",
                "doors:hidden_door_silver_sandstone_block_a",
                "doors:hidden_door_obsidian_a",
                "doors:hidden_door_obsidian_brick_a",
                "doors:hidden_door_obsidian_block_a",
                "doors:hidden_door_tree_a", "doors:hidden_door_jungletree_a",
                "doors:hidden_door_pine_tree_a",
                "doors:hidden_door_acacia_tree_a",
                "doors:hidden_door_aspen_tree_a", "doors:hidden_door_wood_a",
                "doors:hidden_door_junglewood_a",
                "doors:hidden_door_pine_wood_a",
                "doors:hidden_door_acacia_wood_a",
                "doors:hidden_door_aspen_wood_a",
                "doors:hidden_door_bronze_block_a",
                "doors:hidden_door_copper_block_a",
                "doors:hidden_door_gold_block_a",
                "doors:hidden_door_steel_block_a",
                "doors:hidden_door_tin_block_a",
                "doors:hidden_door_dirt_a", "doors:hidden_door_brick_a",
                "doors:hidden_door_ice_a", "doors:hidden_door_diamond_block_a",
                "doors:hidden_door_mese_block_a",
                "doors:hidden_door_bookshelf_a",
                "doors:hidden_door_sand_a", "doors:hidden_door_silver_sand_a",
                "doors:hidden_door_desert_sand_a",
   },

		action = function(pos)
         minetest.remove_node(pos)

         local new_x = pos.x
         local new_y = (pos.y + 1)
         local new_z = pos.z
         local upper_pos = {x = new_x, y = new_y, z = new_z}

         minetest.remove_node(upper_pos)
		end,
})

minetest.register_lbm({
   name = ":standard_remover_b",
   nodenames = {"doors:hidden_door_stone_b", "doors:hidden_door_cobble_b",
                "doors:hidden_door_stone_brick_b",
                "doors:hidden_door_stone_block_b",
                "doors:hidden_door_mossycobble_b",
                "doors:hidden_door_desert_stone_b",
                "doors:hidden_door_desert_cobble_b",
                "doors:hidden_door_desert_stone_brick_b",
                "doors:hidden_door_desert_stone_block_b",
                "doors:hidden_door_sandstone_b",
                "doors:hidden_door_sandstone_brick_b",
                "doors:hidden_door_sandstone_block_b",
                "doors:hidden_door_desert_sandstone_b",
                "doors:hidden_door_desert_sandstone_brick_b",
                "doors:hidden_door_desert_sandstone_block_b",
                "doors:hidden_door_silver_sandstone_b",
                "doors:hidden_door_silver_sandstone_brick_b",
                "doors:hidden_door_silver_sandstone_block_b",
                "doors:hidden_door_obsidian_b",
                "doors:hidden_door_obsidian_brick_b",
                "doors:hidden_door_obsidian_block_b",
                "doors:hidden_door_tree_b", "doors:hidden_door_jungletree_b",
                "doors:hidden_door_pine_tree_b",
                "doors:hidden_door_acacia_tree_b",
                "doors:hidden_door_aspen_tree_b", "doors:hidden_door_wood_b",
                "doors:hidden_door_junglewood_b",
                "doors:hidden_door_pine_wood_b",
                "doors:hidden_door_acacia_wood_b",
                "doors:hidden_door_aspen_wood_b",
                "doors:hidden_door_bronze_block_b",
                "doors:hidden_door_copper_block_b",
                "doors:hidden_door_gold_block_b",
                "doors:hidden_door_steel_block_b",
                "doors:hidden_door_tin_block_b",
                "doors:hidden_door_dirt_b", "doors:hidden_door_brick_b",
                "doors:hidden_door_ice_b", "doors:hidden_door_diamond_block_b",
                "doors:hidden_door_mese_block_b",
                "doors:hidden_door_bookshelf_b",
                "doors:hidden_door_sand_b", "doors:hidden_door_silver_sand_b",
                "doors:hidden_door_desert_sand_b",
   },

		action = function(pos)
         minetest.remove_node(pos)

         local new_x = pos.x
         local new_y = (pos.y + 1)
         local new_z = pos.z
         local upper_pos = {x = new_x, y = new_y, z = new_z}

         minetest.remove_node(upper_pos)
		end,
})

--
-- Compatible modules' based hidden doors
--

if minetest.get_modpath("darkage") then

	minetest.register_lbm({
		name = ":darkage_remover_a",
		nodenames = {"doors:hidden_door_adobe_a", "doors:hidden_door_basalt_a",
                   "doors:hidden_door_basalt_rubble_a",
                   "doors:hidden_door_basalt_brick_a",
                   "doors:hidden_door_basalt_block_a",
                   "doors:hidden_door_gneiss_a",
                   "doors:hidden_door_gneiss_rubble_a",
                   "doors:hidden_door_gneiss_brick_a",
                   "doors:hidden_door_gneiss_block_a",
                   "doors:hidden_door_marble_a",
                   "doors:hidden_door_marble_tile_a",
                   "doors:hidden_door_ors_a", "doors:hidden_door_ors_rubble_a",
                   "doors:hidden_door_ors_brick_a",
                   "doors:hidden_door_ors_block_a",
                   "doors:hidden_door_serpentine_a",
                   "doors:hidden_door_shale_a", "doors:hidden_door_slate_a",
                   "doors:hidden_door_schist_a",
                   "doors:hidden_door_slate_rubble_a",
                   "doors:hidden_door_slate_tile_a",
                   "doors:hidden_door_slate_block_a",
                   "doors:hidden_door_slate_brick_a", "doors:hidden_door_tuff_a",
                   "doors:hidden_door_tuff_bricks_a",
                   "doors:hidden_door_tuff_rubble_a",
                   "doors:hidden_door_rhyolitic_tuff_a",
                   "doors:hidden_door_rhyolitic_tuff_bricks_a",
                   "doors:hidden_door_old_tuff_bricks_a",
                   "doors:hidden_door_rhyolitic_tuff_rubble_a",
      },

		action = function(pos)
         minetest.remove_node(pos)

         local new_x = pos.x
         local new_y = (pos.y + 1)
         local new_z = pos.z
         local upper_pos = {x = new_x, y = new_y, z = new_z}

         minetest.remove_node(upper_pos)
		end,
	})

	minetest.register_lbm({
		name = ":darkage_remover_b",
		nodenames = {"doors:hidden_door_adobe_b", "doors:hidden_door_basalt_b",
                   "doors:hidden_door_basalt_rubble_b",
                   "doors:hidden_door_basalt_brick_b",
                   "doors:hidden_door_basalt_block_b",
                   "doors:hidden_door_gneiss_b",
                   "doors:hidden_door_gneiss_rubble_b",
                   "doors:hidden_door_gneiss_brick_b",
                   "doors:hidden_door_gneiss_block_b",
                   "doors:hidden_door_marble_b",
                   "doors:hidden_door_marble_tile_b",
                   "doors:hidden_door_ors_b", "doors:hidden_door_ors_rubble_b",
                   "doors:hidden_door_ors_brick_b",
                   "doors:hidden_door_ors_block_b",
                   "doors:hidden_door_serpentine_b",
                   "doors:hidden_door_shale_b", "doors:hidden_door_slate_b",
                   "doors:hidden_door_schist_b",
                   "doors:hidden_door_slate_rubble_b",
                   "doors:hidden_door_slate_tile_b",
                   "doors:hidden_door_slate_block_b",
                   "doors:hidden_door_slate_brick_b", "doors:hidden_door_tuff_b",
                   "doors:hidden_door_tuff_bricks_b",
                   "doors:hidden_door_tuff_rubble_b",
                   "doors:hidden_door_rhyolitic_tuff_b",
                   "doors:hidden_door_rhyolitic_tuff_bricks_b",
                   "doors:hidden_door_old_tuff_bricks_b",
                   "doors:hidden_door_rhyolitic_tuff_rubble_b",
      },

		action = function(pos)
         minetest.remove_node(pos)

         local new_x = pos.x
         local new_y = (pos.y + 1)
         local new_z = pos.z
         local upper_pos = {x = new_x, y = new_y, z = new_z}

         minetest.remove_node(upper_pos)
		end,
   })
end

if minetest.get_modpath("moreblocks") then

	minetest.register_lbm({
      name = ":moreblocks_remover_a",
      nodenames = {"doors:hidden_door_jungletree_top_a",
                   "doors:hidden_door_tree_top_a",
                   "doors:hidden_door_cactus_brick_a",
                   "doors:hidden_door_circle_stone_bricks_a",
                   "doors:hidden_door_coal_stone_a",
                   "doors:hidden_door_cobble_compressed_a",
                   "doors:hidden_door_copperpatina_a",
                   "doors:hidden_door_empty_bookshelf_a",
                   "doors:hidden_door_grey_bricks_a",
                   "doors:hidden_door_iron_stone_a",
                   "doors:hidden_door_iron_stone_bricks_a",
                   "doors:hidden_door_plankstone_a",
                   "doors:hidden_door_split_stone_tile_a",
                   "doors:hidden_door_split_stone_tile_alt_a",
                   "doors:hidden_door_stone_tile_a",
                   "doors:hidden_door_tar_a",
                   "doors:hidden_door_trap_stone_a",
                   "doors:hidden_door_wood_tile_full_a",
      },

		action = function(pos)
         minetest.remove_node(pos)

         local new_x = pos.x
         local new_y = (pos.y + 1)
         local new_z = pos.z
         local upper_pos = {x = new_x, y = new_y, z = new_z}

         minetest.remove_node(upper_pos)
		end,
   })

	minetest.register_lbm({
      name = ":moreblocks_remover_b",
      nodenames = {"doors:hidden_door_jungletree_top_b",
                   "doors:hidden_door_tree_top_b",
                   "doors:hidden_door_cactus_brick_b",
                   "doors:hidden_door_circle_stone_bricks_b",
                   "doors:hidden_door_coal_stone_b",
                   "doors:hidden_door_cobble_compressed_b",
                   "doors:hidden_door_copperpatina_b",
                   "doors:hidden_door_empty_bookshelf_b",
                   "doors:hidden_door_grey_bricks_b",
                   "doors:hidden_door_iron_stone_b",
                   "doors:hidden_door_iron_stone_bricks_b",
                   "doors:hidden_door_plankstone_b",
                   "doors:hidden_door_split_stone_tile_b",
                   "doors:hidden_door_split_stone_tile_alt_b",
                   "doors:hidden_door_stone_tile_b",
                   "doors:hidden_door_tar_b",
                   "doors:hidden_door_trap_stone_b",
                   "doors:hidden_door_wood_tile_full_b",
      },

		action = function(pos)
         minetest.remove_node(pos)

         local new_x = pos.x
         local new_y = (pos.y + 1)
         local new_z = pos.z
         local upper_pos = {x = new_x, y = new_y, z = new_z}

         minetest.remove_node(upper_pos)
		end,
   })
end

repo_name: korkut/MeseCraft

license: mit


code:
# Please choose your favorite resolution.
# Allowed resolutions: 16, 32, 64, 128 (pixels).
# The default value is 16 pixels.
hidden_doors_res (Resolution in pixels for the textures) int 16

# Here you can set your preferred value for the stone made hidden
# doors' opening and closing sounds, the default value is 5.0
hidden_doors_vol (Opening and closing sounds' volume in float) float 5.0

# You can choose to have concealed doors remain slightly visible - wooden
# doors which have been painted to match their surroundings.
# This allows players that pay attention to find concealed doors, as well
# as providing decor-matched doors for interior decoration.
hidden_doors_painted (Painted doors - visible but camouflaged) bool false

# Disable the module's nodes and activate the
# L.B.M. based module's nodes remover.
hidden_doors_remover (Disable and remove this mod's nodes) bool false


code:
-- Wire
minetest.register_craftitem("holiday_lights:wire", {
	description = "Wire",
	inventory_image = "holiday_lights_wire.png",
})

-- White Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_white", {
        description = "White Light Bulbs",
        inventory_image = "holiday_lights_bulbs_white.png",
})

-- Yellow Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_yellow", {
        description = "Yellow Light Bulbs",
        inventory_image = "holiday_lights_bulbs_yellow.png",
})

-- Red Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_red", {
        description = "Red Light Bulbs",
        inventory_image = "holiday_lights_bulbs_red.png",
})

-- Green Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_green", {
        description = "Green Light Bulbs",
        inventory_image = "holiday_lights_bulbs_green.png",
})

-- Blue Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_blue", {
        description = "Blue Light Bulbs",
        inventory_image = "holiday_lights_bulbs_blue.png",
})

-- Purple Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_purple", {
        description = "Purple Light Bulbs",
        inventory_image = "holiday_lights_bulbs_purple.png",
})

-- Pink Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_pink", {
        description = "Pink Light Bulbs",
        inventory_image = "holiday_lights_bulbs_pink.png",
})

-- Orange Light Bulbs
minetest.register_craftitem("holiday_lights:bulbs_orange", {
        description = "Orange Light Bulbs",
        inventory_image = "holiday_lights_bulbs_orange.png",
})


code:
-- Base items.

	-- Wire
	minetest.register_craft({
		output = "holiday_lights:wire 16",
		recipe = {
			{"basic_materials:plastic_strip", "basic_materials:plastic_strip", "basic_materials:plastic_strip"},
			{"basic_materials:copper_strip", "basic_materials:copper_strip", "basic_materials:copper_strip"},
			{"basic_materials:plastic_strip", "basic_materials:plastic_strip", "basic_materials:plastic_strip"},
		},
	})

	-- White Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_white 8",
	        recipe = {
	                {"", "default:glass", ""},
	                {"", "basic_materials:plastic_strip", ""},
	                {"", "default:mese_crystal_fragment", ""},
	        },
	})

-- Bulbs

	-- Yellow Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_yellow 3",
		type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:yellow"},
	})

	-- Red Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_red 3",
	        type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:red"},
	})

	-- Green Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_green 3",
	        type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:green"},
	})

	-- Blue Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_blue 3",
	        type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:blue"},
	})

	-- Purple Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_purple 3",
	        type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:violet"},
	})

	-- Pink Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_pink 3",
	        type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:pink"},
	})

	-- Orange Bulbs
	minetest.register_craft({
	        output = "holiday_lights:bulbs_orange 3",
	        type = "shapeless",
	        recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","dye:orange"},
	})

-- String Lights

        -- White String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_white",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:wire"},
        })

        -- Yellow String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_yellow",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_yellow","holiday_lights:bulbs_yellow","holiday_lights:bulbs_yellow","holiday_lights:wire"},
        })

        -- Red String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_red",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_red","holiday_lights:bulbs_red","holiday_lights:bulbs_red","holiday_lights:wire"},
        })

        -- Green String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_green",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_green","holiday_lights:bulbs_green","holiday_lights:bulbs_green","holiday_lights:wire"},
        })

        -- Blue String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_blue",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_blue","holiday_lights:bulbs_blue","holiday_lights:bulbs_blue","holiday_lights:wire"},
        })

        -- Purple String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_purple",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_purple","holiday_lights:bulbs_purple","holiday_lights:bulbs_purple","holiday_lights:wire"},
        })

        -- Pink String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_pink",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_pink","holiday_lights:bulbs_pink","holiday_lights:bulbs_pink","holiday_lights:wire"},
        })

        -- Orange String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_orange",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_orange","holiday_lights:bulbs_orange","holiday_lights:bulbs_orange","holiday_lights:wire"},
        })

-- Special Sets

        -- Rainbow String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_rainbow 2",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_red","holiday_lights:bulbs_yellow","holiday_lights:bulbs_green","holiday_lights:bulbs_blue","holiday_lights:bulbs_purple", "holiday_lights:wire", "holiday_lights:wire"},
        })

        -- Festive String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_festive",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_red","holiday_lights:bulbs_green","holiday_lights:bulbs_red","holiday_lights:bulbs_green", "holiday_lights:wire"},
        })

        -- Spooky String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_spooky",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_orange","holiday_lights:bulbs_purple","holiday_lights:bulbs_orange","holiday_lights:bulbs_purple","holiday_lights:wire"},
        })

        -- Patriotic String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_patriotic",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_red","holiday_lights:bulbs_white","holiday_lights:bulbs_blue","holiday_lights:wire"},
        })

        -- Icy String Lights
        minetest.register_craft({
                output = "holiday_lights:lights_icy",
                type = "shapeless",
                recipe = {"holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:bulbs_white","holiday_lights:wire", "default:ice"},
        })


code:
-- Holiday Lights by FreeGamers.org
-- Description: A simple mod that adds colorful holiday lights.

local path = minetest.get_modpath("holiday_lights")

dofile(path .. "/craftitems.lua")
dofile(path .. "/nodes.lua")
dofile(path .. "/crafts.lua")


code:
name = holiday_lights
description = Brighten up your holidays with some colorful lights.
author = FreeGamers
depends = basic_materials


code:
-- White String Lights
minetest.register_node("holiday_lights:lights_white", {
	description = "White String Lights",
	tiles = {"holiday_lights_white.png"},
	inventory_image = "holiday_lights_white.png",
	wield_image = "holiday_lights_white.png",
	sunlight_propagates = true,
	walkable = false,
	climbable = false,
	is_ground_content = false,
	selection_box = {
		type = "wallmounted",
	},
	legacy_wallmounted = true,
	use_texture_alpha = "clip",
	drawtype = "signlike",
	paramtype = "light",
	light_source = 8,
	paramtype2 = "wallmounted",
	groups = {snappy = 3},
	sounds = default.node_sound_leaves_defaults(),
})

-- Red String Lights
minetest.register_node("holiday_lights:lights_red", {
        description = "Red String Lights",
        tiles = {"holiday_lights_red.png"},
        inventory_image = "holiday_lights_red.png",
        wield_image = "holiday_lights_red.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Green String Lights
minetest.register_node("holiday_lights:lights_green", {
        description = "Green String Lights",
        tiles = {"holiday_lights_green.png"},
        inventory_image = "holiday_lights_green.png",
        wield_image = "holiday_lights_green.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Blue String Lights
minetest.register_node("holiday_lights:lights_blue", {
        description = "Blue String Lights",
        tiles = {"holiday_lights_blue.png"},
        inventory_image = "holiday_lights_blue.png",
        wield_image = "holiday_lights_blue.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Yellow String Lights
minetest.register_node("holiday_lights:lights_yellow", {
        description = "Yellow String Lights",
        tiles = {"holiday_lights_yellow.png"},
        inventory_image = "holiday_lights_yellow.png",
        wield_image = "holiday_lights_yellow.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Purple String Lights
minetest.register_node("holiday_lights:lights_purple", {
        description = "Purple String Lights",
        tiles = {"holiday_lights_purple.png"},
        inventory_image = "holiday_lights_purple.png",
        wield_image = "holiday_lights_purple.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Orange String Lights
minetest.register_node("holiday_lights:lights_orange", {
        description = "Orange String Lights",
        tiles = {"holiday_lights_orange.png"},
        inventory_image = "holiday_lights_orange.png",
        wield_image = "holiday_lights_orange.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Pink String Lights
minetest.register_node("holiday_lights:lights_pink", {
        description = "Pink String Lights",
        tiles = {"holiday_lights_pink.png"},
        inventory_image = "holiday_lights_pink.png",
        wield_image = "holiday_lights_pink.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Rainbow String Lights
minetest.register_node("holiday_lights:lights_rainbow", {
        description = "Rainbow String Lights",
        tiles = {"holiday_lights_rainbow.png"},
        inventory_image = "holiday_lights_rainbow.png",
        wield_image = "holiday_lights_rainbow.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Festive String Lights
minetest.register_node("holiday_lights:lights_festive", {
        description = "Festive String Lights",
        tiles = {"holiday_lights_festive.png"},
        inventory_image = "holiday_lights_festive.png",
        wield_image = "holiday_lights_festive.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Spooky String Lights
minetest.register_node("holiday_lights:lights_spooky", {
        description = "Spooky String Lights",
        tiles = {"holiday_lights_spooky.png"},
        inventory_image = "holiday_lights_spooky.png",
        wield_image = "holiday_lights_spooky.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Patriotic String Lights
minetest.register_node("holiday_lights:lights_patriotic", {
        description = "Patriotic String Lights",
        tiles = {"holiday_lights_patriotic.png"},
        inventory_image = "holiday_lights_patriotic.png",
        wield_image = "holiday_lights_patriotic.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})

-- Icy String Lights
minetest.register_node("holiday_lights:lights_icy", {
        description = "Icy String Lights",
        tiles = {"holiday_lights_icicle.png"},
        inventory_image = "holiday_lights_icicle.png",
        wield_image = "holiday_lights_icicle.png",
        sunlight_propagates = true,
        walkable = false,
        climbable = false,
        is_ground_content = false,
        selection_box = {
                type = "wallmounted",
        },
        legacy_wallmounted = true,
        use_texture_alpha = "clip",
        drawtype = "signlike",
        paramtype = "light",
        light_source = 8,
        paramtype2 = "wallmounted",
        groups = {snappy = 3},
        sounds = default.node_sound_leaves_defaults(),
})


code:
## Hoppers, chutes and sorters

![Hoppers, chutes and sorters](screenshot.png "Hoppers, chutes and sorters")

Based on jordan4ibanez's original hoppers mod, optimized by TenPlus1 and FaceDeer, with chutes and sorters by FaceDeer

Hoppers are nodes that can transfer items to and from the inventories of adjacent nodes. The wide end of a hopper is its "input" end, if there's a chest or other compatible container it will take one item per second into its own internal inventory. It will also draw in items that have been dropped here. The narrow end of the hopper is its "output" end. It will attempt to inject items into a compatible container located at its output end. If there's no compatible container and the hopper's "eject" mode has been enabled it will instead dump the items out into the world.

The location of a hopper relative to a furnace determines which inventory slots the hopper will affect. A hopper directly above a furnace will inject items into the furnace's input slot. A hopper to the furnace's side will inject items into the furnace's fuel slot. A hopper below the furnace will pull items out of the furnace's output slot. Hoppers cannot inject items into inappropriate slots; non-fuel items will not be placed into the furnace's fuel slot and non-cookable items will not be placed into the input slot.

Also included in this mod are a "chute" node and a "sorter" node. These allow for items to be routed over short distances and distributed in sophisticated ways.

A chute simply moves items into adjacent nodes. You'll need to use a hopper or sorter to inject items into it to move along. A screwdriver is a useful tool for getting chutes aimed correctly.

A sorter has two different outputs. Its inventory has a "filter" grid; place items in this grid to set the sorter's filter. Items that match the filter will be sent out the output with the large arrow and other items will be sent out the output with the smaller arrow. A "filter all" option will cause the sorter to attempt to send *all* items in the direction of the large arrow and then if that fails send them in the direction of the smaller arrow. This allows you to have an "overflow" storage should the sorter's primary target fill up, or when used in combination with a selective container (like the furnace's fuel slot, for example) it allows the target inventory to do the filtering for you.

### Advanced settings

This mod has several configurable settings found in the advanced settings menu.

* Hopper texture size: can be set to 16 pixels (matching most standard Minetest node textures) or 32 pixels
* Single craftable item: When enabled (the default) hoppers are crafted as a single item and then select whether the output has a 90-degree turn to the side based on how you place it. When disabled you can craft straight and bent hoppers as separate items.
* Eject items button: this can be used to remove the "eject items" button from hoppers, if it is not desired.

### Change log

- 0.1 - Initial release from jordan4ibanez
- 0.2 - Fixed tool glitch (wear restored by accident)
- 0.3 - transfer function added
- 0.4 - Supports locked chest and protected chest
- 0.5 - Works with 0.4.13's new shift+click for newly placed Hoppers
- 0.6 - Remove formspec from hopper nodes to improve speed for servers
- 0.7 - Halved hopper capacity, can be dug by wooden pick
- 0.8 - Added Napiophelios' new textures and tweaked code
- 0.9 - Added support for Wine mod's wine barrels
- 1.0 - New furances do not work properly with hoppers so old reverted to abm furnaces
- 1.1 - Hoppers now work with new node timer Furnaces.  Reduced Abm's and tidied code.
- 1.2 - Added simple API so that hoppers can work with other containers.
- 1.3 - Hoppers now call on_metadata_inventory_put and on_metadata_inventory_take, triggering furnace timers via their standard callbacks. Updated side hopper rotation handling to allow it to function in any orientation. Added settings options to use 16-pixel or 32-pixel textures. Added settings option to allow explicit crafting of standard/side hoppers or to allow crafting of a single item that selects which type to use on place. Added in-game documentation via optional "doc" mod dependency
- 1.4 - Added intllib support
- 1.5 - Added chutes
- 1.6 - Added "eject items" button to formspecs, "group" support to the API
- 1.7 - Added sorter block to allow for more sophisticated item transfer arrangements

Lucky Blocks: 2


code:
-- 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,
})


code:
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


code:
Hopper API
----------

This API is kept simple by adding a single command which allows mods to add
containers like chests and furnaces to the hopper check list.

Command Usage
-------------

Make sure any mods using this function has 'hopper' in the depends.txt file.

hopper:add_container({ {"where_from", "node_name", "inventory_name"} })

  'where_from' is a string telling the api that items are coming from either
               the 'top' node into a hopper below, going into the 'bottom' node
               from the hopper above or coming from a 'side' hopper into the
               node next door.

  'node_name"  is the name of the container itself (e.g. "default:chest")

  'inventory_name' is the name of the container inventory that is affected.

e.g.

hopper:add_container({
	{"top", "default:furnace", "dst"}, -- take cooked items from above into hopper below
	{"bottom", "default:furnace", "src"}, -- insert items below to be cooked from hopper above
	{"side", "default:furnace", "fuel"}, -- replenish furnace fuel from hopper at side
})

You can also register hopper interaction targets by group, or by a group and a specific group
value. For example:

hopper:add_container({
	{"top", "group:loot_chest", "loot"},
	{"bottom", "group:loot_chest", "loot"},
	{"side", "group:loot_chest", "loot"},
})

Would cause hoppers to interact with the "loot" inventory of all nodes belonging to the group
"loot_chest", and

hopper:add_container({
	{"top", "group:protected_container=1", "main"},
	{"bottom", "group:protected_container=1", "main"},
	{"side", "group:protected_container=1", "main"},
})

Would cause hoppers to interact with the "main" inventory of nodes belonging to the group
"protected_container" provided they had a value of 1 in that group. Hoppers prioritize the most
specific definition first; they check for registrations for a specific node name, then
for registrations that apply to a node's group and group value, and then for registrations
applying to a node's group in general.

Note that if multiple group registrations apply to the same node it's undefined which group
will take priority. Using the above examples, if there were a node that belonged to *both*
the groups "loot_chest" and "protected_container=1" there's no way of knowing ahead of time
whether hoppers would interact with the "loot" or "main" inventories. Try to avoid this situation.

The hopper mod already have support for the wine barrel inside of the Wine mod and protected
chests inside of Protector Redo, as well as default chests, furnaces and hoppers
themselves.


code:
hopper.config = {}

-- settings
hopper.config.texture_resolution = minetest.settings:get("hopper_texture_size")
if hopper.config.texture_resolution == nil then
	hopper.config.texture_resolution = "16"
end

hopper.config.single_craftable_item = minetest.settings:get_bool("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.settings:get_bool("hopper_eject_button")
if hopper.config.eject_button_enabled == nil then
	hopper.config.eject_button_enabled = true
end


code:
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


code:
default?
lucky_block?
doc?
intllib?
protector?
wine?


code:
Adds hoppers to transport items between chests/furnace etc.

Forum: https://forum.minetest.net/viewtopic.php?f=9&t=20058


code:
-- define global
hopper = {}

-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")

if minetest.get_modpath("default") then
	hopper.formspec_bg = default.gui_bg .. default.gui_bg_img .. default.gui_slots
else
	hopper.formspec_bg = "bgcolor[#080808BB;true]" .. "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
end

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")

-------------------------------------------------------------------------------------------
-- Formspec handling

minetest.register_on_player_receive_fields(function(player, formname, fields)
	if "hopper_formspec:" == string.sub(formname, 1, 16) then
		local pos = minetest.string_to_pos(string.sub(formname, 17, -1))
		local meta = minetest.get_meta(pos)
		local eject_setting = meta:get_string("eject") == "true"
		local filter_all_setting = meta:get_string("filter_all") == "true"
		if fields.eject then
			if eject_setting then
				meta:set_string("eject", nil)
			else
				meta:set_string("eject", "true")
			end
		end
		if fields.filter_all then
			if filter_all_setting then
				meta:set_string("filter_all", nil)
			else
				meta:set_string("filter_all", "true")
			end
		end
	end
end)

-- add lucky blocks
if minetest.get_modpath("lucky_block") then
	lucky_block:add_blocks({
		{"dro", {"hopper:hopper"}, 3},
		{"nod", "default:lava_source", 1},
	})
end

print (S("[MOD] Hopper loaded"))


code:
-- Fallback functions for when `intllib` is not installed.
-- Code released under Unlicense <http://unlicense.org>.

-- Get the latest version of this file at:
--   https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua

local function format(str, ...)
	local args = { ... }
	local function repl(escape, open, num, close)
		if escape == "" then
			local replacement = tostring(args[tonumber(num)])
			if open == "" then
				replacement = replacement..close
			end
			return replacement
		else
			return "@"..open..num..close
		end
	end
	return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl))
end

local gettext, ngettext
if minetest.get_modpath("intllib") then
	if intllib.make_gettext_pair then
		-- New method using gettext.
		gettext, ngettext = intllib.make_gettext_pair()
	else
		-- Old method using text files.
		gettext = intllib.Getter()
	end
end

-- Fill in missing functions.

gettext = gettext or function(msgid, ...)
	return format(msgid, ...)
end

ngettext = ngettext or function(msgid, msgid_plural, n, ...)
	return format(n==1 and msgid or msgid_plural, ...)
end

return gettext, ngettext


code:
# Internationalization template for Hopper mod.
# Copyright (C) 2017
# This file is distributed under the same license as the PACKAGE package.
# FaceDeer
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-06 08:42-0700\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"

#: doc.lua:11
msgid "Hopper to transfer items between neighboring blocks' inventories."
msgstr ""

#: 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 "
"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"
msgstr ""

#: 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 "
"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"
msgstr ""

#: 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 ""

#: 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 "
"bottom and inject items into the furnace's \"fuel\" inventory slot when "
"attached to the furnace's side.\n"
"\n"
"Items that cannot be placed in a target block's inventory will remain in the "
"hopper.\n"
"\n"
"Hoppers 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."
msgstr ""

#: doc.lua:20
msgid "A chute to transfer items over longer distances."
msgstr ""

#: 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 "
"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."
msgstr ""

#: doc.lua:23
msgid "A sorter to redirect certain items to an alternate target."
msgstr ""

#: 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.\n"
"\n"
"In addition, there is a button labeled \"Filter All\" that will tell the "
"sorter to not use the filter list and instead first attempt to shunt all "
"items out of the filter, only sending items along the non-filter path if the "
"target cannot accept it for whatever reason. This feature is useful for "
"handling \"overflow\" (when the target's inventory fills up) or for dealing "
"with targets that are selective about what they accept (for example, a "
"furnace's fuel slot)."
msgstr ""

#: init.lua:61
msgid "[MOD] Hopper loaded"
msgstr "[MOD] Trichter geladen"

#: utility.lua:34
msgid ""
"Don't\n"
"Eject"
msgstr ""

#: 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 ""

#: utility.lua:37
msgid ""
"Eject\n"
"Items"
msgstr ""

#: 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 ""

#: nodes\chute.lua:20
msgid "Hopper Chute"
msgstr ""

#: nodes\chute.lua:78
#, fuzzy
msgid "@1 moves stuff to chute at @2"
msgstr "@1 verlagert Dinge in einen Trichter bei @2"

#: nodes\hoppers.lua:60
msgid "Hopper"
msgstr "Trichter"

#: nodes\hoppers.lua:122
#: nodes\hoppers.lua:214
msgid "@1 moves stuff in hopper at @2"
msgstr "@1 bewegt Dinge in einem Trichter bei @2"

#: nodes\hoppers.lua:127
#: nodes\hoppers.lua:219
msgid "@1 moves stuff to hopper at @2"
msgstr "@1 verlagert Dinge in einen Trichter bei @2"

#: nodes\hoppers.lua:132
#: nodes\hoppers.lua:224
msgid "@1 moves stuff from hopper at @2"
msgstr "@1 nimmt Dinge aus einem Trichter bei @2"

#: nodes\hoppers.lua:148
msgid "Side Hopper"
msgstr "Seitentrichter"

#: nodes\sorter.lua:26
msgid ""
"Selective\n"
"Filter"
msgstr ""

#: nodes\sorter.lua:27
msgid ""
"This sorter is currently set to try sending all items\n"
"in the direction of the arrow. Click this button\n"
"to enable an item-type-specific filter."
msgstr ""

#: nodes\sorter.lua:29
msgid "Filter"
msgstr ""

#: nodes\sorter.lua:30
msgid ""
"Filter\n"
"All"
msgstr ""

#: nodes\sorter.lua:31
msgid ""
"This sorter is currently set to only send items listed\n"
"in the filter list in the direction of the arrow.\n"
"Click this button to set it to try sending all\n"
"items that way first."
msgstr ""

#: nodes\sorter.lua:51
msgid "Sorter"
msgstr ""

#: nodes\sorter.lua:144
#, fuzzy
msgid "@1 moves stuff to sorter at @2"
msgstr "@1 verlagert Dinge in einen Trichter bei @2"


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-06 08:42-0700\n"
"PO-Revision-Date: 2018-12-06 00:15+0000\n"
"Last-Translator: Lunovox Heavenfinder <lunovox@disroot.org>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/minetest/mod-"
"hopper/pt/>\n"
"Language: pt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.4-dev\n"

#: doc.lua:11
msgid "Hopper to transfer items between neighboring blocks' inventories."
msgstr "Funil para transferir itens entre os inventários dos blocos vizinhos."

#: 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 "
"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"
msgstr ""
"Os itens são transferidos do bloco na extremidade larga da tremonha para o "
"bloco na extremidade estreita da tremonha a uma taxa de um por segundo. Os "
"itens também podem ser colocados diretamente no estoque do funil, ou podem "
"ser colocados no espaço acima de um funil e serão sugados para o inventário "
"do funil automaticamente.\n"
"\n"

#: 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 "
"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"
msgstr ""
"Os blocos do funil vêm em formulários \"verticais\" e \"laterais\", mas "
"quando no inventário de um jogador ambos são representados por um único item "
"genérico. O tipo de bloco funil que será colocado quando o jogador usa este "
"item depende do que está apontado - quando o item funil é apontado na face "
"superior ou inferior de um bloco, um funil vertical é colocado, quando "
"apontado para o lado de um bloquear um funil lateral é produzido que se "
"conecta ao lado clicado.\n"
"\n"

#: 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 ""
"Os blocos do funil vêm nas formas 'vertical' e 'lateral'. Eles podem ser "
"interconvertidos entre as duas formas através da grade de criação.\n"
"\n"

#: 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 "
"bottom and inject items into the furnace's \"fuel\" inventory slot when "
"attached to the furnace's side.\n"
"\n"
"Items that cannot be placed in a target block's inventory will remain in the "
"hopper.\n"
"\n"
"Hoppers 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."
msgstr ""
"Quando usados com fornos, os funis injetam itens na fenda de estoque de "
"\"matéria-prima\" do forno quando a extremidade estreita é presa à parte "
"superior ou inferior e injetam itens na ranhura de estoque \"combustível\" "
"do forno quando fixados ao lado do forno.\n"
"\n"
"Itens que não podem ser colocados no inventário de um bloco de destino "
"permanecerão no depósito.\n"
"\n"
"Os funis têm as mesmas permissões que o jogador que os colocou. Os funis "
"colocados por você podem pegar itens ou colocar itens em caixas bloqueadas "
"que você possui, mas os funis colocados por outros jogadores não poderão "
"fazê-lo. No entanto, o inventário próprio de um depósito não é bloqueado "
"pelo proprietário, portanto você pode usar isso como uma forma de permitir "
"que outros jogadores depositem itens em seus baús bloqueados."

#: doc.lua:20
msgid "A chute to transfer items over longer distances."
msgstr "Um chute para transferir itens por longas distâncias."

#: 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 "
"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."
msgstr ""
"As calhas funcionam muito bem como tremonhas, mas não possuem sua própria "
"capacidade de admissão. Os itens só podem ser inseridos em um chute "
"manualmente ou por um funil conectado a um chute. Eles transferem itens na "
"direção indicada pela seta em seu segmento estreito a uma taxa de um item "
"por segundo. Eles têm uma capacidade de buffer de memória pequena e todos os "
"itens que não podem ser colocados no inventário do bloco de destino "
"permanecerão alojados no buffer de memória do chute até que sejam removidos "
"manualmente ou seu destino esteja disponível."

#: doc.lua:23
msgid "A sorter to redirect certain items to an alternate target."
msgstr ""
"Um classificador para redirecionar determinados itens para um destino "
"alternativo."

#: 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.\n"
"\n"
"In addition, there is a button labeled \"Filter All\" that will tell the "
"sorter to not use the filter list and instead first attempt to shunt all "
"items out of the filter, only sending items along the non-filter path if the "
"target cannot accept it for whatever reason. This feature is useful for "
"handling \"overflow\" (when the target's inventory fills up) or for dealing "
"with targets that are selective about what they accept (for example, a "
"furnace's fuel slot)."
msgstr ""
"Isso é semelhante a um chute, mas tem uma saída secundária usada para "
"desviar itens específicos para um destino alternativo. Há um conjunto de "
"espaços de inventário rotulados como \"Filtro\" na parte superior da tela de "
"inventário do bloco, se você colocar um item em um desses slots, o "
"classificador registrará o tipo do item (sem realmente tirá-lo de você). Em "
"seguida, quando os itens passarem pelo inventário do classificador que "
"corresponde a um dos itens da lista de filtros, ele primeiro tentará enviá-"
"lo na direção marcada com uma seta nos lados do classificador.\n"
"\n"
"Se o item não corresponder à lista de filtros ou se a saída secundária não "
"puder receber o item por qualquer motivo, o classificador tentará enviar o "
"item para a outra saída.\n"
"\n"
"Além disso, há um botão chamado \"Filtrar tudo\" que informa ao "
"classificador para não usar a lista de filtros e tentar primeiro desviar "
"todos os itens para fora do filtro, enviando apenas itens ao longo do "
"caminho sem filtro se o destino não puder aceitar por qualquer motivo. Esse "
"recurso é útil para manipular \"estouro\" (quando o estoque do alvo é "
"preenchido) ou para lidar com destinos que são seletivos sobre o que eles "
"aceitam (por exemplo, o compartimento de combustível de um forno)."

#: init.lua:61
msgid "[MOD] Hopper loaded"
msgstr "[Hopper] Carregado com sucesso!"

#: utility.lua:34
msgid ""
"Don't\n"
"Eject"
msgstr "Não\nEjetar"

#: 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 ""
"Este alimentador está atualmente configurado para ejetar itens de sua saída, "
"mesmo se não houver um bloco compatível posicionado para recebê-lo. Clique "
"neste botão para desativar esse recurso."

#: utility.lua:37
msgid ""
"Eject\n"
"Items"
msgstr "Ejetar\nItens"

#: 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 ""
"Este funil está atualmente configurado para segurar o item se não houver um "
"bloco compatível posicionado para recebê-lo. Clique neste botão para ejetar "
"itens."

#: nodes\chute.lua:20
msgid "Hopper Chute"
msgstr "Calha de Funil"

#: nodes\chute.lua:78
msgid "@1 moves stuff to chute at @2"
msgstr "@1 moveu coisas para calha em @2"

#: nodes\hoppers.lua:60
msgid "Hopper"
msgstr "Funil"

#: nodes\hoppers.lua:122
#: nodes\hoppers.lua:214
msgid "@1 moves stuff in hopper at @2"
msgstr "@1 moveu coisas no funil em @2"

#: nodes\hoppers.lua:127
#: nodes\hoppers.lua:219
msgid "@1 moves stuff to hopper at @2"
msgstr "@1 moveu as coisas para o funil em @2"

#: nodes\hoppers.lua:132
#: nodes\hoppers.lua:224
msgid "@1 moves stuff from hopper at @2"
msgstr "@1 move as coisas do funil para @2"

#: nodes\hoppers.lua:148
msgid "Side Hopper"
msgstr "Funil Lateral"

#: nodes\sorter.lua:26
msgid ""
"Selective\n"
"Filter"
msgstr "Filtro\nSeletivo"

#: nodes\sorter.lua:27
msgid ""
"This sorter is currently set to try sending all items\n"
"in the direction of the arrow. Click this button\n"
"to enable an item-type-specific filter."
msgstr ""
"Este separador está atualmente configurado para tentar enviar todos os itens "
"na direção da seta. Clique neste botão para ativar um filtro específico para "
"um tipo de item."

#: nodes\sorter.lua:29
msgid "Filter"
msgstr "Filtro"

#: nodes\sorter.lua:30
msgid ""
"Filter\n"
"All"
msgstr "Filtrar\nTudo"

#: nodes\sorter.lua:31
msgid ""
"This sorter is currently set to only send items listed\n"
"in the filter list in the direction of the arrow.\n"
"Click this button to set it to try sending all\n"
"items that way first."
msgstr ""
"Este separador está atualmente configurado para enviar apenas itens listados "
"na lista de filtros na direção da seta. Clique neste botão para configurá-lo "
"para tentar enviar todos os itens dessa maneira primeiro."

#: nodes\sorter.lua:51
msgid "Sorter"
msgstr "Organizador"

#: nodes\sorter.lua:144
msgid "@1 moves stuff to sorter at @2"
msgstr "@1 move coisas para classificador em @2"


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-06 08:42-0700\n"
"PO-Revision-Date: 2018-12-06 00:27+0000\n"
"Last-Translator: Lunovox Heavenfinder <lunovox@disroot.org>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"minetest/mod-hopper/pt_BR/>\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.4-dev\n"

#: doc.lua:11
msgid "Hopper to transfer items between neighboring blocks' inventories."
msgstr "Funil para transferir itens entre os inventários dos blocos vizinhos."

#: 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 "
"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"
msgstr ""
"Os itens são transferidos do bloco na extremidade larga da tremonha para o "
"bloco na extremidade estreita da tremonha a uma taxa de um por segundo. Os "
"itens também podem ser colocados diretamente no estoque do funil, ou podem "
"ser colocados no espaço acima de um funil e serão sugados para o inventário "
"do funil automaticamente.\n"
"\n"

#: 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 "
"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"
msgstr ""
"Os blocos do funil vêm em formulários \"verticais\" e \"laterais\", mas "
"quando no inventário de um jogador ambos são representados por um único item "
"genérico. O tipo de bloco funil que será colocado quando o jogador usa este "
"item depende do que está apontado - quando o item funil é apontado na face "
"superior ou inferior de um bloco, um funil vertical é colocado, quando "
"apontado para o lado de um bloquear um funil lateral é produzido que se "
"conecta ao lado clicado.\n"
"\n"

#: 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 ""
"Os blocos do funil vêm nas formas 'vertical' e 'lateral'. Eles podem ser "
"interconvertidos entre as duas formas através da grade de criação.\n"
"\n"

#: 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 "
"bottom and inject items into the furnace's \"fuel\" inventory slot when "
"attached to the furnace's side.\n"
"\n"
"Items that cannot be placed in a target block's inventory will remain in the "
"hopper.\n"
"\n"
"Hoppers 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."
msgstr ""
"Quando usados com fornos, os funis injetam itens na fenda de estoque de "
"\"matéria-prima\" do forno quando a extremidade estreita é presa à parte "
"superior ou inferior e injetam itens na ranhura de estoque \"combustível\" "
"do forno quando fixados ao lado do forno.\n"
"\n"
"Itens que não podem ser colocados no inventário de um bloco de destino "
"permanecerão no depósito.\n"
"\n"
"Os funis têm as mesmas permissões que o jogador que os colocou. Os funis "
"colocados por você podem pegar itens ou colocar itens em caixas bloqueadas "
"que você possui, mas os funis colocados por outros jogadores não poderão "
"fazê-lo. No entanto, o inventário próprio de um depósito não é bloqueado "
"pelo proprietário, portanto você pode usar isso como uma forma de permitir "
"que outros jogadores depositem itens em seus baús bloqueados."

#: doc.lua:20
msgid "A chute to transfer items over longer distances."
msgstr "Um chute para transferir itens por longas distâncias."

#: 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 "
"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."
msgstr ""
"As calhas funcionam muito bem como tremonhas, mas não possuem sua própria "
"capacidade de admissão. Os itens só podem ser inseridos em um chute "
"manualmente ou por um funil conectado a um chute. Eles transferem itens na "
"direção indicada pela seta em seu segmento estreito a uma taxa de um item "
"por segundo. Eles têm uma capacidade de buffer de memória pequena e todos os "
"itens que não podem ser colocados no inventário do bloco de destino "
"permanecerão alojados no buffer de memória do chute até que sejam removidos "
"manualmente ou seu destino esteja disponível."

#: doc.lua:23
msgid "A sorter to redirect certain items to an alternate target."
msgstr ""
"Um classificador para redirecionar determinados itens para um destino "
"alternativo."

#: 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.\n"
"\n"
"In addition, there is a button labeled \"Filter All\" that will tell the "
"sorter to not use the filter list and instead first attempt to shunt all "
"items out of the filter, only sending items along the non-filter path if the "
"target cannot accept it for whatever reason. This feature is useful for "
"handling \"overflow\" (when the target's inventory fills up) or for dealing "
"with targets that are selective about what they accept (for example, a "
"furnace's fuel slot)."
msgstr ""
"Isso é semelhante a um chute, mas tem uma saída secundária usada para "
"desviar itens específicos para um destino alternativo. Há um conjunto de "
"espaços de inventário rotulados como \"Filtro\" na parte superior da tela de "
"inventário do bloco, se você colocar um item em um desses slots, o "
"classificador registrará o tipo do item (sem realmente tirá-lo de você). Em "
"seguida, quando os itens passarem pelo inventário do classificador que "
"corresponde a um dos itens da lista de filtros, ele primeiro tentará enviá-"
"lo na direção marcada com uma seta nos lados do classificador.\n"
"\n"
"Se o item não corresponder à lista de filtros ou se a saída secundária não "
"puder receber o item por qualquer motivo, o classificador tentará enviar o "
"item para a outra saída.\n"
"\n"
"Além disso, há um botão chamado \"Filtrar tudo\" que informa ao "
"classificador para não usar a lista de filtros e tentar primeiro desviar "
"todos os itens para fora do filtro, enviando apenas itens ao longo do "
"caminho sem filtro se o destino não puder aceitar por qualquer motivo. Esse "
"recurso é útil para manipular \"estouro\" (quando o estoque do alvo é "
"preenchido) ou para lidar com destinos que são seletivos sobre o que eles "
"aceitam (por exemplo, o compartimento de combustível de um forno)."

#: init.lua:61
msgid "[MOD] Hopper loaded"
msgstr "[Hopper] Carregado com sucesso!"

#: utility.lua:34
msgid ""
"Don't\n"
"Eject"
msgstr "Não\nEjetar"

#: 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 ""
"Este alimentador está atualmente configurado para ejetar itens de sua saída, "
"mesmo se não houver um bloco compatível posicionado para recebê-lo. Clique "
"neste botão para desativar esse recurso."

#: utility.lua:37
msgid ""
"Eject\n"
"Items"
msgstr "Ejetar\nItens"

#: 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 ""
"Este funil está atualmente configurado para segurar o item se não houver um "
"bloco compatível posicionado para recebê-lo. Clique neste botão para ejetar "
"itens."

#: nodes\chute.lua:20
msgid "Hopper Chute"
msgstr "Calha de Funil"

#: nodes\chute.lua:78
msgid "@1 moves stuff to chute at @2"
msgstr "@1 moveu coisas para calha em @2"

#: nodes\hoppers.lua:60
msgid "Hopper"
msgstr "Funil"

#: nodes\hoppers.lua:122
#: nodes\hoppers.lua:214
msgid "@1 moves stuff in hopper at @2"
msgstr "@1 moveu coisas no funil em @2"

#: nodes\hoppers.lua:127
#: nodes\hoppers.lua:219
msgid "@1 moves stuff to hopper at @2"
msgstr "@1 moveu as coisas para o funil em @2"

#: nodes\hoppers.lua:132
#: nodes\hoppers.lua:224
msgid "@1 moves stuff from hopper at @2"
msgstr "@1 move as coisas do funil para @2"

#: nodes\hoppers.lua:148
msgid "Side Hopper"
msgstr "Funil Lateral"

#: nodes\sorter.lua:26
msgid ""
"Selective\n"
"Filter"
msgstr "Filtro\nSeletivo"

#: nodes\sorter.lua:27
msgid ""
"This sorter is currently set to try sending all items\n"
"in the direction of the arrow. Click this button\n"
"to enable an item-type-specific filter."
msgstr ""
"Este separador está atualmente configurado para tentar enviar todos os itens "
"na direção da seta. Clique neste botão para ativar um filtro específico para "
"um tipo de item."

#: nodes\sorter.lua:29
msgid "Filter"
msgstr "Filtro"

#: nodes\sorter.lua:30
msgid ""
"Filter\n"
"All"
msgstr "Filtrar\nTudo"

#: nodes\sorter.lua:31
msgid ""
"This sorter is currently set to only send items listed\n"
"in the filter list in the direction of the arrow.\n"
"Click this button to set it to try sending all\n"
"items that way first."
msgstr ""
"Este separador está atualmente configurado para enviar apenas itens listados "
"na lista de filtros na direção da seta. Clique neste botão para configurá-lo "
"para tentar enviar todos os itens dessa maneira primeiro."

#: nodes\sorter.lua:51
msgid "Sorter"
msgstr "Organizador"

#: nodes\sorter.lua:144
msgid "@1 moves stuff to sorter at @2"
msgstr "@1 move coisas para classificador em @2"


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-06 08:42-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: doc.lua:11
msgid "Hopper to transfer items between neighboring blocks' inventories."
msgstr ""

#: 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 "
"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"
msgstr ""

#: 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 "
"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"
msgstr ""

#: 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 ""

#: 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 "
"bottom and inject items into the furnace's \"fuel\" inventory slot when "
"attached to the furnace's side.\n"
"\n"
"Items that cannot be placed in a target block's inventory will remain in the "
"hopper.\n"
"\n"
"Hoppers 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."
msgstr ""

#: doc.lua:20
msgid "A chute to transfer items over longer distances."
msgstr ""

#: 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 "
"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."
msgstr ""

#: doc.lua:23
msgid "A sorter to redirect certain items to an alternate target."
msgstr ""

#: 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.\n"
"\n"
"In addition, there is a button labeled \"Filter All\" that will tell the "
"sorter to not use the filter list and instead first attempt to shunt all "
"items out of the filter, only sending items along the non-filter path if the "
"target cannot accept it for whatever reason. This feature is useful for "
"handling \"overflow\" (when the target's inventory fills up) or for dealing "
"with targets that are selective about what they accept (for example, a "
"furnace's fuel slot)."
msgstr ""

#: init.lua:61
msgid "[MOD] Hopper loaded"
msgstr ""

#: utility.lua:34
msgid ""
"Don't\n"
"Eject"
msgstr ""

#: 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 ""

#: utility.lua:37
msgid ""
"Eject\n"
"Items"
msgstr ""

#: 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 ""

#: nodes\chute.lua:20
msgid "Hopper Chute"
msgstr ""

#: nodes\chute.lua:78
msgid "@1 moves stuff to chute at @2"
msgstr ""

#: nodes\hoppers.lua:60
msgid "Hopper"
msgstr ""

#: nodes\hoppers.lua:122
#: nodes\hoppers.lua:214
msgid "@1 moves stuff in hopper at @2"
msgstr ""

#: nodes\hoppers.lua:127
#: nodes\hoppers.lua:219
msgid "@1 moves stuff to hopper at @2"
msgstr ""

#: nodes\hoppers.lua:132
#: nodes\hoppers.lua:224
msgid "@1 moves stuff from hopper at @2"
msgstr ""

#: nodes\hoppers.lua:148
msgid "Side Hopper"
msgstr ""

#: nodes\sorter.lua:26
msgid ""
"Selective\n"
"Filter"
msgstr ""

#: nodes\sorter.lua:27
msgid ""
"This sorter is currently set to try sending all items\n"
"in the direction of the arrow. Click this button\n"
"to enable an item-type-specific filter."
msgstr ""

#: nodes\sorter.lua:29
msgid "Filter"
msgstr ""

#: nodes\sorter.lua:30
msgid ""
"Filter\n"
"All"
msgstr ""

#: nodes\sorter.lua:31
msgid ""
"This sorter is currently set to only send items listed\n"
"in the filter list in the direction of the arrow.\n"
"Click this button to set it to try sending all\n"
"items that way first."
msgstr ""

#: nodes\sorter.lua:51
msgid "Sorter"
msgstr ""

#: nodes\sorter.lua:144
msgid "@1 moves stuff to sorter at @2"
msgstr ""


code:
@echo off
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
cd ..
set LIST=
for /r %%X in (*.lua) do set LIST=!LIST! %%X
..\intllib\tools\xgettext.bat %LIST%


code:
name = hopper
optional_depends = default, lucky_block, doc, intllib, protector, wine
description = Adds hoppers to transport items between chests/furnace etc


code:
-- 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, 0.8)
		.. "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,
})