From 80a2f67bcfb3bcca2c1c29b186b2e8d412eb72b3 Mon Sep 17 00:00:00 2001 From: Joachim Stolberg Date: Sun, 10 Mar 2019 22:33:03 +0100 Subject: [PATCH] distributor now working --- basic_machines/distributor.lua | 619 ++++++++---------- basic_machines/grinder.lua | 8 +- basis/consumer.lua | 33 +- basis/node_states.lua | 12 +- init.lua | 2 + steam_engine/battery.lua | 123 ++++ textures/techage_appl_distri.png | Bin 0 -> 1547 bytes textures/techage_appl_distri4.png | Bin 0 -> 6248 bytes textures/techage_appl_distri_blue.png | Bin 0 -> 277 bytes textures/techage_appl_distri_green.png | Bin 0 -> 272 bytes textures/techage_appl_distri_red.png | Bin 0 -> 272 bytes textures/techage_appl_distri_yellow.png | Bin 0 -> 273 bytes textures/techage_appl_electric_power.png | Bin 0 -> 542 bytes textures/techage_distributor_active_frame.png | Bin 458 -> 0 bytes textures/techage_inv_blue.png | Bin 0 -> 113 bytes textures/techage_inv_green.png | Bin 0 -> 113 bytes textures/techage_inv_red.png | Bin 0 -> 113 bytes textures/techage_inv_yellow.png | Bin 0 -> 113 bytes 18 files changed, 427 insertions(+), 370 deletions(-) create mode 100644 steam_engine/battery.lua create mode 100644 textures/techage_appl_distri.png create mode 100644 textures/techage_appl_distri4.png create mode 100644 textures/techage_appl_distri_blue.png create mode 100644 textures/techage_appl_distri_green.png create mode 100644 textures/techage_appl_distri_red.png create mode 100644 textures/techage_appl_distri_yellow.png create mode 100644 textures/techage_appl_electric_power.png delete mode 100644 textures/techage_distributor_active_frame.png create mode 100644 textures/techage_inv_blue.png create mode 100644 textures/techage_inv_green.png create mode 100644 textures/techage_inv_red.png create mode 100644 textures/techage_inv_yellow.png diff --git a/basic_machines/distributor.lua b/basic_machines/distributor.lua index 498a943..1f28df9 100644 --- a/basic_machines/distributor.lua +++ b/basic_machines/distributor.lua @@ -8,7 +8,7 @@ LGPLv2.1+ See LICENSE.txt for more information - distributor.lua: + TA2/TA3/TA4 Distributor ]]-- @@ -17,110 +17,109 @@ local S = function(pos) if pos then return minetest.pos_to_string(pos) end end local P = minetest.string_to_pos local M = minetest.get_meta local N = minetest.get_node +-- Techage Related Data +local TRD = function(pos) return (minetest.registered_nodes[minetest.get_node(pos).name] or {}).techage end -local NUM_FILTER_ELEM = 6 -local NUM_FILTER_SLOTS = 4 +-- Load support for intllib. +local MP = minetest.get_modpath("tubelib2") +local I,_ = dofile(MP.."/intllib.lua") -local COUNTDOWN_TICKS = 4 -local STANDBY_TICKS = 8 -local CYCLE_TIME = 2 +local SRC_INV_SIZE = 8 -local function formspec(self, pos, meta) - local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} +local COUNTDOWN_TICKS = 10 +local STANDBY_TICKS = 10 +local CYCLE_TIME = 4 + +local function formspec(self, pos, mem) + local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false} return "size[10.5,8.5]".. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "list[context;src;0,0;2,4;]".. - "image[2,1.5;1,1;tubelib_gui_arrow.png]".. - "image_button[2,3;1,1;"..self:get_state_button_image(meta)..";state_button;]".. + "image[2,1.5;1,1;techage_form_arrow.png]".. + "image_button[2,3;1,1;"..self:get_state_button_image(mem)..";state_button;]".. "checkbox[3,0;filter1;On;"..dump(filter[1]).."]".. "checkbox[3,1;filter2;On;"..dump(filter[2]).."]".. "checkbox[3,2;filter3;On;"..dump(filter[3]).."]".. "checkbox[3,3;filter4;On;"..dump(filter[4]).."]".. - "image[4,0;0.3,1;tubelib_red.png]".. - "image[4,1;0.3,1;tubelib_green.png]".. - "image[4,2;0.3,1;tubelib_blue.png]".. - "image[4,3;0.3,1;tubelib_yellow.png]".. + "image[4,0;0.3,1;techage_inv_red.png]".. + "image[4,1;0.3,1;techage_inv_green.png]".. + "image[4,2;0.3,1;techage_inv_blue.png]".. + "image[4,3;0.3,1;techage_inv_yellow.png]".. "list[context;red;4.5,0;6,1;]".. "list[context;green;4.5,1;6,1;]".. "list[context;blue;4.5,2;6,1;]".. "list[context;yellow;4.5,3;6,1;]".. "list[current_player;main;1.25,4.5;8,4;]".. "listring[context;src]".. - "listring[current_player;main]" + "listring[current_player;main]".. + default.get_hotbar_bg(1.25,4.5) end -local State = tubelib.NodeStates:new({ - node_name_passive = "tubelib:distributor", - node_name_active = "tubelib:distributor_active", - node_name_defect = "tubelib:distributor_defect", - infotext_name = "Tubelib Distributor", - cycle_time = CYCLE_TIME, - standby_ticks = STANDBY_TICKS, - aging_factor = 10, - formspec_func = formspec, -}) --- Return a key/value table with all items and the corresponding stack numbers -local function invlist_content_as_kvlist(list) - local res = {} - for idx,items in ipairs(list) do - local name = items:get_name() - if name ~= "" then - res[name] = idx +--local Side2Color = {B="red", L="green", F="blue", R="yellow"} +local SlotColors = {"red", "green", "blue", "yellow"} +local Num2Ascii = {"B", "L", "F", "R"} +local FilterCache = {} -- local cache for filter settings + +local function filter_settings(pos) + local meta = M(pos) + local param2 = minetest.get_node(pos).param2 + local inv = meta:get_inventory() + local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} + local ItemFilter = {} -- { = {dir,...}] + local OpenPorts = {} -- {dir, ...} + + -- collect all filter settings + for idx,slot in ipairs(SlotColors) do + if filter[idx] == true then + local side = Num2Ascii[idx] + local out_dir = techage.side_to_outdir(side, param2) + if inv:is_empty(slot) then + table.insert(OpenPorts, out_dir) + else + for _,stack in ipairs(inv:get_list(slot)) do + local name = stack:get_name() + if name ~= "" then + if not ItemFilter[name] then + ItemFilter[name] = {} + end + table.insert(ItemFilter[name], out_dir) + end + end + end end end - return res + + FilterCache[minetest.hash_node_position(pos)] = { + ItemFilter = ItemFilter, + OpenPorts = OpenPorts, + } + print("ItemFilter = "..dump(ItemFilter), "\nOpenPorts = "..dump(OpenPorts)) end --- Return the total number of list entries -local function invlist_num_entries(list) - local res = 0 - for _,items in ipairs(list) do - local name = items:get_name() - if name ~= "" then - res = res + items:get_count() - end +-- Return filter table and list of open ports. +-- (see test data) +local function get_filter_settings(pos) +-- local ItemFilter = { +-- ["default:dirt"] = {1,2}, +-- ["default:cobble"] = {4}, +-- } +-- local OpenPorts = {3} +-- return ItemFilter, OpenPorts + + local hash = minetest.hash_node_position(pos) + if FilterCache[hash] == nil then + filter_settings(pos) end - return res + return FilterCache[hash].ItemFilter, FilterCache[hash].OpenPorts end --- Return a gapless table with all items -local function invlist_entries_as_list(list) - local res = {} - for _,items in ipairs(list) do - if items:get_count() > 0 then - res[#res+1] = {items:get_name(), items:get_count()} - end - end - return res -end - - -local function AddToTbl(kvTbl, new_items) - for _, l in ipairs(new_items) do - kvTbl[l[1]] = true - end - return kvTbl -end - --- return the number of items to be pushed to an unconfigured slot -local function num_items(moved_items, name, filter_item_names, rejected_item_names) - if filter_item_names[name] == nil then -- not configured in one filter? - if moved_items < MAX_NUM_PER_CYC then - return math.min(4, MAX_NUM_PER_CYC - moved_items) - end - end - if rejected_item_names[name] then -- rejected item from another slot? - if moved_items < MAX_NUM_PER_CYC then - return math.min(rejected_item_names[name], MAX_NUM_PER_CYC - moved_items) - end - end -end local function allow_metadata_inventory_put(pos, listname, index, stack, player) local meta = M(pos) + local trd = TRD(pos) local inv = meta:get_inventory() local list = inv:get_list(listname) @@ -128,12 +127,14 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player) return 0 end if listname == "src" then - if State:get_state(M(pos)) == tubelib.STANDBY then - State:start(pos, meta) + if trd.State:get_state(M(pos)) == techage.STANDBY then + trd.State:start(pos, meta) end return stack:get_count() - elseif invlist_num_entries(list) < MAX_NUM_PER_CYC then - return stack:get_count() + elseif stack:get_count() == 1 and + (list[index]:get_count() == 0 or stack:get_name() ~= list[index]:get_name()) then + filter_settings(pos) + return 1 end return 0 end @@ -152,120 +153,86 @@ local function allow_metadata_inventory_move(pos, from_list, from_index, to_list return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) end -local SlotColors = {"red", "green", "blue", "yellow"} -local Num2Ascii = {"B", "L", "F", "R"} -- color to side translation -local FilterCache = {} -- local cache for filter settings -local function filter_settings(pos) - local hash = minetest.hash_node_position(pos) - local meta = M(pos) - local inv = meta:get_inventory() - local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} - local kvFilterItemNames = {} -- { = true,...} - local kvSide2ItemNames = {} -- {"F" = {,...},...} - - -- collect all filter settings - for idx,slot in ipairs(SlotColors) do - local side = Num2Ascii[idx] - if filter[idx] == true then - local list = inv:get_list(slot) - local filter = invlist_entries_as_list(list) - AddToTbl(kvFilterItemNames, filter) - kvSide2ItemNames[side] = filter +local function push_item(pos, filter, item_name, num_items, mem) + local idx = 1 + local num_pushed = 0 + local num_ports = #filter + local amount = math.floor(math.max((num_items + 1) / num_ports, 1)) + local successful = false + while num_pushed < num_items do + local push_dir = filter[idx] + local num_to_push = math.min(amount, num_items - num_pushed) + if techage.push_items(pos, push_dir, ItemStack(item_name.." "..num_to_push)) then + num_pushed = num_pushed + num_to_push + successful = true + mem.port_counter[push_dir] = (mem.port_counter[push_dir] or 0) + num_to_push + end + idx = idx + 1 + if idx > num_ports then + idx = 1 + if not successful then break end end end - - FilterCache[hash] = { - kvFilterItemNames = kvFilterItemNames, - kvSide2ItemNames = kvSide2ItemNames, - kvRejectedItemNames = {}, - } + return num_pushed end --- move items from configured filters to the output -local function distributing(pos, meta) - local player_name = meta:get_string("player_name") - local slot_idx = meta:get_int("slot_idx") or 1 - meta:set_int("slot_idx", (slot_idx + 1) % NUM_FILTER_SLOTS) - local side = Num2Ascii[slot_idx+1] - local listname = SlotColors[slot_idx+1] - local inv = meta:get_inventory() - local list = inv:get_list("src") - local kvSrc = invlist_content_as_kvlist(list) - local counter = minetest.deserialize(meta:get_string("item_counter")) or - {red=0, green=0, blue=0, yellow=0} +-- move items to output slots +local function distributing(pos, inv, trd, mem) + local item_filter, open_ports = get_filter_settings(pos) + local sum_num_pushed = 0 + local num_pushed = 0 - -- calculate the filter settings only once - local hash = minetest.hash_node_position(pos) - if FilterCache[hash] == nil then - filter_settings(pos) - end + -- start searching after last position + local offs = mem.last_index or 1 - -- read data from Cache - -- all filter items as key/value { = true,...} - local kvFilterItemNames = FilterCache[hash].kvFilterItemNames - -- filter items of one slot as list {{, },...} - local items = FilterCache[hash].kvSide2ItemNames[side] - -- rejected items from other filter slots - local rejected = FilterCache[hash].kvRejectedItemNames - - if items == nil then return end - - local moved_items_total = 0 - if next(items) then - for _,item in ipairs(items) do - local name, num = item[1], item[2] - if kvSrc[name] then - local item = tubelib.get_this_item(meta, "src", kvSrc[name], num) -- <<=== tubelib - if item then - if not tubelib.push_items(pos, side, item, player_name) then -- <<=== tubelib - tubelib.put_item(meta, "src", item) - rejected[name] = num - else - counter[listname] = counter[listname] + num - moved_items_total = moved_items_total + num - end - end - end + for i = 1, SRC_INV_SIZE do + local idx = ((i + offs - 1) % 8) + 1 + local stack = inv:get_stack("src", idx) + local item_name = stack:get_name() + local num_items = stack:get_count() + local num_to_push = math.min(trd.num_items - sum_num_pushed, num_items) + num_pushed = 0 + + if item_filter[item_name] then + -- Push items based on filter + num_pushed = push_item(pos, item_filter[item_name], item_name, num_to_push, mem) + print("num_pushed",num_pushed, "num_to_push", num_to_push) + end + if num_pushed == 0 and #open_ports > 0 then + -- Push items based on open ports + num_pushed = push_item(pos, open_ports, item_name, num_to_push, mem) + end + + sum_num_pushed = sum_num_pushed + num_pushed + stack:take_item(num_pushed) + inv:set_stack("src", idx, stack) + if sum_num_pushed >= trd.num_items then + mem.last_index = idx + break end end - -- move additional items from unconfigured filters to the output - if next(items) == nil then - local moved_items = 0 - for name,_ in pairs(kvSrc) do - local num = num_items(moved_items, name, kvFilterItemNames, rejected) - if num then - local item = tubelib.get_this_item(meta, "src", kvSrc[name], num) -- <<=== tubelib - if item then - if not tubelib.push_items(pos, side, item, player_name) then -- <<=== tubelib - tubelib.put_item(meta, "src", item) - else - counter[listname] = counter[listname] + num - moved_items = moved_items + num - moved_items_total = moved_items_total + num - end - end - end - end - -- delete list for next slot round - if moved_items > 0 then - FilterCache[hash].kvRejectedItemNames = {} - end - end - meta:set_string("item_counter", minetest.serialize(counter)) - if moved_items_total > 0 then - State:keep_running(pos, meta, COUNTDOWN_TICKS, moved_items_total) + print("sum_num_pushed",sum_num_pushed) + if num_pushed == 0 then + trd.State:blocked(pos, mem) else - State:idle(pos, meta) + trd.State:keep_running(pos, mem, COUNTDOWN_TICKS, 1) end end -- move items to the output slots local function keep_running(pos, elapsed) - local meta = M(pos) - distributing(pos, meta) - return State:is_active(meta) + local mem = tubelib2.get_mem(pos) + mem.port_counter = mem.port_counter or {} + local trd = TRD(pos) + local inv = M(pos):get_inventory() + if not inv:is_empty("src") then + distributing(pos, inv, trd, mem) + else + trd.State:idle(pos, mem) + end + return trd.State:is_active(mem) end local function on_receive_fields(pos, formname, fields, player) @@ -273,6 +240,7 @@ local function on_receive_fields(pos, formname, fields, player) return end local meta = M(pos) + local trd = TRD(pos) local filter = minetest.deserialize(meta:get_string("filter")) if fields.filter1 ~= nil then filter[1] = fields.filter1 == "true" @@ -287,14 +255,15 @@ local function on_receive_fields(pos, formname, fields, player) filter_settings(pos) + local mem = tubelib2.get_mem(pos) if fields.state_button ~= nil then - State:state_button_event(pos, fields) + trd.State:state_button_event(pos, mem, fields) else - meta:set_string("formspec", formspec(State, pos, meta)) + meta:set_string("formspec", formspec(trd.State, pos, mem)) end end --- tubelib command to turn on/off filter channels +-- techage command to turn on/off filter channels local function change_filter_settings(pos, slot, val) local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4} local meta = M(pos) @@ -307,189 +276,70 @@ local function change_filter_settings(pos, slot, val) filter_settings(pos) - meta:set_string("formspec", formspec(State, pos, meta)) + meta:set_string("formspec", formspec(TRD(pos).State, pos, meta)) return true end -minetest.register_node("tubelib:distributor", { - description = "Tubelib Distributor", - tiles = { - -- up, down, right, left, back, front - 'tubelib_distributor.png', - 'tubelib_front.png', - 'tubelib_distributor_yellow.png', - 'tubelib_distributor_green.png', - "tubelib_distributor_red.png", - "tubelib_distributor_blue.png", - }, +local function can_dig(pos, player) + if minetest.is_protected(pos, player:get_player_name()) then + return false + end + local inv = M(pos):get_inventory() + return inv:is_empty("src") +end - after_place_node = function(pos, placer) - local meta = M(pos) - local number = tubelib.add_node(pos, "tubelib:distributor") -- <<=== tubelib - local filter = {false,false,false,false} - meta:set_string("filter", minetest.serialize(filter)) - State:node_init(pos, number) - meta:set_string("player_name", placer:get_player_name()) - - local inv = meta:get_inventory() - inv:set_size('src', 8) - inv:set_size('yellow', 6) - inv:set_size('green', 6) - inv:set_size('red', 6) - inv:set_size('blue', 6) - meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) - end, - - on_receive_fields = on_receive_fields, - - can_dig = function(pos, player) - if minetest.is_protected(pos, player:get_player_name()) then - return false - end - local inv = M(pos):get_inventory() - return inv:is_empty("src") - end, - - after_dig_node = function(pos, oldnode, oldmetadata, digger) - tubelib.remove_node(pos) -- <<=== tubelib - State:after_dig_node(pos, oldnode, oldmetadata, digger) - end, - - allow_metadata_inventory_put = allow_metadata_inventory_put, - allow_metadata_inventory_take = allow_metadata_inventory_take, - allow_metadata_inventory_move = allow_metadata_inventory_move, - - on_timer = keep_running, - on_rotate = screwdriver.disallow, - - drop = "", - paramtype = "light", - sunlight_propagates = true, - paramtype2 = "facedir", - groups = {choppy=2, cracky=2, crumbly=2}, - is_ground_content = false, - sounds = default.node_sound_wood_defaults(), -}) - - -minetest.register_node("tubelib:distributor_active", { - description = "Tubelib Distributor", - tiles = { - -- up, down, right, left, back, front - { - image = "tubelib_distributor_active.png", - backface_culling = false, - animation = { - type = "vertical_frames", - aspect_w = 32, - aspect_h = 32, - length = 2.0, - }, +local tiles = {} +-- '#' will be replaced by the stage number +-- '{power}' will be replaced by the power PNG +tiles.pas = { + -- up, down, right, left, back, front + "techage_filling_ta#.png^techage_appl_distri.png^techage_frame_ta#_top.png", + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_yellow.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_green.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_red.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_blue.png", +} +tiles.act = { + -- up, down, right, left, back, front + { + image = "techage_filling4_ta#.png^techage_appl_distri4.png^techage_frame4_ta#_top.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 1.0, }, - 'tubelib_front.png', - 'tubelib_distributor_yellow.png', - 'tubelib_distributor_green.png', - "tubelib_distributor_red.png", - "tubelib_distributor_blue.png", }, + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_yellow.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_green.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_red.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_blue.png", +} +tiles.def = { + -- up, down, right, left, back, front + "techage_filling_ta#.png^techage_appl_distri.png^techage_frame_ta#_top.png", + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_yellow.png^techage_appl_defect.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_green.png^techage_appl_defect.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_red.png^techage_appl_defect.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_distri_blue.png^techage_appl_defect.png", +} - on_receive_fields = on_receive_fields, - - allow_metadata_inventory_put = allow_metadata_inventory_put, - allow_metadata_inventory_take = allow_metadata_inventory_take, - allow_metadata_inventory_move = allow_metadata_inventory_move, - - on_timer = keep_running, - on_rotate = screwdriver.disallow, - - paramtype = "light", - sunlight_propagates = true, - paramtype2 = "facedir", - groups = {crumbly=0, not_in_creative_inventory=1}, - is_ground_content = false, - sounds = default.node_sound_wood_defaults(), -}) - -minetest.register_node("tubelib:distributor_defect", { - description = "Tubelib Distributor", - tiles = { - -- up, down, right, left, back, front - 'tubelib_distributor.png', - 'tubelib_front.png', - 'tubelib_distributor_yellow.png^tubelib_defect.png', - 'tubelib_distributor_green.png^tubelib_defect.png', - "tubelib_distributor_red.png^tubelib_defect.png", - "tubelib_distributor_blue.png^tubelib_defect.png", - }, - - after_place_node = function(pos, placer) - local meta = M(pos) - local number = tubelib.add_node(pos, "tubelib:distributor") -- <<=== tubelib - State:node_init(pos, number) - meta:set_string("player_name", placer:get_player_name()) - - local filter = {false,false,false,false} - meta:set_string("filter", minetest.serialize(filter)) - local inv = meta:get_inventory() - inv:set_size('src', 8) - inv:set_size('yellow', 6) - inv:set_size('green', 6) - inv:set_size('red', 6) - inv:set_size('blue', 6) - meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) - State:defect(pos, meta) - end, - - on_receive_fields = on_receive_fields, - - can_dig = function(pos, player) - if minetest.is_protected(pos, player:get_player_name()) then - return false - end +local tubing = { + on_pull_item = function(pos, in_dir, num) local inv = M(pos):get_inventory() - return inv:is_empty("src") + return techage.get_items(inv, "src", num) end, - - after_dig_node = function(pos, oldnode, oldmetadata, digger) - tubelib.remove_node(pos) -- <<=== tubelib + on_push_item = function(pos, in_dir, stack) + local inv = M(pos):get_inventory() + return techage.put_items(inv, "src", stack) end, - - allow_metadata_inventory_put = allow_metadata_inventory_put, - allow_metadata_inventory_take = allow_metadata_inventory_take, - allow_metadata_inventory_move = allow_metadata_inventory_move, - - on_rotate = screwdriver.disallow, - - paramtype = "light", - sunlight_propagates = true, - paramtype2 = "facedir", - groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, - is_ground_content = false, - sounds = default.node_sound_wood_defaults(), -}) - - -minetest.register_craft({ - output = "tubelib:distributor 2", - recipe = { - {"group:wood", "default:steel_ingot", "group:wood"}, - {"tubelib:tubeS", "default:mese_crystal", "tubelib:tubeS"}, - {"group:wood", "default:steel_ingot", "group:wood"}, - }, -}) - - ---------------------------------------------------------------- tubelib -tubelib.register_node("tubelib:distributor", - {"tubelib:distributor_active", "tubelib:distributor_defect"}, { - on_pull_item = function(pos, side) - return tubelib.get_item(M(pos), "src") - end, - on_push_item = function(pos, side, item) - return tubelib.put_item(M(pos), "src", item) - end, - on_unpull_item = function(pos, side, item) - return tubelib.put_item(M(pos), "src", item) + on_unpull_item = function(pos, in_dir, stack) + local inv = M(pos):get_inventory() + return techage.put_items(inv, "src", stack) end, on_recv_message = function(pos, topic, payload) if topic == "filter" then @@ -502,7 +352,7 @@ tubelib.register_node("tubelib:distributor", local meta = minetest.get_meta(pos) meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) else - local resp = State:on_receive_message(pos, topic, payload) + local resp = TRD(pos).State:on_receive_message(pos, topic, payload) if resp then return resp else @@ -512,10 +362,65 @@ tubelib.register_node("tubelib:distributor", end, on_node_load = function(pos) - State:on_node_load(pos) + TRD(pos).State:on_node_load(pos) end, on_node_repair = function(pos) - return State:on_node_repair(pos) + return TRD(pos).State:on_node_repair(pos) end, -}) ---------------------------------------------------------------- tubelib +} + +local node_name_ta2, node_name_ta3, node_name_ta4 = + techage.register_consumer("distributor", I("Distributor"), tiles, { + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + has_item_meter = true, + aging_factor = 10, + formspec = formspec, + tubing = tubing, + after_place_node = function(pos, placer) + local meta = M(pos) + local filter = {false,false,false,false} + meta:set_string("filter", minetest.serialize(filter)) + local inv = meta:get_inventory() + inv:set_size('src', 8) + inv:set_size('yellow', 6) + inv:set_size('green', 6) + inv:set_size('red', 6) + inv:set_size('blue', 6) + end, + can_dig = can_dig, + node_timer = keep_running, + on_receive_fields = on_receive_fields, + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, + + on_metadata_inventory_move = function(pos, from_list, from_index, to_list) + if from_list ~= "src" or to_list ~= "src" then + filter_settings(pos) + end + end, + on_metadata_inventory_put = function(pos, listname) + if listname ~= "src" then + filter_settings(pos) + end + end, + on_metadata_inventory_take = function(pos, listname) + if listname ~= "src" then + filter_settings(pos) + end + end, + + groups = {choppy=2, cracky=2, crumbly=2}, + sounds = default.node_sound_wood_defaults(), + num_items = {0,4,12,36}, + }) + +minetest.register_craft({ + output = node_name_ta2, + recipe = { + {"group:wood", "default:steel_ingot", "group:wood"}, + {"tubelib:tubeS", "default:mese_crystal", "tubelib:tubeS"}, + {"group:wood", "default:steel_ingot", "group:wood"}, + }, +}) diff --git a/basic_machines/grinder.lua b/basic_machines/grinder.lua index dd01329..646c3b9 100644 --- a/basic_machines/grinder.lua +++ b/basic_machines/grinder.lua @@ -8,7 +8,7 @@ LGPLv2.1+ See LICENSE.txt for more information - TA2/TA3/TA4 Grinding Cobble/Basalt to Gravel + TA2/TA3/TA4 Grinder, grinding Cobble/Basalt to Gravel ]]-- @@ -48,7 +48,8 @@ local function formspec(self, pos, mem) "listring[context;dst]".. "listring[current_player;main]".. "listring[context;src]".. - "listring[current_player;main]" + "listring[current_player;main]".. + default.get_hotbar_bg(0, 4) end local function allow_metadata_inventory_put(pos, listname, index, stack, player) @@ -77,10 +78,8 @@ end local function src_to_dst(src_stack, idx, num_items, inv, dst_name) local taken = src_stack:take_item(num_items) local output = ItemStack(dst_name) - print("taken:get_count()", taken:get_count(), output:get_count() * taken:get_count()) output:set_count(output:get_count() * taken:get_count()) if inv:room_for_item("dst", output) then - print("output:get_count()", output:get_count()) inv:set_stack("src", idx, src_stack) inv:add_item("dst", output) return true @@ -220,7 +219,6 @@ local node_name_ta2, node_name_ta3, node_name_ta4 = formspec = formspec, tubing = tubing, after_place_node = function(pos, placer) - print("my after_place_node") local inv = M(pos):get_inventory() inv:set_size('src', 9) inv:set_size('dst', 9) diff --git a/basis/consumer.lua b/basis/consumer.lua index 05063eb..740c17c 100644 --- a/basis/consumer.lua +++ b/basis/consumer.lua @@ -83,6 +83,18 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) end power_png = 'techage_appl_hole_electric.png' end + + -- No power needed? + if not tNode.power_consumption then + start_node = nil + stop_node = nil + turn_on_clbk = nil + valid_power_dir = nil + power_network = nil + tNode.power_consumption = {0,0,0,0} -- needed later + else + power_network:add_secondary_node_names({name_pas, name_act}) + end local tState = techage.NodeStates:new({ node_name_passive = name_pas, @@ -116,7 +128,12 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) techage = tTechage, after_place_node = function(pos, placer, itemstack, pointed_thing) - local mem = consumer.after_place_node(pos, placer) + local mem + if power_network then + mem = consumer.after_place_node(pos, placer) + else + mem = tubelib2.init_mem(pos) + end local meta = M(pos) local node = minetest.get_node(pos) meta:set_int("push_dir", techage.side_to_indir("L", node.param2)) @@ -137,7 +154,9 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) end techage.remove_node(pos) TRDN(oldnode).State:after_dig_node(pos, oldnode, oldmetadata, digger) - consumer.after_dig_node(pos, oldnode) + if power_network then + consumer.after_dig_node(pos, oldnode) + end end, after_tube_update = consumer.after_tube_update, @@ -148,6 +167,9 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) allow_metadata_inventory_put = tNode.allow_metadata_inventory_put, allow_metadata_inventory_move = tNode.allow_metadata_inventory_move, allow_metadata_inventory_take = tNode.allow_metadata_inventory_take, + on_metadata_inventory_move = tNode.on_metadata_inventory_move, + on_metadata_inventory_put = tNode.on_metadata_inventory_put, + on_metadata_inventory_take = tNode.on_metadata_inventory_take, drop = "", paramtype2 = "facedir", @@ -170,6 +192,9 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) allow_metadata_inventory_put = tNode.allow_metadata_inventory_put, allow_metadata_inventory_move = tNode.allow_metadata_inventory_move, allow_metadata_inventory_take = tNode.allow_metadata_inventory_take, + on_metadata_inventory_move = tNode.on_metadata_inventory_move, + on_metadata_inventory_put = tNode.on_metadata_inventory_put, + on_metadata_inventory_take = tNode.on_metadata_inventory_take, paramtype2 = "facedir", diggable = false, @@ -205,6 +230,9 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) allow_metadata_inventory_put = tNode.allow_metadata_inventory_put, allow_metadata_inventory_move = tNode.allow_metadata_inventory_move, allow_metadata_inventory_take = tNode.allow_metadata_inventory_take, + on_metadata_inventory_move = tNode.on_metadata_inventory_move, + on_metadata_inventory_put = tNode.on_metadata_inventory_put, + on_metadata_inventory_take = tNode.on_metadata_inventory_take, after_dig_node = function(pos, oldnode, oldmetadata, digger) if tNode.after_dig_node then @@ -221,7 +249,6 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode) }) techage.register_node(name_pas, {name_act, name_def}, tNode.tubing) - power_network:add_secondary_node_names({name_pas, name_act}) end return names[1], names[2], names[3] end diff --git a/basis/node_states.lua b/basis/node_states.lua index 42d68f4..76af1a8 100644 --- a/basis/node_states.lua +++ b/basis/node_states.lua @@ -406,11 +406,13 @@ function NodeStates:on_node_load(pos, not_start_timer) return end - -- wrong number? - local info = techage.get_node_info(number) - if not info or not info.pos or not vector.equals(pos, info.pos) then - swap_node(pos, "techage:defect_dummy") - return + -- wrong number and no dummy number? + if number ~= "-" then + local info = techage.get_node_info(number) + if not info or not info.pos or not vector.equals(pos, info.pos) then + swap_node(pos, "techage:defect_dummy") + return + end end -- state corrupt? diff --git a/init.lua b/init.lua index a6cb66f..bccecc1 100644 --- a/init.lua +++ b/init.lua @@ -30,6 +30,7 @@ dofile(MP.."/steam_engine/cylinder.lua") dofile(MP.."/steam_engine/flywheel.lua") dofile(MP.."/steam_engine/gearbox.lua") dofile(MP.."/steam_engine/consumer.lua") +dofile(MP.."/steam_engine/battery.lua") dofile(MP.."/electric/electric_cable.lua") dofile(MP.."/electric/test.lua") @@ -39,6 +40,7 @@ dofile(MP.."/electric/consumer.lua") dofile(MP.."/basic_machines/pusher.lua") dofile(MP.."/basic_machines/legacy_nodes.lua") dofile(MP.."/basic_machines/grinder.lua") +dofile(MP.."/basic_machines/distributor.lua") --dofile(MP.."/fermenter/biogas_pipe.lua") diff --git a/steam_engine/battery.lua b/steam_engine/battery.lua new file mode 100644 index 0000000..5a194d1 --- /dev/null +++ b/steam_engine/battery.lua @@ -0,0 +1,123 @@ +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + +-- Load support for intllib. +local MP = minetest.get_modpath("tubelib2") +local I,_ = dofile(MP.."/intllib.lua") + +local STANDBY_TICKS = 4 +local COUNTDOWN_TICKS = 4 +local CYCLE_TIME = 16 +local POWER_CAPACITY = 12 + +local Axle = techage.Axle +local generator = techage.generator + +local function formspec(self, pos, mem) + return "size[8,7]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "image[6,0.5;1,2;"..generator.formspec_level(mem, mem.power_result).. + "image_button[5,1;1,1;".. self:get_state_button_image(mem) ..";state_button;]".. + "button[2.5,1;1.8,1;update;"..I("Update").."]".. + "list[current_player;main;0,3;8,4;]".. + default.get_hotbar_bg(0, 3) +end + +local function start_node(pos, mem, state) + generator.turn_power_on(pos, POWER_CAPACITY) +end + +local function stop_node(pos, mem, state) + generator.turn_power_on(pos, 0) +end + +local State = techage.NodeStates:new({ + node_name_passive = "techage:battery", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + formspec_func = formspec, + start_node = start_node, + stop_node = stop_node, +}) + + +local function node_timer(pos, elapsed) + local mem = tubelib2.get_mem(pos) + return State:is_active(mem) +end + +local function turn_power_on(pos, in_dir, sum) + local mem = tubelib2.get_mem(pos) + -- store result for formspec + mem.power_result = sum + if State:is_active(mem) and sum <= 0 then + State:fault(pos, mem) + -- No automatic turn on + mem.power_capacity = 0 + end + M(pos):set_string("formspec", formspec(State, pos, mem)) +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + local mem = tubelib2.get_mem(pos) + State:state_button_event(pos, mem, fields) + + if fields.update then + M(pos):set_string("formspec", formspec(State, pos, mem)) + end +end + +local function on_rightclick(pos) + local mem = tubelib2.get_mem(pos) + M(pos):set_string("formspec", formspec(State, pos, mem)) +end + +minetest.register_node("techage:battery", { + description = "TA2 Battery", + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta2.png^techage_frame_ta2_top.png", + "techage_filling_ta2.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_axle_clutch.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_electric_power.png", + "techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_electric_power.png", + "techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_electric_power.png", + }, + paramtype2 = "facedir", + groups = {cracky=2, crumbly=2, choppy=2}, + on_rotate = screwdriver.disallow, + is_ground_content = false, + + techage = { + turn_on = turn_power_on, + read_power_consumption = generator.read_power_consumption, + power_network = Axle, + power_side = "R", + animated_power_network = true, + }, + + after_place_node = function(pos, placer) + local mem = generator.after_place_node(pos) + State:node_init(pos, mem, "") + on_rightclick(pos) + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + State:after_dig_node(pos, oldnode, oldmetadata, digger) + generator.after_dig_node(pos, oldnode) + end, + + after_tube_update = generator.after_tube_update, + on_receive_fields = on_receive_fields, + on_rightclick = on_rightclick, + on_timer = node_timer, +}) + +Axle:add_secondary_node_names({"techage:battery"}) \ No newline at end of file diff --git a/textures/techage_appl_distri.png b/textures/techage_appl_distri.png new file mode 100644 index 0000000000000000000000000000000000000000..9361894b992886da9de0d2ca153a6c0635081d42 GIT binary patch literal 1547 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 literal 0 HcmV?d00001 diff --git a/textures/techage_appl_distri_green.png b/textures/techage_appl_distri_green.png new file mode 100644 index 0000000000000000000000000000000000000000..801c04b13b46856086021a6e311d32229df929e0 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&pI^nTuD4!S%z!qd=j#o-U3d5r^MSy~}%8fu}`3aQY72 zh~`M8(ivVeTTO2qO1`k%WyM*3Ro5+-YV|!NdMu@RI4;gym=*4H>*KeL`vWyCq6M5h z7#u#GO-obQ+4u8KQ}MeGJ+~tnR1EJfUv>Lz|IaGk8IhModQ`ct1PRq#4i6C86LcY@ zas849T}<^KMgP|cmW4aW2YxS;N%mR))_l5o{_*It_kS4_TPz-Mp4x4dU*<>&pI^nTuCj(}Q_^9#Ckmr;B4q#NoG7@A4j2;AznhoW4Uh zqB&BjbcWZ=R?{1Yk}oWGS#g$M)pg6IT73_R9!qH+j*BxFrUf%y>f7A^x7X|7%_adS zCWcA*X2#4XOV2zPn^WALe&-yMLg!1n(7SncXRc=-I5TTmf==LqX_Fqz-q$qg!PKT@ zTs5k!;UYh}*Z=t5y<>&pI^nTuD4|Em9<5TMXJPZ!6Kh{JEEKICmt;AxdVrn-wY z+o1a-Z}KCZH3!9H7k_`Pcf`0$BGq|u^&R(_au95!rY=_X<%MvsK7fhSWFU8GbZ8()Nlj2>E@cM*00DwYL_t(o!|j((O2a@D z#=mLWNleGKAc&h(5d@*+3NE{>?mU5uUcsdcPvKfG;05#oT@*L2nkqX-l#i8|&$ozvEyxw%@#7e~6CK>%2LQ0f9wyue5dj94 zmC%YZTR(u!0|a6Q?g;>Z4-ZioVmuzh@xKzX-!I_Di2&Ey56luA%F4XUQe zIRkMV=hp@E(${N0Px#07*qoM6N<$f=1QY(f|Me literal 0 HcmV?d00001 diff --git a/textures/techage_distributor_active_frame.png b/textures/techage_distributor_active_frame.png deleted file mode 100644 index 23fc309219493f62e504e832f5078f5a3562339f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 458 zcmeAS@N?(olHy`uVBq!ia0vp^3JeU44jjxt)+_Zs4It$a;1lA?CCjyO2dthsZC8G%Ay}Nh2eYKW_=-9ZJ9B%S2bXHT=mko*b>+J5Vsjr%z zVwaVhw7oj4x1}QaKC?Q|OvaKRzhDN3XE)M7oFs2|7lsa2Sq~tGv%n*=n1O*?7=#%a zX3dcR3bL1Y`ns||X5toO<(a#_z!50)+tbA{B;(%ODHpj88*sP^bA^BSZ(osRCDHuq z@V#Rjw|EM_Hubc9U9@xd6EWXAnIC6~t<64K^6l}Y`_p7UOI?VI{y6vCi{)3_)3zNd zwVm}_ROs8A36mFIahc%cG`HocRu$)a)jj?&#dH1hfx*Dw>FVdQ I&MBb@0E*7EYXATM diff --git a/textures/techage_inv_blue.png b/textures/techage_inv_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..b8d75c17a492bfc50f36dd921b5c092fe61427ae GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%B90G|+7gRJ{p`BOk@c|2VlLpZJ{Cn)d&c?JxO$5*xX0a*;5u6{1-oD!M< Dnco;L literal 0 HcmV?d00001 diff --git a/textures/techage_inv_green.png b/textures/techage_inv_green.png new file mode 100644 index 0000000000000000000000000000000000000000..014a96e6351be1d02f036552a78953b7aa29d84c GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%B90G|+7xl1;>i!*isxjddOjv*Y^lM@tpfjk2S#^bA6`+zJ4Pgg&ebxsLQ E0IH%GqyPW_ literal 0 HcmV?d00001 diff --git a/textures/techage_inv_red.png b/textures/techage_inv_red.png new file mode 100644 index 0000000000000000000000000000000000000000..4e4cd2abea8de0f409984b373b28814b61a21529 GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%B90G|-o{|pS0k2uYNTpmvs#}JO|$q5R)K%M~umdKI;Vst E0Ex{PzyJUM literal 0 HcmV?d00001 diff --git a/textures/techage_inv_yellow.png b/textures/techage_inv_yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..8ac93436cf5c8bfac4d0533ab0b3604f7c9b7bd5 GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%B90G|-ok6#4pqy-)TxjddOjv*Y^lM@tpfjk2S#^bA6`+zJ4Pgg&ebxsLQ E0KEAb1ONa4 literal 0 HcmV?d00001