summaryrefslogtreecommitdiff
path: root/filter-injector.lua
diff options
context:
space:
mode:
Diffstat (limited to 'filter-injector.lua')
-rw-r--r--filter-injector.lua201
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