Set hopper redstone rules
[MineClone/MineClone2.git] / mods / ITEMS / mcl_hoppers / init.lua
blob1689f08613f91283b2e7c963f41bb1d4f395fa61
1 local chest = minetest.get_content_id("mcl_chests:chest")
3 local mcl_hoppers_formspec =
4 "size[9,7]"..
5 "background[-0.19,-0.25;9.41,10.48;mcl_hoppers_inventory.png]"..
6 mcl_vars.inventory_header..
7 "list[current_name;main;2,0.5;5,1;]"..
8 "list[current_player;main;0,2.5;9,3;9]"..
9 "list[current_player;main;0,5.74;9,1;]"..
10 "listring[current_name;main]"..
11 "listring[current_player;main]"
14 --[[ BEGIN OF NODE DEFINITIONS ]]
16 local redstone_rules =
17 {{x= 1, y= 0, z= 0},
18 {x=-1, y= 0, z= 0},
19 {x= 0, y= 1, z= 0},
20 {x= 0, y= -1, z= 0},
21 {x= 0, y= 0, z= 1},
22 {x= 0, y= 0, z=-1}}
24 -- Downwards hopper (base definition)
26 local def_hopper = {
27 inventory_image = "mcl_hoppers_item.png",
28 wield_image = "mcl_hoppers_item.png",
29 groups = {pickaxey=1, container=2,deco_block=1,},
30 drawtype = "nodebox",
31 paramtype = "light",
32 sunlight_propagates = true,
33 tiles = {"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_inside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png"},
34 node_box = {
35 type = "fixed",
36 fixed = {
37 --funnel walls
38 {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
39 {0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
40 {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
41 {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
42 --funnel base
43 {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5},
44 --spout
45 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
46 {-0.1, -0.3, -0.1, 0.1, -0.5, 0.1},
49 selection_box = {
50 type = "fixed",
51 fixed = {
52 --funnel
53 {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5},
54 --spout
55 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
56 {-0.1, -0.3, -0.1, 0.1, -0.5, 0.1},
59 is_ground_content = false,
61 on_construct = function(pos)
62 local meta = minetest.get_meta(pos)
63 meta:set_string("formspec", mcl_hoppers_formspec)
64 local inv = meta:get_inventory()
65 inv:set_size("main", 5)
66 end,
68 after_dig_node = function(pos, oldnode, oldmetadata, digger)
69 local meta = minetest.get_meta(pos)
70 local meta2 = meta
71 meta:from_table(oldmetadata)
72 local inv = meta:get_inventory()
73 for i=1,inv:get_size("main") do
74 local stack = inv:get_stack("main", i)
75 if not stack:is_empty() then
76 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}
77 minetest.add_item(p, stack)
78 end
79 end
80 meta:from_table(meta2:to_table())
81 end,
82 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
83 minetest.log("action", player:get_player_name()..
84 " moves stuff in mcl_hoppers at "..minetest.pos_to_string(pos))
85 end,
86 on_metadata_inventory_put = function(pos, listname, index, stack, player)
87 minetest.log("action", player:get_player_name()..
88 " moves stuff to mcl_hoppers at "..minetest.pos_to_string(pos))
89 end,
90 on_metadata_inventory_take = function(pos, listname, index, stack, player)
91 minetest.log("action", player:get_player_name()..
92 " takes stuff from mcl_hoppers at "..minetest.pos_to_string(pos))
93 end,
94 sounds = mcl_sounds.node_sound_metal_defaults(),
96 _mcl_blast_resistance = 24,
97 _mcl_hardness = 3,
100 -- Redstone variants (on/off) of downwards hopper.
101 -- Note a hopper is enabled when it is *not* supplied with redstone power and disabled when it is supplied with redstone power.
103 -- Enabled downwards hopper
104 local def_hopper_enabled = table.copy(def_hopper)
105 def_hopper_enabled.description = "Hopper"
106 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.
108 Hoppers interact with containers the following way:
109 • 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
110 • Ender chests: Hoppers don't interact with ender chests
111 • Other containers: Hoppers interact with them normally
113 Hoppers can be disabled by supplying them with redstone power. Disabled hoppers don't move items.]]
114 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."
115 def_hopper_enabled.on_place = function(itemstack, placer, pointed_thing)
116 local upos = pointed_thing.under
117 local apos = pointed_thing.above
119 local uposnode = minetest.get_node(upos)
120 local uposnodedef = minetest.registered_nodes[uposnode.name]
121 if not uposnodedef then return itemstack end
122 -- Use pointed node's on_rightclick function first, if present
123 if placer and not placer:get_player_control().sneak then
124 if uposnodedef and uposnodedef.on_rightclick then
125 return uposnodedef.on_rightclick(pointed_thing.under, uposnode, placer, itemstack) or itemstack
129 local bpos
130 if uposnodedef.buildable_to then
131 bpos = upos
132 else
133 local aposnodedef = minetest.registered_nodes[minetest.get_node(apos).name]
134 if not aposnodedef then return itemstack end
135 if aposnodedef.buildable_to then
136 bpos = apos
140 if bpos == nil then
141 return itemstack
144 local x = upos.x - apos.x
145 local y = upos.y - apos.y
146 local z = upos.z - apos.z
148 if x == -1 then
149 minetest.set_node(bpos, {name="mcl_hoppers:hopper_side", param2=0})
150 elseif x == 1 then
151 minetest.set_node(bpos, {name="mcl_hoppers:hopper_side", param2=2})
152 elseif z == -1 then
153 minetest.set_node(bpos, {name="mcl_hoppers:hopper_side", param2=3})
154 elseif z == 1 then
155 minetest.set_node(bpos, {name="mcl_hoppers:hopper_side", param2=1})
156 else
157 minetest.set_node(bpos, {name="mcl_hoppers:hopper", param2=0})
159 if not minetest.settings:get_bool("creative_mode") then
160 itemstack:take_item()
162 return itemstack
164 def_hopper_enabled.mesecons = {
165 effector = {
166 action_on = function(pos, node)
167 minetest.swap_node(pos, {name="mcl_hoppers:hopper_disabled", param2=node.param2})
168 end,
169 rules = redstone_rules,
173 minetest.register_node("mcl_hoppers:hopper", def_hopper_enabled)
175 -- Disabled downwards hopper
176 local def_hopper_disabled = table.copy(def_hopper)
177 def_hopper_disabled.description = "Disabled Hopper"
178 def_hopper_disabled._doc_items_create_entry = false
179 def_hopper_disabled.groups.not_in_creative_inventory = 1
180 def_hopper_disabled.drop = "mcl_hoppers:hopper"
181 def_hopper_disabled.mesecons = {
182 effector = {
183 action_off = function(pos, node)
184 minetest.swap_node(pos, {name="mcl_hoppers:hopper", param2=node.param2})
185 end,
186 rules = redstone_rules,
190 minetest.register_node("mcl_hoppers:hopper_disabled", def_hopper_disabled)
194 local on_rotate
195 if minetest.get_modpath("screwdriver") then
196 on_rotate = screwdriver.rotate_simple
199 -- Sidewars hopper (base definition)
200 local def_hopper_side = {
201 _doc_items_create_entry = false,
202 drop = "mcl_hoppers:hopper",
203 groups = {pickaxey=1, container=2,not_in_creative_inventory=1},
204 drawtype = "nodebox",
205 paramtype = "light",
206 sunlight_propagates = true,
207 paramtype2 = "facedir",
208 tiles = {"mcl_hoppers_hopper_inside.png^mcl_hoppers_hopper_top.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_inside.png", "mcl_hoppers_hopper_outside.png", "mcl_hoppers_hopper_outside.png"},
209 node_box = {
210 type = "fixed",
211 fixed = {
212 --funnel walls
213 {-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
214 {0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
215 {-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
216 {-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
217 --funnel base
218 {-0.5, 0.0, -0.5, 0.5, 0.1, 0.5},
219 --spout
220 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
221 {-0.5, -0.3, -0.1, 0.1, -0.1, 0.1},
224 selection_box = {
225 type = "fixed",
226 fixed = {
227 --funnel
228 {-0.5, 0.0, -0.5, 0.5, 0.5, 0.5},
229 --spout
230 {-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
231 {-0.5, -0.3, -0.1, 0.1, -0.1, 0.1},
234 is_ground_content = false,
236 on_construct = function(pos)
237 local meta = minetest.get_meta(pos)
238 meta:set_string("formspec", mcl_hoppers_formspec)
239 local inv = meta:get_inventory()
240 inv:set_size("main", 5)
241 end,
243 after_dig_node = function(pos, oldnode, oldmetadata, digger)
244 local meta = minetest.get_meta(pos)
245 local meta2 = meta
246 meta:from_table(oldmetadata)
247 local inv = meta:get_inventory()
248 for i=1,inv:get_size("main") do
249 local stack = inv:get_stack("main", i)
250 if not stack:is_empty() then
251 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}
252 minetest.add_item(p, stack)
255 meta:from_table(meta2:to_table())
256 end,
257 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
258 minetest.log("action", player:get_player_name()..
259 " moves stuff in mcl_hoppers at "..minetest.pos_to_string(pos))
260 end,
261 on_metadata_inventory_put = function(pos, listname, index, stack, player)
262 minetest.log("action", player:get_player_name()..
263 " moves stuff to mcl_hoppers at "..minetest.pos_to_string(pos))
264 end,
265 on_metadata_inventory_take = function(pos, listname, index, stack, player)
266 minetest.log("action", player:get_player_name()..
267 " takes stuff from mcl_hoppers at "..minetest.pos_to_string(pos))
268 end,
269 on_rotate = on_rotate,
270 sounds = mcl_sounds.node_sound_metal_defaults(),
272 _mcl_blast_resistance = 24,
273 _mcl_hardness = 3,
276 local def_hopper_side_enabled = table.copy(def_hopper_side)
277 def_hopper_side_enabled.description = "Side Hopper"
278 def_hopper_side_enabled.mesecons = {
279 effector = {
280 action_on = function(pos, node)
281 minetest.swap_node(pos, {name="mcl_hoppers:hopper_side_disabled", param2=node.param2})
282 end,
283 rules = redstone_rules,
286 minetest.register_node("mcl_hoppers:hopper_side", def_hopper_side_enabled)
288 local def_hopper_side_disabled = table.copy(def_hopper_side)
289 def_hopper_side_disabled.description = "Disabled Side Hopper"
290 def_hopper_side_disabled.mesecons = {
291 effector = {
292 action_off = function(pos, node)
293 minetest.swap_node(pos, {name="mcl_hoppers:hopper_side", param2=node.param2})
294 end,
295 rules = redstone_rules,
298 minetest.register_node("mcl_hoppers:hopper_side_disabled", def_hopper_side_disabled)
300 --[[ END OF NODE DEFINITIONS ]]
302 --[[ BEGIN OF ABM DEFINITONS ]]
304 -- Make hoppers suck in dropped items
305 minetest.register_abm({
306 label = "Hoppers suck in dropped items",
307 nodenames = {"mcl_hoppers:hopper","mcl_hoppers:hopper_side"},
308 interval = 1.0,
309 chance = 1,
310 action = function(pos, node, active_object_count, active_object_count_wider)
311 local abovenode = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
312 if not minetest.registered_items[abovenode.name] then return end
313 -- Don't bother checking item enties if node above is a container (should save some CPU)
314 if minetest.registered_items[abovenode.name].groups.container then
315 return
317 local meta = minetest.get_meta(pos)
318 local inv = meta:get_inventory()
320 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do
321 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then
322 if inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
323 -- Item must get sucked in when the item just TOUCHES the block above the hopper
324 -- This is the reason for the Y calculation.
325 -- Test: Items on farmland and slabs get sucked, but items on full blocks don't
326 local posob = object:getpos()
327 local posob_miny = posob.y + object:get_properties().collisionbox[2]
328 if math.abs(posob.x-pos.x) <= 0.5 and (posob_miny-pos.y < 1.5 and posob.y-pos.y >= 0.3) then
329 inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
330 object:get_luaentity().itemstring = ""
331 object:remove()
336 end,
339 -- Returns true if itemstack is fuel, but not for lava bucket if destination already has one
340 local is_transferrable_fuel = function(itemstack, src_inventory, src_list, dst_inventory, dst_list)
341 if mcl_util.is_fuel(itemstack) then
342 if itemstack:get_name() == "mcl_buckets:bucket_lava" then
343 return dst_inventory:is_empty(dst_list)
344 else
345 return true
347 else
348 return false
354 minetest.register_abm({
355 label = "Hopper/container item exchange",
356 nodenames = {"mcl_hoppers:hopper"},
357 neighbors = {"group:container"},
358 interval = 1.0,
359 chance = 1,
360 action = function(pos, node, active_object_count, active_object_count_wider)
361 -- Get node pos' for item transfer
362 local uppos = {x=pos.x,y=pos.y+1,z=pos.z}
363 local downpos = {x=pos.x,y=pos.y-1,z=pos.z}
365 -- Suck an item from the container above into the hopper
366 local upnode = minetest.get_node(uppos)
367 if not minetest.registered_nodes[upnode.name] then return end
368 local g = minetest.registered_nodes[upnode.name].groups.container
369 local sucked = mcl_util.move_item_container(uppos, pos)
371 -- Also suck in non-fuel items from furnace fuel slot
372 if not sucked and g == 4 then
373 local finv = minetest.get_inventory({type="node", pos=uppos})
374 if finv and not mcl_util.is_fuel(finv:get_stack("fuel", 1)) then
375 mcl_util.move_item_container(uppos, pos, "fuel")
379 -- Move an item from the hopper into container below
380 local downnode = minetest.get_node(downpos)
381 if not minetest.registered_nodes[downnode.name] then return end
382 g = minetest.registered_nodes[downnode.name].groups.container
383 mcl_util.move_item_container(pos, downpos)
384 end,
387 minetest.register_abm({
388 label = "Side-hopper/container item exchange",
389 nodenames = {"mcl_hoppers:hopper_side"},
390 neighbors = {"group:container"},
391 interval = 1.0,
392 chance = 1,
393 action = function(pos, node, active_object_count, active_object_count_wider)
394 -- Determine to which side the hopper is facing, get nodes
395 local face = minetest.get_node(pos).param2
396 local front = {}
397 if face == 0 then
398 front = {x=pos.x-1,y=pos.y,z=pos.z}
399 elseif face == 1 then
400 front = {x=pos.x,y=pos.y,z=pos.z+1}
401 elseif face == 2 then
402 front = {x=pos.x+1,y=pos.y,z=pos.z}
403 elseif face == 3 then
404 front = {x=pos.x,y=pos.y,z=pos.z-1}
406 local above = {x=pos.x,y=pos.y+1,z=pos.z}
408 local frontnode = minetest.get_node(front)
409 if not minetest.registered_nodes[frontnode.name] then return end
411 -- Suck an item from the container above into the hopper
412 local abovenode = minetest.get_node(above)
413 if not minetest.registered_nodes[abovenode.name] then return end
414 local g = minetest.registered_nodes[abovenode.name].groups.container
415 mcl_util.move_item_container(above, pos)
417 -- Move an item from the hopper into the container to which the hopper points to
418 local g = minetest.registered_nodes[frontnode.name].groups.container
419 if g == 2 or g == 3 or g == 5 or g == 6 then
420 mcl_util.move_item_container(pos, front)
421 elseif g == 4 then
422 -- Put fuel into fuel slot
423 local sinv = minetest.get_inventory({type="node", pos = pos})
424 local dinv = minetest.get_inventory({type="node", pos = front})
425 local slot_id, stack = mcl_util.get_eligible_transfer_item_slot(sinv, "main", dinv, "fuel", is_transferrable_fuel)
426 if slot_id then
427 mcl_util.move_item_container(pos, front, nil, slot_id, "fuel")
433 minetest.register_craft({
434 output = "mcl_hoppers:hopper",
435 recipe = {
436 {"mcl_core:iron_ingot","","mcl_core:iron_ingot"},
437 {"mcl_core:iron_ingot","mcl_chests:chest","mcl_core:iron_ingot"},
438 {"","mcl_core:iron_ingot",""},
442 -- Add entry aliases for the Help
443 if minetest.get_modpath("doc") then
444 doc.add_entry_alias("nodes", "mcl_hoppers:hopper", "nodes", "mcl_hoppers:hopper_side")
447 -- Legacy
448 minetest.register_alias("mcl_hoppers:hopper_item", "mcl_hoppers:hopper")