diff options
Diffstat (limited to 'filter-injector.lua')
-rw-r--r-- | filter-injector.lua | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/filter-injector.lua b/filter-injector.lua new file mode 100644 index 0000000..599303f --- /dev/null +++ b/filter-injector.lua @@ -0,0 +1,201 @@ +local function delay(x) + return (function() return x end) +end + +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 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;]".. + fs_helpers.cycling_button(meta, "button[0,3.5;4,1", "slotseq_mode", + {"Sequence slots by Priority", + "Sequence slots Randomly", + "Sequence slots by Rotation"}).. + "list[current_player;main;0,4.5;8,4;]" + meta:set_string("formspec", formspec) +end + +-- todo SOON: this function has *way too many* parameters +local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,fakePlayer,all) + local sposes = {} + for spos,stack in ipairs(frominv:get_list(frominvname)) do + 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 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 + count = math.min(stack:get_count(), doRemove) + else + count = 1 + end + if fromtube.remove_items then + -- it could be the entire stack... + item = fromtube.remove_items(frompos, fromnode, stack, dir, count) + else + item = stack:take_item(count) + frominv:set_stack(frominvname, spos, stack) + if fromdef.on_metadata_inventory_take then + fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer) + end + end + local pos = vector.add(frompos, vector.multiply(dir, 1.4)) + local start_pos = vector.add(frompos, dir) + local item1 = pipeworks.tube_inject_item(pos, start_pos, dir, item) + return true-- only fire one item, please + end + end + return false +end + +local function punch_filter(data, filtpos, filtnode) + local filtmeta = minetest.get_meta(filtpos) + local filtinv = filtmeta:get_inventory() + local owner = filtmeta:get_string("owner") + local fakePlayer = { + get_player_name = delay(owner), + } -- TODO: use a mechanism as the wielder one + local dir = minetest.facedir_to_right_dir(filtnode.param2) + local frompos = vector.subtract(filtpos, dir) + 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, fakePlayer, data.stackwise) then + done = true + break + end + end + if done then break end + end + if fromtube.after_filter then fromtube.after_filter(frompos) end +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, 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, + after_place_node = function (pos, placer) + minetest.get_meta(pos):set_string("owner", placer:get_player_name()) + end, + on_receive_fields = function(pos, formname, fields, sender) + fs_helpers.on_receive_fields(pos, fields) + local meta = minetest.get_meta(pos) + meta:set_int("slotseq_index", 1) + 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, + 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 |