--[[ TechAge ======= Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information TA4 Doser ]]-- local S2P = minetest.string_to_pos local P2S = minetest.pos_to_string local M = minetest.get_meta local S = techage.S local Pipe = techage.LiquidPipe local liquid = networks.liquid local recipes = techage.recipes local Liquids = {} -- {hash(pos) = {name = outdir},...} local STANDBY_TICKS = 2 local COUNTDOWN_TICKS = 3 local CYCLE_TIME = 10 local function formspec(self, pos, nvm) return "size[6,3.6]".. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "box[0,-0.1;5.8,0.5;#c6e8ff]".. "label[2.5,-0.1;"..minetest.colorize( "#000000", S("Doser")).."]".. recipes.formspec(0.1, 0.8, "ta4_doser", nvm).. "image_button[5,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "tooltip[5,2;1,1;"..self:get_state_tooltip(nvm).."]" end local function get_liquids(pos) local hash = minetest.hash_node_position(pos) if Liquids[hash] then return Liquids[hash] end -- determine the available input liquids local tbl = {} for outdir = 1,4 do local name, num = liquid.peek(pos, Pipe, outdir) if name then tbl[name] = outdir end end Liquids[hash] = tbl return Liquids[hash] end local function del_liquids(pos) local hash = minetest.hash_node_position(pos) Liquids[hash] = nil end -- if liquids are missing, update the cached liquid table local function reload_liquids(pos) local hash = minetest.hash_node_position(pos) -- determine the available input liquids local tbl = {} for outdir = 1,4 do local name, num = liquid.peek(pos, Pipe, outdir) if name then tbl[name] = outdir end end Liquids[hash] = tbl return Liquids[hash] end local function reactor_cmnd(pos, cmnd, payload) return techage.transfer( pos, 6, -- outdir cmnd, -- topic payload, -- payload Pipe, -- network {"techage:ta4_reactor_fillerpipe"}) end local function can_start(pos, nvm, state) -- check reactor local res = reactor_cmnd(pos, "check") if not res then return S("reactor defect") end res = reactor_cmnd(pos, "can_start") if not res then return S("reactor defect or no power") end local recipe = recipes.get(nvm, "ta4_doser") if recipe.catalyst then res = reactor_cmnd(pos, "catalyst") if not res or res == "" then return S("catalyst missing") end if res ~= recipe.catalyst then return S("wrong catalyst") end end return true end local function start_node(pos, nvm, state) reactor_cmnd(pos, "start") del_liquids(pos) nvm.running = true end local function stop_node(pos, nvm, state) reactor_cmnd(pos, "stop") nvm.running = false end local State = techage.NodeStates:new({ node_name_passive = "techage:ta4_doser", node_name_active = "techage:ta4_doser_on", cycle_time = CYCLE_TIME, standby_ticks = STANDBY_TICKS, formspec_func = formspec, infotext_name = "TA4 Doser", can_start = can_start, start_node = start_node, stop_node = stop_node, }) local function untake(pos, taken) for _,item in pairs(taken) do liquid.untake(pos, Pipe, item.outdir, item.name, item.num) end end local function dosing(pos, nvm, elapsed) -- trigger reactor (power) if not reactor_cmnd(pos, "power") then if not nvm.techage_countdown or nvm.techage_countdown < 3 then reactor_cmnd(pos, "stop") State:nopower(pos, nvm, S("reactor has no power")) return end State:idle(pos, nvm) return end -- available liquids local liquids = get_liquids(pos) local recipe = recipes.get(nvm, "ta4_doser") if not liquids or not recipe then return end -- check from time to time nvm.check_cnt = (nvm.check_cnt or 0) + 1 if nvm.check_cnt >= 4 then nvm.check_cnt = 0 local res = reactor_cmnd(pos, "check") if not res then State:fault(pos, nvm, S("reactor defect")) reactor_cmnd(pos, "stop") return end if recipe.catalyst then res = reactor_cmnd(pos, "catalyst") if not res then State:fault(pos, nvm, S("catalyst missing")) reactor_cmnd(pos, "stop") return end if res ~= recipe.catalyst then State:fault(pos, nvm, S("wrong catalyst")) reactor_cmnd(pos, "stop") return end end end -- check leftover local leftover local mem = techage.get_mem(pos) if mem.waste_leftover then leftover = reactor_cmnd(pos, "waste", { name = mem.waste_leftover.name, amount = mem.waste_leftover.num}) or mem.waste_leftover.num if leftover > 0 then mem.waste_leftover.num = leftover State:blocked(pos, nvm) return end mem.waste_leftover = nil end if mem.output_leftover then leftover = reactor_cmnd(pos, "output", { name = mem.output_leftover.name, amount = mem.output_leftover.num}) or mem.output_leftover.num if leftover > 0 then mem.output_leftover.num = leftover State:blocked(pos, nvm) return end mem.output_leftover = nil end -- inputs local taken = {} mem.dbg_cycles = (mem.dbg_cycles or 0) - 1 for _,item in pairs(recipe.input) do if item.name ~= "" then local outdir = liquids[item.name] or reload_liquids(pos)[item.name] if not outdir then State:standby(pos, nvm) reactor_cmnd(pos, "stop") untake(pos, taken) return end local num = liquid.take(pos, Pipe, outdir, item.name, item.num, mem.dbg_cycles > 0) if num < item.num then taken[#taken + 1] = {outdir = outdir, name = item.name, num = num} State:standby(pos, nvm) reactor_cmnd(pos, "stop") untake(pos, taken) return end taken[#taken + 1] = {outdir = outdir, name = item.name, num = item.num} end end -- waste if recipe.waste.name ~= "" then leftover = reactor_cmnd(pos, "waste", { name = recipe.waste.name, amount = recipe.waste.num}) or recipe.waste.num if leftover > 0 then mem.waste_leftover = {name = recipe.waste.name, num = leftover} mem.output_leftover = {name = recipe.output.name, num = recipe.output.num} State:blocked(pos, nvm) reactor_cmnd(pos, "stop") return end end -- output leftover = reactor_cmnd(pos, "output", { name = recipe.output.name, amount = recipe.output.num}) or recipe.output.num if leftover > 0 then mem.output_leftover = {name = recipe.output.name, num = leftover} State:blocked(pos, nvm) reactor_cmnd(pos, "stop") return end State:keep_running(pos, nvm, COUNTDOWN_TICKS) end local function node_timer(pos, elapsed) local nvm = techage.get_nvm(pos) dosing(pos, nvm, elapsed) return State:is_active(nvm) end local function on_rightclick(pos) local nvm = techage.get_nvm(pos) M(pos):set_string("formspec", formspec(State, pos, nvm)) end local function on_receive_fields(pos, formname, fields, player) if minetest.is_protected(pos, player:get_player_name()) then return end local nvm = techage.get_nvm(pos) if not nvm.running then if recipes.on_receive_fields(pos, formname, fields, player) then local mem = techage.get_mem(pos) mem.waste_leftover = nil mem.output_leftover = nil end end local mem = techage.get_mem(pos) mem.dbg_cycles = 5 State:state_button_event(pos, nvm, fields) M(pos):set_string("formspec", formspec(State, pos, nvm)) end minetest.register_node("techage:ta4_doser", { description = S("TA4 Doser"), tiles = { -- up, down, right, left, back, front "techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_hole_pipe.png", "techage_filling_ta4.png^techage_frame_ta4.png", "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_pump_up.png", }, after_place_node = function(pos, placer) local meta = M(pos) local nvm = techage.get_nvm(pos) local number = techage.add_node(pos, "techage:ta4_doser") meta:set_string("node_number", number) meta:set_string("owner", placer:get_player_name()) meta:set_string("formspec", formspec(State, pos, nvm)) meta:set_string("infotext", S("TA4 Doser").." "..number) State:node_init(pos, nvm, number) Pipe:after_place_node(pos) end, tubelib2_on_update2 = function(pos, dir, tlib2, node) liquid.update_network(pos, dir, tlib2, node) del_liquids(pos) end, after_dig_node = function(pos, oldnode, oldmetadata, digger) techage.remove_node(pos, oldnode, oldmetadata) Pipe:after_dig_node(pos) techage.del_mem(pos) end, on_receive_fields = on_receive_fields, on_rightclick = on_rightclick, on_timer = node_timer, paramtype2 = "facedir", on_rotate = screwdriver.disallow, groups = {cracky=2}, is_ground_content = false, sounds = default.node_sound_metal_defaults(), }) minetest.register_node("techage:ta4_doser_on", { description = S("TA4 Doser"), tiles = { -- up, down, right, left, back, front "techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_hole_pipe.png", "techage_filling_ta4.png^techage_frame_ta4.png", { image = "techage_filling8_ta4.png^techage_frame8_ta4.png^techage_appl_pump_up8.png", backface_culling = false, animation = { type = "vertical_frames", aspect_w = 32, aspect_h = 32, length = 2.0, }, }, }, tubelib2_on_update2 = function(pos, dir, tlib2, node) liquid.update_network(pos, dir, tlib2, node) del_liquids(pos) end, on_receive_fields = on_receive_fields, on_rightclick = on_rightclick, on_timer = node_timer, paramtype2 = "facedir", on_rotate = screwdriver.disallow, diggable = false, groups = {not_in_creative_inventory=1}, is_ground_content = false, sounds = default.node_sound_metal_defaults(), }) liquid.register_nodes({"techage:ta4_doser", "techage:ta4_doser_on"}, Pipe, "pump", nil, {}) techage.register_node({"techage:ta4_doser", "techage:ta4_doser_on"}, { on_recv_message = function(pos, src, topic, payload) if topic == "recipe" then techage.recipes.set_recipe(pos, "ta4_doser", payload) return true else return State:on_receive_message(pos, topic, payload) end end, on_beduino_receive_cmnd = function(pos, src, topic, payload) return State:on_beduino_receive_cmnd(pos, topic, payload) end, on_beduino_request_data = function(pos, src, topic, payload) return State:on_beduino_request_data(pos, topic, payload) end, }) techage.recipes.register_craft_type("ta4_doser", { description = S("TA4 Reactor"), icon = 'techage_reactor_filler_plan.png', width = 2, height = 2, }) minetest.register_craft({ output = "techage:ta4_doser", recipe = { {"", "techage:ta3_pipeS", ""}, {"techage:ta3_pipeS", "techage:t4_pump", "techage:ta3_pipeS"}, {"", "techage:ta4_wlanchip", ""}, }, })