Version 0.41.3
[MineClone/MineClone2/MineClone2-Fixes.git] / mods / ITEMS / mcl_hoppers / init.lua
blobdd9a63a5c2dd81fab8776c959a8523a710a66295
1 local chest = minetest.get_content_id("mcl_chests:chest")
4 --[[ BEGIN OF NODE DEFINITIONS ]]
6 local mcl_hoppers_formspec =
7 "size[9,7]"..
8 "background[-0.19,-0.25;9.41,10.48;mcl_hoppers_inventory.png]"..
9 mcl_vars.inventory_header..
10 "list[current_name;main;2,0.5;5,1;]"..
11 "list[current_player;main;0,2.5;9,3;9]"..
12 "list[current_player;main;0,5.74;9,1;]"..
13 "listring[current_name;main]"..
14 "listring[current_player;main]"
16 -- Downwards hopper (base definition)
18 local def_hopper = {
19 inventory_image = "mcl_hoppers_item.png",
20 wield_image = "mcl_hoppers_item.png",
21 groups = {pickaxey=1, container=2,deco_block=1,},
22 drawtype = "nodebox",
23 paramtype = "light",
24 -- FIXME: mcl_hoppers_hopper_inside.png is unused by hoppers.
25 tiles = {"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png"},
26 node_box = {
27 type = "fixed",
28 fixed = {
29 --funnel walls
30 {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
31 {0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
32 {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
33 {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
34 --funnel base
35 {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5},
36 --spout
37 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
38 {-0.1, -0.3, -0.1, 0.1, -0.5, 0.1},
41 selection_box = {
42 type = "fixed",
43 fixed = {
44 --funnel
45 {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5},
46 --spout
47 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
48 {-0.1, -0.3, -0.1, 0.1, -0.5, 0.1},
51 is_ground_content = false,
53 on_construct = function(pos)
54 local meta = minetest.get_meta(pos)
55 meta:set_string("formspec", mcl_hoppers_formspec)
56 local inv = meta:get_inventory()
57 inv:set_size("main", 5)
58 end,
60 after_dig_node = function(pos, oldnode, oldmetadata, digger)
61 local meta = minetest.get_meta(pos)
62 local meta2 = meta
63 meta:from_table(oldmetadata)
64 local inv = meta:get_inventory()
65 for i=1,inv:get_size("main") do
66 local stack = inv:get_stack("main", i)
67 if not stack:is_empty() then
68 local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
69 minetest.add_item(p, stack)
70 end
71 end
72 meta:from_table(meta2:to_table())
73 end,
74 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
75 minetest.log("action", player:get_player_name()..
76 " moves stuff in mcl_hoppers at "..minetest.pos_to_string(pos))
77 end,
78 on_metadata_inventory_put = function(pos, listname, index, stack, player)
79 minetest.log("action", player:get_player_name()..
80 " moves stuff to mcl_hoppers at "..minetest.pos_to_string(pos))
81 end,
82 on_metadata_inventory_take = function(pos, listname, index, stack, player)
83 minetest.log("action", player:get_player_name()..
84 " takes stuff from mcl_hoppers at "..minetest.pos_to_string(pos))
85 end,
86 sounds = mcl_sounds.node_sound_metal_defaults(),
88 _mcl_blast_resistance = 24,
89 _mcl_hardness = 3,
92 -- Redstone variants (on/off) of downwards hopper.
93 -- Note a hopper is enabled when it is *not* supplied with redstone power and disabled when it is supplied with redstone power.
95 -- Enabled downwards hopper
96 local def_hopper_enabled = table.copy(def_hopper)
97 def_hopper_enabled.description = "Hopper"
98 def_hopper_enabled._doc_items_longdesc = [[Hoppers are containers with 5 inventory slots. They collect dropped items from above, take items from a container above and attempts to put its items it into an adjacent container. Hoppers can go either downwards or sideways. Hoppers interact with chests, droppers, dispensers, shulker boxes, furnaces and hoppers.
100 Hoppers interact with containers the following way:
101 • Furnaces: Hoppers from above will put items into the source slot. Hoppers from below take items from the output slot. They also take items from the fuel slot when they can't be used as a fuel. Sideway hoppers put items into the fuel slot
102 • Ender chests: Hoppers don't interact with ender chests
103 • Other containers: Hoppers interact with them normally
105 Hoppers can be disabled by supplying them with redstone power. Disabled hoppers don't move items.]]
106 def_hopper_enabled._doc_items_usagehelp = "To place a hopper vertically, place it on the floor or a ceiling. To place it sideways, place it at the side of a block. Remember you can place at usable blocks (such as chests) with sneak + right-click. The hopper will keep its orientation when the blocks around it are changed. To access the hopper's inventory, rightclick it."
107 def_hopper_enabled.on_place = function(itemstack, placer, pointed_thing)
108 local upos = pointed_thing.under
109 local apos = pointed_thing.above
111 local uposnode = minetest.get_node(upos)
112 local uposnodedef = minetest.registered_nodes[uposnode.name]
113 if not uposnodedef then return itemstack end
114 -- Use pointed node's on_rightclick function first, if present
115 if placer and not placer:get_player_control().sneak then
116 if uposnodedef and uposnodedef.on_rightclick then
117 return uposnodedef.on_rightclick(pointed_thing.under, uposnode, placer, itemstack) or itemstack
121 local x = upos.x - apos.x
122 local z = upos.z - apos.z
124 local fake_itemstack = ItemStack(itemstack)
125 local newnode, param2
126 if x == -1 then
127 fake_itemstack:set_name("mcl_hoppers:hopper_side")
128 param2 = 0
129 elseif x == 1 then
130 fake_itemstack:set_name("mcl_hoppers:hopper_side")
131 param2 = 2
132 elseif z == -1 then
133 fake_itemstack:set_name("mcl_hoppers:hopper_side")
134 param2 = 3
135 elseif z == 1 then
136 fake_itemstack:set_name("mcl_hoppers:hopper_side")
137 param2 = 1
139 local itemstack, success = minetest.item_place_node(fake_itemstack, placer, pointed_thing, param2)
140 itemstack:set_name("mcl_hoppers:hopper")
141 return itemstack
143 def_hopper_enabled.mesecons = {
144 effector = {
145 action_on = function(pos, node)
146 minetest.swap_node(pos, {name="mcl_hoppers:hopper_disabled", param2=node.param2})
147 end,
151 minetest.register_node("mcl_hoppers:hopper", def_hopper_enabled)
153 -- Disabled downwards hopper
154 local def_hopper_disabled = table.copy(def_hopper)
155 def_hopper_disabled.description = "Disabled Hopper"
156 def_hopper_disabled._doc_items_create_entry = false
157 def_hopper_disabled.groups.not_in_creative_inventory = 1
158 def_hopper_disabled.drop = "mcl_hoppers:hopper"
159 def_hopper_disabled.mesecons = {
160 effector = {
161 action_off = function(pos, node)
162 minetest.swap_node(pos, {name="mcl_hoppers:hopper", param2=node.param2})
163 end,
167 minetest.register_node("mcl_hoppers:hopper_disabled", def_hopper_disabled)
171 local on_rotate
172 if minetest.get_modpath("screwdriver") then
173 on_rotate = screwdriver.rotate_simple
176 -- Sidewars hopper (base definition)
177 local def_hopper_side = {
178 _doc_items_create_entry = false,
179 drop = "mcl_hoppers:hopper",
180 groups = {pickaxey=1, container=2,not_in_creative_inventory=1},
181 drawtype = "nodebox",
182 paramtype = "light",
183 paramtype2 = "facedir",
184 tiles = {"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png"},
185 node_box = {
186 type = "fixed",
187 fixed = {
188 --funnel walls
189 {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
190 {0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
191 {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
192 {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
193 --funnel base
194 {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5},
195 --spout
196 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
197 {-0.5, -0.3, -0.1, 0.1, -0.1, 0.1},
200 selection_box = {
201 type = "fixed",
202 fixed = {
203 --funnel
204 {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5},
205 --spout
206 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
207 {-0.5, -0.3, -0.1, 0.1, -0.1, 0.1},
210 is_ground_content = false,
212 on_construct = function(pos)
213 local meta = minetest.get_meta(pos)
214 meta:set_string("formspec", mcl_hoppers_formspec)
215 local inv = meta:get_inventory()
216 inv:set_size("main", 5)
217 end,
219 after_dig_node = function(pos, oldnode, oldmetadata, digger)
220 local meta = minetest.get_meta(pos)
221 local meta2 = meta
222 meta:from_table(oldmetadata)
223 local inv = meta:get_inventory()
224 for i=1,inv:get_size("main") do
225 local stack = inv:get_stack("main", i)
226 if not stack:is_empty() then
227 local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
228 minetest.add_item(p, stack)
231 meta:from_table(meta2:to_table())
232 end,
233 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
234 minetest.log("action", player:get_player_name()..
235 " moves stuff in mcl_hoppers at "..minetest.pos_to_string(pos))
236 end,
237 on_metadata_inventory_put = function(pos, listname, index, stack, player)
238 minetest.log("action", player:get_player_name()..
239 " moves stuff to mcl_hoppers at "..minetest.pos_to_string(pos))
240 end,
241 on_metadata_inventory_take = function(pos, listname, index, stack, player)
242 minetest.log("action", player:get_player_name()..
243 " takes stuff from mcl_hoppers at "..minetest.pos_to_string(pos))
244 end,
245 on_rotate = on_rotate,
246 sounds = mcl_sounds.node_sound_metal_defaults(),
248 _mcl_blast_resistance = 24,
249 _mcl_hardness = 3,
252 local def_hopper_side_enabled = table.copy(def_hopper_side)
253 def_hopper_side_enabled.description = "Side Hopper"
254 def_hopper_side_enabled.mesecons = {
255 effector = {
256 action_on = function(pos, node)
257 minetest.swap_node(pos, {name="mcl_hoppers:hopper_side_disabled", param2=node.param2})
258 end,
261 minetest.register_node("mcl_hoppers:hopper_side", def_hopper_side_enabled)
263 local def_hopper_side_disabled = table.copy(def_hopper_side)
264 def_hopper_side_disabled.description = "Disabled Side Hopper"
265 def_hopper_side_disabled.mesecons = {
266 effector = {
267 action_off = function(pos, node)
268 minetest.swap_node(pos, {name="mcl_hoppers:hopper_side", param2=node.param2})
269 end,
272 minetest.register_node("mcl_hoppers:hopper_side_disabled", def_hopper_side_disabled)
274 --[[ END OF NODE DEFINITIONS ]]
276 --[[ BEGIN OF ABM DEFINITONS ]]
278 -- Make hoppers suck in dropped items
279 minetest.register_abm({
280 label = "Hoppers suck in dropped items",
281 nodenames = {"mcl_hoppers:hopper","mcl_hoppers:hopper_side"},
282 interval = 1.0,
283 chance = 1,
284 action = function(pos, node, active_object_count, active_object_count_wider)
285 local abovenode = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
286 if not minetest.registered_items[abovenode.name] then return end
287 -- Don't bother checking item enties if node above is a container (should save some CPU)
288 if minetest.registered_items[abovenode.name].groups.container then
289 return
291 local meta = minetest.get_meta(pos)
292 local inv = meta:get_inventory()
294 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do
295 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then
296 if inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
297 -- Item must get sucked in when the item just TOUCHES the block above the hopper
298 -- This is the reason for the Y calculation.
299 -- Test: Items on farmland and slabs get sucked, but items on full blocks don't
300 local posob = object:getpos()
301 local posob_miny = posob.y + object:get_properties().collisionbox[2]
302 if math.abs(posob.x-pos.x) <= 0.5 and (posob_miny-pos.y < 1.5 and posob.y-pos.y >= 0.3) then
303 inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
304 object:get_luaentity().itemstring = ""
305 object:remove()
310 end,
313 -- Returns true if itemstack is fuel, but not for lava bucket if destination already has one
314 local is_transferrable_fuel = function(itemstack, src_inventory, src_list, dst_inventory, dst_list)
315 if mcl_util.is_fuel(itemstack) then
316 if itemstack:get_name() == "mcl_buckets:bucket_lava" then
317 return dst_inventory:is_empty(dst_list)
318 else
319 return true
321 else
322 return false
328 minetest.register_abm({
329 label = "Hopper/container item exchange",
330 nodenames = {"mcl_hoppers:hopper"},
331 neighbors = {"group:container"},
332 interval = 1.0,
333 chance = 1,
334 action = function(pos, node, active_object_count, active_object_count_wider)
335 -- Get node pos' for item transfer
336 local uppos = {x=pos.x,y=pos.y+1,z=pos.z}
337 local downpos = {x=pos.x,y=pos.y-1,z=pos.z}
339 -- Suck an item from the container above into the hopper
340 local upnode = minetest.get_node(uppos)
341 if not minetest.registered_nodes[upnode.name] then return end
342 local g = minetest.registered_nodes[upnode.name].groups.container
343 local sucked = mcl_util.move_item_container(uppos, pos)
345 -- Also suck in non-fuel items from furnace fuel slot
346 if not sucked and g == 4 then
347 local finv = minetest.get_inventory({type="node", pos=uppos})
348 if finv and not mcl_util.is_fuel(finv:get_stack("fuel", 1)) then
349 mcl_util.move_item_container(uppos, pos, "fuel")
353 -- Move an item from the hopper into container below
354 local downnode = minetest.get_node(downpos)
355 if not minetest.registered_nodes[downnode.name] then return end
356 g = minetest.registered_nodes[downnode.name].groups.container
357 mcl_util.move_item_container(pos, downpos)
358 end,
361 minetest.register_abm({
362 label = "Side-hopper/container item exchange",
363 nodenames = {"mcl_hoppers:hopper_side"},
364 neighbors = {"group:container"},
365 interval = 1.0,
366 chance = 1,
367 action = function(pos, node, active_object_count, active_object_count_wider)
368 -- Determine to which side the hopper is facing, get nodes
369 local face = minetest.get_node(pos).param2
370 local front = {}
371 if face == 0 then
372 front = {x=pos.x-1,y=pos.y,z=pos.z}
373 elseif face == 1 then
374 front = {x=pos.x,y=pos.y,z=pos.z+1}
375 elseif face == 2 then
376 front = {x=pos.x+1,y=pos.y,z=pos.z}
377 elseif face == 3 then
378 front = {x=pos.x,y=pos.y,z=pos.z-1}
380 local above = {x=pos.x,y=pos.y+1,z=pos.z}
382 local frontnode = minetest.get_node(front)
383 if not minetest.registered_nodes[frontnode.name] then return end
385 -- Suck an item from the container above into the hopper
386 local abovenode = minetest.get_node(above)
387 if not minetest.registered_nodes[abovenode.name] then return end
388 local g = minetest.registered_nodes[abovenode.name].groups.container
389 mcl_util.move_item_container(above, pos)
391 -- Move an item from the hopper into the container to which the hopper points to
392 local g = minetest.registered_nodes[frontnode.name].groups.container
393 if g == 2 or g == 3 or g == 5 or g == 6 then
394 mcl_util.move_item_container(pos, front)
395 elseif g == 4 then
396 -- Put fuel into fuel slot
397 local sinv = minetest.get_inventory({type="node", pos = pos})
398 local dinv = minetest.get_inventory({type="node", pos = front})
399 local slot_id, stack = mcl_util.get_eligible_transfer_item_slot(sinv, "main", dinv, "fuel", is_transferrable_fuel)
400 if slot_id then
401 mcl_util.move_item_container(pos, front, nil, slot_id, "fuel")
407 minetest.register_craft({
408 output = "mcl_hoppers:hopper",
409 recipe = {
410 {"mcl_core:iron_ingot","","mcl_core:iron_ingot"},
411 {"mcl_core:iron_ingot","mcl_chests:chest","mcl_core:iron_ingot"},
412 {"","mcl_core:iron_ingot",""},
416 -- Add entry aliases for the Help
417 if minetest.get_modpath("doc") then
418 doc.add_entry_alias("nodes", "mcl_hoppers:hopper", "nodes", "mcl_hoppers:hopper_side")
421 -- Legacy
422 minetest.register_alias("mcl_hoppers:hopper_item", "mcl_hoppers:hopper")