--[[ TechAge ======= Copyright (C) 2019-2020 Joachim Stolberg AGPL v3 See LICENSE.txt for more information Consumer node basis functionality. It handles: - up to 3 stages of nodes (TA2/TA3/TA4) - power consumption - node state handling - registration of passive and active nodes - Tube connections are on left and right side (from left to right) - Power connection are on front and back side (front or back) ]]-- -- 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 -- Consumer Related Data local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end local CRDN = function(node) return (minetest.registered_nodes[node.name] or {}).consumer end local power = techage.power local networks = techage.networks local Pipe = techage.LiquidPipe local liquid = techage.liquid local function has_power(pos, nvm, state) local crd = CRD(pos) return power.power_available(pos, crd.power_netw) end local function start_node(pos, nvm, state) local crd = CRD(pos) power.consumer_start(pos, crd.power_netw, crd.cycle_time) end local function stop_node(pos, nvm, state) local crd = CRD(pos) power.consumer_stop(pos, crd.power_netw) end local function on_power(pos) local crd = CRD(pos) local nvm = techage.get_nvm(pos) crd.State:start(pos, nvm) end local function on_nopower(pos) local crd = CRD(pos) local nvm = techage.get_nvm(pos) crd.State:nopower(pos, nvm) end local function node_timer(pos, elapsed) local crd = CRD(pos) local nvm = techage.get_nvm(pos) if crd.power_netw and techage.needs_power(nvm) then power.consumer_alive(pos, crd.power_netw, crd.cycle_time) end -- call the node timer routine if techage.is_operational(nvm) then crd.node_timer(pos, crd.cycle_time) end return crd.State:is_active(nvm) end local function prepare_tiles(tiles, stage, power_png) local tbl = {} for _,item in ipairs(tiles) do if type(item) == "string" then tbl[#tbl+1] = item:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#') else local temp = table.copy(item) temp.image = temp.image:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#') tbl[#tbl+1] = temp end end return tbl end -- 'validStates' is optional and can be used to e.g. enable -- only one TA2 node {false, true, false, false} function techage.register_consumer(base_name, inv_name, tiles, tNode, validStates) local names = {} validStates = validStates or {true, true, true, true} for stage = 2,4 do local name_pas = "techage:ta"..stage.."_"..base_name.."_pas" local name_act = "techage:ta"..stage.."_"..base_name.."_act" local name_inv = "TA"..stage.." "..inv_name names[#names+1] = name_pas if validStates[stage] then local on_recv_message = tNode.tubing.on_recv_message if stage > 2 then on_recv_message = function(pos, src, topic, payload) return "unsupported" end end local power_network local power_png = 'techage_axle_clutch.png' local power_used = tNode.power_consumption ~= nil local tNetworks -- power needed? if power_used then if stage > 2 then power_network = techage.ElectricCable power_png = 'techage_appl_hole_electric.png' tNetworks = { ele1 = { sides = tNode.power_sides or {F=1, B=1, U=1, D=1}, ntype = "con1", nominal = tNode.power_consumption[stage], on_power = on_power, on_nopower = on_nopower, is_running = function(pos, nvm) return techage.is_running(nvm) end, }, } if tNode.networks and tNode.networks.pipe2 then tNetworks.pipe2 = tNode.networks.pipe2 end else power_network = techage.Axle power_png = 'techage_axle_clutch.png' tNetworks = { axle = { sides = tNode.power_sides or {F=1, B=1, U=1, D=1}, ntype = "con1", nominal = tNode.power_consumption[stage], on_power = on_power, on_nopower = on_nopower, } } end end local tState = techage.NodeStates:new({ node_name_passive = name_pas, node_name_active = name_act, infotext_name = name_inv, cycle_time = tNode.cycle_time, standby_ticks = tNode.standby_ticks, formspec_func = tNode.formspec, on_state_change = tNode.on_state_change, can_start = tNode.can_start, has_power = tNode.has_power or power_used and has_power or nil, start_node = power_used and start_node or nil, stop_node = power_used and stop_node or nil, }) local tConsumer = { stage = stage, State = tState, -- number of items to be processed per cycle num_items = tNode.num_items and tNode.num_items[stage], power_consumption = power_used and tNode.power_consumption[stage] or 0, node_timer = tNode.node_timer, cycle_time = tNode.cycle_time, power_netw = power_network, } local after_place_node = function(pos, placer, itemstack, pointed_thing) local crd = CRD(pos) local meta = M(pos) local nvm = techage.get_nvm(pos) local node = minetest.get_node(pos) meta:set_int("push_dir", techage.side_to_indir("L", node.param2)) meta:set_int("pull_dir", techage.side_to_indir("R", node.param2)) -- Delete existing node number. Needed for Digtron compatibility. if (meta:contains("node_number")) then meta:set_string("node_number", "") end local number = techage.add_node(pos, name_pas, stage == 2) if crd.power_netw then crd.power_netw:after_place_node(pos) end if tNode.after_place_node then tNode.after_place_node(pos, placer, itemstack, pointed_thing) end crd.State:node_init(pos, nvm, number) end local after_dig_node = function(pos, oldnode, oldmetadata, digger) if tNode.after_dig_node then tNode.after_dig_node(pos, oldnode, oldmetadata, digger) end local crd = CRDN(oldnode) if crd.power_netw then crd.power_netw:after_dig_node(pos) end techage.remove_node(pos, oldnode, oldmetadata) techage.del_mem(pos) end local tubelib2_on_update2 = function(pos, outdir, tlib2, node) if tNode.tubelib2_on_update2 then tNode.tubelib2_on_update2(pos, outdir, tlib2, node) end if tlib2.tube_type == "pipe2" then liquid.update_network(pos, outdir, tlib2) else power.update_network(pos, outdir, tlib2) end end tNode.groups.not_in_creative_inventory = 0 minetest.register_node(name_pas, { description = name_inv, tiles = prepare_tiles(tiles.pas, stage, power_png), consumer = tConsumer, drawtype = tNode.drawtype, node_box = tNode.node_box, selection_box = tNode.selection_box, can_dig = tNode.can_dig, on_rotate = tNode.on_rotate or screwdriver.disallow, on_timer = node_timer, on_receive_fields = tNode.on_receive_fields, on_rightclick = tNode.on_rightclick, after_place_node = after_place_node, after_dig_node = after_dig_node, preserve_metadata = tNode.preserve_metadata, tubelib2_on_update2 = tubelib2_on_update2, 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, networks = tNetworks and table.copy(tNetworks), paramtype = tNode.paramtype, paramtype2 = "facedir", drop = tNode.drop, groups = table.copy(tNode.groups), is_ground_content = false, sounds = tNode.sounds, }) tNode.groups.not_in_creative_inventory = 1 minetest.register_node(name_act, { description = name_inv, tiles = prepare_tiles(tiles.act, stage, power_png), consumer = tConsumer, drawtype = tNode.drawtype, node_box = tNode.node_box, selection_box = tNode.selection_box, on_rotate = tNode.on_rotate or screwdriver.disallow, on_timer = node_timer, on_receive_fields = tNode.on_receive_fields, on_rightclick = tNode.on_rightclick, after_place_node = after_place_node, after_dig_node = after_dig_node, tubelib2_on_update2 = tubelib2_on_update2, 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, networks = tNetworks and table.copy(tNetworks), paramtype = tNode.paramtype, paramtype2 = "facedir", drop = "", diggable = false, groups = table.copy(tNode.groups), is_ground_content = false, sounds = tNode.sounds, }) if power_used then power_network:add_secondary_node_names({name_pas, name_act}) end techage.register_node({name_pas, name_act}, tNode.tubing) end end return names[1], names[2], names[3] end