diff --git a/item_transport.lua b/item_transport.lua index 3813e8b..f01506b 100644 --- a/item_transport.lua +++ b/item_transport.lua @@ -38,19 +38,81 @@ end -- both optional w/ sensible defaults and fallback to normal allow_* function -- XXX: possibly change insert_object to insert_item --- sname = the current name to allow for, or nil if it allows anything +local function set_filter_infotext(data, meta) + local infotext = data.wise_desc.." Filter-Injector" + if meta:get_int("slotseq_mode") == 2 then + infotext = infotext .. " (slot #"..meta:get_int("slotseq_index").." next)" + end + meta:set_string("infotext", infotext) +end -local function grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,dir,all) +local function set_filter_formspec(data, meta) + local itemname = data.wise_desc.." Filter-Injector" + local formspec = "size[8,8.5]".. + "item_image[0,0;1,1;pipeworks:"..data.name.."]".. + "label[1,0;"..minetest.formspec_escape(itemname).."]".. + "label[0,1;Prefer item types:]".. + "list[current_name;main;0,1.5;8,2;]" + local slotseq_mode = meta:get_int("slotseq_mode") + if slotseq_mode == 1 then + formspec = formspec .. "button[0,3.5;4,1;slotseq_mode2;Sequence slots Randomly]" + elseif slotseq_mode == 2 then + formspec = formspec .. "button[0,3.5;4,1;slotseq_mode0;Sequence slots by Rotation]" + else + formspec = formspec .. "button[0,3.5;4,1;slotseq_mode1;Sequence slots by Priority]" + end + formspec = formspec .. "list[current_player;main;0,4.5;8,4;]" + meta:set_string("formspec", formspec) +end + +local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,all) + local sposes = {} for spos,stack in ipairs(frominv:get_list(frominvname)) do - if (sname == nil and stack:get_name() ~= "") or stack:get_name() == sname then + local matches + if filtername == "" then + matches = stack:get_name() ~= "" + else + matches = stack:get_name() == filtername + end + if matches then table.insert(sposes, spos) end + end + if #sposes == 0 then return false end + if slotseq_mode == 1 then + for i = #sposes, 2, -1 do + local j = math.random(i) + local t = sposes[j] + sposes[j] = sposes[i] + sposes[i] = t + end + elseif slotseq_mode == 2 then + local headpos = filtmeta:get_int("slotseq_index") + table.sort(sposes, function (a, b) + if a >= headpos then + if b < headpos then return true end + else + if b >= headpos then return false end + end + return a < b + end) + end + for _, spos in ipairs(sposes) do + local stack = frominv:get_stack(frominvname, spos) local doRemove = stack:get_count() - if tube.can_remove then - doRemove = tube.can_remove(frompos, fromnode, stack, dir) - elseif idef.allow_metadata_inventory_take then - doRemove = idef.allow_metadata_inventory_take(frompos, frominvname,spos, stack, fakePlayer) + if fromtube.can_remove then + doRemove = fromtube.can_remove(frompos, fromnode, stack, dir) + elseif fromdef.allow_metadata_inventory_take then + doRemove = fromdef.allow_metadata_inventory_take(frompos, frominvname,spos, stack, fakePlayer) end -- stupid lack of continue statements grumble if doRemove > 0 then + if slotseq_mode == 2 then + local nextpos = spos + 1 + if nextpos > frominv:get_size(frominvname) then + nextpos = 1 + end + filtmeta:set_int("slotseq_index", nextpos) + set_filter_infotext(data, filtmeta) + end local item local count if all then @@ -58,14 +120,14 @@ local function grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef, else count = 1 end - if tube.remove_items then + if fromtube.remove_items then -- it could be the entire stack... - item = tube.remove_items(frompos, fromnode, stack, dir, count) + item = fromtube.remove_items(frompos, fromnode, stack, dir, count) else item = stack:take_item(count) frominv:set_stack(frominvname, spos, stack) - if idef.on_metadata_inventory_take then - idef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer) + if fromdef.on_metadata_inventory_take then + fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer) end end local item1 = pipeworks.tube_item(vector.add(frompos, vector.multiply(dir, 1.4)), item) @@ -74,184 +136,113 @@ local function grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef, item1:setacceleration({x=0, y=0, z=0}) return true-- only fire one item, please end - end end return false end -minetest.register_node("pipeworks:filter", { - description = "Itemwise Filter-Injector", - tiles = {"pipeworks_filter_top.png", "pipeworks_filter_top.png", "pipeworks_filter_output.png", - "pipeworks_filter_input.png", "pipeworks_filter_side.png", "pipeworks_filter_top.png"}, - paramtype2 = "facedir", - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2}, - legacy_facedir_simple = true, - sounds = default.node_sound_wood_defaults(), - on_construct = function(pos) - local meta = minetest.get_meta(pos) - meta:set_string("formspec", - "invsize[8,6.5;]".. - "list[current_name;main;0,0;8,2;]".. - "list[current_player;main;0,2.5;8,4;]") - meta:set_string("infotext", "Itemwise Filter-Injector") - local inv = meta:get_inventory() - inv:set_size("main", 8*2) - end, - can_dig = function(pos,player) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory() - return inv:is_empty("main") - end, - after_place_node = function(pos) - pipeworks.scan_for_tube_objects(pos) - end, - after_dig_node = function(pos) - pipeworks.scan_for_tube_objects(pos) - end, - mesecons={effector={action_on=function(pos,node) - minetest.registered_nodes[node.name].on_punch(pos,node,nil) - end}}, - tube={connect_sides={right=1}}, - on_punch = function (pos, node, puncher) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory() - local dir = facedir_to_right_dir(node.param2) - local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z} - local fromnode=minetest.get_node(frompos) - if not fromnode then return end - local idef = minetest.registered_nodes[fromnode.name] - -- assert(idef) - local tube = idef.tube - if not (tube and tube.input_inventory) then - return - end - if tube.before_filter then - tube.before_filter(frompos) - end - local frommeta = minetest.get_meta(frompos) - local frominv = frommeta:get_inventory() - - local function from_inventory(frominvname) - local sname - for _,filter in ipairs(inv:get_list("main")) do - sname = filter:get_name() - if sname ~= "" then - -- XXX: that's a lot of parameters - if grabAndFire(frominv, frominvname, frompos, fromnode, sname, tube, idef, dir) then - return true - end - end +local function punch_filter(data, filtpos, filtnode) + local filtmeta = minetest.get_meta(filtpos) + local filtinv = filtmeta:get_inventory() + local dir = facedir_to_right_dir(filtnode.param2) + local frompos = {x=filtpos.x - dir.x, y=filtpos.y - dir.y, z=filtpos.z - dir.z} + local fromnode = minetest.get_node(frompos) + if not fromnode then return end + local fromdef = minetest.registered_nodes[fromnode.name] + if not fromdef then return end + local fromtube = fromdef.tube + if not (fromtube and fromtube.input_inventory) then return end + local filters = {} + for _, filterstack in ipairs(filtinv:get_list("main")) do + local filtername = filterstack:get_name() + if filtername ~= "" then table.insert(filters, filtername) end + end + if #filters == 0 then table.insert(filters, "") end + local slotseq_mode = filtmeta:get_int("slotseq_mode") + local frommeta = minetest.get_meta(frompos) + local frominv = frommeta:get_inventory() + if fromtube.before_filter then fromtube.before_filter(frompos) end + for _, frominvname in ipairs(type(fromtube.input_inventory) == "table" and fromtube.input_inventory or {fromtube.input_inventory}) do + local done = false + for _, filtername in ipairs(filters) do + if grabAndFire(data, slotseq_mode, filtmeta, frominv, frominvname, frompos, fromnode, filtername, fromtube, fromdef, dir, data.stackwise) then + done = true + break end - if inv:is_empty("main") then - if grabAndFire(frominv, frominvname, frompos, fromnode, nil, tube, idef, dir) then - return true - end - end - return false end - - if type(tube.input_inventory) == "table" then - for _, i in ipairs(tube.input_inventory) do - if from_inventory(i) then -- fired an item - break - end - end - else - from_inventory(tube.input_inventory) - end - - if tube.after_filter then - tube.after_filter(frompos) - end - end, -}) + if done then break end + end + if fromtube.after_filter then fromtube.after_filter(frompos) end +end -minetest.register_node("pipeworks:mese_filter", { - description = "Stackwise Filter-Injector", - tiles = {"pipeworks_mese_filter_top.png", "pipeworks_mese_filter_top.png", "pipeworks_mese_filter_output.png", - "pipeworks_mese_filter_input.png", "pipeworks_mese_filter_side.png", "pipeworks_mese_filter_top.png"}, - paramtype2 = "facedir", - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2}, - legacy_facedir_simple = true, - sounds = default.node_sound_wood_defaults(), - on_construct = function(pos) - local meta = minetest.get_meta(pos) - meta:set_string("formspec", - "invsize[8,6.5;]".. - "list[current_name;main;0,0;8,2;]".. - "list[current_player;main;0,2.5;8,4;]") - meta:set_string("infotext", "Stackwise Filter-Injector") - local inv = meta:get_inventory() - inv:set_size("main", 8*2) - end, - can_dig = function(pos,player) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory() - return inv:is_empty("main") - end, - after_place_node = function(pos) - pipeworks.scan_for_tube_objects(pos) - end, - after_dig_node = function(pos) - pipeworks.scan_for_tube_objects(pos) - end, - mesecons={effector={action_on=function(pos,node) - minetest.registered_nodes[node.name].on_punch(pos,node,nil) - end}}, - tube={connect_sides={right=1}}, - on_punch = function (pos, node, puncher) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory() - local dir = facedir_to_right_dir(node.param2) - local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z} - local fromnode=minetest.get_node(frompos) - local idef = minetest.registered_nodes[fromnode.name] - -- assert(idef) - local tube = idef.tube - if not (tube and tube.input_inventory) then - return - end - - if tube.before_filter then - tube.before_filter(frompos) - end - local frommeta = minetest.get_meta(frompos) - local frominv = frommeta:get_inventory() - - local function from_inventory(frominvname) - local sname - for _,filter in ipairs(inv:get_list("main")) do - sname = filter:get_name() - if sname ~= "" then - -- XXX: that's a lot of parameters - if grabAndFire(frominv, frominvname, frompos, fromnode, sname, tube, idef, dir, true) then - return true - end +for _, data in ipairs({ + { + name = "filter", + wise_desc = "Itemwise", + stackwise = false, + }, + { + name = "mese_filter", + wise_desc = "Stackwise", + stackwise = true, + }, +}) do + minetest.register_node("pipeworks:"..data.name, { + description = data.wise_desc.." Filter-Injector", + tiles = { + "pipeworks_"..data.name.."_top.png", + "pipeworks_"..data.name.."_top.png", + "pipeworks_"..data.name.."_output.png", + "pipeworks_"..data.name.."_input.png", + "pipeworks_"..data.name.."_side.png", + "pipeworks_"..data.name.."_top.png", + }, + paramtype2 = "facedir", + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + set_filter_formspec(data, meta) + set_filter_infotext(data, meta) + local inv = meta:get_inventory() + inv:set_size("main", 8*2) + end, + on_receive_fields = function(pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + for k, _ in pairs(fields) do + if k:sub(1, 12) == "slotseq_mode" then + local mode = tonumber(k:sub(13, 13)) + meta:set_int("slotseq_mode", mode) + meta:set_int("slotseq_index", mode == 2 and 1 or 0) end end - if inv:is_empty("main") then - if grabAndFire(frominv, frominvname, frompos, fromnode, nil, tube, idef, dir, true) then - return true - end - end - return false - end - - if type(tube.input_inventory) == "table" then - for _, i in ipairs(tube.input_inventory) do - if from_inventory(i) then -- fired an item - break - end - end - else - from_inventory(tube.input_inventory) - end - - if tube.after_filter then - tube.after_filter(frompos) - end - end, -}) + set_filter_formspec(data, meta) + set_filter_infotext(data, meta) + end, + can_dig = function(pos,player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:is_empty("main") + end, + after_place_node = function(pos) + pipeworks.scan_for_tube_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_tube_objects(pos) + end, + mesecons = { + effector = { + action_on = function(pos, node) + punch_filter(data, pos, node) + end, + }, + }, + tube={connect_sides={right=1}}, + on_punch = function (pos, node, puncher) + punch_filter(data, pos, node) + end, + }) +end local function roundpos(pos) return {x=math.floor(pos.x+0.5),y=math.floor(pos.y+0.5),z=math.floor(pos.z+0.5)}