Novatux
2014-07-11 563a4c071d5a14905a8ee729705ababf8d46d9f6
Make switching station run all machines it is connected to, including those in unloaded blocks.
18 files modified
1687 ■■■■ changed files
technic/locale/template.txt 1 ●●●● patch | view | raw | blame | history
technic/machines/HV/forcefield.lua 87 ●●●● patch | view | raw | blame | history
technic/machines/HV/nuclear_reactor.lua 194 ●●●● patch | view | raw | blame | history
technic/machines/HV/quarry.lua 70 ●●●● patch | view | raw | blame | history
technic/machines/LV/cnc.lua 91 ●●●● patch | view | raw | blame | history
technic/machines/LV/geothermal.lua 127 ●●●● patch | view | raw | blame | history
technic/machines/LV/music_player.lua 91 ●●●● patch | view | raw | blame | history
technic/machines/LV/solar_panel.lua 66 ●●●● patch | view | raw | blame | history
technic/machines/LV/water_mill.lua 138 ●●●● patch | view | raw | blame | history
technic/machines/MV/tool_workshop.lua 95 ●●●● patch | view | raw | blame | history
technic/machines/MV/wind_mill.lua 68 ●●●● patch | view | raw | blame | history
technic/machines/register/battery_box.lua 157 ●●●● patch | view | raw | blame | history
technic/machines/register/cables.lua 4 ●●● patch | view | raw | blame | history
technic/machines/register/generator.lua 107 ●●●● patch | view | raw | blame | history
technic/machines/register/machine_base.lua 126 ●●●● patch | view | raw | blame | history
technic/machines/register/solar_array.lua 73 ●●●● patch | view | raw | blame | history
technic/machines/supply_converter.lua 72 ●●●● patch | view | raw | blame | history
technic/machines/switching_station.lua 120 ●●●● patch | view | raw | blame | history
technic/locale/template.txt
@@ -43,6 +43,7 @@
%s Unpowered =
%s Out Of Fuel =
%s Has Bad Cabling =
%s (Slave) =
%s Has No Network =
%s Finished =
Enable/Disable =
technic/machines/HV/forcefield.lua
@@ -103,10 +103,45 @@
    }
}
local run = function(pos, node, active_object_count, active_object_count_wider)
    local meta = minetest.get_meta(pos)
    local eu_input   = meta:get_int("HV_EU_input")
    local eu_demand  = meta:get_int("HV_EU_demand")
    local enabled    = meta:get_int("enabled")
    local machine_name = S("%s Forcefield Emitter"):format("HV")
    local power_requirement = math.floor(
            4 * math.pi * math.pow(meta:get_int("range"), 2)
        ) * forcefield_power_drain
    if meta:get_int("enabled") == 0 then
        if node.name == "technic:forcefield_emitter_on" then
            meta:set_int("HV_EU_demand", 0)
            update_forcefield(pos, meta:get_int("range"), false)
            technic.swap_node(pos, "technic:forcefield_emitter_off")
            meta:set_string("infotext", S("%s Disabled"):format(machine_name))
            return
        end
    elseif eu_input < power_requirement then
        meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
        if node.name == "technic:forcefield_emitter_on" then
            update_forcefield(pos, meta:get_int("range"), false)
            technic.swap_node(pos, "technic:forcefield_emitter_off")
        end
    elseif eu_input >= power_requirement then
        if node.name == "technic:forcefield_emitter_off" then
            technic.swap_node(pos, "technic:forcefield_emitter_on")
            meta:set_string("infotext", S("%s Active"):format(machine_name))
        end
        update_forcefield(pos, meta:get_int("range"), true)
    end
    meta:set_int("HV_EU_demand", power_requirement)
end
minetest.register_node("technic:forcefield_emitter_off", {
    description = S("%s Forcefield Emitter"):format("HV"),
    tiles = {"technic_forcefield_emitter_off.png"},
    groups = {cracky = 1},
    groups = {cracky = 1, technic_machine = 1},
    on_receive_fields = forcefield_receive_fields,
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
@@ -117,13 +152,14 @@
        meta:set_string("infotext", S("%s Forcefield Emitter"):format("HV"))
        set_forcefield_formspec(meta)
    end,
    mesecons = mesecons
    mesecons = mesecons,
    technic_run = run,
})
minetest.register_node("technic:forcefield_emitter_on", {
    description = S("%s Forcefield Emitter"):format("HV"),
    tiles = {"technic_forcefield_emitter_on.png"},
    groups = {cracky = 1, not_in_creative_inventory=1},
    groups = {cracky = 1, technic_machine = 1, not_in_creative_inventory=1},
    drop = "technic:forcefield_emitter_off",
    on_receive_fields = forcefield_receive_fields,
    on_construct = function(pos) 
@@ -135,7 +171,9 @@
        local meta = minetest.get_meta(pos)
        update_forcefield(pos, meta:get_int("range"), false)
    end,
    mesecons = mesecons
    mesecons = mesecons,
    technic_run = run,
    technic_disabled_machine_name = "technic:forcefield_emitter",
})
minetest.register_node("technic:forcefield", {
@@ -156,52 +194,11 @@
        },
    }},
})
minetest.register_abm({
    nodenames = {"technic:forcefield_emitter_on", "technic:forcefield_emitter_off"},
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta = minetest.get_meta(pos)
        local eu_input   = meta:get_int("HV_EU_input")
        local eu_demand  = meta:get_int("HV_EU_demand")
        local enabled    = meta:get_int("enabled")
        local machine_name = S("%s Forcefield Emitter"):format("HV")
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "HV")
        local power_requirement = math.floor(
                4 * math.pi * math.pow(meta:get_int("range"), 2)
            ) * forcefield_power_drain
        if meta:get_int("enabled") == 0 then
            if node.name == "technic:forcefield_emitter_on" then
                meta:set_int("HV_EU_demand", 0)
                update_forcefield(pos, meta:get_int("range"), false)
                technic.swap_node(pos, "technic:forcefield_emitter_off")
                meta:set_string("infotext", S("%s Disabled"):format(machine_name))
                return
            end
        elseif eu_input < power_requirement then
            meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
            if node.name == "technic:forcefield_emitter_on" then
                update_forcefield(pos, meta:get_int("range"), false)
                technic.swap_node(pos, "technic:forcefield_emitter_off")
            end
        elseif eu_input >= power_requirement then
            if node.name == "technic:forcefield_emitter_off" then
                technic.swap_node(pos, "technic:forcefield_emitter_on")
                meta:set_string("infotext", S("%s Active"):format(machine_name))
            end
            update_forcefield(pos, meta:get_int("range"), true)
        end
        meta:set_int("HV_EU_demand", power_requirement)
    end
})
if minetest.get_modpath("mesecons_mvps") then
    mesecon:register_mvps_stopper("technic:forcefield")
end
-- TODO: Register a stopper for frames
technic.register_machine("HV", "technic:forcefield_emitter_on",  technic.receiver)
technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver)
technic/machines/HV/nuclear_reactor.lua
@@ -48,60 +48,6 @@
    { -0.303, -0.303, -0.397, 0.303, 0.303, 0.397 },
}
minetest.register_node("technic:hv_nuclear_reactor_core", {
    description = S("Nuclear %s Generator Core"):format("HV"),
    tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
             "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
             "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drawtype="nodebox",
    paramtype = "light",
    stack_max = 1,
    node_box = {
        type = "fixed",
        fixed = nodebox
    },
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Nuclear %s Generator Core"):format("HV"))
        meta:set_int("HV_EU_supply", 0)
        -- Signal to the switching station that this device burns some
        -- sort of fuel and needs special handling
        meta:set_int("HV_EU_from_fuel", 1)
        meta:set_int("burn_time", 0)
        meta:set_string("formspec", generator_formspec)
        local inv = meta:get_inventory()
        inv:set_size("src", 6)
    end,
    can_dig = technic.machine_can_dig,
    allow_metadata_inventory_put = technic.machine_inventory_put,
    allow_metadata_inventory_take = technic.machine_inventory_take,
    allow_metadata_inventory_move = technic.machine_inventory_move,
})
minetest.register_node("technic:hv_nuclear_reactor_core_active", {
    tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
             "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
         "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drop="technic:hv_nuclear_reactor_core",
    drawtype="nodebox",
    light_source = 15,
    paramtype = "light",
    node_box = {
        type = "fixed",
        fixed = nodebox
    },
    can_dig = technic.machine_can_dig,
    allow_metadata_inventory_put = technic.machine_inventory_put,
    allow_metadata_inventory_take = technic.machine_inventory_take,
    allow_metadata_inventory_move = technic.machine_inventory_move,
})
local check_reactor_structure = function(pos)
    -- The reactor consists of a 9x9x9 cube structure
    -- A cross section through the middle:
@@ -188,57 +134,109 @@
    end
end
minetest.register_abm({
    nodenames = {"technic:hv_nuclear_reactor_core", "technic:hv_nuclear_reactor_core_active"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta = minetest.get_meta(pos)
        local machine_name = S("Nuclear %s Generator Core"):format("HV")
        local burn_time = meta:get_int("burn_time") or 0
local run = function(pos, node)
    local meta = minetest.get_meta(pos)
    local machine_name = S("Nuclear %s Generator Core"):format("HV")
    local burn_time = meta:get_int("burn_time") or 0
        if burn_time >= burn_ticks or burn_time == 0 then
            local inv = meta:get_inventory()
            if not inv:is_empty("src") then
                local srclist = inv:get_list("src")
                local correct_fuel_count = 0
                for _, srcstack in pairs(srclist) do
                    if srcstack then
                        if  srcstack:get_name() == fuel_type then
                            correct_fuel_count = correct_fuel_count + 1
                        end
    if burn_time >= burn_ticks or burn_time == 0 then
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            local srclist = inv:get_list("src")
            local correct_fuel_count = 0
            for _, srcstack in pairs(srclist) do
                if srcstack then
                    if  srcstack:get_name() == fuel_type then
                        correct_fuel_count = correct_fuel_count + 1
                    end
                end
                -- Check that the reactor is complete as well
                -- as the correct number of correct fuel
                if correct_fuel_count == 6 and
                   check_reactor_structure(pos) then
                    meta:set_int("burn_time", 1)
                    technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active")
                    meta:set_int("HV_EU_supply", power_supply)
                    for idx, srcstack in pairs(srclist) do
                        srcstack:take_item()
                        inv:set_stack("src", idx, srcstack)
                    end
                    return
            end
            -- Check that the reactor is complete as well
            -- as the correct number of correct fuel
            if correct_fuel_count == 6 and
               check_reactor_structure(pos) then
                meta:set_int("burn_time", 1)
                technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active")
                meta:set_int("HV_EU_supply", power_supply)
                for idx, srcstack in pairs(srclist) do
                    srcstack:take_item()
                    inv:set_stack("src", idx, srcstack)
                end
                return
            end
            meta:set_int("HV_EU_supply", 0)
            meta:set_int("burn_time", 0)
            meta:set_string("infotext", S("%s Idle"):format(machine_name))
            technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
        elseif burn_time > 0 then
            damage_nearby_players(pos)
            if not check_reactor_structure(pos) then
                explode_reactor(pos)
            end
            burn_time = burn_time + 1
            meta:set_int("burn_time", burn_time)
            local percent = math.floor(burn_time / burn_ticks * 100)
            meta:set_string("infotext", machine_name.." ("..percent.."%)")
            meta:set_int("HV_EU_supply", power_supply)
        end
        meta:set_int("HV_EU_supply", 0)
        meta:set_int("burn_time", 0)
        meta:set_string("infotext", S("%s Idle"):format(machine_name))
        technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
    elseif burn_time > 0 then
        damage_nearby_players(pos)
        if not check_reactor_structure(pos) then
            explode_reactor(pos)
        end
        burn_time = burn_time + 1
        meta:set_int("burn_time", burn_time)
        local percent = math.floor(burn_time / burn_ticks * 100)
        meta:set_string("infotext", machine_name.." ("..percent.."%)")
        meta:set_int("HV_EU_supply", power_supply)
    end
end
minetest.register_node("technic:hv_nuclear_reactor_core", {
    description = S("Nuclear %s Generator Core"):format("HV"),
    tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
             "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
             "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drawtype="nodebox",
    paramtype = "light",
    stack_max = 1,
    node_box = {
        type = "fixed",
        fixed = nodebox
    },
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Nuclear %s Generator Core"):format("HV"))
        meta:set_int("HV_EU_supply", 0)
        -- Signal to the switching station that this device burns some
        -- sort of fuel and needs special handling
        meta:set_int("HV_EU_from_fuel", 1)
        meta:set_int("burn_time", 0)
        meta:set_string("formspec", generator_formspec)
        local inv = meta:get_inventory()
        inv:set_size("src", 6)
    end,
    can_dig = technic.machine_can_dig,
    allow_metadata_inventory_put = technic.machine_inventory_put,
    allow_metadata_inventory_take = technic.machine_inventory_take,
    allow_metadata_inventory_move = technic.machine_inventory_move,
    technic_run = run,
})
minetest.register_node("technic:hv_nuclear_reactor_core_active", {
    tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
             "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
         "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drop="technic:hv_nuclear_reactor_core",
    drawtype="nodebox",
    light_source = 15,
    paramtype = "light",
    node_box = {
        type = "fixed",
        fixed = nodebox
    },
    can_dig = technic.machine_can_dig,
    allow_metadata_inventory_put = technic.machine_inventory_put,
    allow_metadata_inventory_take = technic.machine_inventory_take,
    allow_metadata_inventory_move = technic.machine_inventory_move,
    technic_run = run,
    technic_disabled_machine_name = "technic:hv_nuclear_reactor_core",
})
technic.register_machine("HV", "technic:hv_nuclear_reactor_core",        technic.producer)
technic/machines/HV/quarry.lua
@@ -126,13 +126,43 @@
    end
end
local run = function(pos, node)
    local meta = minetest.get_meta(pos)
    local size = meta:get_int("size")
    local eu_input = meta:get_int("HV_EU_input")
    local demand = 10000
    local center = get_quarry_center(pos, size)
    local dig_y = meta:get_int("dig_y")
    local machine_name = S("%s Quarry"):format("HV")
    if meta:get_int("enabled") == 0 then
        meta:set_string("infotext", S("%s Disabled"):format(machine_name))
        meta:set_int("HV_EU_demand", 0)
        return
    end
    if eu_input < demand then
        meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
    elseif eu_input >= demand then
        meta:set_string("infotext", S("%s Active"):format(machine_name))
        local items = quarry_dig(pos, center, size)
        send_items(items, pos, node)
        if dig_y < pos.y - quarry_max_depth then
            meta:set_string("infotext", S("%s Finished"):format(machine_name))
        end
    end
    meta:set_int("HV_EU_demand", demand)
end
minetest.register_node("technic:quarry", {
    description = S("%s Quarry"):format("HV"),
    tiles = {"technic_carbon_steel_block.png", "technic_carbon_steel_block.png",
             "technic_carbon_steel_block.png", "technic_carbon_steel_block.png",
             "technic_carbon_steel_block.png^default_tool_mesepick.png", "technic_carbon_steel_block.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, tubedevice=1},
    groups = {cracky=2, tubedevice=1, technic_machine = 1},
    tube = {
        connect_sides = {top = 1},
    },
@@ -150,43 +180,7 @@
    end,
    after_dig_node = pipeworks.scan_for_tube_objects,
    on_receive_fields = quarry_receive_fields,
})
minetest.register_abm({
    nodenames = {"technic:quarry"},
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta = minetest.get_meta(pos)
        local size = meta:get_int("size")
        local eu_input = meta:get_int("HV_EU_input")
        local demand = 10000
        local center = get_quarry_center(pos, size)
        local dig_y = meta:get_int("dig_y")
        local machine_name = S("%s Quarry"):format("HV")
        technic.switching_station_timeout_count(pos, "HV")
        if meta:get_int("enabled") == 0 then
            meta:set_string("infotext", S("%s Disabled"):format(machine_name))
            meta:set_int("HV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
        elseif eu_input >= demand then
            meta:set_string("infotext", S("%s Active"):format(machine_name))
            local items = quarry_dig(pos, center, size)
            send_items(items, pos, node)
            if dig_y < pos.y - quarry_max_depth then
                meta:set_string("infotext", S("%s Finished"):format(machine_name))
            end
        end
        meta:set_int("HV_EU_demand", demand)
    end
    technic_run = run,
})
technic.register_machine("HV", "technic:quarry", technic.receiver)
technic/machines/LV/cnc.lua
@@ -125,6 +125,44 @@
    return
end
-- Action code performing the transformation
local run = function(pos, node)
    local meta         = minetest.get_meta(pos)
    local inv          = meta:get_inventory()
    local eu_input     = meta:get_int("LV_EU_input")
    local machine_name = S("%s CNC Machine"):format("LV")
    local machine_node = "technic:cnc"
    local demand       = 450
    local result = meta:get_string("cnc_product")
    if inv:is_empty("src") or
       (not minetest.registered_nodes[result]) or
       (not inv:room_for_item("dst", result)) then
        technic.swap_node(pos, machine_node)
        meta:set_string("infotext", S("%s Idle"):format(machine_name))
        meta:set_string("cnc_product", "")
        meta:set_int("LV_EU_demand", 0)
        return
    end
    if eu_input < demand then
        technic.swap_node(pos, machine_node)
        meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
    elseif eu_input >= demand then
        technic.swap_node(pos, machine_node.."_active")
        meta:set_string("infotext", S("%s Active"):format(machine_name))
        meta:set_int("src_time", meta:get_int("src_time") + 1)
        if meta:get_int("src_time") >= 3 then -- 3 ticks per output
            meta:set_int("src_time", 0)
            srcstack = inv:get_stack("src", 1)
            srcstack:take_item()
            inv:set_stack("src", 1, srcstack)
            inv:add_item("dst", result.." "..meta:get_int("cnc_multiplier"))
        end
    end
    meta:set_int("LV_EU_demand", demand)
end
-- The actual block inactive state
minetest.register_node("technic:cnc", {
    description = S("%s CNC Machine"):format("LV"),
@@ -139,7 +177,7 @@
            {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
        },
    },
    groups = {cracky=2},
    groups = {cracky=2, technic_machine=1},
    legacy_facedir_simple = true,
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
@@ -155,6 +193,7 @@
    allow_metadata_inventory_take = technic.machine_inventory_take,
    allow_metadata_inventory_move = technic.machine_inventory_move,
    on_receive_fields = form_handler,
    technic_run = run,
})
-- Active state block
@@ -164,60 +203,16 @@
                   "technic_cnc_side.png",       "technic_cnc_side.png",   "technic_cnc_front_active.png"},
    paramtype2 = "facedir",
    drop = "technic:cnc",
    groups = {cracky=2, not_in_creative_inventory=1},
    groups = {cracky=2, technic_machine=1, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    can_dig = technic.machine_can_dig,
    allow_metadata_inventory_put = technic.machine_inventory_put,
    allow_metadata_inventory_take = technic.machine_inventory_take,
    allow_metadata_inventory_move = technic.machine_inventory_move,
    on_receive_fields = form_handler,
    technic_run = run,
    technic_disabled_machine_name = "technic:cnc",
})
-- Action code performing the transformation
minetest.register_abm({
    nodenames = {"technic:cnc","technic:cnc_active"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta         = minetest.get_meta(pos)
        local inv          = meta:get_inventory()
        local eu_input     = meta:get_int("LV_EU_input")
        local machine_name = S("%s CNC Machine"):format("LV")
        local machine_node = "technic:cnc"
        local demand       = 450
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "LV")
        local result = meta:get_string("cnc_product")
        if inv:is_empty("src") or
           (not minetest.registered_nodes[result]) or
           (not inv:room_for_item("dst", result)) then
            technic.swap_node(pos, machine_node)
            meta:set_string("infotext", S("%s Idle"):format(machine_name))
            meta:set_string("cnc_product", "")
            meta:set_int("LV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            technic.swap_node(pos, machine_node)
            meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
        elseif eu_input >= demand then
            technic.swap_node(pos, machine_node.."_active")
            meta:set_string("infotext", S("%s Active"):format(machine_name))
            meta:set_int("src_time", meta:get_int("src_time") + 1)
            if meta:get_int("src_time") >= 3 then -- 3 ticks per output
                meta:set_int("src_time", 0)
                srcstack = inv:get_stack("src", 1)
                srcstack:take_item()
                inv:set_stack("src", 1, srcstack)
                inv:add_item("dst", result.." "..meta:get_int("cnc_multiplier"))
            end
        end
        meta:set_int("LV_EU_demand", demand)
    end
})
technic.register_machine("LV", "technic:cnc",        technic.receiver)
technic.register_machine("LV", "technic:cnc_active", technic.receiver)
technic/machines/LV/geothermal.lua
@@ -20,19 +20,78 @@
    description = S("Geothermal %s Generator"):format("LV"),
}) 
local check_node_around = function(pos)
    local node = minetest.get_node(pos)
    if node.name == "default:water_source" or node.name == "default:water_flowing" then return 1 end
    if node.name == "default:lava_source"  or node.name == "default:lava_flowing"  then return 2 end
    return 0
end
local run = function(pos, node)
    local meta             = minetest.get_meta(pos)
    local water_nodes      = 0
    local lava_nodes       = 0
    local production_level = 0
    local eu_supply        = 0
    -- Correct positioning is water on one side and lava on the other.
    -- The two cannot be adjacent because the lava the turns into obsidian or rock.
    -- To get to 100% production stack the water and lava one extra block down as well:
    --    WGL (W=Water, L=Lava, G=the generator, |=an LV cable)
    --    W|L
    local positions = {
        {x=pos.x+1, y=pos.y,   z=pos.z},
        {x=pos.x+1, y=pos.y-1, z=pos.z},
        {x=pos.x-1, y=pos.y,   z=pos.z},
        {x=pos.x-1, y=pos.y-1, z=pos.z},
        {x=pos.x,   y=pos.y,   z=pos.z+1},
        {x=pos.x,   y=pos.y-1, z=pos.z+1},
        {x=pos.x,   y=pos.y,   z=pos.z-1},
        {x=pos.x,   y=pos.y-1, z=pos.z-1},
    }
    for _, p in pairs(positions) do
        local check = check_node_around(p)
        if check == 1 then water_nodes = water_nodes + 1 end
        if check == 2 then lava_nodes  = lava_nodes  + 1 end
    end
    if water_nodes == 1 and lava_nodes == 1 then production_level =  25; eu_supply = 50 end
    if water_nodes == 2 and lava_nodes == 1 then production_level =  50; eu_supply = 100 end
    if water_nodes == 1 and lava_nodes == 2 then production_level =  75; eu_supply = 200 end
    if water_nodes == 2 and lava_nodes == 2 then production_level = 100; eu_supply = 300 end
    if production_level > 0 then
        meta:set_int("LV_EU_supply", eu_supply)
    end
    meta:set_string("infotext",
        S("Geothermal %s Generator"):format("LV").." ("..production_level.."%)")
    if production_level > 0 and minetest.get_node(pos).name == "technic:geothermal" then
        technic.swap_node (pos, "technic:geothermal_active")
        return
    end
    if production_level == 0 then
        technic.swap_node(pos, "technic:geothermal")
        meta:set_int("LV_EU_supply", 0)
    end
end
minetest.register_node("technic:geothermal", {
    description = S("Geothermal %s Generator"):format("LV"),
    tiles = {"technic_geothermal_top.png", "technic_machine_bottom.png", "technic_geothermal_side.png",
             "technic_geothermal_side.png", "technic_geothermal_side.png", "technic_geothermal_side.png"},
    paramtype2 = "facedir",
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Geothermal %s Generator"):format("LV"))
        meta:set_int("LV_EU_supply", 0)
    end,
    end,
    technic_run = run,
})
minetest.register_node("technic:geothermal_active", {
@@ -44,70 +103,8 @@
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drop = "technic:geothermal",
    technic_run = run,
})
local check_node_around = function(pos)
    local node = minetest.get_node(pos)
    if node.name == "default:water_source" or node.name == "default:water_flowing" then return 1 end
    if node.name == "default:lava_source"  or node.name == "default:lava_flowing"  then return 2 end
    return 0
end
minetest.register_abm({
    nodenames = {"technic:geothermal","technic:geothermal_active"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta             = minetest.get_meta(pos)
        local water_nodes      = 0
        local lava_nodes       = 0
        local production_level = 0
        local eu_supply        = 0
        -- Correct positioning is water on one side and lava on the other.
        -- The two cannot be adjacent because the lava the turns into obsidian or rock.
        -- To get to 100% production stack the water and lava one extra block down as well:
        --    WGL (W=Water, L=Lava, G=the generator, |=an LV cable)
        --    W|L
        local positions = {
            {x=pos.x+1, y=pos.y,   z=pos.z},
            {x=pos.x+1, y=pos.y-1, z=pos.z},
            {x=pos.x-1, y=pos.y,   z=pos.z},
            {x=pos.x-1, y=pos.y-1, z=pos.z},
            {x=pos.x,   y=pos.y,   z=pos.z+1},
            {x=pos.x,   y=pos.y-1, z=pos.z+1},
            {x=pos.x,   y=pos.y,   z=pos.z-1},
            {x=pos.x,   y=pos.y-1, z=pos.z-1},
        }
        for _, p in pairs(positions) do
            local check = check_node_around(p)
            if check == 1 then water_nodes = water_nodes + 1 end
            if check == 2 then lava_nodes  = lava_nodes  + 1 end
        end
        if water_nodes == 1 and lava_nodes == 1 then production_level =  25; eu_supply = 50 end
        if water_nodes == 2 and lava_nodes == 1 then production_level =  50; eu_supply = 100 end
        if water_nodes == 1 and lava_nodes == 2 then production_level =  75; eu_supply = 200 end
        if water_nodes == 2 and lava_nodes == 2 then production_level = 100; eu_supply = 300 end
        if production_level > 0 then
            meta:set_int("LV_EU_supply", eu_supply)
        end
        meta:set_string("infotext",
            S("Geothermal %s Generator"):format("LV").." ("..production_level.."%)")
        if production_level > 0 and minetest.get_node(pos).name == "technic:geothermal" then
            technic.swap_node (pos, "technic:geothermal_active")
            return
        end
        if production_level == 0 then
            technic.swap_node(pos, "technic:geothermal")
            meta:set_int("LV_EU_supply", 0)
        end
    end
})
technic.register_machine("LV", "technic:geothermal",        technic.producer)
technic.register_machine("LV", "technic:geothermal_active", technic.producer)
technic/machines/LV/music_player.lua
@@ -36,11 +36,51 @@
            {pos = pos, gain = 1.0, loop = true, max_hear_distance = 72,})
end
local run = function(pos, node)
    local meta         = minetest.get_meta(pos)
    local eu_input     = meta:get_int("LV_EU_input")
    local machine_name = S("%s Music Player"):format("LV")
    local machine_node = "technic:music_player"
    local demand       = 150
    local current_track = meta:get_int("current_track")
    local pos_hash      = minetest.hash_node_position(pos)
    local music_handle  = music_handles[pos_hash]
    -- Setup meta data if it does not exist.
    if not eu_input then
        meta:set_int("LV_EU_demand", demand)
        meta:set_int("LV_EU_input", 0)
        return
    end
    if meta:get_int("active") == 0 then
        meta:set_string("infotext", S("%s Idle"):format(machine_name))
        meta:set_int("LV_EU_demand", 0)
        return
    end
    if eu_input < demand then
        meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
        if music_handle then
            minetest.sound_stop(music_handle)
            music_handle = nil
        end
    elseif eu_input >= demand then
        meta:set_string("infotext", S("%s Active"):format(machine_name))
        if not music_handle then
            music_handle = play_track(pos, current_track)
        end
    end
    music_handles[pos_hash] = music_handle
    meta:set_int("LV_EU_demand", demand)
end
minetest.register_node("technic:music_player", {
    description = S("%s Music Player"):format("LV"),
    tiles = {"technic_music_player_top.png", "technic_machine_bottom.png", "technic_music_player_side.png",
             "technic_music_player_side.png", "technic_music_player_side.png", "technic_music_player_side.png"},
    groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
@@ -95,54 +135,7 @@
        end
        music_handles[pos_hash] = music_handle
    end,
})
minetest.register_abm({
    nodenames = {"technic:music_player"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta         = minetest.get_meta(pos)
        local eu_input     = meta:get_int("LV_EU_input")
        local machine_name = S("%s Music Player"):format("LV")
        local machine_node = "technic:music_player"
        local demand       = 150
        local current_track = meta:get_int("current_track")
        local pos_hash      = minetest.hash_node_position(pos)
        local music_handle  = music_handles[pos_hash]
        -- Setup meta data if it does not exist.
        if not eu_input then
            meta:set_int("LV_EU_demand", demand)
            meta:set_int("LV_EU_input", 0)
            return
        end
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "LV")
        if meta:get_int("active") == 0 then
            meta:set_string("infotext", S("%s Idle"):format(machine_name))
            meta:set_int("LV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
            if music_handle then
                minetest.sound_stop(music_handle)
                music_handle = nil
            end
        elseif eu_input >= demand then
            meta:set_string("infotext", S("%s Active"):format(machine_name))
            if not music_handle then
                music_handle = play_track(pos, current_track)
            end
        end
        music_handles[pos_hash] = music_handle
        meta:set_int("LV_EU_demand", demand)
    end
    technic_run = run,
})
technic.register_machine("LV", "technic:music_player", technic.receiver)
technic/machines/LV/solar_panel.lua
@@ -4,10 +4,38 @@
local S = technic.getter
local run = function(pos, node)
    -- The action here is to make the solar panel prodice power
    -- Power is dependent on the light level and the height above ground
    -- There are many ways to cheat by using other light sources like lamps.
    -- As there is no way to determine if light is sunlight that is just a shame.
    -- To take care of some of it solar panels do not work outside daylight hours or if
    -- built below 0m
    local pos1 = {x=pos.x, y=pos.y+1, z=pos.z}
    local machine_name = S("Small Solar %s Generator"):format("LV")
    local light = minetest.get_node_light(pos1, nil)
    local time_of_day = minetest.get_timeofday()
    local meta = minetest.get_meta(pos)
    if light == nil then light = 0 end
    -- turn on panel only during day time and if sufficient light
        -- I know this is counter intuitive when cheating by using other light sources underground.
    if light >= 12 and time_of_day >= 0.24 and time_of_day <= 0.76 and pos.y > -10 then
        local charge_to_give = math.floor((light + pos1.y) * 3)
        charge_to_give = math.max(charge_to_give, 0)
        charge_to_give = math.min(charge_to_give, 200)
        meta:set_string("infotext", S("%s Active"):format(machine_name).." ("..charge_to_give.."EU)")
        meta:set_int("LV_EU_supply", charge_to_give)
    else
        meta:set_string("infotext", S("%s Idle"):format(machine_name))
        meta:set_int("LV_EU_supply", 0)
    end
end
minetest.register_node("technic:solar_panel", {
    tiles = {"technic_solar_panel_top.png",  "technic_solar_panel_bottom.png", "technic_solar_panel_side.png",
             "technic_solar_panel_side.png", "technic_solar_panel_side.png",   "technic_solar_panel_side.png"},
    groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    sounds = default.node_sound_wood_defaults(),
        description = S("Small Solar %s Generator"):format("LV"),
    active = false,
@@ -23,6 +51,7 @@
        meta:set_int("LV_EU_supply", 0)
        meta:set_string("infotext", S("Small Solar %s Generator"):format("LV"))
    end,
    technic_run = run,
})
minetest.register_craft({
@@ -33,41 +62,6 @@
    }
})
minetest.register_abm({
    nodenames = {"technic:solar_panel"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        -- The action here is to make the solar panel prodice power
        -- Power is dependent on the light level and the height above ground
        -- 130m and above is optimal as it would be above cloud level.
        -- Height gives 1/4 of the effect, light 3/4. Max. effect is 26EU.
        -- There are many ways to cheat by using other light sources like lamps.
        -- As there is no way to determine if light is sunlight that is just a shame.
        -- To take care of some of it solar panels do not work outside daylight hours or if
        -- built below -10m
        local pos1 = {x=pos.x, y=pos.y+1, z=pos.z}
        local machine_name = S("Small Solar %s Generator"):format("LV")
        local light = minetest.get_node_light(pos1, nil)
        local time_of_day = minetest.get_timeofday()
        local meta = minetest.get_meta(pos)
        if light == nil then light = 0 end
        -- turn on panel only during day time and if sufficient light
                -- I know this is counter intuitive when cheating by using other light sources underground.
        if light >= 12 and time_of_day >= 0.24 and time_of_day <= 0.76 and pos.y > -10 then
            local charge_to_give = math.floor((light + pos1.y) * 3)
            charge_to_give = math.max(charge_to_give, 0)
            charge_to_give = math.min(charge_to_give, 200)
            meta:set_string("infotext", S("%s Active"):format(machine_name).." ("..charge_to_give.."EU)")
            meta:set_int("LV_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", S("%s Idle"):format(machine_name))
            meta:set_int("LV_EU_supply", 0)
        end
    end,
})
technic.register_machine("LV", "technic:solar_panel", technic.producer)
technic/machines/LV/water_mill.lua
@@ -15,34 +15,6 @@
    }
})
minetest.register_node("technic:water_mill", {
    description = S("Hydro %s Generator"):format("LV"),
    tiles = {"technic_water_mill_top.png",  "technic_machine_bottom.png",
             "technic_water_mill_side.png", "technic_water_mill_side.png",
             "technic_water_mill_side.png", "technic_water_mill_side.png"},
    paramtype2 = "facedir",
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Hydro %s Generator"):format("LV"))
        meta:set_int("LV_EU_supply", 0)
    end,
})
minetest.register_node("technic:water_mill_active", {
    description = S("Hydro %s Generator"):format("LV"),
    tiles = {"technic_water_mill_top_active.png", "technic_machine_bottom.png",
             "technic_water_mill_side.png",       "technic_water_mill_side.png",
             "technic_water_mill_side.png",       "technic_water_mill_side.png"},
    paramtype2 = "facedir",
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drop = "technic:water_mill",
})
local function check_node_around_mill(pos)
    local node = minetest.get_node(pos)
    if node.name == "default:water_flowing" or
@@ -52,52 +24,78 @@
    return false
end
minetest.register_abm({
    nodenames = {"technic:water_mill", "technic:water_mill_active"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta             = minetest.get_meta(pos)
        local water_nodes      = 0
        local lava_nodes       = 0
        local production_level = 0
        local eu_supply        = 0
local run = function(pos, node)
    local meta             = minetest.get_meta(pos)
    local water_nodes      = 0
    local lava_nodes       = 0
    local production_level = 0
    local eu_supply        = 0
        local positions = {
            {x=pos.x+1, y=pos.y, z=pos.z},
            {x=pos.x-1, y=pos.y, z=pos.z},
            {x=pos.x,   y=pos.y, z=pos.z+1},
            {x=pos.x,   y=pos.y, z=pos.z-1},
        }
    local positions = {
        {x=pos.x+1, y=pos.y, z=pos.z},
        {x=pos.x-1, y=pos.y, z=pos.z},
        {x=pos.x,   y=pos.y, z=pos.z+1},
        {x=pos.x,   y=pos.y, z=pos.z-1},
    }
        for _, p in pairs(positions) do
            local check = check_node_around_mill(p)
            if check then
                water_nodes = water_nodes + 1
            end
        end
        production_level = 25 * water_nodes
        eu_supply = 30 * water_nodes
        if production_level > 0 then
            meta:set_int("LV_EU_supply", eu_supply)
        end
        meta:set_string("infotext",
            S("Hydro %s Generator"):format("LV").." ("..production_level.."%)")
        if production_level > 0 and
           minetest.get_node(pos).name == "technic:water_mill" then
            technic.swap_node (pos, "technic:water_mill_active")
            meta:set_int("LV_EU_supply", 0)
            return
        end
        if production_level == 0 then
            technic.swap_node(pos, "technic:water_mill")
    for _, p in pairs(positions) do
        local check = check_node_around_mill(p)
        if check then
            water_nodes = water_nodes + 1
        end
    end
})
    production_level = 25 * water_nodes
    eu_supply = 30 * water_nodes
    if production_level > 0 then
        meta:set_int("LV_EU_supply", eu_supply)
    end
    meta:set_string("infotext",
        S("Hydro %s Generator"):format("LV").." ("..production_level.."%)")
    if production_level > 0 and
       minetest.get_node(pos).name == "technic:water_mill" then
        technic.swap_node (pos, "technic:water_mill_active")
        meta:set_int("LV_EU_supply", 0)
        return
    end
    if production_level == 0 then
        technic.swap_node(pos, "technic:water_mill")
    end
end
minetest.register_node("technic:water_mill", {
    description = S("Hydro %s Generator"):format("LV"),
    tiles = {"technic_water_mill_top.png",  "technic_machine_bottom.png",
             "technic_water_mill_side.png", "technic_water_mill_side.png",
             "technic_water_mill_side.png", "technic_water_mill_side.png"},
    paramtype2 = "facedir",
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Hydro %s Generator"):format("LV"))
        meta:set_int("LV_EU_supply", 0)
    end,
    technic_run,
})
minetest.register_node("technic:water_mill_active", {
    description = S("Hydro %s Generator"):format("LV"),
    tiles = {"technic_water_mill_top_active.png", "technic_machine_bottom.png",
             "technic_water_mill_side.png",       "technic_water_mill_side.png",
             "technic_water_mill_side.png",       "technic_water_mill_side.png"},
    paramtype2 = "facedir",
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drop = "technic:water_mill",
    technic_run,
    technic_disabled_machine_name = "technic:water_mill",
})
technic.register_machine("LV", "technic:water_mill",        technic.producer)
technic.register_machine("LV", "technic:water_mill_active", technic.producer)
technic/machines/MV/tool_workshop.lua
@@ -20,11 +20,53 @@
    "label[0,0;"..S("%s Tool Workshop"):format("MV").."]"..
    "list[current_player;main;0,5;8,4;]"
local run = function(pos, node)
    local meta         = minetest.get_meta(pos)
    local inv          = meta:get_inventory()
    local eu_input     = meta:get_int("MV_EU_input")
    local machine_name = S("%s Tool Workshop"):format("MV")
    local machine_node = "technic:tool_workshop"
    local demand       = 5000
    -- Setup meta data if it does not exist.
    if not eu_input then
        meta:set_int("MV_EU_demand", demand)
        meta:set_int("MV_EU_input", 0)
        return
    end
    local repairable = false
    local srcstack = inv:get_stack("src", 1)
    if not srcstack:is_empty() then
        local itemdef = minetest.registered_items[srcstack:get_name()]
        if itemdef and
                (not itemdef.wear_represents or
                itemdef.wear_represents == "mechanical_wear") and
                srcstack:get_wear() ~= 0 then
            repairable = true
        end
    end
    if not repairable then
        meta:set_string("infotext", S("%s Idle"):format(machine_name))
        meta:set_int("MV_EU_demand", 0)
        return
    end
    if eu_input < demand then
        meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
    elseif eu_input >= demand then
        meta:set_string("infotext", S("%s Active"):format(machine_name))
        srcstack:add_wear(-1000)
        inv:set_stack("src", 1, srcstack)
    end
    meta:set_int("MV_EU_demand", demand)
end
minetest.register_node("technic:tool_workshop", {
    description = S("%s Tool Workshop"):format("MV"),
    tiles = {"technic_workshop_top.png", "technic_machine_bottom.png", "technic_workshop_side.png",
             "technic_workshop_side.png", "technic_workshop_side.png", "technic_workshop_side.png"},
    groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
@@ -36,57 +78,8 @@
    can_dig = technic.machine_can_dig,
    allow_metadata_inventory_put = technic.machine_inventory_put,
    allow_metadata_inventory_take = technic.machine_inventory_take,
    technic_run = run,
})
minetest.register_abm({
    nodenames = {"technic:tool_workshop"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta         = minetest.get_meta(pos)
        local inv          = meta:get_inventory()
        local eu_input     = meta:get_int("MV_EU_input")
        local machine_name = S("%s Tool Workshop"):format("MV")
        local machine_node = "technic:tool_workshop"
        local demand       = 5000
        -- Setup meta data if it does not exist.
        if not eu_input then
            meta:set_int("MV_EU_demand", demand)
            meta:set_int("MV_EU_input", 0)
            return
        end
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "MV")
        local repairable = false
        local srcstack = inv:get_stack("src", 1)
        if not srcstack:is_empty() then
            local itemdef = minetest.registered_items[srcstack:get_name()]
            if itemdef and
                    (not itemdef.wear_represents or
                    itemdef.wear_represents == "mechanical_wear") and
                    srcstack:get_wear() ~= 0 then
                repairable = true
            end
        end
        if not repairable then
            meta:set_string("infotext", S("%s Idle"):format(machine_name))
            meta:set_int("MV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
        elseif eu_input >= demand then
            meta:set_string("infotext", S("%s Active"):format(machine_name))
            srcstack:add_wear(-1000)
            inv:set_stack("src", 1, srcstack)
        end
        meta:set_int("MV_EU_demand", demand)
    end
})
technic.register_machine("MV", "technic:tool_workshop", technic.receiver)
technic/machines/MV/wind_mill.lua
@@ -29,11 +29,40 @@
    paramtype = "light",
})
local function check_wind_mill(pos)
    if pos.y < 30 then
        return false
    end
    for i = 1, 20 do
        local node = minetest.get_node({x=pos.x, y=pos.y-i, z=pos.z})
        if node.name ~= "technic:wind_mill_frame" then
            return false
        end
    end
    return true
end
local run = function(pos, node)
    local meta = minetest.get_meta(pos)
    local machine_name = S("Wind %s Generator"):format("MV")
    local power = math.min(pos.y * 100, 5000)
    if not check_wind_mill(pos) then
        meta:set_int("MV_EU_supply", 0)
        meta:set_string("infotext", S("%s Improperly Placed"):format(machine_name))
        return
    else
        meta:set_int("MV_EU_supply", power)
    end
    meta:set_string("infotext", machine_name.." ("..power.."EU)")
end
minetest.register_node("technic:wind_mill", {
    description = S("Wind %s Generator"):format("MV"),
    tiles = {"technic_carbon_steel_block.png"},
    paramtype2 = "facedir",
    groups = {cracky=1},
    groups = {cracky=1, technic_machine=1},
    sounds = default.node_sound_stone_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
@@ -50,41 +79,8 @@
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Wind %s Generator"):format("MV"))
        meta:set_int("MV_EU_supply", 0)
    end,
})
local function check_wind_mill(pos)
    if pos.y < 30 then
        return false
    end
    for i = 1, 20 do
        local node = minetest.get_node({x=pos.x, y=pos.y-i, z=pos.z})
        if node.name ~= "technic:wind_mill_frame" then
            return false
        end
    end
    return true
end
minetest.register_abm({
    nodenames = {"technic:wind_mill"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta = minetest.get_meta(pos)
        local machine_name = S("Wind %s Generator"):format("MV")
        local power = math.min(pos.y * 100, 5000)
        if not check_wind_mill(pos) then
            meta:set_int("MV_EU_supply", 0)
            meta:set_string("infotext", S("%s Improperly Placed"):format(machine_name))
            return
        else
            meta:set_int("MV_EU_supply", power)
        end
        meta:set_string("infotext", machine_name.." ("..power.."EU)")
    end
    end,
    technic_run = run,
})
technic.register_machine("MV", "technic:wind_mill", technic.producer)
technic/machines/register/battery_box.lua
@@ -80,8 +80,78 @@
            "label[3.5,4;"..S("Upgrade Slots").."]"
    end
    local run = function(pos, node)
        local meta           = minetest.get_meta(pos)
        local eu_input       = meta:get_int(tier.."_EU_input")
        local current_charge = meta:get_int("internal_EU_charge")
        local EU_upgrade, tube_upgrade = 0, 0
        if data.upgrade then
            EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
        end
        local max_charge = data.max_charge * (1 + EU_upgrade / 10)
        -- Charge/discharge the battery with the input EUs
        if eu_input >= 0 then
            current_charge = math.min(current_charge + eu_input, max_charge)
        else
            current_charge = math.max(current_charge + eu_input, 0)
        end
        -- Charging/discharging tools here
        local tool_full, tool_empty
        current_charge, tool_full = technic.charge_tools(meta,
                current_charge, data.charge_step)
        current_charge, tool_empty = technic.discharge_tools(meta,
                current_charge, data.discharge_step,
                max_charge)
        if data.tube then
            local inv = meta:get_inventory()
            technic.handle_machine_pipeworks(pos, tube_upgrade,
            function(pos, x_velocity, z_velocity)
                if tool_full and not inv:is_empty("src") then
                    technic.send_items(pos, x_velocity, z_velocity, "src")
                elseif tool_empty and not inv:is_empty("dst") then
                    technic.send_items(pos, x_velocity, z_velocity, "dst")
                end
            end)
        end
        -- We allow batteries to charge on less than the demand
        meta:set_int(tier.."_EU_demand",
                math.min(data.charge_rate, max_charge - current_charge))
        meta:set_int(tier.."_EU_supply",
                math.min(data.discharge_rate, current_charge))
            meta:set_int("internal_EU_charge", current_charge)
        -- Select node textures
        local charge_count = math.ceil((current_charge / max_charge) * 8)
        charge_count = math.min(charge_count, 8)
        charge_count = math.max(charge_count, 0)
        local last_count = meta:get_float("last_side_shown")
        if charge_count ~= last_count then
            technic.swap_node(pos,"technic:"..ltier.."_battery_box"..charge_count)
            meta:set_float("last_side_shown", charge_count)
        end
        local charge_percent = math.floor(current_charge / max_charge * 100)
        meta:set_string("formspec",
            formspec..
            "image[1,1;1,2;technic_power_meter_bg.png"
            .."^[lowpart:"..charge_percent
            ..":technic_power_meter_fg.png]")
        local infotext = S("%s Battery Box: %d/%d"):format(tier,
                current_charge, max_charge)
        if eu_input == 0 then
            infotext = S("%s Idle"):format(infotext)
        end
        meta:set_string("infotext", infotext)
    end
    for i = 0, 8 do
        local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}
        local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1}
        if i ~= 0 then
            groups.not_in_creative_inventory = 1
        end
@@ -124,92 +194,9 @@
            allow_metadata_inventory_put = technic.machine_inventory_put,
            allow_metadata_inventory_take = technic.machine_inventory_take,
            allow_metadata_inventory_move = technic.machine_inventory_move,
            technic_run = run,
        })
    end
    minetest.register_abm({
        nodenames = {"technic:"..ltier.."_battery_box0", "technic:"..ltier.."_battery_box1",
                     "technic:"..ltier.."_battery_box2", "technic:"..ltier.."_battery_box3",
                     "technic:"..ltier.."_battery_box4", "technic:"..ltier.."_battery_box5",
                     "technic:"..ltier.."_battery_box6", "technic:"..ltier.."_battery_box7",
                     "technic:"..ltier.."_battery_box8"},
        interval = 1,
        chance   = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            local meta           = minetest.get_meta(pos)
            local eu_input       = meta:get_int(tier.."_EU_input")
            local current_charge = meta:get_int("internal_EU_charge")
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, tier)
            local EU_upgrade, tube_upgrade = 0, 0
            if data.upgrade then
                EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
            end
            local max_charge = data.max_charge * (1 + EU_upgrade / 10)
            -- Charge/discharge the battery with the input EUs
            if eu_input >= 0 then
                current_charge = math.min(current_charge + eu_input, max_charge)
            else
                current_charge = math.max(current_charge + eu_input, 0)
            end
            -- Charging/discharging tools here
            local tool_full, tool_empty
            current_charge, tool_full = technic.charge_tools(meta,
                    current_charge, data.charge_step)
            current_charge, tool_empty = technic.discharge_tools(meta,
                    current_charge, data.discharge_step,
                    max_charge)
            if data.tube then
                local inv = meta:get_inventory()
                technic.handle_machine_pipeworks(pos, tube_upgrade,
                function(pos, x_velocity, z_velocity)
                    if tool_full and not inv:is_empty("src") then
                        technic.send_items(pos, x_velocity, z_velocity, "src")
                    elseif tool_empty and not inv:is_empty("dst") then
                        technic.send_items(pos, x_velocity, z_velocity, "dst")
                    end
                end)
            end
            -- We allow batteries to charge on less than the demand
            meta:set_int(tier.."_EU_demand",
                    math.min(data.charge_rate, max_charge - current_charge))
            meta:set_int(tier.."_EU_supply",
                    math.min(data.discharge_rate, current_charge))
            meta:set_int("internal_EU_charge", current_charge)
            -- Select node textures
            local charge_count = math.ceil((current_charge / max_charge) * 8)
            charge_count = math.min(charge_count, 8)
            charge_count = math.max(charge_count, 0)
            local last_count = meta:get_float("last_side_shown")
            if charge_count ~= last_count then
                technic.swap_node(pos,"technic:"..ltier.."_battery_box"..charge_count)
                meta:set_float("last_side_shown", charge_count)
            end
            local charge_percent = math.floor(current_charge / max_charge * 100)
            meta:set_string("formspec",
                formspec..
                "image[1,1;1,2;technic_power_meter_bg.png"
                .."^[lowpart:"..charge_percent
                ..":technic_power_meter_fg.png]")
            local infotext = S("%s Battery Box: %d/%d"):format(tier,
                    current_charge, max_charge)
            if eu_input == 0 then
                infotext = S("%s Idle"):format(infotext)
            end
            meta:set_string("infotext", infotext)
        end
    })
    -- Register as a battery type
    -- Battery type machines function as power reservoirs and can both receive and give back power
technic/machines/register/cables.lua
@@ -59,7 +59,6 @@
    end
end
minetest.register_on_placenode(function(pos, node)
    for tier, machine_list in pairs(technic.machines) do
        if machine_list[node.name] ~= nil then
@@ -78,7 +77,6 @@
        end
    end
end)
function technic.get_cable_id(links)
    return (links[6] * 1) + (links[5] * 2)
@@ -146,7 +144,7 @@
    local box_center = {-size, -size, -size, size,  size, size}
    local box_y1 =     {-size, -size, -size, size,  0.5,  size} -- y+
    local box_x1 =     {-size, -size, -size, 0.5,   size, size} -- x+
    local box_z1 =     {-size, -size,  size, size,  size, 0.5}   -- z+
    local box_z1 =     {-size, -size,  size, size,  size, 0.5}  -- z+
    local box_z2 =     {-size, -size, -0.5,  size,  size, size} -- z-
    local box_y2 =     {-size, -0.5,  -size, size,  size, size} -- y-
    local box_x2 =     {-0.5,  -size, -size, size,  size, size} -- x-
technic/machines/register/generator.lua
@@ -18,8 +18,8 @@
    local tier = data.tier
    local ltier = string.lower(tier)
    local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}
    local active_groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1}
    local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1}
    local active_groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, not_in_creative_inventory=1}
    if data.tube then
        groups.tubedevice = 1
        groups.tubedevice_receiver = 1
@@ -35,6 +35,54 @@
        "list[current_player;main;0,5;8,4;]"
    
    local desc = S("Fuel-Fired %s Generator"):format(tier)
    local run = function(pos, node)
        local meta = minetest.get_meta(pos)
        local burn_time = meta:get_int("burn_time")
        local burn_totaltime = meta:get_int("burn_totaltime")
        -- If more to burn and the energy produced was used: produce some more
        if burn_time > 0 then
            meta:set_int(tier.."_EU_supply", data.supply)
            burn_time = burn_time - 1
            meta:set_int("burn_time", burn_time)
        end
        -- Burn another piece of fuel
        if burn_time == 0 then
            local inv = meta:get_inventory()
            if not inv:is_empty("src") then
                local fuellist = inv:get_list("src")
                local fuel = minetest.get_craft_result(
                        {method = "fuel", width = 1,
                        items = fuellist})
                if not fuel or fuel.time == 0 then
                    meta:set_string("infotext", S("%s Out Of Fuel"):format(desc))
                    technic.swap_node(pos, "technic:"..ltier.."_generator")
                    return
                end
                meta:set_int("burn_time", fuel.time)
                meta:set_int("burn_totaltime", fuel.time)
                local stack = inv:get_stack("src", 1)
                stack:take_item()
                inv:set_stack("src", 1, stack)
                technic.swap_node(pos, "technic:"..ltier.."_generator_active")
                meta:set_int(tier.."_EU_supply", data.supply)
            else
                technic.swap_node(pos, "technic:"..ltier.."_generator")
                meta:set_int(tier.."_EU_supply", 0)
            end
        end
        if burn_totaltime == 0 then burn_totaltime = 1 end
        local percent = math.floor((burn_time / burn_totaltime) * 100)
        meta:set_string("infotext", desc.." ("..percent.."%)")
            meta:set_string("formspec",
                "size[8, 9]"..
                "label[0, 0;"..minetest.formspec_escape(desc).."]"..
                "list[current_name;src;3, 1;1, 1;]"..
                "image[4, 1;1, 1;default_furnace_fire_bg.png^[lowpart:"..
                (percent)..":default_furnace_fire_fg.png]"..
                "list[current_player;main;0, 5;8, 4;]")
    end
    minetest.register_node("technic:"..ltier.."_generator", {
        description = desc,
        tiles = {"technic_"..ltier.."_generator_top.png", "technic_machine_bottom.png",
@@ -59,6 +107,7 @@
        allow_metadata_inventory_put = technic.machine_inventory_put,
        allow_metadata_inventory_take = technic.machine_inventory_take,
        allow_metadata_inventory_move = technic.machine_inventory_move,
        technic_run = run,
    })
    minetest.register_node("technic:"..ltier.."_generator_active", {
@@ -76,58 +125,10 @@
        allow_metadata_inventory_put = technic.machine_inventory_put,
        allow_metadata_inventory_take = technic.machine_inventory_take,
        allow_metadata_inventory_move = technic.machine_inventory_move,
        technic_run = run,
        technic_disabled_machine_name = "technic:"..ltier.."_generator",
    })
    minetest.register_abm({
        nodenames = {"technic:"..ltier.."_generator", "technic:"..ltier.."_generator_active"},
        interval = 1,
        chance = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            local meta = minetest.get_meta(pos)
            local burn_time = meta:get_int("burn_time")
            local burn_totaltime = meta:get_int("burn_totaltime")
            -- If more to burn and the energy produced was used: produce some more
            if burn_time > 0 then
                meta:set_int(tier.."_EU_supply", data.supply)
                burn_time = burn_time - 1
                meta:set_int("burn_time", burn_time)
            end
            -- Burn another piece of fuel
            if burn_time == 0 then
                local inv = meta:get_inventory()
                if not inv:is_empty("src") then
                    local fuellist = inv:get_list("src")
                    local fuel = minetest.get_craft_result(
                            {method = "fuel", width = 1,
                            items = fuellist})
                    if not fuel or fuel.time == 0 then
                        meta:set_string("infotext", S("%s Out Of Fuel"):format(desc))
                        technic.swap_node(pos, "technic:"..ltier.."_generator")
                        return
                    end
                    meta:set_int("burn_time", fuel.time)
                    meta:set_int("burn_totaltime", fuel.time)
                    local stack = inv:get_stack("src", 1)
                    stack:take_item()
                    inv:set_stack("src", 1, stack)
                    technic.swap_node(pos, "technic:"..ltier.."_generator_active")
                    meta:set_int(tier.."_EU_supply", data.supply)
                else
                    technic.swap_node(pos, "technic:"..ltier.."_generator")
                    meta:set_int(tier.."_EU_supply", 0)
                end
            end
            if burn_totaltime == 0 then burn_totaltime = 1 end
            local percent = math.floor((burn_time / burn_totaltime) * 100)
            meta:set_string("infotext", desc.." ("..percent.."%)")
                meta:set_string("formspec",
                    "size[8, 9]"..
                    "label[0, 0;"..minetest.formspec_escape(desc).."]"..
                    "list[current_name;src;3, 1;1, 1;]"..
                    "image[4, 1;1, 1;default_furnace_fire_bg.png^[lowpart:"..
                    (percent)..":default_furnace_fire_fg.png]"..
                    "list[current_player;main;0, 5;8, 4;]")
        end
    })
    technic.register_machine(tier, "technic:"..ltier.."_generator",        technic.producer)
    technic.register_machine(tier, "technic:"..ltier.."_generator_active", technic.producer)
end
technic/machines/register/machine_base.lua
@@ -23,8 +23,8 @@
    local tier = data.tier
    local ltier = string.lower(tier)
    local groups = {cracky = 2}
    local active_groups = {cracky = 2, not_in_creative_inventory = 1}
    local groups = {cracky = 2, technic_machine = 1}
    local active_groups = {cracky = 2, technic_machine = 1, not_in_creative_inventory = 1}
    if data.tube then
        groups.tubedevice = 1
        groups.tubedevice_receiver = 1
@@ -46,6 +46,61 @@
            "label[1,4;"..S("Upgrade Slots").."]"
    end
    local run = function(pos, node)
        local meta     = minetest.get_meta(pos)
        local inv      = meta:get_inventory()
        local eu_input = meta:get_int(tier.."_EU_input")
        local machine_desc_tier = machine_desc:format(tier)
        local machine_node      = "technic:"..ltier.."_"..machine_name
        local machine_demand    = data.demand
        -- Setup meta data if it does not exist.
        if not eu_input then
            meta:set_int(tier.."_EU_demand", machine_demand[1])
            meta:set_int(tier.."_EU_input", 0)
            return
        end
        local EU_upgrade, tube_upgrade = 0, 0
        if data.upgrade then
            EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
        end
        if data.tube then
            technic.handle_machine_pipeworks(pos, tube_upgrade)
        end
        local result = technic.get_recipe(typename, inv:get_list("src"))
        if not result then
            technic.swap_node(pos, machine_node)
            meta:set_string("infotext", S("%s Idle"):format(machine_desc_tier))
            meta:set_int(tier.."_EU_demand", 0)
            return
        end
        if eu_input < machine_demand[EU_upgrade+1] then
            -- Unpowered - go idle
            technic.swap_node(pos, machine_node)
            meta:set_string("infotext", S("%s Unpowered"):format(machine_desc_tier))
        elseif eu_input >= machine_demand[EU_upgrade+1] then
            -- Powered
            technic.swap_node(pos, machine_node.."_active")
            meta:set_string("infotext", S("%s Active"):format(machine_desc_tier))
            meta:set_int("src_time", meta:get_int("src_time") + 1)
            if meta:get_int("src_time") >= result.time / data.speed then
                meta:set_int("src_time", 0)
                local result_stack = ItemStack(result.output)
                if inv:room_for_item("dst", result_stack) then
                    inv:set_list("src", result.new_input)
                    inv:add_item("dst", result_stack)
                end
            end
        end
        meta:set_int(tier.."_EU_demand", machine_demand[EU_upgrade+1])
    end
    minetest.register_node("technic:"..ltier.."_"..machine_name, {
        description = machine_desc:format(tier),
        tiles = {"technic_"..ltier.."_"..machine_name.."_top.png", 
@@ -75,6 +130,7 @@
        allow_metadata_inventory_put = technic.machine_inventory_put,
        allow_metadata_inventory_take = technic.machine_inventory_take,
        allow_metadata_inventory_move = technic.machine_inventory_move,
        technic_run = run,
    })
    minetest.register_node("technic:"..ltier.."_"..machine_name.."_active",{
@@ -95,70 +151,8 @@
        allow_metadata_inventory_put = technic.machine_inventory_put,
        allow_metadata_inventory_take = technic.machine_inventory_take,
        allow_metadata_inventory_move = technic.machine_inventory_move,
    })
    minetest.register_abm({
        nodenames = {"technic:"..ltier.."_"..machine_name,
                     "technic:"..ltier.."_"..machine_name.."_active"},
        interval = 1,
        chance   = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            local meta     = minetest.get_meta(pos)
            local inv      = meta:get_inventory()
            local eu_input = meta:get_int(tier.."_EU_input")
            local machine_desc_tier = machine_desc:format(tier)
            local machine_node      = "technic:"..ltier.."_"..machine_name
            local machine_demand    = data.demand
            -- Setup meta data if it does not exist.
            if not eu_input then
                meta:set_int(tier.."_EU_demand", machine_demand[1])
                meta:set_int(tier.."_EU_input", 0)
                return
            end
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, tier)
            local EU_upgrade, tube_upgrade = 0, 0
            if data.upgrade then
                EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
            end
            if data.tube then
                technic.handle_machine_pipeworks(pos, tube_upgrade)
            end
            local result = technic.get_recipe(typename, inv:get_list("src"))
            if not result then
                technic.swap_node(pos, machine_node)
                meta:set_string("infotext", S("%s Idle"):format(machine_desc_tier))
                meta:set_int(tier.."_EU_demand", 0)
                return
            end
            if eu_input < machine_demand[EU_upgrade+1] then
                -- Unpowered - go idle
                technic.swap_node(pos, machine_node)
                meta:set_string("infotext", S("%s Unpowered"):format(machine_desc_tier))
            elseif eu_input >= machine_demand[EU_upgrade+1] then
                -- Powered
                technic.swap_node(pos, machine_node.."_active")
                meta:set_string("infotext", S("%s Active"):format(machine_desc_tier))
                meta:set_int("src_time", meta:get_int("src_time") + 1)
                if meta:get_int("src_time") >= result.time / data.speed then
                    meta:set_int("src_time", 0)
                    local result_stack = ItemStack(result.output)
                    if inv:room_for_item("dst", result_stack) then
                        inv:set_list("src", result.new_input)
                        inv:add_item("dst", result_stack)
                    end
                end
            end
            meta:set_int(tier.."_EU_demand", machine_demand[EU_upgrade+1])
        end
        technic_run = run,
        technic_disabled_machine_name = "technic:"..ltier.."_"..machine_name,
    })
    technic.register_machine(tier, "technic:"..ltier.."_"..machine_name,            technic.receiver)
technic/machines/register/solar_array.lua
@@ -5,11 +5,42 @@
    local tier = data.tier
    local ltier = string.lower(tier)
    local run = function(pos, node)
        -- The action here is to make the solar array produce power
        -- Power is dependent on the light level and the height above ground
        -- There are many ways to cheat by using other light sources like lamps.
        -- As there is no way to determine if light is sunlight that is just a shame.
        -- To take care of some of it solar panels do not work outside daylight hours or if
        -- built below 0m
        local pos1 = {}
        local machine_name = S("Arrayed Solar %s Generator"):format(tier)
        pos1.y = pos.y + 1
        pos1.x = pos.x
        pos1.z = pos.z
        local light = minetest.get_node_light(pos1, nil)
        local time_of_day = minetest.get_timeofday()
        local meta = minetest.get_meta(pos)
        light = light or 0
        -- turn on array only during day time and if sufficient light
        -- I know this is counter intuitive when cheating by using other light sources.
        if light >= 12 and time_of_day >= 0.24 and time_of_day <= 0.76 and pos.y > 0 then
            local charge_to_give = math.floor((light + pos.y) * data.power)
            charge_to_give = math.max(charge_to_give, 0)
            charge_to_give = math.min(charge_to_give, data.power * 50)
            meta:set_string("infotext", S("%s Active"):format(machine_name).." ("..charge_to_give.."EU)")
            meta:set_int(tier.."_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", S("%s Idle"):format(machine_name))
            meta:set_int(tier.."_EU_supply", 0)
        end
    end
    minetest.register_node("technic:solar_array_"..ltier, {
        tiles = {"technic_"..ltier.."_solar_array_top.png",  "technic_"..ltier.."_solar_array_bottom.png",
             "technic_"..ltier.."_solar_array_side.png", "technic_"..ltier.."_solar_array_side.png",
             "technic_"..ltier.."_solar_array_side.png", "technic_"..ltier.."_solar_array_side.png"},
        groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
        groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
        sounds = default.node_sound_wood_defaults(),
        description = S("Arrayed Solar %s Generator"):format(tier),
        active = false,
@@ -24,45 +55,7 @@
            local name = minetest.get_node(pos).name
            meta:set_int(tier.."_EU_supply", 0)
        end,
    })
    minetest.register_abm({
        nodenames = {"technic:solar_array_"..ltier},
        interval = 1,
        chance = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            -- The action here is to make the solar array produce power
            -- Power is dependent on the light level and the height above ground
            -- 130m and above is optimal as it would be above cloud level.
            -- Height gives 1/4 of the effect, light 3/4. Max. effect is 2880EU for the array.
            -- There are many ways to cheat by using other light sources like lamps.
            -- As there is no way to determine if light is sunlight that is just a shame.
            -- To take care of some of it solar panels do not work outside daylight hours or if
            -- built below -10m
            local pos1 = {}
            local machine_name = S("Arrayed Solar %s Generator"):format(tier)
            pos1.y = pos.y + 1
            pos1.x = pos.x
            pos1.z = pos.z
            local light = minetest.get_node_light(pos1, nil)
            local time_of_day = minetest.get_timeofday()
            local meta = minetest.get_meta(pos)
            light = light or 0
            -- turn on array only during day time and if sufficient light
            -- I know this is counter intuitive when cheating by using other light sources.
            if light >= 12 and time_of_day >= 0.24 and time_of_day <= 0.76 and pos.y > 0 then
                local charge_to_give = math.floor((light + pos.y) * data.power)
                charge_to_give = math.max(charge_to_give, 0)
                charge_to_give = math.min(charge_to_give, data.power * 50)
                meta:set_string("infotext", S("%s Active"):format(machine_name).." ("..charge_to_give.."EU)")
                meta:set_int(tier.."_EU_supply", charge_to_give)
            else
                meta:set_string("infotext", S("%s Idle"):format(machine_name))
                meta:set_int(tier.."_EU_supply", 0)
            end
        end,
        technic_run = run,
    })
    technic.register_machine(tier, "technic:solar_array_"..ltier, technic.producer)
technic/machines/supply_converter.lua
@@ -9,12 +9,44 @@
local S = technic.getter
local run = function(pos, node)
    local demand = 10000
    local remain = 0.9
    -- Machine information
    local machine_name  = S("Supply Converter")
    local meta          = minetest.get_meta(pos)
    local pos_up        = {x=pos.x, y=pos.y+1, z=pos.z}
    local pos_down      = {x=pos.x, y=pos.y-1, z=pos.z}
    local name_up       = minetest.get_node(pos_up).name
    local name_down     = minetest.get_node(pos_down).name
    local from = technic.get_cable_tier(name_up)
    local to   = technic.get_cable_tier(name_down)
    if from and to then
        technic.switching_station_timeout_count(pos, from)
        local input = meta:get_int(from.."_EU_input")
        meta:set_int(from.."_EU_demand", demand)
        meta:set_int(from.."_EU_supply", 0)
        meta:set_int(to.."_EU_demand", 0)
        meta:set_int(to.."_EU_supply", input * remain)
        meta:set_string("infotext", machine_name
            .." ("..input.." "..from.." -> "
            ..input * remain.." "..to..")")
    else
        meta:set_string("infotext", S("%s Has Bad Cabling"):format(machine_name))
        return
    end
end
minetest.register_node("technic:supply_converter", {
    description = S("Supply Converter"),
    tiles  = {"technic_supply_converter_top.png", "technic_supply_converter_bottom.png",
              "technic_supply_converter_side.png", "technic_supply_converter_side.png",
              "technic_supply_converter_side.png", "technic_supply_converter_side.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
    sounds = default.node_sound_wood_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
@@ -27,6 +59,7 @@
        meta:set_string("infotext", S("Supply Converter"))
        meta:set_float("active", false)
    end,
    technic_run = run,
})
minetest.register_craft({
@@ -36,43 +69,6 @@
        {'technic:mv_transformer',        'technic:machine_casing', 'technic:lv_transformer'},
        {'technic:mv_cable0',             'technic:rubber',         'technic:lv_cable0'},
    }
})
minetest.register_abm({
    nodenames = {"technic:supply_converter"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local demand = 10000
        local remain = 0.9
        -- Machine information
        local machine_name  = S("Supply Converter")
        local meta          = minetest.get_meta(pos)
        local pos_up        = {x=pos.x, y=pos.y+1, z=pos.z}
        local pos_down      = {x=pos.x, y=pos.y-1, z=pos.z}
        local name_up       = minetest.get_node(pos_up).name
        local name_down     = minetest.get_node(pos_down).name
        local from = technic.get_cable_tier(name_up)
        local to   = technic.get_cable_tier(name_down)
        if from and to then
            technic.switching_station_timeout_count(pos, from)
            local input = meta:get_int(from.."_EU_input")
            meta:set_int(from.."_EU_demand", demand)
            meta:set_int(from.."_EU_supply", 0)
            meta:set_int(to.."_EU_demand", 0)
            meta:set_int(to.."_EU_supply", input * remain)
            meta:set_string("infotext", machine_name
                .." ("..input.." "..from.." -> "
                ..input * remain.." "..to..")")
        else
            meta:set_string("infotext", S("%s Has Bad Cabling"):format(machine_name))
            return
        end
    end,
})
for tier, machines in pairs(technic.machines) do
technic/machines/switching_station.lua
@@ -57,23 +57,9 @@
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", S("Switching Station"))
        meta:set_string("active", 1)
    end,
})
--------------------------------------------------
-- Functions to help the machines on the electrical network
--------------------------------------------------
-- This one provides a timeout for a node in case it was disconnected from the network
-- A node must be touched by the station continuously in order to function
function technic.switching_station_timeout_count(pos, tier)
    local meta = minetest.get_meta(pos)
    local timeout = meta:get_int(tier.."_EU_timeout")
    if timeout == 0 then
        meta:set_int(tier.."_EU_input", 0)
    else
        meta:set_int(tier.."_EU_timeout", timeout - 1)
    end
end
--------------------------------------------------
-- Functions to traverse the electrical network
@@ -93,8 +79,14 @@
    return true
end
local load_position = function(pos)
    local vm = VoxelManip()
    local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
end
-- Generic function to add found connected nodes to the right classification array
local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, all_nodes, pos, machines, tier)
local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos)
    load_position(pos)
    local meta = minetest.get_meta(pos)
    local name = minetest.get_node(pos).name
@@ -109,6 +101,12 @@
        elseif machines[name] == technic.producer_receiver then
            add_new_cable_node(PR_nodes, pos)
            add_new_cable_node(RE_nodes, pos)
        elseif machines[name] == "SPECIAL" and
                (pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) then
            -- Another switching station -> disable it
            add_new_cable_node(SP_nodes, pos)
            meta:set_int("active", 0)
            meta:set_string("active_pos", minetest.serialize(sw_pos))
        elseif machines[name] == technic.battery then
            add_new_cable_node(BA_nodes, pos)
        end
@@ -118,7 +116,7 @@
end
-- Traverse a network given a list of machines and a cable type name
local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, all_nodes, i, machines, tier)
local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, i, machines, tier, sw_pos)
    local pos = all_nodes[i]
    local positions = {
        {x=pos.x+1, y=pos.y,   z=pos.z},
@@ -129,7 +127,7 @@
        {x=pos.x,   y=pos.y,   z=pos.z-1}}
    --print("ON")
    for i, cur_pos in pairs(positions) do
        check_node_subp(PR_nodes, RE_nodes, BA_nodes, all_nodes, cur_pos, machines, tier)
        check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, cur_pos, machines, tier, sw_pos)
    end
end
@@ -140,25 +138,32 @@
    end
end
local get_network = function(pos1, tier)
local get_network = function(sw_pos, pos1, tier)
    local cached = technic.networks[minetest.hash_node_position(pos1)]
    if cached and cached.tier == tier then
        touch_nodes(cached.PR_nodes, tier)
        touch_nodes(cached.BA_nodes, tier)
        touch_nodes(cached.RE_nodes, tier)
        for _, pos in ipairs(cached.SP_nodes) do
            local meta = minetest.get_meta(pos)
            meta:set_int("active", 0)
            meta:set_string("active_pos", minetest.serialize(sw_pos))
        end
        return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes
    end
    local i = 1
    local PR_nodes = {}
    local BA_nodes = {}
    local RE_nodes = {}
    local SP_nodes = {}
    local all_nodes = {pos1}
    repeat
        traverse_network(PR_nodes, RE_nodes, BA_nodes, all_nodes,
                i, technic.machines[tier], tier)
        traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes,
                i, technic.machines[tier], tier, sw_pos)
        i = i + 1
    until all_nodes[i] == nil
    technic.networks[minetest.hash_node_position(pos1)] = {tier = tier, PR_nodes = PR_nodes, RE_nodes = RE_nodes, BA_nodes = BA_nodes}
    technic.networks[minetest.hash_node_position(pos1)] = {tier = tier, PR_nodes = PR_nodes,
            RE_nodes = RE_nodes, BA_nodes = BA_nodes, SP_nodes = SP_nodes}
    return PR_nodes, BA_nodes, RE_nodes
end
@@ -184,22 +189,47 @@
        local RE_nodes
        local machine_name = S("Switching Station")
        if meta:get_int("active") ~= 1 then
            meta:set_int("active", 1)
            local active_pos = minetest.deserialize(meta:get_string("active_pos"))
            if active_pos then
                local meta1 = minetest.get_meta(active_pos)
                meta:set_string("infotext", S("%s (Slave)"):format(meta1:get_string("infotext")))
            end
            return
        end
        -- Which kind of network are we on:
        pos1 = {x=pos.x, y=pos.y-1, z=pos.z}
        local name = minetest.get_node(pos1).name
        local tier = technic.get_cable_tier(name)
        if tier then
            PR_nodes, BA_nodes, RE_nodes = get_network(pos1, tier)
            PR_nodes, BA_nodes, RE_nodes = get_network(pos, pos1, tier)
        else
            --dprint("Not connected to a network")
            meta:set_string("infotext", S("%s Has No Network"):format(machine_name))
            return
        end
        --dprint("nodes="..table.getn(all_nodes)
        --        .." PR="..table.getn(PR_nodes)
        --        .." BA="..table.getn(BA_nodes)
        --        .." RE="..table.getn(RE_nodes))
        -- Run all the nodes
        local function run_nodes(list)
            for _, pos2 in ipairs(list) do
                load_position(pos2)
                local node2 = minetest.get_node(pos2)
                local nodedef
                if node2 and node2.name then
                    nodedef = minetest.registered_nodes[node2.name]
                end
                if nodedef and nodedef.technic_run then
                    nodedef.technic_run(pos2, node2)
                end
            end
        end
        run_nodes(PR_nodes)
        run_nodes(RE_nodes)
        run_nodes(BA_nodes)
        -- Strings for the meta data
        local eu_demand_str    = tier.."_EU_demand"
@@ -306,6 +336,42 @@
    end,
})
-- Timeout ABM
-- Timeout for a node in case it was disconnected from the network
-- A node must be touched by the station continuously in order to function
local function switching_station_timeout_count(pos, tier)
    local meta = minetest.get_meta(pos)
    local timeout = meta:get_int(tier.."_EU_timeout")
    if timeout <= 0 then
        --meta:set_int(tier.."_EU_input", 0) -- Not needed anymore
        return true
    else
        meta:set_int(tier.."_EU_timeout", timeout - 1)
        return false
    end
end
minetest.register_abm({
    nodenames = {"group:technic_machine"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        for tier, machines in pairs(technic.machines) do
            if machines[node.name] and switching_station_timeout_count(pos, tier) then
                local nodedef = minetest.registered_nodes[node.name]
                if nodedef and nodedef.technic_disabled_machine_name then
                    print(nodedef.technic_disabled_machine_name)
                    node.name = nodedef.technic_disabled_machine_name
                    minetest.swap_node(pos, node)
                end
                if nodedef then
                    local meta = minetest.get_meta(pos)
                    meta:set_string("infotext", S("%s Has No Network"):format(nodedef.description))
                end
            end
        end
    end,
})
for tier, machines in pairs(technic.machines) do
    -- SPECIAL will not be traversed
    technic.register_machine(tier, "technic:switching_station", "SPECIAL")