ShadowNinja
2013-07-17 ee0765804c0a21deeb2f33c22ac1a36cb0db5f43
Partial rewrite
35 files deleted
49 files added
23 files modified
17 files renamed
14134 ■■■■■ changed files
concrete/init.lua 622 ●●●● patch | view | raw | blame | history
item_drop/init.lua 39 ●●●● patch | view | raw | blame | history
technic/config.lua 38 ●●●● patch | view | raw | blame | history
technic/crafts.lua 169 ●●●●● patch | view | raw | blame | history
technic/depends.txt 2 ●●● patch | view | raw | blame | history
technic/init.lua 60 ●●●●● patch | view | raw | blame | history
technic/items.lua 239 ●●●● patch | view | raw | blame | history
technic/legacy.lua 30 ●●●●● patch | view | raw | blame | history
technic/machines/HV/battery_box.lua 19 ●●●●● patch | view | raw | blame | history
technic/machines/HV/cables.lua 12 ●●●●● patch | view | raw | blame | history
technic/machines/HV/forcefield.lua 206 ●●●●● patch | view | raw | blame | history
technic/machines/HV/init.lua 12 ●●●●● patch | view | raw | blame | history
technic/machines/HV/nuclear_reactor.lua 259 ●●●●● patch | view | raw | blame | history
technic/machines/HV/quarry.lua 200 ●●●●● patch | view | raw | blame | history
technic/machines/HV/solar_array.lua 14 ●●●●● patch | view | raw | blame | history
technic/machines/LV/alloy_furnace.lua 14 ●●●●● patch | view | raw | blame | history
technic/machines/LV/battery_box.lua 46 ●●●●● patch | view | raw | blame | history
technic/machines/LV/cables.lua 12 ●●●●● patch | view | raw | blame | history
technic/machines/LV/cnc.lua 254 ●●●●● patch | view | raw | blame | history
technic/machines/LV/cnc_api.lua 354 ●●●●● patch | view | raw | blame | history
technic/machines/LV/cnc_nodes.lua 71 ●●●●● patch | view | raw | blame | history
technic/machines/LV/coal_alloy_furnace.lua 181 ●●●●● patch | view | raw | blame | history
technic/machines/LV/compressor.lua 169 ●●●●● patch | view | raw | blame | history
technic/machines/LV/electric_furnace.lua 16 ●●●●● patch | view | raw | blame | history
technic/machines/LV/extractor.lua 175 ●●●●● patch | view | raw | blame | history
technic/machines/LV/generator.lua 139 ●●●●● patch | view | raw | blame | history
technic/machines/LV/geothermal.lua 123 ●●●●● patch | view | raw | blame | history
technic/machines/LV/grinder.lua 13 ●●●●● patch | view | raw | blame | history
technic/machines/LV/init.lua 10 ●●●● patch | view | raw | blame | history
technic/machines/LV/music_player.lua 138 ●●●●● patch | view | raw | blame | history
technic/machines/LV/solar_array.lua 18 ●●●●● patch | view | raw | blame | history
technic/machines/LV/solar_panel.lua 70 ●●●●● patch | view | raw | blame | history
technic/machines/LV/water_mill.lua 101 ●●●●● patch | view | raw | blame | history
technic/machines/MV/alloy_furnace.lua 14 ●●●●● patch | view | raw | blame | history
technic/machines/MV/battery_box.lua 20 ●●●●● patch | view | raw | blame | history
technic/machines/MV/cables.lua 14 ●●●●● patch | view | raw | blame | history
technic/machines/MV/electric_furnace.lua 18 ●●●●● patch | view | raw | blame | history
technic/machines/MV/grinder.lua 13 ●●●●● patch | view | raw | blame | history
technic/machines/MV/init.lua 15 ●●●●● patch | view | raw | blame | history
technic/machines/MV/lighting.lua 38 ●●●● patch | view | raw | blame | history
technic/machines/MV/power_radiator.lua 220 ●●●●● patch | view | raw | blame | history
technic/machines/MV/solar_array.lua 12 ●●●●● patch | view | raw | blame | history
technic/machines/MV/tool_workshop.lua 90 ●●●●● patch | view | raw | blame | history
technic/machines/MV/wind_mill.lua 88 ●●●●● patch | view | raw | blame | history
technic/machines/alloy_furnaces_commons.lua 85 ●●●●● patch | view | raw | blame | history
technic/machines/battery_boxes_commons.lua 80 ●●●●● patch | view | raw | blame | history
technic/machines/grinder_gloopores.lua 55 ●●●●● patch | view | raw | blame | history
technic/machines/hv/battery_box.lua 157 ●●●●● patch | view | raw | blame | history
technic/machines/hv/forcefield.lua 228 ●●●●● patch | view | raw | blame | history
technic/machines/hv/init.lua 8 ●●●●● patch | view | raw | blame | history
technic/machines/hv/nuclear_reactor.lua 245 ●●●●● patch | view | raw | blame | history
technic/machines/hv/solar_array.lua 78 ●●●●● patch | view | raw | blame | history
technic/machines/hv/wires.lua 398 ●●●●● patch | view | raw | blame | history
technic/machines/init.lua 13 ●●●●● patch | view | raw | blame | history
technic/machines/lv/alloy_furnace.lua 367 ●●●●● patch | view | raw | blame | history
technic/machines/lv/battery_box.lua 188 ●●●●● patch | view | raw | blame | history
technic/machines/lv/cnc.lua 293 ●●●●● patch | view | raw | blame | history
technic/machines/lv/cnc_api.lua 372 ●●●●● patch | view | raw | blame | history
technic/machines/lv/cnc_nodes.lua 70 ●●●●● patch | view | raw | blame | history
technic/machines/lv/compressor.lua 207 ●●●●● patch | view | raw | blame | history
technic/machines/lv/electric_furnace.lua 160 ●●●●● patch | view | raw | blame | history
technic/machines/lv/extractor.lua 220 ●●●●● patch | view | raw | blame | history
technic/machines/lv/generator.lua 150 ●●●●● patch | view | raw | blame | history
technic/machines/lv/geothermal.lua 156 ●●●●● patch | view | raw | blame | history
technic/machines/lv/grinder.lua 352 ●●●●● patch | view | raw | blame | history
technic/machines/lv/music_player.lua 156 ●●●●● patch | view | raw | blame | history
technic/machines/lv/solar_array.lua 78 ●●●●● patch | view | raw | blame | history
technic/machines/lv/solar_panel.lua 78 ●●●●● patch | view | raw | blame | history
technic/machines/lv/tool_workshop.lua 122 ●●●●● patch | view | raw | blame | history
technic/machines/lv/water_mill.lua 122 ●●●●● patch | view | raw | blame | history
technic/machines/lv/wires.lua 401 ●●●●● patch | view | raw | blame | history
technic/machines/mv/alloy_furnace.lua 460 ●●●●● patch | view | raw | blame | history
technic/machines/mv/battery_box.lua 152 ●●●●● patch | view | raw | blame | history
technic/machines/mv/electric_furnace.lua 305 ●●●●● patch | view | raw | blame | history
technic/machines/mv/grinder.lua 293 ●●●●● patch | view | raw | blame | history
technic/machines/mv/power_radiator.lua 226 ●●●●● patch | view | raw | blame | history
technic/machines/mv/solar_array.lua 82 ●●●●● patch | view | raw | blame | history
technic/machines/mv/wires.lua 400 ●●●●● patch | view | raw | blame | history
technic/machines/other/constructor.lua 38 ●●●● patch | view | raw | blame | history
technic/machines/register/alloy_furnace.lua 284 ●●●●● patch | view | raw | blame | history
technic/machines/register/battery_box.lua 216 ●●●●● patch | view | raw | blame | history
technic/machines/register/cables.lua 170 ●●●●● patch | view | raw | blame | history
technic/machines/register/common.lua 111 ●●●●● patch | view | raw | blame | history
technic/machines/register/electric_furnace.lua 203 ●●●●● patch | view | raw | blame | history
technic/machines/register/grinder.lua 184 ●●●●● patch | view | raw | blame | history
technic/machines/register/grinder_recipes.lua 94 ●●●●● patch | view | raw | blame | history
technic/machines/register/init.lua 11 ●●●●● patch | view | raw | blame | history
technic/machines/register/solar_array.lua 69 ●●●●● patch | view | raw | blame | history
technic/machines/supply_converter.lua 273 ●●●● patch | view | raw | blame | history
technic/machines/switching_station.lua 501 ●●●●● patch | view | raw | blame | history
technic/register.lua 48 ●●●●● patch | view | raw | blame | history
technic/register_machine_and_tool.lua 63 ●●●●● patch | view | raw | blame | history
technic/rubber.lua 123 ●●●●● patch | view | raw | blame | history
technic/textures/technic_hv_battery_box_side.png patch | view | raw | blame | history
technic/textures/technic_lv_alloy_furnace_bottom.png patch | view | raw | blame | history
technic/textures/technic_lv_alloy_furnace_front.png patch | view | raw | blame | history
technic/textures/technic_lv_alloy_furnace_front_active.png patch | view | raw | blame | history
technic/textures/technic_lv_alloy_furnace_side.png patch | view | raw | blame | history
technic/textures/technic_lv_alloy_furnace_top.png patch | view | raw | blame | history
technic/textures/technic_lv_battery_box_bottom.png patch | view | raw | blame | history
technic/textures/technic_lv_battery_box_side.png patch | view | raw | blame | history
technic/textures/technic_lv_battery_box_top.png patch | view | raw | blame | history
technic/textures/technic_lv_electric_furnace_bottom.png patch | view | raw | blame | history
technic/textures/technic_lv_electric_furnace_front.png patch | view | raw | blame | history
technic/textures/technic_lv_electric_furnace_front_active.png patch | view | raw | blame | history
technic/textures/technic_lv_electric_furnace_side.png patch | view | raw | blame | history
technic/textures/technic_lv_electric_furnace_top.png patch | view | raw | blame | history
technic/textures/technic_mv_battery_box_side.png patch | view | raw | blame | history
technic/textures/technic_power_meter0.png patch | view | raw | blame | history
technic/textures/technic_uranium_fuel.png patch | view | raw | blame | history
technic/tools/chainsaw.lua 17 ●●●● patch | view | raw | blame | history
technic/tools/flashlight.lua 131 ●●●● patch | view | raw | blame | history
technic/tools/init.lua 6 ●●●● patch | view | raw | blame | history
technic/tools/mining_drill.lua 81 ●●●● patch | view | raw | blame | history
technic/tools/mining_laser_mk1.lua 4 ●●●● patch | view | raw | blame | history
technic/tools/sonic_screwdriver.lua 4 ●●●● patch | view | raw | blame | history
technic/tools/tree_tap.lua 104 ●●●● patch | view | raw | blame | history
technic_worldgen/crafts.lua 99 ●●●● patch | view | raw | blame | history
technic_worldgen/init.lua 10 ●●●● patch | view | raw | blame | history
technic_worldgen/oregen.lua 8 ●●●● patch | view | raw | blame | history
technic_worldgen/rubber.lua 104 ●●●●● patch | view | raw | blame | history
unified_inventory/api.lua 8 ●●●●● patch | view | raw | blame | history
unified_inventory/bags.lua 44 ●●●● patch | view | raw | blame | history
unified_inventory/depends.txt 2 ●●● patch | view | raw | blame | history
concrete/init.lua
@@ -1,6 +1,15 @@
--Minetest 0.4.7 mod: concrete 
--(c) 2013 by RealBadAngel <mk@realbadangel.pl>
local technic = technic or {}
technic.concrete_posts = {}
minetest.register_alias("technic:concrete_post",   "technic:concrete_post0")
minetest.register_alias("technic:concrete_post32", "technic:concrete_post12")
minetest.register_alias("technic:concrete_post33", "technic:concrete_post3")
minetest.register_alias("technic:concrete_post34", "technic:concrete_post28")
minetest.register_alias("technic:concrete_post35", "technic:concrete_post19")
minetest.register_craft({
    output = 'technic:rebar 6',
    recipe = {
@@ -22,12 +31,12 @@
minetest.register_craft({
    output = 'technic:concrete_post_platform 6',
    recipe = {
        {'technic:concrete','technic:concrete_post','technic:concrete'},
        {'technic:concrete','technic:concrete_post0','technic:concrete'},
    }
})
minetest.register_craft({
    output = 'technic:concrete_post 12',
    output = 'technic:concrete_post0 12',
    recipe = {
        {'default:stone','technic:rebar','default:stone'},
        {'default:stone','technic:rebar','default:stone'},
@@ -44,500 +53,195 @@
    }
})
platform_box = {-0.5 , 0.3 , -0.5 , 0.5 ,  0.5 , 0.5  }
post_str_y={ -0.15 , -0.5 , -0.15 , 0.15 ,  0.5 , 0.15  }
post_str_x1={ 0 , -0.3 , -0.1, 0.5 ,  0.3 , 0.1 }  -- x+
post_str_z1={ -0.1 , -0.3 , 0, 0.1 ,  0.3 , 0.5 } -- z+
post_str_x2={ 0 , -0.3 , -0.1, -0.5 ,  0.3 , 0.1 } -- x-
post_str_z2={ -0.1 , -0.3 , 0, 0.1 ,  0.3 , -0.5 } -- z-
local box_platform = {-0.5,  0.3,  -0.5,  0.5,  0.5, 0.5}
local box_center   = {-0.15, -0.5, -0.15, 0.15, 0.5, 0.15}
local box_x1       = {0,     -0.3, -0.1,  0.5,  0.3, 0.1}
local box_z1       = {-0.1,  -0.3, 0,     0.1,  0.3, 0.5}
local box_x2       = {0,     -0.3, -0.1,  -0.5, 0.3, 0.1}
local box_z2       = {-0.1,  -0.3, 0,     0.1,  0.3, -0.5}
minetest.register_craftitem(":technic:rebar", {
    description = "Rebar",
    inventory_image = "technic_rebar.png",
    stack_max = 99,
})
minetest.register_craftitem(":technic:blast_resistant_concrete", {
    description = "Blast-resistant Concrete Block",
    inventory_image = "technic_blast_resistant_concrete_block.png",
    stack_max = 99,
})
minetest.register_craftitem(":technic:concrete", {
    description = "Concrete Block",
    inventory_image = "technic_concrete_block.png",
    stack_max = 99,
})
minetest.register_craftitem(":technic:concrete_post", {
    description = "Concrete Post",
    stack_max = 99,
})
minetest.register_craftitem(":technic:concrete_post_platform", {
    description = "Concrete Post Platform",
    stack_max = 99,
})
minetest.register_node(":technic:concrete", {
    description = "Concrete Block",
    tile_images = {"technic_concrete_block.png",},
    is_ground_content = true,
    groups={cracky=1,level=2},
    groups = {cracky=1, level=2, concrete=1},
    sounds = default.node_sound_stone_defaults(),
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    on_construct = function(pos)
        meta=minetest.env:get_meta(pos)
        meta:set_float("postlike",1)
        check_post_connections (pos,1)
    after_place_node = function(pos, placer, itemstack)
        technic.update_posts(pos, false)
    end,
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        check_post_connections  (pos,0)
        technic.update_posts(pos, false)
    end,
})
minetest.register_node(":technic:blast_resistant_concrete", {
    description = "Blast-resistant Concrete Block",
    tile_images = {"technic_blast_resistant_concrete_block.png",},
    is_ground_content = true,
    groups={cracky=1,level=3},
    groups={cracky=1, level=3, concrete=1},
    sounds = default.node_sound_stone_defaults(),
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    on_construct = function(pos)
        meta=minetest.env:get_meta(pos)
        meta:set_float("postlike",1)
        check_post_connections (pos,1)
    after_place_node = function(pos, player, itemstack)
        technic.update_posts(pos, false)
    end,
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        check_post_connections  (pos,0)
        technic.update_posts(pos, false)
    end,
})
minetest.register_node(":technic:concrete_post_platform", {
    description = "Concrete Post Platform",
    tile_images = {"technic_concrete_block.png",},
    is_ground_content = true,
    groups={cracky=1,level=2},
    groups={cracky=1, level=2},
    sounds = default.node_sound_stone_defaults(),
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox", 
    selection_box = {
        type = "fixed",
        fixed = {platform_box}
        },
    node_box = {
        type = "fixed",
        fixed = {platform_box}
        },
    on_place=function (itemstack, placer, pointed_thing)
    local node=minetest.env:get_node(pointed_thing.under)
    if minetest.get_item_group(node.name, "concrete_post")==0 then
        return minetest.item_place_node(itemstack, placer, pointed_thing)
        fixed = {box_platform}
    },
    on_place = function (itemstack, placer, pointed_thing)
        local node = minetest.get_node(pointed_thing.under)
        if not technic.concrete_posts[node.name] then
            return minetest.item_place_node(itemstack, placer, pointed_thing)
        end
        local links = technic.concrete_posts[node.name]
        if links[5] ~= 0 then -- The post already has a platform
            return minetest.item_place_node(itemstack, placer, pointed_thing)
        end
        local id = technic.get_post_id({links[1], links[2], links[3], links[4], 1})
        minetest.set_node(pointed_thing.under, {name="technic:concrete_post"..id})
        itemstack:take_item()
        placer:set_wielded_item(itemstack)
        return itemstack
    end,
})
local function gen_post_nodebox(x1, x2, z1, z2, platform)
    local box = {box_center}
    if x1 ~= 0 then
        table.insert(box, box_x1)
    end
    local meta=minetest.env:get_meta(pointed_thing.under)
    y1=meta:get_float("y1")
    platform=meta:get_float("platform")
    if y1==1 or platform==1 then
        return minetest.item_place_node(itemstack, placer, pointed_thing)
    if x2 ~= 0 then
        table.insert(box, box_x2)
    end
    y2=meta:get_float("y2")
    x1=meta:get_float("x1")
    x2=meta:get_float("x2")
    z1=meta:get_float("z1")
    z2=meta:get_float("z2")
    rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,1)
    meta:set_float("platform",1)
    hacky_swap_posts(pointed_thing.under,"technic:concrete_post"..rule)
    itemstack:take_item()
    placer:set_wielded_item(itemstack)
    return itemstack
    end,
})
    if z1 ~= 0 then
        table.insert(box, box_z1)
    end
    if z2 ~= 0 then
        table.insert(box, box_z2)
    end
    if platform ~= 0 then
        table.insert(box, box_platform)
    end
    return box
end
local function dig_post_with_platform(pos, oldnode, oldmetadata)
    oldnode.name = "technic:concrete_post0"
    minetest.set_node(pos, oldnode)
    technic.update_posts(pos, true)
end
minetest.register_node(":technic:concrete_post", {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = { -0.15 , -0.5 , -0.15 , 0.15 ,  0.5 , 0.15 }},
    node_box = {
        type = "fixed",
        fixed = {-0.15 , -0.5 , -0.15 , 0.15 ,  0.5 , 0.15  }},
    on_construct = function(pos)
    meta=minetest.env:get_meta(pos)
    meta:set_int("postlike",1)
    meta:set_int("platform",0)
    meta:set_int("x1",0)
    meta:set_int("x2",0)
    meta:set_int("y1",0)
    meta:set_int("y2",0)
    meta:set_int("z1",0)
    meta:set_int("z2",0)
    check_post_connections (pos,1)
    end,
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
    check_post_connections  (pos,0)
    end,
})
local x1,x2,y1,z1,z2
local count=0
for x1 = 0, 1, 1 do    --x-
    for x2 = 0, 1, 1 do    --x+
        for z1 = 0, 1, 1 do    --z-
            for z2 = 0, 1, 1 do    --z+
                temp_x1={} temp_x2={} temp_z1={} temp_z2={}
                    if x1==1 then     temp_x1=post_str_x1  end
                    if x2==1 then     temp_x2=post_str_x2  end
                    if z1==1 then     temp_z1=post_str_z1  end
                    if z2==1 then     temp_z2=post_str_z2  end
minetest.register_node(":technic:concrete_post"..count, {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,not_in_creative_inventory=1,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    drop = "technic:concrete_post",
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = {
        temp_x1,temp_x2,post_str_y,temp_z1,temp_z2,
        }},
    node_box = {
        type = "fixed",
        fixed = {
        temp_x1,temp_x2,post_str_y,temp_z1,temp_z2,
        }},
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
    check_post_connections  (pos,0)
    end,
})
minetest.register_node(":technic:concrete_post"..count+16, {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,not_in_creative_inventory=1,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    drop = "technic:concrete_post_platform",
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = {
        platform_box,temp_x1,temp_x2,post_str_y,temp_z1,temp_z2,
        }},
    node_box = {
        type = "fixed",
        fixed = {
        platform_box,temp_x1,temp_x2,post_str_y,temp_z1,temp_z2,
        }},
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        dig_post_with_platform (pos,oldnode,oldmetadata)
    end,
})
count=count+1 end end end end
minetest.register_node(":technic:concrete_post32", {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,not_in_creative_inventory=1,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    drop = "technic:concrete_post",
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = {-0.5,-0.3,-0.1,0.5,0.3,0.1},
        },
    node_box = {
        type = "fixed",
        fixed = {
        post_str_x1,post_str_x2,
        }},
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        check_post_connections  (pos,0)
    end,
})
minetest.register_node(":technic:concrete_post33", {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,not_in_creative_inventory=1,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    drop = "technic:concrete_post",
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = {
        post_str_z1,post_str_z2,
        }},
    node_box = {
        type = "fixed",
        fixed = {
        post_str_z1,post_str_z2,
        }},
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        check_post_connections  (pos,0)
    end,
})
minetest.register_node(":technic:concrete_post34", {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,not_in_creative_inventory=1,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    drop = "technic:concrete_post_platform",
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = {
        platform_box,post_str_x1,post_str_x2,
        }},
    node_box = {
        type = "fixed",
        fixed = {
        platform_box,post_str_x1,post_str_x2,
        }},
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        dig_post_with_platform (pos,oldnode,oldmetadata)
    end,
})
minetest.register_node(":technic:concrete_post35", {
    description = "Concrete Post",
    tiles = {"technic_concrete_block.png"},
    groups={cracky=1,level=2,not_in_creative_inventory=1,concrete_post=1},
    sounds = default.node_sound_stone_defaults(),
    drop = "technic:concrete_post_platform",
    paramtype = "light",
    light_source = 0,
    sunlight_propagates = true,
    drawtype = "nodebox",
    selection_box = {
        type = "fixed",
        fixed = {
        platform_box,post_str_z1,post_str_z2,
        }},
    node_box = {
        type = "fixed",
        fixed = {
        platform_box,post_str_z1,post_str_z2,
        }},
    after_dig_node = function (pos, oldnode, oldmetadata, digger)
        dig_post_with_platform (pos,oldnode,oldmetadata)
    end,
})
dig_post_with_platform = function (pos,oldnode,oldmetadata)
    x1=tonumber(oldmetadata.fields["x1"])
    x2=tonumber(oldmetadata.fields["x2"])
    y1=tonumber(oldmetadata.fields["y1"])
    y2=tonumber(oldmetadata.fields["y2"])
    z1=tonumber(oldmetadata.fields["z1"])
    z2=tonumber(oldmetadata.fields["z2"])
    print(dump(x1))
    oldmetadata.fields["platform"]="0"
    local rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,0)
    --print(dump(rule))
    oldnode.name="technic:concrete_post"..rule
    minetest.env:set_node(pos,oldnode)
    meta = minetest.env:get_meta(pos)
    meta:from_table(oldmetadata)
end
check_post_connections = function(pos,mode)
        local pos1={}
        pos1.x=pos.x
        pos1.y=pos.y
        pos1.z=pos.z
        tempx1=0
        tempx2=0
        tempy1=0
        tempy2=0
        tempz1=0
        tempz2=0
        pos1.x=pos1.x+1
        if minetest.env:get_meta(pos1):get_int("postlike")==1 then
            x2=mode
            x1=minetest.env:get_meta(pos1):get_int("x1")
            y1=minetest.env:get_meta(pos1):get_int("y1")
            y2=minetest.env:get_meta(pos1):get_int("y2")
            z1=minetest.env:get_meta(pos1):get_int("z1")
            z2=minetest.env:get_meta(pos1):get_int("z2")
            platform=minetest.env:get_meta(pos1):get_int("platform")
            rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,platform)
            hacky_swap_posts(pos1,"technic:concrete_post"..rule)
            meta=minetest.env:get_meta(pos1)
            meta:set_int("x2",x2)
            tempx1=mode
        end
        pos1.x=pos1.x-2
        if minetest.env:get_meta(pos1):get_int("postlike")==1 then
            x1=mode
            x2=minetest.env:get_meta(pos1):get_int("x2")
            y1=minetest.env:get_meta(pos1):get_int("y1")
            y2=minetest.env:get_meta(pos1):get_int("y2")
            z1=minetest.env:get_meta(pos1):get_int("z1")
            z2=minetest.env:get_meta(pos1):get_int("z2")
            platform=minetest.env:get_meta(pos1):get_int("platform")
            rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,platform)
            hacky_swap_posts(pos1,"technic:concrete_post"..rule)
            meta=minetest.env:get_meta(pos1)
            meta:set_int("x1",x1)
            tempx2=mode
        end
        pos1.x=pos1.x+1
        pos1.y=pos1.y+1
        if minetest.env:get_meta(pos1):get_int("postlike")==1 then
            y2=mode
            x1=minetest.env:get_meta(pos1):get_int("x1")
            x2=minetest.env:get_meta(pos1):get_int("x2")
            y1=minetest.env:get_meta(pos1):get_int("y1")
            z1=minetest.env:get_meta(pos1):get_int("z1")
            z2=minetest.env:get_meta(pos1):get_int("z2")
            platform=minetest.env:get_meta(pos1):get_int("platform")
            rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,platform)
            hacky_swap_posts(pos1,"technic:concrete_post"..rule)
            meta=minetest.env:get_meta(pos1)
            meta:set_int("y2",y2)
            tempy1=mode
        end
        pos1.y=pos1.y-2
        if minetest.env:get_meta(pos1):get_int("postlike")==1 then
            y1=mode
            x1=minetest.env:get_meta(pos1):get_int("x1")
            x2=minetest.env:get_meta(pos1):get_int("x2")
            y2=minetest.env:get_meta(pos1):get_int("y2")
            z1=minetest.env:get_meta(pos1):get_int("z1")
            z2=minetest.env:get_meta(pos1):get_int("z2")
            platform=minetest.env:get_meta(pos1):get_int("platform")
            rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,platform)
            hacky_swap_posts(pos1,"technic:concrete_post"..rule)
            meta=minetest.env:get_meta(pos1)
            meta:set_int("y1",y1)
            tempy2=mode
        end
        pos1.y=pos1.y+1
        pos1.z=pos1.z+1
        if minetest.env:get_meta(pos1):get_int("postlike")==1 then
            z2=mode
            x1=minetest.env:get_meta(pos1):get_int("x1")
            x2=minetest.env:get_meta(pos1):get_int("x2")
            y1=minetest.env:get_meta(pos1):get_int("y1")
            y2=minetest.env:get_meta(pos1):get_int("y2")
            z1=minetest.env:get_meta(pos1):get_int("z1")
            platform=minetest.env:get_meta(pos1):get_int("platform")
            rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,platform)
            hacky_swap_posts(pos1,"technic:concrete_post"..rule)
            meta=minetest.env:get_meta(pos1)
            meta:set_int("z2",z2)
            tempz1=mode
        end
        pos1.z=pos1.z-2
        if minetest.env:get_meta(pos1):get_int("postlike")==1 then
            z1=mode
            x1=minetest.env:get_meta(pos1):get_int("x1")
            x2=minetest.env:get_meta(pos1):get_int("x2")
            y1=minetest.env:get_meta(pos1):get_int("y1")
            y2=minetest.env:get_meta(pos1):get_int("y2")
            z2=minetest.env:get_meta(pos1):get_int("z2")
            platform=minetest.env:get_meta(pos1):get_int("platform")
            rule=make_post_rule_number(x1,x2,y1,y2,z1,z2,platform)
            hacky_swap_posts(pos1,"technic:concrete_post"..rule)
            meta=minetest.env:get_meta(pos1)
            meta:set_int("z1",z1)
            tempz2=mode
        end
        pos1.z=pos1.z+1
        if mode==1 then
            meta=minetest.env:get_meta(pos)
            meta:set_int("x1",tempx1)
            meta:set_int("x2",tempx2)
            meta:set_int("y1",tempy1)
            meta:set_int("y2",tempy2)
            meta:set_int("z1",tempz1)
            meta:set_int("z2",tempz2)
            rule=make_post_rule_number(tempx1,tempx2,tempy1,tempy2,tempz1,tempz2,0)
            hacky_swap_posts(pos,"technic:concrete_post"..rule)
        end
end
function make_post_rule_number (x1,x2,y1,y2,z1,z2,platform)
    local tempy=y1+y2
    local tempx=x1+x2
    local tempz=z1+z2
    if platform==0 then
        if tempy==0 and tempx==0 and tempz==0 then return 0 end
        if x1==1 and x2==1 and tempz==0 and tempy==0 then return 32 end
        if z1==1 and z2==1 and tempx==0 and tempy==0 then return 33 end
        return z2+z1*2+x2*4+x1*8
    else
        if tempy==0 and tempx==0 and tempz==0 then return 16 end
        if x1==1 and x2==1 and tempz==0 and tempy==0 then return 34 end
        if z1==1 and z2==1 and tempx==0 and tempy==0 then return 35 end
        return z2+z1*2+x2*4+x1*8+16
function technic.posts_should_connect(pos)
    local node = minetest.get_node(pos)
    if technic.concrete_posts[node.name] then
        return "post"
    elseif minetest.get_item_group(node.name, "concrete") ~= 0 then
        return "block"
    end
end
function hacky_swap_posts(pos,name)
    local node = minetest.env:get_node(pos)
        if node.name == "technic:concrete" or node.name == "technic:blast_resistant_concrete" then
        return nil
    end
    local meta = minetest.env:get_meta(pos)
    local meta0 = meta:to_table()
    node.name = name
    local meta0 = meta:to_table()
    minetest.env:set_node(pos,node)
    meta = minetest.env:get_meta(pos)
    meta:from_table(meta0)
    return 1
function technic.get_post_id(links)
    return (links[4] * 1) + (links[3] * 2)
        + (links[2] * 4) + (links[1] * 8)
        + (links[5] * 16)
end
function technic.update_posts(pos, set, secondrun)
    local node = minetest.get_node(pos)
    local link_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 links = {0, 0, 0, 0, 0}
    for i, link_pos in pairs(link_positions) do
        local connecttype = technic.posts_should_connect(link_pos)
        if connecttype then
            links[i] = 1
            -- Have posts next to us update theirselves,
            -- but only once. (We don't want to start an
            -- infinite loop of updates)
            if not secondrun and connecttype == "post" then
                technic.update_posts(link_pos, true, true)
            end
        end
    end
    -- We don't want to set ourselves if we have been removed or we are
    -- updating a concrete node
    if set then
        -- Preserve platform
        local oldlinks = technic.concrete_posts[node.name]
        if oldlinks then
            links[5] = oldlinks[5]
        end
        minetest.set_node(pos, {name="technic:concrete_post"
                ..technic.get_post_id(links)})
    end
end
for x1 = 0, 1 do
for x2 = 0, 1 do
for z1 = 0, 1 do
for z2 = 0, 1 do
for platform = 0, 1 do
    local links = {x1, x2, z1, z2, platform}
    local id = technic.get_post_id(links)
    technic.concrete_posts["technic:concrete_post"..id] = links
    local groups = {cracky=1, level=2, concrete_post=1}
    if id ~= 0 then
        groups.not_in_creative_inventory = 1
    end
    local drop = "technic:concrete_post0"
    local after_dig_node = function(pos, oldnode, oldmetadata, digger)
        technic.update_posts(pos, false)
    end
    if platform ~= 0 then
        drop = "technic:concrete_post_platform"
        after_dig_node = function(pos, oldnode, oldmetadata, digger)
            dig_post_with_platform(pos, oldnode, oldmetadata)
        end
    end
    minetest.register_node(":technic:concrete_post"..id, {
        description = "Concrete Post",
        tiles = {"technic_concrete_block.png"},
        groups = groups,
        sounds = default.node_sound_stone_defaults(),
        drop = drop,
        paramtype = "light",
        sunlight_propagates = true,
        drawtype = "nodebox",
        node_box = {
            type = "fixed",
            fixed = gen_post_nodebox(x1, x2, z1, z2, platform),
        },
        after_place_node = function(pos, placer, itemstack)
            technic.update_posts(pos, true)
        end,
        after_dig_node = after_dig_node,
    })
end
end
end
end
end
item_drop/init.lua
@@ -1,38 +1,39 @@
dofile(minetest.get_modpath("item_drop").."/item_entity.lua")
time_pick = 3
if technic.config:getBool("enable_item_pickup") then
if technic.config:get_bool("enable_item_pickup") then
    minetest.register_globalstep(function(dtime)
        for _,player in ipairs(minetest.get_connected_players()) do
            if player and player:get_hp() > 0 then
            local pos = player:getpos()
            pos.y = pos.y+0.5
            local inv = player:get_inventory()
            for _,object in ipairs(minetest.env:get_objects_inside_radius(pos, 2)) do
                if not object:is_player() and object:get_luaentity() then
                    local obj=object:get_luaentity()
                    if obj.name == "__builtin:item" then
                        if inv:room_for_item("main", ItemStack(obj.itemstring)) then
                            if obj.timer > time_pick then
                                inv:add_item("main", ItemStack(obj.itemstring))
                                if obj.itemstring ~= "" then
                                    minetest.sound_play("item_drop_pickup",{pos = pos, gain = 1.0, max_hear_distance = 10})
                                end
                                if object:get_luaentity() then
                                    object:get_luaentity().itemstring = ""
                                    object:remove()
                local pos = player:getpos()
                pos.y = pos.y + 0.5
                local inv = player:get_inventory()
                for _, object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do
                    if not object:is_player() and object:get_luaentity() then
                        local obj = object:get_luaentity()
                        if obj.name == "__builtin:item" then
                            if inv and inv:room_for_item("main", ItemStack(obj.itemstring)) then
                                if obj.timer > time_pick then
                                    inv:add_item("main", ItemStack(obj.itemstring))
                                    if obj.itemstring ~= "" then
                                        minetest.sound_play("item_drop_pickup",
                                            {pos = pos, gain = 1.0, max_hear_distance = 10})
                                    end
                                    if object:get_luaentity() then
                                        object:get_luaentity().itemstring = ""
                                        object:remove()
                                    end
                                end
                            end
                        end
                    end
                end
            end
            end
        end
    end)
end
if technic.config:getBool("enable_item_drop") then
if technic.config:get_bool("enable_item_drop") then
    function minetest.handle_node_drops(pos, drops, digger)
        for _,item in ipairs(drops) do
            local count, name
technic/config.lua
@@ -1,8 +1,11 @@
technic.config = {}
technic.config.loaded = {}
local worldpath = minetest.get_worldpath()
technic.config.default = {
technic.config = Settings(worldpath.."/technic.conf")
local conf_table = technic.config:to_table()
local defaults = {
    enable_mining_drill = "true",
    enable_mining_laser = "true",
    enable_flashlight = "true",
@@ -10,33 +13,12 @@
    enable_item_pickup = "true",
    enable_rubber_tree_generation = "true",
    enable_marble_generation = "true",
    enable_granite_generation = "true"
    enable_granite_generation = "true",
}
function technic.config:load(filename)
    file, error = io.open(filename, "r")
    if error then return end
    local line = file:read("*l")
    while line do
        local found, _, setting, value = line:find("^([^#%s=]+)%s?=%s?([^%s#]+)")
        if found then
            self.loaded[setting] = value
        end
        line = file:read("*l")
    end
    file:close()
end
technic.config:load(minetest.get_worldpath().."/technic.conf")
function technic.config:get(setting)
    if self.loaded[setting] then
        return self.loaded[setting]
    else
        return self.default[setting]
for k, v in pairs(defaults) do
    if conf_table[k] == nil then
        technic.config:set(k, v)
    end
end
function technic.config:getBool(setting)
    return string.lower(self:get(setting)) == "true"
end
technic/crafts.lua
New file
@@ -0,0 +1,169 @@
-- tubes crafting recipes
minetest.register_craft({
    output = 'pipeworks:tube_000000 9',
    recipe = {
        {'technic:stainless_steel_ingot', 'default:glass', 'technic:stainless_steel_ingot'},
        {'technic:stainless_steel_ingot', 'default:glass', 'technic:stainless_steel_ingot'},
        {'technic:stainless_steel_ingot', 'default:glass', 'technic:stainless_steel_ingot'},
    }
})
minetest.register_craft({
    output = 'pipeworks:mese_tube_000000',
    recipe = {
        {'default:mese_crystal_fragment', 'pipeworks:tube_000000', 'default:mese_crystal_fragment'},
        }
})
minetest.register_craft({
    output = 'pipeworks:accelerator_tube_000000',
    recipe = {
        {'technic:copper_coil', 'pipeworks:tube_000000', 'technic:copper_coil'},
        }
})
minetest.register_craft({
    output = 'pipeworks:detector_tube_off_000000',
    recipe = {
        {'mesecons:mesecon', 'pipeworks:tube_000000', 'mesecons:mesecon'},
        }
})
minetest.register_craft({
    output = 'pipeworks:sand_tube_000000',
    recipe = {
        {'default:sand', 'pipeworks:tube_000000', 'default:sand'},
        }
})
minetest.register_craft({
    output = 'pipeworks:mese_sand_tube_000000',
    recipe = {
        {'default:mese_crystal_fragment', 'pipeworks:sand_tube_000000', 'default:mese_crystal_fragment'},
        }
})
minetest.register_craft({
    output = 'pipeworks:teleport_tube_000000',
    recipe = {
        {'default:mese_crystal', 'technic:copper_coil', 'default:mese_crystal'},
        {'pipeworks:tube_000000', 'technic:control_logic_unit', 'pipeworks:tube_000000'},
        {'default:mese_crystal', 'technic:copper_coil', 'default:mese_crystal'},
        }
})
minetest.register_craft({
    output = 'technic:diamond_drill_head',
    recipe = {
        {'technic:stainless_steel_ingot', 'default:diamond', 'technic:stainless_steel_ingot'},
        {'default:diamond',               '',                'default:diamond'},
        {'technic:stainless_steel_ingot', 'default:diamond', 'technic:stainless_steel_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:green_energy_crystal',
    recipe = {
        {'default:gold_ingot', 'technic:battery', 'dye:green'},
        {'technic:battery', 'technic:red_energy_crystal', 'technic:battery'},
        {'dye:green', 'technic:battery', 'default:gold_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:blue_energy_crystal',
    recipe = {
        {'default:gold_ingot', 'technic:battery', 'dye:blue'},
        {'technic:battery', 'technic:green_energy_crystal', 'technic:battery'},
        {'dye:blue', 'technic:battery', 'default:gold_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:red_energy_crystal',
    recipe = {
        {'default:gold_ingot', 'technic:battery', 'dye:red'},
        {'technic:battery', 'default:diamondblock', 'technic:battery'},
        {'dye:red', 'technic:battery', 'default:gold_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:fine_copper_wire 2',
    recipe = {
        {'', 'default:copper_ingot', ''},
        {'', 'default:copper_ingot', ''},
        {'', 'default:copper_ingot', ''},
    }
})
minetest.register_craft({
    output = 'technic:copper_coil 1',
    recipe = {
        {'technic:fine_copper_wire', 'default:steel_ingot', 'technic:fine_copper_wire'},
        {'default:steel_ingot', '', 'default:steel_ingot'},
        {'technic:fine_copper_wire', 'default:steel_ingot', 'technic:fine_copper_wire'},
    }
})
minetest.register_craft({
    output = 'technic:motor',
    recipe = {
        {'default:steel_ingot', 'technic:copper_coil', 'default:steel_ingot'},
        {'default:steel_ingot', 'technic:copper_coil', 'default:steel_ingot'},
        {'default:steel_ingot', 'default:copper_ingot', 'default:steel_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:lv_transformer',
    recipe = {
        {'default:iron_lump',   'default:iron_lump', 'default:iron_lump'},
        {'technic:copper_coil', 'default:iron_lump', 'technic:copper_coil'},
        {'default:iron_lump',   'default:iron_lump', 'default:iron_lump'},
    }
})
minetest.register_craft({
    output = 'technic:mv_transformer',
    recipe = {
        {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
        {'technic:copper_coil', 'default:steel_ingot', 'technic:copper_coil'},
        {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:hv_transformer',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'technic:copper_coil',           'technic:stainless_steel_ingot', 'technic:copper_coil'},
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:control_logic_unit',
    recipe = {
        {'', 'default:gold_ingot', ''},
        {'default:copper_ingot', 'technic:silicon_wafer', 'default:copper_ingot'},
        {'', 'default:copper_ingot', ''},
    }
})
minetest.register_craft({
    output = 'technic:mixed_metal_ingot 9',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'default:bronze_ingot',          'default:bronze_ingot',          'default:bronze_ingot'},
        {'moreores:tin_ingot',            'moreores:tin_ingot',            'moreores:tin_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:carbon_cloth',
    recipe = {
        {'technic:graphite', 'technic:graphite', 'technic:graphite'}
    }
})
technic/depends.txt
@@ -2,4 +2,4 @@
moreores
pipeworks
mesecons
moretrees
mesecons_mvps?
technic/init.lua
@@ -4,26 +4,25 @@
technic = {}
local load_start = os.clock()
local modpath = minetest.get_modpath("technic")
technic.modpath = modpath
technic.dprint = function(string)
    if technic.DBG == 1 then
        print(string)
    end
end
--Read technic config file
-- Read configuration file
dofile(modpath.."/config.lua")
--helper functions
-- Helper functions
dofile(modpath.."/helpers.lua")
--items
-- Items
dofile(modpath.."/items.lua")
-- Craft recipes for items
dofile(modpath.."/crafts.lua")
-- Register functions
dofile(modpath.."/register_machine_and_tool.lua")
dofile(modpath.."/register.lua")
-- Machines
dofile(modpath.."/machines/init.lua")
@@ -31,24 +30,31 @@
-- Tools
dofile(modpath.."/tools/init.lua")
function has_locked_chest_privilege(meta, player)
   if player:get_player_name() ~= meta:get_string("owner") then
      return false
   end
   return true
end
-- Aliases for legacy node/item names
dofile(modpath.."/legacy.lua")
function has_locked_chest_privilege(meta, player)
    if player:get_player_name() ~= meta:get_string("owner") then
        return false
    end
    return true
end
-- Swap nodes out. Return the node name.
function hacky_swap_node(pos,name)
   local node = minetest.env:get_node(pos)
   if node.name ~= name then
      local meta = minetest.env:get_meta(pos)
      local meta0 = meta:to_table()
      node.name = name
      minetest.env:set_node(pos,node)
      meta = minetest.env:get_meta(pos)
      meta:from_table(meta0)
   end
   return node.name
function hacky_swap_node(pos, name)
    local node = minetest.get_node(pos)
    if node.name ~= name then
        local meta = minetest.get_meta(pos)
        local meta_table = meta:to_table()
        node.name = name
        minetest.set_node(pos, node)
        meta = minetest.get_meta(pos)
        meta:from_table(meta_table)
    end
    return node.name
end
if minetest.setting_get("log_mod") then
    print("[Technic] Loaded in "..tostring(os.clock() - load_start).."s")
end
technic/items.lua
@@ -1,131 +1,69 @@
minetest.register_craftitem( "technic:silicon_wafer", {
    description = "Silicon Wafer",
    inventory_image = "technic_silicon_wafer.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craftitem( "technic:doped_silicon_wafer", {
    description = "Doped Silicon Wafer",
    inventory_image = "technic_doped_silicon_wafer.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craftitem( "technic:enriched_uranium", {
minetest.register_craftitem("technic:enriched_uranium", {
    description = "Enriched Uranium",
    inventory_image = "technic_enriched_uranium.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
-- tubes crafting recipes
minetest.register_craft({
    output = 'pipeworks:tube_000000 9',
    recipe = {
        {'technic:stainless_steel_ingot', 'default:glass', 'technic:stainless_steel_ingot'},
        {'technic:stainless_steel_ingot', 'default:glass', 'technic:stainless_steel_ingot'},
        {'technic:stainless_steel_ingot', 'default:glass', 'technic:stainless_steel_ingot'},
    }
})
minetest.register_craft({
    output = 'pipeworks:mese_tube_000000',
    recipe = {
        {'default:mese_crystal_fragment', 'pipeworks:tube_000000', 'default:mese_crystal_fragment'},
        }
})
minetest.register_craft({
    output = 'pipeworks:accelerator_tube_000000',
    recipe = {
        {'technic:copper_coil', 'pipeworks:tube_000000', 'technic:copper_coil'},
        }
})
minetest.register_craft({
    output = 'pipeworks:detector_tube_off_000000',
    recipe = {
        {'mesecons:mesecon', 'pipeworks:tube_000000', 'mesecons:mesecon'},
        }
})
minetest.register_craft({
    output = 'pipeworks:sand_tube_000000',
    recipe = {
        {'default:sand', 'pipeworks:tube_000000', 'default:sand'},
        }
})
minetest.register_craft({
    output = 'pipeworks:mese_sand_tube_000000',
    recipe = {
        {'default:mese_crystal_fragment', 'pipeworks:sand_tube_000000', 'default:mese_crystal_fragment'},
        }
})
minetest.register_craft({
    output = 'pipeworks:teleport_tube_000000',
    recipe = {
        {'default:mese_crystal', 'technic:copper_coil', 'default:mese_crystal'},
        {'pipeworks:tube_000000', 'technic:control_logic_unit', 'pipeworks:tube_000000'},
        {'default:mese_crystal', 'technic:copper_coil', 'default:mese_crystal'},
        }
minetest.register_craftitem("technic:uranium_fuel", {
    description = "Uranium Fuel",
    inventory_image = "technic_uranium_fuel.png",
})
minetest.register_craftitem( "technic:diamond_drill_head", {
    description = "Diamond Drill Head",
    inventory_image = "technic_diamond_drill_head.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:diamond_drill_head',
    recipe = {
        {'technic:stainless_steel_ingot', 'default:diamond', 'technic:stainless_steel_ingot'},
        {'default:diamond', '', 'default:diamond'},
        {'technic:stainless_steel_ingot', 'default:diamond', 'technic:stainless_steel_ingot'},
minetest.register_tool("technic:blue_energy_crystal", {
    description = "Blue Energy Crystal",
    inventory_image = minetest.inventorycube(
        "technic_diamond_block_blue.png",
        "technic_diamond_block_blue.png",
        "technic_diamond_block_blue.png"),
    tool_capabilities = {
        max_drop_level = 0,
        groupcaps = {
            fleshy = {times={}, uses=10000, maxlevel=0}
        }
    }
})
})
minetest.register_craft({
    output = 'technic:green_energy_crystal',
    recipe = {
        {'default:gold_ingot', 'technic:battery', 'dye:green'},
        {'technic:battery', 'technic:red_energy_crystal', 'technic:battery'},
        {'dye:green', 'technic:battery', 'default:gold_ingot'},
minetest.register_tool("technic:green_energy_crystal", {
    description = "Green Energy Crystal",
    inventory_image = minetest.inventorycube(
        "technic_diamond_block_green.png",
        "technic_diamond_block_green.png",
        "technic_diamond_block_green.png"),
    tool_capabilities = {
        max_drop_level = 0,
        groupcaps = {
            fleshy = {times={}, uses=10000, maxlevel=0}
        }
    }
})
})
minetest.register_craft({
    output = 'technic:blue_energy_crystal',
    recipe = {
        {'default:gold_ingot', 'technic:battery', 'dye:blue'},
        {'technic:battery', 'technic:green_energy_crystal', 'technic:battery'},
        {'dye:blue', 'technic:battery', 'default:gold_ingot'},
minetest.register_tool("technic:red_energy_crystal", {
    description = "Red Energy Crystal",
    inventory_image = minetest.inventorycube(
        "technic_diamond_block_red.png",
        "technic_diamond_block_red.png",
        "technic_diamond_block_red.png"),
    tool_capabilities = {
        max_drop_level = 0,
        groupcaps = {
            fleshy = {times={}, uses=10000, maxlevel=0}
        }
    }
})
minetest.register_craft({
    output = 'technic:red_energy_crystal',
    recipe = {
        {'default:gold_ingot', 'technic:battery', 'dye:red'},
        {'technic:battery', 'default:diamondblock', 'technic:battery'},
        {'dye:red', 'technic:battery', 'default:gold_ingot'},
    }
})
minetest.register_tool("technic:blue_energy_crystal",
{description = "Blue Energy Crystal",
inventory_image = minetest.inventorycube("technic_diamond_block_blue.png", "technic_diamond_block_blue.png", "technic_diamond_block_blue.png"),
tool_capabilities = {load=0,max_drop_level=0, groupcaps={fleshy={times={}, uses=10000, maxlevel=0}}}})
minetest.register_tool("technic:green_energy_crystal",
{description = "Green Energy Crystal",
inventory_image = minetest.inventorycube("technic_diamond_block_green.png", "technic_diamond_block_green.png", "technic_diamond_block_green.png"),
tool_capabilities = {load=0,max_drop_level=0, groupcaps={fleshy={times={}, uses=10000, maxlevel=0}}}})
minetest.register_tool("technic:red_energy_crystal",
{description = "Red Energy Crystal",
inventory_image = minetest.inventorycube("technic_diamond_block_red.png", "technic_diamond_block_red.png", "technic_diamond_block_red.png"),
tool_capabilities = {load=0,max_drop_level=0, groupcaps={fleshy={times={}, uses=10000, maxlevel=0}}}})
})
minetest.register_craftitem( "technic:fine_copper_wire", {
@@ -134,28 +72,10 @@
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:fine_copper_wire 2',
    recipe = {
        {'', 'default:copper_ingot', ''},
        {'', 'default:copper_ingot', ''},
        {'', 'default:copper_ingot', ''},
    }
})
minetest.register_craftitem( "technic:copper_coil", {
    description = "Copper Coil",
    inventory_image = "technic_copper_coil.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:copper_coil 1',
    recipe = {
        {'technic:fine_copper_wire', 'default:steel_ingot', 'technic:fine_copper_wire'},
        {'default:steel_ingot', '', 'default:steel_ingot'},
        {'technic:fine_copper_wire', 'default:steel_ingot', 'technic:fine_copper_wire'},
    }
})
minetest.register_craftitem( "technic:motor", {
@@ -164,13 +84,10 @@
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:motor',
    recipe = {
        {'default:steel_ingot', 'technic:copper_coil', 'default:steel_ingot'},
        {'default:steel_ingot', 'technic:copper_coil', 'default:steel_ingot'},
        {'default:steel_ingot', 'default:copper_ingot', 'default:steel_ingot'},
    }
minetest.register_craftitem( "technic:lv_transformer", {
    description = "Low Voltage Transformer",
    inventory_image = "technic_lv_transformer.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craftitem( "technic:lv_transformer", {
@@ -178,44 +95,10 @@
    inventory_image = "technic_lv_transformer.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:lv_transformer',
    recipe = {
        {'default:iron_lump',   'default:iron_lump', 'default:iron_lump'},
        {'technic:copper_coil', 'default:iron_lump', 'technic:copper_coil'},
        {'default:iron_lump',   'default:iron_lump', 'default:iron_lump'},
    }
})
minetest.register_craftitem( "technic:lv_transformer", {
    description = "Low Voltage Transformer",
    inventory_image = "technic_lv_transformer.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:lv_transformer',
    recipe = {
        {'default:iron_lump',   'default:iron_lump', 'default:iron_lump'},
        {'technic:copper_coil', 'default:iron_lump', 'technic:copper_coil'},
        {'default:iron_lump',   'default:iron_lump', 'default:iron_lump'},
    }
})
minetest.register_craftitem( "technic:mv_transformer", {
    description = "Medium Voltage Transformer",
    inventory_image = "technic_mv_transformer.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:mv_transformer',
    recipe = {
        {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
        {'technic:copper_coil', 'default:steel_ingot', 'technic:copper_coil'},
        {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
    }
})
minetest.register_craftitem( "technic:hv_transformer", {
@@ -224,43 +107,16 @@
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:hv_transformer',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'technic:copper_coil',           'technic:stainless_steel_ingot', 'technic:copper_coil'},
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
    }
})
minetest.register_craftitem( "technic:control_logic_unit", {
    description = "Control Logic Unit",
    inventory_image = "technic_control_logic_unit.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:control_logic_unit',
    recipe = {
        {'', 'default:gold_ingot', ''},
        {'default:copper_ingot', 'technic:silicon_wafer', 'default:copper_ingot'},
        {'', 'default:copper_ingot', ''},
    }
})
minetest.register_craftitem("technic:mixed_metal_ingot", {
    description = "Mixed Metal Ingot",
    inventory_image = "technic_mixed_metal_ingot.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:mixed_metal_ingot 2',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'default:bronze_ingot', 'default:bronze_ingot', 'default:bronze_ingot'},
        {'moreores:tin_ingot', 'moreores:tin_ingot', 'moreores:tin_ingot'},
    }
})
minetest.register_craftitem("technic:composite_plate", {
@@ -291,12 +147,5 @@
    description = "Carbon Cloth",
    inventory_image = "technic_carbon_cloth.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craft({
    output = 'technic:carbon_cloth',
    recipe = {
        {'technic:graphite', 'technic:graphite', 'technic:graphite'}
    }
})
technic/legacy.lua
New file
@@ -0,0 +1,30 @@
-- Aliases to convert from legacy node/item names
technic.legacy_nodenames = {
    ["technic:alloy_furnace"]        = "technic:lv_alloy_furnace",
    ["technic:alloy_furnace_active"] = "technic:lv_alloy_furnace_active",
    ["technic:battery_box"]  = "technic:lv_battery_box0",
    ["technic:battery_box1"] = "technic:lv_battery_box1",
    ["technic:battery_box2"] = "technic:lv_battery_box2",
    ["technic:battery_box3"] = "technic:lv_battery_box3",
    ["technic:battery_box4"] = "technic:lv_battery_box4",
    ["technic:battery_box5"] = "technic:lv_battery_box5",
    ["technic:battery_box6"] = "technic:lv_battery_box6",
    ["technic:battery_box7"] = "technic:lv_battery_box7",
    ["technic:battery_box8"] = "technic:lv_battery_box8",
    ["technic:electric_furnace"]        = "technic:lv_electric_furnace",
    ["technic:electric_furnace_active"] = "technic:lv_electric_furnace_active",
    ["technic:grinder"]        = "technic:lv_grinder",
    ["technic:grinder_active"] = "technic:lv_grinder_active",
    ["technic:hv_battery_box"] = "technic:hv_battery_box0",
    ["technic:hv_cable"] = "technic:hv_cable0",
    ["technic:lv_cable"] = "technic:lv_cable0",
    ["technic:mv_cable"] = "technic:mv_cable0",
    ["technic:mv_battery_box"] = "technic:mv_battery_box0",
}
for old, new in pairs(technic.legacy_nodenames) do
    minetest.register_alias(old, new)
end
technic/machines/HV/battery_box.lua
New file
@@ -0,0 +1,19 @@
-- HV battery box
minetest.register_craft({
    output = 'technic:hv_battery_box0',
    recipe = {
        {'technic:mv_battery_box0', 'technic:mv_battery_box0', 'technic:mv_battery_box0'},
        {'technic:mv_battery_box0', 'technic:hv_transformer',  'technic:mv_battery_box0'},
        {'',                        'technic:hv_cable0',       ''},
    }
})
technic.register_battery_box({
    tier           = "HV",
    max_charge     = 1500000,
    charge_rate    = 100000,
    discharge_rate = 400000,
    charge_step    = 10000,
    discharge_step = 40000,
})
technic/machines/HV/cables.lua
New file
@@ -0,0 +1,12 @@
minetest.register_craft({
    output = 'technic:hv_cable0 3',
    recipe = {
        {'technic:rubber',    'technic:rubber',    'technic:rubber'},
        {'technic:mv_cable0', 'technic:mv_cable0', 'technic:mv_cable0'},
        {'technic:rubber',    'technic:rubber',    'technic:rubber'},
    }
})
technic.register_cable("HV", 3/16)
technic/machines/HV/forcefield.lua
New file
@@ -0,0 +1,206 @@
-- Forcefield mod by ShadowNinja
-- Modified by kpoppel
--
-- Forcefields are powerful barriers but they consume huge amounts of power.
-- Forcefield Generator is a HV machine.
-- How expensive is the generator?
-- Leaves room for upgrades lowering the power drain?
local forcefield_power_drain   = 10
local forcefield_step_interval = 1
minetest.register_craft({
    output = 'technic:forcefield_emitter_off',
    recipe = {
            {'default:mese',         'technic:deployer_off', 'default:mese'        },
            {'technic:deployer_off', 'technic:motor',        'technic:deployer_off'},
            {'default:mese',         'technic:deployer_off', 'default:mese'        },
    }
})
-- Idea: Let forcefields have different colors by upgrade slot.
-- Idea: Let forcefields add up by detecting if one hits another.
--    ___   __
--   /   \/   \
--  |          |
--   \___/\___/
local function update_forcefield(pos, range, active)
    local vm = VoxelManip()
    local p1 = {x = pos.x-range, y = pos.y-range, z = pos.z-range}
    local p2 = {x = pos.x+range, y = pos.y+range, z = pos.z+range}
    local MinEdge, MaxEdge = vm:read_from_map(p1, p2)
    local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
    local data = vm:get_data()
    local c_air   = minetest.get_content_id("air")
    local c_field = minetest.get_content_id("technic:forcefield")
    for z=-range, range do
    for y=-range, range do
    local vi = area:index(pos.x+(-range), pos.y+y, pos.z+z)
    for x=-range, range do
        if x*x+y*y+z*z <= range     *  range    +  range    and
           x*x+y*y+z*z >= (range-1) * (range-1) + (range-1) then
            if active and data[vi] == c_air then
                data[vi] = c_field
            elseif not active and data[vi] == c_field then
                data[vi] = c_air
            end
        end
        vi = vi + 1
    end
    end
    end
    vm:set_data(data)
    vm:update_liquids()
    vm:write_to_map()
    vm:update_map()
end
local get_forcefield_formspec = function(range)
    return "size[3,1.5]"..
        "field[1,0.5;2,1;range;Range;"..range.."]"..
        "button[0,1;3,1;toggle;Enable/Disable]"
end
local forcefield_receive_fields = function(pos, formname, fields, sender)
    local meta = minetest.get_meta(pos)
    local range = fields.range
    if fields.toggle then
        if meta:get_int("enabled") == 1 then
           meta:set_int("enabled", 0)
        else
           meta:set_int("enabled", 1)
        end
    end
    -- Smallest field is 5. Anything less is asking for trouble.
    -- Largest is 20. It is a matter of pratical node handling.
    -- At the maximim range updating the forcefield takes about 0.2s
    range = math.max(range, 5)
    range = math.min(range, 20)
    if meta:get_int("range") ~= range then
        update_forcefield(pos, meta:get_int("range"), false)
        meta:set_int("range", range)
        meta:set_string("formspec", get_forcefield_formspec(range))
    end
end
local mesecons = {
    effector = {
        action_on = function(pos, node)
            minetest.get_meta(pos):set_int("enabled", 0)
        end,
        action_off = function(pos, node)
            minetest.get_meta(pos):set_int("enabled", 1)
        end
    }
}
minetest.register_node("technic:forcefield_emitter_off", {
    description = "Forcefield emitter",
    tiles = {"technic_forcefield_emitter_off.png"},
    groups = {cracky = 1},
    on_receive_fields = forcefield_receive_fields,
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_int("HV_EU_input", 0)
        meta:set_int("HV_EU_demand", 0)
        meta:set_int("range", 10)
        meta:set_int("enabled", 0)
        meta:set_string("formspec", get_forcefield_formspec(10))
        meta:set_string("infotext", "Forcefield emitter");
    end,
    mesecons = mesecons
})
minetest.register_node("technic:forcefield_emitter_on", {
    description = "Forcefield emitter on (you hacker you)",
    tiles = {"technic_forcefield_emitter_on.png"},
    groups = {cracky = 1, not_in_creative_inventory=1},
    drop = "technic:forcefield_emitter_off",
    on_receive_fields = forcefield_receive_fields,
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        local range = meta:get_int("range")
        meta:set_string("formspec", get_forcefield_formspec(range))
    end,
    on_destruct = function(pos)
        local meta = minetest.get_meta(pos)
        update_forcefield(pos, meta:get_int("range"), false)
    end,
    mesecons = mesecons
})
minetest.register_node("technic:forcefield", {
    description = "Forcefield (you hacker you)",
    sunlight_propagates = true,
    drawtype = "glasslike",
    groups = {not_in_creative_inventory=1, unbreakable=1},
    paramtype = "light",
        light_source = 15,
    drop = '',
    tiles = {{
        name = "technic_forcefield_animated.png",
        animation = {
            type = "vertical_frames",
            aspect_w = 16,
            aspect_h = 16,
            length = 1.0,
        },
    }},
})
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")
        -- 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)
                hacky_swap_node(pos, "technic:forcefield_emitter_off")
                meta:set_string("infotext", "Forcefield Generator Disabled")
                return
            end
        elseif eu_input < power_requirement then
            meta:set_string("infotext", "Forcefield Generator Unpowered")
            if node.name == "technic:forcefield_emitter_on" then
                update_forcefield(pos, meta:get_int("range"), false)
                hacky_swap_node(pos, "technic:forcefield_emitter_off")
            end
        elseif eu_input >= power_requirement then
            if node.name == "technic:forcefield_emitter_off" then
                hacky_swap_node(pos, "technic:forcefield_emitter_on")
                meta:set_string("infotext", "Forcefield Generator Active")
            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/init.lua
New file
@@ -0,0 +1,12 @@
technic.register_tier("HV", "High Voltage")
local path = technic.modpath.."/machines/HV"
dofile(path.."/cables.lua")
dofile(path.."/quarry.lua")
dofile(path.."/forcefield.lua")
dofile(path.."/battery_box.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/nuclear_reactor.lua")
technic/machines/HV/nuclear_reactor.lua
New file
@@ -0,0 +1,259 @@
-- The enriched uranium rod driven EU generator.
-- A very large and advanced machine providing vast amounts of power.
-- Very efficient but also expensive to run as it needs uranium. (10000EU 86400 ticks (24h))
-- Provides HV EUs that can be down converted as needed.
--
-- The nuclear reactor core needs water and a protective shield to work.
-- This is checked now and then and if the machine is tampered with... BOOM!
local burn_ticks   = 7 * 24 * 60 * 60       -- (seconds).
local power_supply = 100000                 -- EUs
local fuel_type    = "technic:uranium_fuel" -- The reactor burns this stuff
-- FIXME: recipe must make more sense like a rod recepticle, steam chamber, HV generator?
minetest.register_craft({
    output = 'technic:hv_nuclear_reactor_core',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'technic:stainless_steel_ingot',                              '', 'technic:stainless_steel_ingot'},
        {'technic:stainless_steel_ingot',              'technic:hv_cable', 'technic:stainless_steel_ingot'},
    }
})
local generator_formspec =
    "invsize[8,9;]"..
    "label[0,0;Nuclear Reactor Rod Compartment]"..
    "list[current_name;src;2,1;3,2;]"..
    "list[current_player;main;0,5;8,4;]"
-- "Boxy sphere"
local nodebox = {
    { -0.353, -0.353, -0.353, 0.353, 0.353, 0.353 }, -- Box
    { -0.495, -0.064, -0.064, 0.495, 0.064, 0.064 }, -- Circle +-x
    { -0.483, -0.128, -0.128, 0.483, 0.128, 0.128 },
    { -0.462, -0.191, -0.191, 0.462, 0.191, 0.191 },
    { -0.433, -0.249, -0.249, 0.433, 0.249, 0.249 },
    { -0.397, -0.303, -0.303, 0.397, 0.303, 0.303 },
    { -0.305, -0.396, -0.305, 0.305, 0.396, 0.305 }, -- Circle +-y
    { -0.250, -0.432, -0.250, 0.250, 0.432, 0.250 },
    { -0.191, -0.461, -0.191, 0.191, 0.461, 0.191 },
    { -0.130, -0.482, -0.130, 0.130, 0.482, 0.130 },
    { -0.066, -0.495, -0.066, 0.066, 0.495, 0.066 },
    { -0.064, -0.064, -0.495, 0.064, 0.064, 0.495 }, -- Circle +-z
    { -0.128, -0.128, -0.483, 0.128, 0.128, 0.483 },
    { -0.191, -0.191, -0.462, 0.191, 0.191, 0.462 },
    { -0.249, -0.249, -0.433, 0.249, 0.249, 0.433 },
    { -0.303, -0.303, -0.397, 0.303, 0.303, 0.397 },
}
minetest.register_node("technic:hv_nuclear_reactor_core", {
    description = "Nuclear Reactor",
    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", "Nuclear Reactor Core")
        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 = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
minetest.register_node("technic:hv_nuclear_reactor_core_active", {
    description = "HV Uranium Reactor",
    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 = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
local check_reactor_structure = function(pos)
    -- The reactor consists of a 9x9x9 cube structure
    -- A cross section through the middle:
    --  CCCC CCCC
    --  CBBB BBBC
    --  CBSS SSBC
    --  CBSWWWSBC
    --  CBSW#WSBC
    --  CBSW|WSBC
    --  CBSS|SSBC
    --  CBBB|BBBC
    --  CCCC|CCCC
    --  C = Concrete, B = Blast resistant concrete, S = Stainless Steel,
    --  W = water node, # = reactor core, | = HV cable
    --  The man-hole and the HV cable is only in the middle
    --  The man-hole is optional
    local vm = VoxelManip()
    local pos1 = vector.subtract(pos, 4)
    local pos2 = vector.add(pos, 4)
    local MinEdge, MaxEdge = vm:read_from_map(pos1, pos2)
    local data = vm:get_data()
    local area = VoxelArea:new({MinEdge=MinEdge, MaxEdge=MaxEdge})
    local c_concrete = minetest.get_content_id("technic:concrete")
    local c_blast_concrete = minetest.get_content_id("technic:blast_resistant_concrete")
    local c_stainless_steel = minetest.get_content_id("technic:stainless_steel_block")
    local c_water_source = minetest.get_content_id("default:water_source")
    local c_water_flowing = minetest.get_content_id("default:water_flowing")
    local concretelayer, blastlayer, steellayer, waterlayer = 0, 0, 0, 0
    for z = pos1.z, pos2.z do
    for y = pos1.y, pos2.y do
    for x = pos1.x, pos2.x do
        -- If the position is in the outer layer
        if x == pos1.x or x == pos2.x or
           y == pos1.y or y == pos2.y or
           z == pos1.z or z == pos2.z then
            if data[area:index(x, y, z)] == c_concrete then
                concretelayer = concretelayer + 1
            end
        elseif x == pos1.x+1 or x == pos2.x-1 or
           y == pos1.y+1 or y == pos2.y-1 or
           z == pos1.z+1 or z == pos2.z-1 then
            if data[area:index(x, y, z)] == c_blast_concrete then
                blastlayer = blastlayer + 1
            end
        elseif x == pos1.x+2 or x == pos2.x-2 or
           y == pos1.y+2 or y == pos2.y-2 or
           z == pos1.z+2 or z == pos2.z-2 then
            if data[area:index(x, y, z)] == c_stainless_steel then
                steellayer = steellayer + 1
            end
        elseif x == pos1.x+3 or x == pos2.x-3 or
           y == pos1.y+3 or y == pos2.y-3 or
           z == pos1.z+3 or z == pos2.z-3 then
               local cid = data[area:index(x, y, z)]
            if cid == c_water_source or cid == c_water_flowing then
                waterlayer = waterlayer + 1
            end
        end
    end
    end
    end
    if waterlayer >= 25 and
       steellayer >= 96 and
       blastlayer >= 216 and
       concretelayer >= 384 then
        return true
    end
end
local explode_reactor = function(pos)
    print("A reactor exploded at "..minetest.pos_to_string(pos))
end
local function damage_nearby_players(pos)
    local objs = minetest.get_objects_inside_radius(pos, 4)
    for _, o in pairs(objs) do
        if o:is_player() then
            o:set_hp(math.max(o:get_hp() - 2, 0))
        end
    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 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
                    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)
                    hacky_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
            end
            meta:set_int("HV_EU_supply", 0)
            meta:set_int("burn_time", 0)
            meta:set_string("infotext", "Nuclear Reactor Core (idle)")
            hacky_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", "Nuclear Reactor Core ("..percent.."%)")
            meta:set_int("HV_EU_supply", power_supply)
        end
    end
})
technic.register_machine("HV", "technic:hv_nuclear_reactor_core",        technic.producer)
technic.register_machine("HV", "technic:hv_nuclear_reactor_core_active", technic.producer)
technic/machines/HV/quarry.lua
New file
@@ -0,0 +1,200 @@
minetest.register_craft({
    recipe = {
        {"default:steelblock", "pipeworks:filter",           "default:steelblock"},
        {"default:steelblock", "technic:motor",              "default:steelblock"},
        {"default:steelblock", "technic:diamond_drill_head", "default:steelblock"}},
    output = "technic:quarry",
})
local quarry_dig_above_nodes = 3 -- How far above the quarry we will dig nodes
local quarry_max_depth       = 100
local function get_quarry_formspec(size)
    return "size[3,1.5]"..
        "field[1,0.5;2,1;size;Radius;"..size.."]"..
        "button[0,1;3,1;toggle;Enable/Disable]"
end
local function quarry_receive_fields(pos, formname, fields, sender)
    local meta = minetest.get_meta(pos)
    local size = tonumber(fields.size)
    if fields.toggle then
        if meta:get_int("enabled") == 0 then
            meta:set_int("enabled", 1)
        else
            meta:set_int("enabled", 0)
        end
    end
    -- Smallest size is 2. Anything less is asking for trouble.
    -- Largest is 8. It is a matter of pratical node handling.
    size = math.max(size, 2)
    size = math.min(size, 8)
    if meta:get_int("size") ~= size then
        meta:set_int("size", size)
        meta:set_string("formspec", get_quarry_formspec(size))
    end
end
local function get_quarry_center(pos, size)
    local node     = minetest.get_node(pos)
    local back_dir = minetest.facedir_to_dir(node.param2)
    local relative_center = vector.multiply(back_dir, size + 1)
    local center = vector.add(pos, relative_center)
    return center
end
local function gen_next_digpos(center, digpos, size)
    digpos.x = digpos.x + 1
    if digpos.x > center.x + size then
        digpos.x = center.x - size
        digpos.z = digpos.z + 1
    end
    if digpos.z > center.z + size then
        digpos.x = center.x - size
        digpos.z = center.z - size
        digpos.y = digpos.y - 1
    end
end
local function find_next_digpos(data, area, center, dig_y, size)
    local c_air = minetest.get_content_id("air")
    for y = center.y + quarry_dig_above_nodes, dig_y - 1, -1 do
    for z = center.z - size, center.z + size do
    for x = center.x - size, center.x + size do
        if data[area:index(x, y, z)] ~= c_air then
            return vector.new(x, y, z)
        end
    end
    end
    end
end
local function quarry_dig(pos, center, size)
    local meta = minetest.get_meta(pos)
    local drops = {}
    local dig_y = meta:get_int("dig_y")
    local owner = meta:get_int("owner")
    local vm = VoxelManip()
    local p1 = vector.new(
            center.x - size,
            center.y + quarry_dig_above_nodes,
            center.z - size)
    local p2 = vector.new(
            center.x + size,
            dig_y - 1, -- One node lower in case we have finished the current layer
            center.z + size)
    local e1, e2 = vm:read_from_map(p1, p2)
    local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
    local data = vm:get_data()
    local digpos = find_next_digpos(data, area, center, dig_y, size)
    if digpos then
        if digpos.y < pos.y - quarry_max_depth then
            meta:set_int("dig_y", digpos.y)
            return drops
        end
        if minetest.is_protected and minetest.is_protected(digpos, owner) then
            meta:set_int("enabled", 0)
            return
        end
        dig_y = digpos.y
        local node = minetest.get_node(digpos)
        drops = minetest.get_node_drops(node.name, "")
        minetest.dig_node(digpos)
        if minetest.get_node(digpos).name == node.name then
            -- We tried to dig something undigable like a
            -- filled chest. Notice that we check for a node
            -- change, not for air. This is so that we get drops
            -- from things like concrete posts with platforms,
            -- which turn into regular concrete posts when dug.
            drops = {}
        end
    elseif not (dig_y < pos.y - quarry_max_depth) then
        dig_y = dig_y - 16
    end
    meta:set_int("dig_y", dig_y)
    return drops
end
local function send_items(items, pos, node)
    for _, item in pairs(items) do
        local tube_item = tube_item(vector.new(pos), item)
        tube_item:get_luaentity().start_pos = vector.new(pos)
        tube_item:setvelocity(vector.new(0, 1, 0))
        tube_item:setacceleration({x=0, y=0, z=0})
    end
end
minetest.register_node("technic:quarry", {
    description = "Quarry",
    tiles = {"default_steel_block.png", "default_steel_block.png",
             "default_steel_block.png", "default_steel_block.png",
             "default_steel_block.png^default_tool_mesepick.png", "default_steel_block.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, tubedevice=1},
    tube = {
        connect_sides = {top = 1},
    },
    on_construct = function(pos)
        local size = 4
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "Quarry")
        meta:set_string("formspec", get_quarry_formspec(4))
        meta:set_int("size", size)
        meta:set_int("dig_y", pos.y)
    end,
    after_place_node = function(pos, placer, itemstack)
        local meta = minetest.get_meta(pos)
        meta:set_string("owner", placer:get_player_name())
        tube_scanforobjects(pos)
    end,
    after_dig_node = tube_scanforobjects,
    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")
        technic.switching_station_timeout_count(pos, "HV")
        if meta:get_int("enabled") == 0 then
            meta:set_string("infotext", "Quarry Disabled")
            meta:set_int("HV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            meta:set_string("infotext", "Quarry Unpowered")
        elseif eu_input >= demand then
            meta:set_string("infotext", "Quarry Active")
            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", "Quarry Finished")
            end
        end
        meta:set_int("HV_EU_demand", demand)
    end
})
technic.register_machine("HV", "technic:quarry", technic.receiver)
technic/machines/HV/solar_array.lua
New file
@@ -0,0 +1,14 @@
-- The high voltage solar array is an assembly of medium voltage arrays.
-- Solar arrays are not able to store large amounts of energy.
minetest.register_craft({
    output = 'technic:solar_array_hv 1',
    recipe = {
        {'technic:solar_array_mv', 'technic:solar_array_mv',  'technic:solar_array_mv'},
        {'default:steel_ingot',    'technic:hv_transformer',  'default:steel_ingot'},
        {'',                       'technic:hv_cable0',       ''},
    }
})
technic.register_solar_array({tier="HV", power=100})
technic/machines/LV/alloy_furnace.lua
New file
@@ -0,0 +1,14 @@
-- LV Alloy furnace
-- FIXME: kpoppel: I'd like to introduce an induction heating element here...
minetest.register_craft({
    output = 'technic:lv_alloy_furnace',
    recipe = {
        {'default:brick',       'default:brick',        'default:brick'},
        {'default:brick',       '',                     'default:brick'},
        {'default:steel_ingot', 'default:copper_ingot', 'default:steel_ingot'},
    }
})
technic.register_alloy_furnace({tier="LV", cook_time=6, demand={300}})
technic/machines/LV/battery_box.lua
New file
@@ -0,0 +1,46 @@
-- LV Battery box and some other nodes...
technic.register_power_tool("technic:battery", 10000)
technic.register_power_tool("technic:red_energy_crystal", 100000)
technic.register_power_tool("technic:green_energy_crystal", 250000)
technic.register_power_tool("technic:blue_energy_crystal", 500000)
minetest.register_craft({
    output = 'technic:battery',
    recipe = {
        {'group:wood', 'default:copper_ingot', 'group:wood'},
        {'group:wood', 'moreores:tin_ingot',   'group:wood'},
        {'group:wood', 'default:copper_ingot', 'group:wood'},
    }
})
minetest.register_tool("technic:battery", {
    description = "RE Battery",
    inventory_image = "technic_battery.png",
    tool_capabilities = {
        charge = 0,
        max_drop_level = 0,
        groupcaps = {
            fleshy = {times={}, uses=10000, maxlevel=0}
        }
    }
})
minetest.register_craft({
    output = 'technic:lv_battery_box0',
    recipe = {
        {'technic:battery',     'group:wood',           'technic:battery'},
        {'technic:battery',     'default:copper_ingot', 'technic:battery'},
        {'default:steel_ingot', 'default:steel_ingot',  'default:steel_ingot'},
    }
})
technic.register_battery_box({
    tier           = "LV",
    max_charge     = 50000,
    charge_rate    = 1000,
    discharge_rate = 4000,
    charge_step    = 500,
    discharge_step = 800,
})
technic/machines/LV/cables.lua
New file
@@ -0,0 +1,12 @@
minetest.register_alias("lv_cable", "technic:lv_cable0")
minetest.register_craft({
    output = 'technic:lv_cable0 6',
    recipe = {
        {'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'},
    }
})
technic.register_cable("LV", 2/16)
technic/machines/LV/cnc.lua
New file
@@ -0,0 +1,254 @@
-- Technic CNC v1.0 by kpoppel
-- Based on the NonCubic Blocks MOD v1.4 by yves_de_beck
-- Idea:
--   Somehow have a tabbed/paged panel if the number of shapes should expand
--   beyond what is available in the panel today.
--   I could imagine some form of API allowing modders to come with their own node
--   box definitions and easily stuff it in the this machine for production.
local shape = {}
local onesize_products = {
    slope                    = 2,
    slope_edge               = 1,
    slope_inner_edge         = 1,
    pyramid                  = 2,
    spike                    = 1,
    cylinder                 = 2,
    sphere                   = 1,
    stick                    = 8,
    slope_upsdown            = 2,
    slope_edge_upsdown       = 1,
    slope_inner_edge_upsdown = 1,
    cylinder_horizontal      = 2,
    slope_lying              = 2,
    onecurvededge            = 1,
    twocurvededge            = 1,
}
local twosize_products = {
    element_straight         = 4,
    element_end              = 2,
    element_cross            = 1,
    element_t                = 1,
    element_edge             = 2,
}
local cnc_formspec =
    "invsize[9,11;]"..
    "label[1,0;Choose Milling Program:]"..
    "image_button[1,0.5;1,1;technic_cnc_slope.png;slope; ]"..
    "image_button[2,0.5;1,1;technic_cnc_slope_edge.png;slope_edge; ]"..
    "image_button[3,0.5;1,1;technic_cnc_slope_inner_edge.png;slope_inner_edge; ]"..
    "image_button[4,0.5;1,1;technic_cnc_pyramid.png;pyramid; ]"..
    "image_button[5,0.5;1,1;technic_cnc_spike.png;spike; ]"..
    "image_button[6,0.5;1,1;technic_cnc_cylinder.png;cylinder; ]"..
    "image_button[7,0.5;1,1;technic_cnc_sphere.png;sphere; ]"..
    "image_button[8,0.5;1,1;technic_cnc_stick.png;stick; ]"..
    "image_button[1,1.5;1,1;technic_cnc_slope_upsdwn.png;slope_upsdown; ]"..
    "image_button[2,1.5;1,1;technic_cnc_slope_edge_upsdwn.png;slope_edge_upsdown; ]"..
    "image_button[3,1.5;1,1;technic_cnc_slope_inner_edge_upsdwn.png;slope_inner_edge_upsdown; ]"..
    "image_button[4,1.5;1,1;technic_cnc_cylinder_horizontal.png;cylinder_horizontal; ]"..
    "image_button[1,2.5;1,1;technic_cnc_slope_lying.png;slope_lying; ]"..
    "image_button[2,2.5;1,1;technic_cnc_onecurvededge.png;onecurvededge; ]"..
    "image_button[3,2.5;1,1;technic_cnc_twocurvededge.png;twocurvededge; ]"..
    "label[1,3.5;Slim Elements half / normal height:]"..
    "image_button[1,4;1,0.5;technic_cnc_full.png;full; ]"..
    "image_button[1,4.5;1,0.5;technic_cnc_half.png;half; ]"..
    "image_button[2,4;1,1;technic_cnc_element_straight.png;element_straight; ]"..
    "image_button[3,4;1,1;technic_cnc_element_end.png;element_end; ]"..
    "image_button[4,4;1,1;technic_cnc_element_cross.png;element_cross; ]"..
    "image_button[5,4;1,1;technic_cnc_element_t.png;element_t; ]"..
    "image_button[6,4;1,1;technic_cnc_element_edge.png;element_edge; ]"..
    "label[0, 5.5;In:]"..
    "list[current_name;src;0.5,5.5;1,1;]"..
    "label[4, 5.5;Out:]"..
    "list[current_name;dst;5,5.5;4,1;]"..
    "list[current_player;main;0,7;8,4;]"
local size = 1;
-- The form handler is declared here because we need it in both the inactive and active modes
-- in order to be able to change programs wile it is running.
local function form_handler(pos, formname, fields, sender)
    -- REGISTER MILLING PROGRAMS AND OUTPUTS:
    ------------------------------------------
    -- Program for half/full size
    if fields["full"] then
        size = 1
        return
    end
    if fields["half"] then
        size = 2
        return
    end
    -- Resolve the node name and the number of items to make
    local meta       = minetest.get_meta(pos)
    local inv        = meta:get_inventory()
    local inputstack = inv:get_stack("src", 1)
    local inputname  = inputstack:get_name()
    local multiplier = 0
    for k, _ in pairs(fields) do
        -- Set a multipier for the half/full size capable blocks
        if twosize_products[k] ~= nil then
            multiplier = size * twosize_products[k]
        else
            multiplier = onesize_products[k]
        end
        if onesize_products[k] ~= nil or twosize_products[k] ~= nil then
            meta:set_float( "cnc_multiplier", multiplier)
            meta:set_string("cnc_user", sender:get_player_name())
        end
        if onesize_products[k] ~= nil or (twosize_products[k] ~= nil and size==2) then
            meta:set_string("cnc_product",  inputname .. "_technic_cnc_" .. k)
            --print(inputname .. "_technic_cnc_" .. k)
            break
        end
        if twosize_products[k] ~= nil and size==1 then
            meta:set_string("cnc_product",  inputname .. "_technic_cnc_" .. k .. "_double")
            --print(inputname .. "_technic_cnc_" .. k .. "_double")
            break
        end
    end
    return
end
-- The actual block inactive state
minetest.register_node("technic:cnc", {
    description = "CNC Milling Machine",
    tiles       = {"technic_cnc_top.png", "technic_cnc_bottom.png", "technic_cnc_side.png",
                   "technic_cnc_side.png", "technic_cnc_side.png", "technic_cnc_front.png"},
    drawtype    = "nodebox",
    paramtype   = "light",
    paramtype2  = "facedir",
    node_box    = {
        type  = "fixed",
        fixed = {
            {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
        },
    },
    groups = {cracky=2},
    legacy_facedir_simple = true,
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "CNC Machine")
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", cnc_formspec)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 4)
    end,
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") or not inv:is_empty("dst") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
    on_receive_fields = form_handler,
})
-- Active state block
minetest.register_node("technic:cnc_active", {
    description = "CNC Machine",
    tiles       = {"technic_cnc_top_active.png", "technic_cnc_bottom.png", "technic_cnc_side.png",
                   "technic_cnc_side.png",       "technic_cnc_side.png",   "technic_cnc_front_active.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") or not inv:is_empty("dst") then
            minetest.chat_send_player(player:get_player_name(),
                "CNC machine cannot be removed because it is not empty");
            return false
        end
        return true
    end,
    on_receive_fields = form_handler,
})
-- 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 = "CNC"
        local machine_node = "technic:cnc"
        local demand       = 450
        -- Setup meta data if it does not exist. state is used as an indicator of this
        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")
        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
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Idle")
            meta:set_string("cnc_product", "")
            return
        end
        if eu_input < demand then
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
        elseif eu_input >= demand then
            hacky_swap_node(pos, machine_node.."_active")
            meta:set_string("infotext", machine_name.." Active")
            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)
-------------------------
-- CNC Machine Recipe
-------------------------
minetest.register_craft({
    output = 'technic:cnc',
    recipe = {
        {'default:glass',              'technic:diamond_drill_head', 'default:glass'},
        {'technic:control_logic_unit', 'technic:motor',              'default:steel_ingot'},
        {'default:steel_ingot',        'default:copper_ingot',       'default:steel_ingot'},
    },
})
technic/machines/LV/cnc_api.lua
New file
@@ -0,0 +1,354 @@
-- API for the technic CNC machine
-- Again code is adapted from the NonCubic Blocks MOD v1.4 by yves_de_beck
technic.cnc = {}
technic.cnc.detail_level = 16
-- REGISTER NONCUBIC FORMS, CREATE MODELS AND RECIPES:
------------------------------------------------------
local function cnc_sphere()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    local sehne
    for i = 1, detail - 1 do
        sehne = math.sqrt(0.25 - (((i / detail) - 0.5) ^ 2))
        nodebox[i]={-sehne, (i/detail) - 0.5, -sehne, sehne, (i/detail)+(1/detail)-0.5, sehne}
    end
    return nodebox
end
local function cnc_cylinder_horizontal()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    local sehne
    for i = 1, detail - 1 do
        sehne = math.sqrt(0.25 - (((i / detail) - 0.5) ^ 2))
        nodebox[i]={-0.5, (i/detail)-0.5, -sehne, 0.5, (i/detail)+(1/detail)-0.5, sehne}
    end
    return nodebox
end
local function cnc_cylinder()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    local sehne
    for i = 1, detail - 1 do
        sehne = math.sqrt(0.25 - (((i / detail) - 0.5) ^ 2))
        nodebox[i]={(i/detail) - 0.5, -0.5, -sehne, (i/detail)+(1/detail)-0.5, 0.5, sehne}
    end
    return nodebox
end
local function cnc_twocurvededge()
    local nodebox = {}
    local detail = technic.cnc.detail_level * 2
    local sehne
    for i = (detail / 2) - 1, detail - 1 do
        sehne = math.sqrt(0.25 - (((i / detail) - 0.5) ^ 2))
        nodebox[i]={-sehne, -0.5, -sehne, 0.5, (i/detail)+(1/detail)-0.5, 0.5}
    end
    return nodebox
end
local function cnc_onecurvededge()
    local nodebox = {}
    local detail = technic.cnc.detail_level * 2
    local sehne
    for i = (detail / 2) - 1, detail - 1 do
        sehne = math.sqrt(0.25 - (((i / detail) - 0.5) ^ 2))
        nodebox[i]={-0.5, -0.5, -sehne, 0.5, (i/detail)+(1/detail)-0.5, 0.5}
    end
    return nodebox
end
local function cnc_spike()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail - 1 do
        nodebox[i+1] = {(i/detail/2)-0.5, (i/detail/2)-0.5, (i/detail/2)-0.5,
                0.5-(i/detail/2), (i/detail)-0.5+(1/detail), 0.5-(i/detail/2)}
    end
    return nodebox
end
local function cnc_pyramid()
    local nodebox = {}
    local detail = technic.cnc.detail_level / 2
    for i = 0, detail - 1 do
        nodebox[i+1] = {(i/detail/2)-0.5, (i/detail/2)-0.5, (i/detail/2)-0.5, 0.5-(i/detail/2), (i/detail/2)-0.5+(1/detail), 0.5-(i/detail/2)}
    end
    return nodebox
end
local function cnc_slope_inner_edge_upsdown()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {0.5-(i/detail)-(1/detail), (i/detail)-0.5, -0.5, 0.5, (i/detail)-0.5+(1/detail), 0.5}
        nodebox[i+detail+1] = {-0.5, (i/detail)-0.5, 0.5-(i/detail)-(1/detail), 0.5, (i/detail)-0.5+(1/detail), 0.5}
    end
    return nodebox
end
local function cnc_slope_edge_upsdown()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {(-1*(i/detail))+0.5-(1/detail), (i/detail)-0.5, (-1*(i/detail))+0.5-(1/detail), 0.5, (i/detail)-0.5+(1/detail), 0.5}
    end
    return nodebox
end
local function cnc_slope_inner_edge()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {(i/detail)-0.5, -0.5, -0.5, 0.5, (i/detail)-0.5+(1/detail), 0.5}
        nodebox[i+detail+1] = {-0.5, -0.5, (i/detail)-0.5, 0.5, (i/detail)-0.5+(1/detail), 0.5}
    end
    return nodebox
end
local function cnc_slope_edge()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {(i/detail)-0.5, -0.5, (i/detail)-0.5, 0.5, (i/detail)-0.5+(1/detail), 0.5}
    end
    return nodebox
end
local function cnc_slope_upsdown()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {-0.5, (i/detail)-0.5, (-1*(i/detail))+0.5-(1/detail), 0.5, (i/detail)-0.5+(1/detail), 0.5}
    end
    return nodebox
end
local function cnc_slope_lying()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {(i/detail)-0.5, -0.5, (i/detail)-0.5, (i/detail)-0.5+(1/detail), 0.5 , 0.5}
    end
    return nodebox
end
local function cnc_slope()
    local nodebox = {}
    local detail = technic.cnc.detail_level
    for i = 0, detail-1 do
        nodebox[i+1] = {-0.5, (i/detail)-0.5, (i/detail)-0.5, 0.5, (i/detail)-0.5+(1/detail), 0.5}
    end
    return nodebox
end
-- Define slope boxes for the various nodes
-------------------------------------------
technic.cnc.programs = {
    {suffix  = "technic_cnc_stick",
    nodebox = {-0.15, -0.5, -0.15, 0.15, 0.5, 0.15},
    desc    = "Stick"},
    {suffix  = "technic_cnc_element_end_double",
    nodebox = {-0.3, -0.5, -0.3, 0.3, 0.5, 0.5},
    desc    = "Element End Double"},
    {suffix  = "technic_cnc_element_cross_double",
    nodebox = {
        {0.3, -0.5, -0.3, 0.5, 0.5, 0.3},
        {-0.3, -0.5, -0.5, 0.3, 0.5, 0.5},
        {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}},
    desc    = "Element Cross Double"},
    {suffix  = "technic_cnc_element_t_double",
    nodebox = {
        {-0.3, -0.5, -0.5, 0.3, 0.5, 0.3},
        {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3},
        {0.3, -0.5, -0.3, 0.5, 0.5, 0.3}},
    desc    = "Element T Double"},
    {suffix  = "technic_cnc_element_edge_double",
    nodebox = {
        {-0.3, -0.5, -0.5, 0.3, 0.5, 0.3},
        {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}},
    desc    = "Element Edge Double"},
    {suffix  = "technic_cnc_element_straight_double",
    nodebox = {-0.3, -0.5, -0.5, 0.3, 0.5, 0.5},
    desc    = "Element Straight Double"},
    {suffix  = "technic_cnc_element_end",
    nodebox = {-0.3, -0.5, -0.3, 0.3, 0, 0.5},
    desc    = "Element End"},
    {suffix  = "technic_cnc_element_cross",
    nodebox = {
        {0.3, -0.5, -0.3, 0.5, 0, 0.3},
        {-0.3, -0.5, -0.5, 0.3, 0, 0.5},
        {-0.5, -0.5, -0.3, -0.3, 0, 0.3}},
    desc    = "Element Cross"},
    {suffix  = "technic_cnc_element_t",
    nodebox = {
        {-0.3, -0.5, -0.5, 0.3, 0, 0.3},
        {-0.5, -0.5, -0.3, -0.3, 0, 0.3},
        {0.3, -0.5, -0.3, 0.5, 0, 0.3}},
    desc    = "Element T"},
    {suffix  = "technic_cnc_element_edge",
    nodebox = {
        {-0.3, -0.5, -0.5, 0.3, 0, 0.3},
        {-0.5, -0.5, -0.3, -0.3, 0, 0.3}},
    desc    = "Element Edge"},
    {suffix  = "technic_cnc_element_straight",
    nodebox = {-0.3, -0.5, -0.5, 0.3, 0, 0.5},
    desc    = "Element Straight"},
    {suffix  = "technic_cnc_sphere",
    nodebox = cnc_sphere(),
    desc    = "Sphere"},
    {suffix  = "technic_cnc_cylinder_horizontal",
    nodebox = cnc_cylinder_horizontal(),
    desc    = "Cylinder Horizontal"},
    {suffix  = "technic_cnc_cylinder",
    nodebox = cnc_cylinder(),
    desc    = ""},
    {suffix  = "technic_cnc_twocurvededge",
    nodebox = cnc_twocurvededge(),
    desc    = "One Curved Edge Block"},
    {suffix  = "technic_cnc_onecurvededge",
    nodebox = cnc_onecurvededge(),
    desc    = "Two Curved Edge Block"},
    {suffix  = "technic_cnc_spike",
    nodebox = cnc_spike(),
    desc    = "Spike"},
    {suffix  = "technic_cnc_pyramid",
    nodebox = cnc_pyramid(),
    desc    = "Pyramid"},
    {suffix  = "technic_cnc_slope_inner_edge_upsdown",
    nodebox = cnc_slope_inner_edge_upsdown(),
    desc    = "Slope Upside Down Inner Edge"},
    {suffix  = "technic_cnc_slope_edge_upsdown",
    nodebox = cnc_slope_edge_upsdown(),
    desc    = "Slope Upside Down Edge"},
    {suffix  = "technic_cnc_slope_inner_edge",
    nodebox = cnc_slope_inner_edge(),
    desc    = "Slope Inner Edge"},
    {suffix  = "technic_cnc_slope_edge",
    nodebox = cnc_slope_edge(),
    desc    = "Slope Edge"},
    {suffix  = "technic_cnc_slope_upsdown",
    nodebox = cnc_slope_upsdown(),
    desc    = "Slope Upside Down"},
    {suffix  = "technic_cnc_slope_lying",
    nodebox = cnc_slope_lying(),
    desc    = "Slope Lying"},
    {suffix  = "technic_cnc_slope",
    nodebox = cnc_slope(),
    desc    = "Slope"},
}
-- Allow disabling certain programs for some node. Default is allowing all types for all nodes
technic.cnc.programs_disable = {
    -- ["default:brick"] = {"technic_cnc_stick"}, -- Example: Disallow the stick for brick
    -- ...
    ["default:dirt"] = {"technic_cnc_sphere", "technic_cnc_slope_upsdown", "technic_cnc_edge",
                        "technic_cnc_inner_edge", "technic_cnc_slope_edge_upsdown",
                        "technic_cnc_slope_inner_edge_upsdown", "technic_cnc_stick",
                        "technic_cnc_cylinder_horizontal"}
}
-- Generic function for registering all the different node types
function technic.cnc.register_program(recipeitem, suffix, nodebox, groups, images, description)
    minetest.register_node(":"..recipeitem.."_"..suffix, {
        description   = description,
        drawtype      = "nodebox",
        tiles         = images,
        paramtype     = "light",
        paramtype2    = "facedir",
        walkable      = true,
        node_box = {
            type  = "fixed",
            fixed = nodebox
        },
        groups        = groups,
    })
end
-- function to iterate over all the programs the CNC machine knows
function technic.cnc.register_all(recipeitem, groups, images, description)
    for _, data in ipairs(technic.cnc.programs) do
        -- Disable node creation for disabled node types for some material
        local do_register = true
        if technic.cnc.programs_disable[recipeitem] ~= nil then
            for __, disable in ipairs(technic.cnc.programs_disable[recipeitem]) do
                if disable == data.suffix then
                    do_register = false
                end
            end
        end
        -- Create the node if it passes the test
        if do_register then
            technic.cnc.register_program(recipeitem, data.suffix, data.nodebox, groups, images, description.." "..data.desc)
        end
    end
end
-- REGISTER NEW TECHNIC_CNC_API's PART 2: technic.cnc..register_element_end(subname, recipeitem, groups, images, desc_element_xyz)
-----------------------------------------------------------------------------------------------------------------------
function technic.cnc.register_slope_edge_etc(recipeitem, groups, images, desc_slope, desc_slope_lying, desc_slope_upsdown, desc_slope_edge, desc_slope_inner_edge, desc_slope_upsdwn_edge, desc_slope_upsdwn_inner_edge, desc_pyramid, desc_spike, desc_onecurvededge, desc_twocurvededge, desc_cylinder, desc_cylinder_horizontal, desc_sphere, desc_element_straight, desc_element_edge, desc_element_t, desc_element_cross, desc_element_end)
         technic.cnc.register_slope(recipeitem, groups, images, desc_slope)
         technic.cnc.register_slope_lying(recipeitem, groups, images, desc_slope_lying)
         technic.cnc.register_slope_upsdown(recipeitem, groups, images, desc_slope_upsdown)
         technic.cnc.register_slope_edge(recipeitem, groups, images, desc_slope_edge)
         technic.cnc.register_slope_inner_edge(recipeitem, groups, images, desc_slope_inner_edge)
         technic.cnc.register_slope_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_edge)
         technic.cnc.register_slope_inner_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_inner_edge)
         technic.cnc.register_pyramid(recipeitem, groups, images, desc_pyramid)
         technic.cnc.register_spike(recipeitem, groups, images, desc_spike)
         technic.cnc.register_onecurvededge(recipeitem, groups, images, desc_onecurvededge)
         technic.cnc.register_twocurvededge(recipeitem, groups, images, desc_twocurvededge)
         technic.cnc.register_cylinder(recipeitem, groups, images, desc_cylinder)
         technic.cnc.register_cylinder_horizontal(recipeitem, groups, images, desc_cylinder_horizontal)
         technic.cnc.register_sphere(recipeitem, groups, images, desc_sphere)
         technic.cnc.register_element_straight(recipeitem, groups, images, desc_element_straight)
         technic.cnc.register_element_edge(recipeitem, groups, images, desc_element_edge)
         technic.cnc.register_element_t(recipeitem, groups, images, desc_element_t)
         technic.cnc.register_element_cross(recipeitem, groups, images, desc_element_cross)
         technic.cnc.register_element_end(recipeitem, groups, images, desc_element_end)
end
-- REGISTER STICKS: noncubic.register_xyz(recipeitem, groups, images, desc_element_xyz)
------------------------------------------------------------------------------------------------------------
function technic.cnc.register_stick_etc(recipeitem, groups, images, desc_stick)
         technic.cnc.register_stick(recipeitem, groups, images, desc_stick)
end
function technic.cnc.register_elements(recipeitem, groups, images, desc_element_straight_double, desc_element_edge_double, desc_element_t_double, desc_element_cross_double, desc_element_end_double)
         technic.cnc.register_element_straight_double(recipeitem, groups, images, desc_element_straight_double)
         technic.cnc.register_element_edge_double(recipeitem, groups, images, desc_element_edge_double)
         technic.cnc.register_element_t_double(recipeitem, groups, images, desc_element_t_double)
         technic.cnc.register_element_cross_double(recipeitem, groups, images, desc_element_cross_double)
         technic.cnc.register_element_end_double(recipeitem, groups, images, desc_element_end_double)
end
technic/machines/LV/cnc_nodes.lua
New file
@@ -0,0 +1,71 @@
-- REGISTER MATERIALS AND PROPERTIES FOR NONCUBIC ELEMENTS:
-----------------------------------------------------------
-- DIRT
-------
technic.cnc.register_all("default:dirt",
                {snappy=2,choppy=2,oddly_breakable_by_hand=3,not_in_creative_inventory=1},
                {"default_grass.png", "default_dirt.png", "default_grass.png"},
                "Dirt")
technic.cnc.programs_disable["default:dirt"] = {"technic_cnc_sphere", "technic_cnc_slope_upsdown",
        "technic_cnc_edge",   "technic_cnc_inner_edge",
        "technic_cnc_slope_edge_upsdown", "technic_cnc_slope_inner_edge_upsdown",
        "technic_cnc_stick", "technic_cnc_cylinder_horizontal"}
-- TREE
-------
technic.cnc.register_all("default:tree",
                {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
                {"default_tree.png"},
                "Wooden")
-- WOOD
-------
technic.cnc.register_all("default:wood",
                {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
                {"default_wood.png"},
                "Wooden")
-- STONE
--------
technic.cnc.register_all("default:stone",
                {cracky=3, not_in_creative_inventory=1},
                {"default_stone.png"},
                "Stone")
-- COBBLE
---------
technic.cnc.register_all("default:cobble",
                {cracky=3, not_in_creative_inventory=1},
                {"default_cobble.png"},
                "Cobble")
-- BRICK
--------
technic.cnc.register_all("default:brick",
                {cracky=3, not_in_creative_inventory=1},
                {"default_brick.png"},
                "Brick")
-- SANDSTONE
------------
technic.cnc.register_all("default:sandstone",
                {crumbly=2, cracky=2, not_in_creative_inventory=1},
                {"default_sandstone.png"},
                "Sandstone")
-- LEAVES
---------
technic.cnc.register_all("default:leaves",
                {snappy=2, choppy=2, oddly_breakable_by_hand=3, not_in_creative_inventory=1},
                {"default_leaves.png"},
                "Leaves")
-- TREE
-------
technic.cnc.register_all("default:tree",
                {snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=3, wood=1, not_in_creative_inventory=1},
                {"default_tree.png"},
                "Tree")
-- STEEL
--------
technic.cnc.register_all("default:steel",
                {snappy=1, bendy=2, cracky=1, melty=2, level=2, not_in_creative_inventory=1},
                {"default_steel_block.png"},
                "Steel")
technic/machines/LV/coal_alloy_furnace.lua
New file
@@ -0,0 +1,181 @@
-- Coal driven alloy furnace. This uses no EUs:
minetest.register_craft({
    output = 'technic:coal_alloy_furnace',
    recipe = {
        {'default:brick', 'default:brick', 'default:brick'},
        {'default:brick', '',              'default:brick'},
        {'default:brick', 'default:brick', 'default:brick'},
    }
})
minetest.register_node("technic:coal_alloy_furnace", {
    description = "Alloy Furnace",
    tiles = {"technic_coal_alloy_furnace_top.png", "technic_coal_alloy_furnace_bottom.png", "technic_coal_alloy_furnace_side.png",
        "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2},
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("formspec", coal_alloy_furnace_formspec)
        meta:set_string("infotext", "Alloy Furnace")
        local inv = meta:get_inventory()
        inv:set_size("fuel", 1)
        inv:set_size("src", 1)
        inv:set_size("src2", 1)
        inv:set_size("dst", 4)
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not (inv:is_empty("fuel") or inv:is_empty("dst") or inv:is_empty("src") or inv:is_empty("src2") )then
            return false
            end
        return true
    end,
})
minetest.register_node("technic:coal_alloy_furnace_active", {
    description = "Alloy Furnace",
    tiles = {"technic_coal_alloy_furnace_top.png", "technic_coal_alloy_furnace_bottom.png", "technic_coal_alloy_furnace_side.png",
             "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:coal_alloy_furnace",
    groups = {cracky=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not (inv:is_empty("fuel") or inv:is_empty("dst") or
            inv:is_empty("src") or inv:is_empty("src2")) then
            return false
        end
        return true
    end,
})
minetest.register_abm({
    nodenames = {"technic:coal_alloy_furnace", "technic:coal_alloy_furnace_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 recipe = nil
        local formspec =
            "size[8,9]"..
            "label[0,0;Alloy Furnace]"..
            "image[2,2;1,1;default_furnace_fire_bg.png]"..
            "list[current_name;fuel;2,3;1,1;]"..
            "list[current_name;src;2,1;1,1;]"..
            "list[current_name;src2;3,1;1,1;]"..
            "list[current_name;dst;5,1;2,2;]"..
            "list[current_player;main;0,5;8,4;]"
        for i, name in pairs({
                "fuel_totaltime",
                "fuel_time",
                "src_totaltime",
                "src_time"}) do
            if not meta:get_float(name) then
                meta:set_float(name, 0.0)
            end
        end
        -- Get what to cook if anything
        local srcstack = inv:get_stack("src", 1)
        local src2stack = inv:get_stack("src2", 1)
        local recipe = technic.get_alloy_recipe(srcstack, src2stack)
        if srcstack:get_name() > src2stack:get_name() then
            local temp = srcstack
            srcstack = src2stack
            src2stack = temp
        end
        local was_active = false
        if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then
            was_active = true
            meta:set_int("fuel_time", meta:get_int("fuel_time") + 1)
            if recipe then
                meta:set_int("src_time", meta:get_int("src_time") + 1)
                if meta:get_int("src_time") == 6 then
                    -- check if there's room for output in "dst" list
                    local dst_stack = ItemStack(recipe.output)
                    if inv:room_for_item("dst", dst_stack) then
                        srcstack:take_item(recipe.input[1].count)
                        inv:set_stack("src", 1, srcstack)
                        src2stack:take_item(recipe.input[2].count)
                        inv:set_stack("src2", 1, src2stack)
                        inv:add_item("dst", dst_stack)
                    end
                    meta:set_int("src_time", 0)
                end
            else
                meta:set_int("src_time", 0)
            end
        end
        if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then
            local percent = math.floor(meta:get_float("fuel_time") /
                    meta:get_float("fuel_totaltime") * 100)
            meta:set_string("infotext","Furnace active: "..percent.."%")
            hacky_swap_node(pos, "technic:coal_alloy_furnace_active")
            meta:set_string("formspec",
                    "size[8,9]"..
                    "label[0,0;Electric Alloy Furnace]"..
                    "image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:"..
                    (100-percent)..":default_furnace_fire_fg.png]"..
                    "list[current_name;fuel;2,3;1,1;]"..
                    "list[current_name;src;2,1;1,1;]"..
                    "list[current_name;src2;3,1;1,1;]"..
                    "list[current_name;dst;5,1;2,2;]"..
                    "list[current_player;main;0,5;8,4;]")
            return
        end
        -- FIXME: Make this look more like the electrical version.
        -- This code refetches the recipe to see if it can be done again after the iteration
        srcstack = inv:get_stack("src", 1)
        srcstack = inv:get_stack("src2", 1)
        local recipe = technic.get_alloy_recipe(srcstack, src2stack)
        if recipe then
            if was_active then
                meta:set_string("infotext", "Furnace is empty")
                hacky_swap_node(pos, "technic:coal_alloy_furnace")
                meta:set_string("formspec", formspec)
            end
            return
        end
        -- Next take a hard look at the fuel situation
        local fuel = nil
        local fuellist = inv:get_list("fuel")
        if fuellist then
            fuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
        end
        if fuel.time <= 0 then
            meta:set_string("infotext", "Furnace out of fuel")
            hacky_swap_node(pos, "technic:coal_alloy_furnace")
            meta:set_string("formspec", formspec)
            return
        end
        meta:set_string("fuel_totaltime", fuel.time)
        meta:set_string("fuel_time", 0)
        local stack = inv:get_stack("fuel", 1)
        stack:take_item()
        inv:set_stack("fuel", 1, stack)
    end,
})
technic/machines/LV/compressor.lua
New file
@@ -0,0 +1,169 @@
technic.compressor_recipes ={}
technic.register_compressor_recipe = function(src, src_count, dst, dst_count)
    technic.compressor_recipes[src] = {src_count = src_count, dst_name = dst, dst_count = dst_count}
    if unified_inventory then
        unified_inventory.register_craft(
        {
            type = "compressing",
            output = dst.." "..dst_count,
            items = {src.." "..src_count},
            width = 0,
        })
    end
end
technic.get_compressor_recipe = function(item)
    if technic.compressor_recipes[item.name] and
       item.count >= technic.compressor_recipes[item.name].src_count then
        return technic.compressor_recipes[item.name]
    else
        return nil
    end
end
technic.register_compressor_recipe("default:snowblock",         1, "default:ice",             1)
technic.register_compressor_recipe("default:sand",              1, "default:sandstone",       1)
technic.register_compressor_recipe("default:desert_sand",       1, "default:desert_stone",    1)
technic.register_compressor_recipe("technic:mixed_metal_ingot", 1, "technic:composite_plate", 1)
technic.register_compressor_recipe("default:copper_ingot",      5, "technic:copper_plate",    1)
technic.register_compressor_recipe("technic:coal_dust",         4, "technic:graphite",        1)
technic.register_compressor_recipe("technic:carbon_cloth",      1, "technic:carbon_plate",    1)
technic.register_compressor_recipe("technic:enriched_uranium",  4, "technic:uranium_fuel",    1)
minetest.register_alias("compressor", "technic:compressor")
minetest.register_craft({
    output = 'technic:compressor',
    recipe = {
        {'default:stone',    'default:stone',    'default:stone'},
        {'mesecons:piston',    'technic:motor',    'mesecons:piston'},
        {'default:stone',    'technic:lv_cable0',    'default:stone'},
    }
})
local compressor_formspec =
    "invsize[8,9;]"..
    "label[0,0;Compressor]"..
    "list[current_name;src;3,1;1,1;]"..
    "list[current_name;dst;5,1;2,2;]"..
    "list[current_player;main;0,5;8,4;]"
minetest.register_node("technic:compressor", {
    description = "Compressor",
    tiles = {"technic_compressor_top.png",  "technic_compressor_bottom.png",
             "technic_compressor_side.png", "technic_compressor_side.png",
             "technic_compressor_back.png", "technic_compressor_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=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", "Compressor")
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", compressor_formspec)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 4)
    end,
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        if not inv:is_empty("src") or not inv:is_empty("dst") then
            minetest.chat_send_player(player:get_player_name(),
                    "Machine cannot be removed because it is not empty")
            return false
        else
            return true
        end
    end,
})
minetest.register_node("technic:compressor_active", {
    description = "Compressor",
    tiles = {"technic_compressor_top.png",  "technic_compressor_bottom.png",
             "technic_compressor_side.png", "technic_compressor_side.png",
             "technic_compressor_back.png", "technic_compressor_front_active.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") or not inv:is_empty("dst") then
            minetest.chat_send_player(player:get_player_name(),
                    "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
minetest.register_abm({
    nodenames = {"technic:compressor","technic:compressor_active"},
    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 = "Compressor"
        local machine_node = "technic:compressor"
        local demand       = 300
         -- 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")
        local inv    = meta:get_inventory()
        local empty  = inv:is_empty("src")
        local srcstack  = inv:get_stack("src", 1)
        local src_item, recipe, result = nil, nil, nil
        if srcstack then
            src_item = srcstack:to_table()
        end
        if src_item then
            recipe = technic.get_compressor_recipe(src_item)
        end
        if recipe then
            result = {name=recipe.dst_name, count=recipe.dst_count}
        end
        if empty or (not result) or
           (not inv:room_for_item("dst", result)) then
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Idle")
            meta:set_int("LV_EU_demand", 0)
            meta:set_int("src_time", 0)
            return
        end
        if eu_input < demand then
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
        elseif eu_input >= demand then
            hacky_swap_node(pos, machine_node.."_active")
            meta:set_string("infotext", machine_name.." Active")
            meta:set_int("src_time", meta:get_int("src_time") + 1)
            if meta:get_int("src_time") >= 4 then
                meta:set_int("src_time", 0)
                srcstack:take_item(recipe.src_count)
                inv:set_stack("src", 1, srcstack)
                inv:add_item("dst", result)
            end
        end
        meta:set_int("LV_EU_demand", demand)
    end
})
technic.register_machine("LV", "technic:compressor",        technic.receiver)
technic.register_machine("LV", "technic:compressor_active", technic.receiver)
technic/machines/LV/electric_furnace.lua
New file
@@ -0,0 +1,16 @@
-- LV Electric Furnace
-- This is a faster version of the stone furnace which runs on EUs
-- FIXME: kpoppel I'd like to introduce an induction heating element here also
minetest.register_craft({
    output = 'technic:electric_furnace',
    recipe = {
        {'default:cobble',      'default:cobble',        'default:cobble'},
        {'default:cobble',      '',                      'default:cobble'},
        {'default:steel_ingot', 'moreores:copper_ingot', 'default:steel_ingot'},
    }
})
technic.register_electric_furnace({tier="LV", demand={300}, speed = 2})
technic/machines/LV/extractor.lua
New file
@@ -0,0 +1,175 @@
technic.extractor_recipes ={}
technic.register_extractor_recipe = function(src, src_count, dst, dst_count)
    technic.extractor_recipes[src] = {src_count = src_count, dst_name = dst, dst_count = dst_count}
    if unified_inventory then
        unified_inventory.register_craft({
            type = "extracting",
            output = dst.." "..dst_count,
            items = {src.." "..src_count},
            width = 0,
        })
    end
end
-- Receive an ItemStack of result by an ItemStack input
technic.get_extractor_recipe = function(item)
    if technic.extractor_recipes[item.name] and
       item.count >= technic.extractor_recipes[item.name].src_count then
        return technic.extractor_recipes[item.name]
    else
        return nil
    end
end
technic.register_extractor_recipe("technic:coal_dust",        1,          "dye:black",      2)
technic.register_extractor_recipe("default:cactus",           1,          "dye:green",      2)
technic.register_extractor_recipe("default:dry_shrub",        1,          "dye:brown",      2)
technic.register_extractor_recipe("flowers:geranium",         1,          "dye:blue",       2)
technic.register_extractor_recipe("flowers:dandelion_white",  1,          "dye:white",      2)
technic.register_extractor_recipe("flowers:dandelion_yellow", 1,          "dye:yellow",     2)
technic.register_extractor_recipe("flowers:tulip",            1,          "dye:orange",     2)
technic.register_extractor_recipe("flowers:rose",             1,          "dye:red",        2)
technic.register_extractor_recipe("flowers:viola",            1,          "dye:violet",     2)
technic.register_extractor_recipe("technic:raw_latex",        1,          "technic:rubber", 3)
technic.register_extractor_recipe("moretrees:rubber_tree_trunk_empty", 1, "technic:rubber", 1)
technic.register_extractor_recipe("moretrees:rubber_tree_trunk",       1, "technic:rubber", 1)
technic.register_extractor_recipe("technic:uranium",          5,          "technic:enriched_uranium", 1)
minetest.register_alias("extractor", "technic:extractor")
minetest.register_craft({
    output = 'technic:extractor',
    recipe = {
        {'technic:treetap', 'technic:motor',     'technic:treetap'},
        {'technic:treetap', 'technic:lv_cable0', 'technic:treetap'},
        {'',                '',                  ''},
    }
})
local extractor_formspec =
   "invsize[8,9;]"..
   "label[0,0;Extractor]"..
   "list[current_name;src;3,1;1,1;]"..
   "list[current_name;dst;5,1;2,2;]"..
   "list[current_player;main;0,5;8,4;]"
minetest.register_node("technic:extractor", {
    description = "Extractor",
    tiles = {"technic_lv_grinder_top.png",  "technic_lv_grinder_bottom.png", "technic_lv_grinder_side.png",
             "technic_lv_grinder_side.png", "technic_lv_grinder_side.png",   "technic_lv_grinder_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=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", "Extractor")
        meta:set_string("formspec", extractor_formspec)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 4)
    end,
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") or not inv:is_empty("dst") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
minetest.register_node("technic:extractor_active", {
    description = "Extractor",
    tiles = {"technic_lv_grinder_top.png",  "technic_lv_grinder_bottom.png",
             "technic_lv_grinder_side.png", "technic_lv_grinder_side.png",
             "technic_lv_grinder_side.png", "technic_lv_grinder_front_active.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") or not inv:is_empty("dst") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
minetest.register_abm({
    nodenames = {"technic:extractor", "technic:extractor_active"},
    interval = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        -- The machine will automatically shut down if disconnected from power in some fashion.
        local meta     = minetest.get_meta(pos)
        local inv      = meta:get_inventory()
        local srcstack = inv:get_stack("src", 1)
        local eu_input = meta:get_int("LV_EU_input")
        -- Machine information
        local machine_name = "Extractor"
        local machine_node = "technic:extractor"
        local demand       = 300
        -- 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 srcstack then
            src_item = srcstack:to_table()
        end
        if src_item then
            recipe = technic.get_extractor_recipe(src_item)
        end
        if recipe then
            result = {name=recipe.dst_name, count=recipe.dst_count}
        end
        if inv:is_empty("src") or (not recipe) or (not result) or
           (not inv:room_for_item("dst", result)) then
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Idle")
            meta:set_int("LV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            -- unpowered - go idle
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
        elseif eu_input >= demand then
            -- Powered
            hacky_swap_node(pos, machine_node.."_active")
            meta:set_string("infotext", machine_name.." Active")
            meta:set_int("src_time", meta:get_int("src_time") + 1)
            if meta:get_int("src_time") >= 4 then -- 4 ticks per output
                meta:set_int("src_time", 0)
                srcstack:take_item(recipe.src_count)
                inv:set_stack("src", 1, srcstack)
                inv:add_item("dst", result)
            end
        end
        meta:set_int("LV_EU_demand", demand)
    end
})
technic.register_machine("LV", "technic:extractor",        technic.receiver)
technic.register_machine("LV", "technic:extractor_active", technic.receiver)
technic/machines/LV/generator.lua
New file
@@ -0,0 +1,139 @@
-- The electric generator.
-- A simple device to get started on the electric machines.
-- Inefficient and expensive in fuel (200EU per tick)
-- Also only allows for LV machinery to run.
minetest.register_alias("generator", "technic:generator")
minetest.register_alias("generator", "technic:generator_active")
minetest.register_craft({
    output = 'technic:generator',
    recipe = {
        {'default:stone', 'default:stone',        'default:stone'},
        {'default:stone', '',                     'default:stone'},
        {'default:stone', 'default:copper_ingot', 'default:stone'},
    }
})
local generator_formspec =
    "invsize[8,9;]"..
    "label[0,0;Generator]"..
    "list[current_name;src;3,1;1,1;]"..
    "image[4,1;1,1;default_furnace_fire_bg.png]"..
    "list[current_player;main;0,5;8,4;]"
minetest.register_node("technic:generator", {
    description = "Electric Generator",
    tiles = {"technic_generator_top.png", "technic_machine_bottom.png", "technic_generator_side.png",
             "technic_generator_side.png", "technic_generator_side.png", "technic_generator_front.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", "Electric Generator")
        meta:set_int("LV_EU_supply", 0)
        -- Signal to the switching station that this device burns some
        -- sort of fuel and needs special handling
        meta:set_int("LV_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", 1)
    end,
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
minetest.register_node("technic:generator_active", {
    description = "Electric Generator",
    tiles = {"technic_generator_top.png",  "technic_machine_bottom.png",
             "technic_generator_side.png", "technic_generator_side.png",
             "technic_generator_side.png", "technic_generator_front_active.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:generator",
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        else
            return true
        end
    end,
})
minetest.register_abm({
    nodenames = {"technic:generator", "technic: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("LV_EU_supply", 200) -- Give 200EUs
            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")
                fuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
                if not fuel or fuel.time == 0 then
                    meta:set_string("infotext", "Generator out of fuel")
                    hacky_swap_node(pos, "technic: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)
                hacky_swap_node(pos, "technic:generator_active")
                meta:set_int("LV_EU_supply", 200) -- Give 200EUs
            else
                hacky_swap_node(pos, "technic:generator")
                meta:set_int("LV_EU_supply", 0)
            end
        end
        local percent = math.floor((burn_time / burn_totaltime) * 100)
        meta:set_string("infotext", "Electric Generator ("..percent.."%)")
        meta:set_string("formspec",
            "size[8,9]"..
            "label[0,0;Generator]"..
            "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("LV", "technic:generator",        technic.producer)
technic.register_machine("LV", "technic:generator_active", technic.producer)
technic/machines/LV/geothermal.lua
New file
@@ -0,0 +1,123 @@
-- A geothermal EU generator
-- Using hot lava and water this device can create energy from steam
-- The machine is only producing LV EUs and can thus not drive more advanced equipment
-- The output is a little more than the coal burning generator (max 300EUs)
minetest.register_alias("geothermal", "technic:geothermal")
minetest.register_craft({
    output = 'technic:geothermal',
    recipe = {
        {'default:stone', 'default:stone', 'default:stone'},
        {'default:copper_ingot', 'default:diamond', 'default:copper_ingot'},
        {'default:stone', 'default:copper_ingot', 'default:stone'},
    }
})
minetest.register_craftitem("technic:geothermal", {
    description = "Geothermal Generator",
    stack_max = 99,
})
local geothermal_formspec =
    "invsize[8,4;]"..
    "label[0,0;Geothermal Generator]"..
    "list[current_player;main;0,5;8,4;]"
minetest.register_node("technic:geothermal", {
    description = "Geothermal Generator",
    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},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "Geothermal Generator")
        meta:set_float("technic_power_machine", 1)
        meta:set_int("LV_EU_supply", 0)
        meta:set_string("formspec", geothermal_formspec)
    end,
})
minetest.register_node("technic:geothermal_active", {
    description = "Geothermal Generator",
    tiles = {"technic_geothermal_top_active.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, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_wood_defaults(),
    drop = "technic:geothermal",
})
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("formspec",
            "invsize[8,4;]"..
            "label[0,0;Geothermal Generator]"..
            "label[4,0;Production at "..tostring(production_level).."%]")
        if production_level > 0 and minetest.get_node(pos).name == "technic:geothermal" then
            hacky_swap_node (pos, "technic:geothermal_active")
            return
        end
        if production_level == 0 then
            hacky_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/grinder.lua
New file
@@ -0,0 +1,13 @@
minetest.register_alias("grinder", "technic:grinder")
minetest.register_craft({
    output = 'technic:grinder',
    recipe = {
        {'default:desert_stone', 'default:desert_stone',  'default:desert_stone'},
        {'default:desert_stone', 'default:diamond',       'default:desert_stone'},
        {'default:stone',        'moreores:copper_ingot', 'default:stone'},
    }
})
technic.register_grinder({tier="LV", demand={200}, speed=1})
technic/machines/LV/init.lua
File was renamed from technic/machines/lv/init.lua
@@ -1,15 +1,18 @@
local path = technic.modpath.."/machines/lv"
dofile(path.."/wires.lua")
technic.register_tier("LV", "Low Voltage")
local path = technic.modpath.."/machines/LV"
dofile(path.."/cables.lua")
dofile(path.."/battery_box.lua")
dofile(path.."/alloy_furnace.lua")
dofile(path.."/coal_alloy_furnace.lua")
dofile(path.."/solar_panel.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/geothermal.lua")
dofile(path.."/water_mill.lua")
dofile(path.."/generator.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/tool_workshop.lua")
dofile(path.."/music_player.lua")
dofile(path.."/grinder.lua")
dofile(path.."/cnc.lua")
@@ -17,3 +20,4 @@
dofile(path.."/cnc_nodes.lua")
dofile(path.."/extractor.lua")
dofile(path.."/compressor.lua")
technic/machines/LV/music_player.lua
New file
@@ -0,0 +1,138 @@
-- LV Music player.
-- The player can play music. But it is high ampage!
minetest.register_alias("music_player", "technic:music_player")
minetest.register_craft({
    output = 'technic:music_player',
    recipe = {
        {'group:wood',      'group:wood',           'group:wood'},
        {'default:diamond', 'default:diamond',      'default:diamond'},
        {'default:stone',   'default:copper_ingot', 'default:stone'},
    }
})
local music_player_formspec =
    "invsize[8,9;]"..
    "label[0,0;Music Player]"..
    "button[4,1;1,1;track1;1]"..
    "button[5,1;1,1;track2;2]"..
    "button[6,1;1,1;track3;3]"..
    "button[4,2;1,1;track4;4]"..
    "button[5,2;1,1;track5;5]"..
    "button[6,2;1,1;track6;6]"..
    "button[4,3;1,1;track7;7]"..
    "button[5,3;1,1;track8;8]"..
    "button[6,3;1,1;track9;9]"..
    "button[4,4;1,2;play;Play]"..
    "button[6,4;1,2;stop;Stop]"..
    "label[4,0;Current track --]"
minetest.register_node("technic:music_player", {
    description = "Music Player",
    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},
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "Music Player")
        meta:set_int("active", 0)
        meta:set_int("current_track", 1)
        meta:set_string("formspec", music_player_formspec)
    end,
    on_receive_fields = function(pos, formanme, fields, sender)
        local meta          = minetest.get_meta(pos)
        local music_handle  = meta:get_int("music_handle")
        local current_track = meta:get_int("current_track")
        if fields.track1 then current_track = 1 end
        if fields.track2 then current_track = 2 end
        if fields.track3 then current_track = 3 end
        if fields.track4 then current_track = 4 end
        if fields.track5 then current_track = 5 end
        if fields.track6 then current_track = 6 end
        if fields.track7 then current_track = 7 end
        if fields.track8 then current_track = 8 end
        if fields.track9 then current_track = 9 end
        meta:set_int("current_track", current_track)
        meta:set_string("formspec",
                "invsize[8,9;]"..
                "label[0,0;Music Player]"..
                "button[4,1;1,1;track1;1]"..
                "button[5,1;1,1;track2;2]"..
                "button[6,1;1,1;track3;3]"..
                "button[4,2;1,1;track4;4]"..
                "button[5,2;1,1;track5;5]"..
                "button[6,2;1,1;track6;6]"..
                "button[4,3;1,1;track7;7]"..
                "button[5,3;1,1;track8;8]"..
                "button[6,3;1,1;track9;9]"..
                "button[4,4;1,2;play;Play]"..
                "button[6,4;1,2;stop;Stop]"..
                "label[4,0;Current track "
                ..current_track.."]")
        if fields.play then
            if music_handle then
                minetest.sound_stop(music_handle)
            end
            meta:set_int("active", 1)
        end
        if fields.stop then
            meta:set_int("active", 0)
            if music_handle then
                minetest.sound_stop(music_handle)
            end
        end
        meta:set_int("music_handle", 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 = "Music Player"
        local machine_node = "technic:music_player"
        local demand       = 150
        local music_handle = meta:get_int("music_handle")
        local current_track = meta:get_int("current_track")
        -- 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", machine_name.." Idle")
            meta:set_int("LV_EU_demand", 0)
            if music_handle then
                minetest.sound_stop(music_handle)
            end
            return
        end
        if eu_input < demand then
            meta:set_string("infotext", machine_name.." Unpowered")
            if music_handle then
                minetest.sound_stop(music_handle)
            end
        elseif eu_input >= demand then
            meta:set_string("infotext", machine_name.." Active")
            music_handle = minetest.sound_play("technic_track"..current_track,
                    {pos = pos, gain = 1.0, loop = true, max_hear_distance = 72,})
            meta:set_int("music_handle", music_handle)
        end
        meta:set_int("LV_EU_demand", demand)
    end
})
technic.register_machine("LV", "technic:music_player", technic.receiver)
technic/machines/LV/solar_array.lua
New file
@@ -0,0 +1,18 @@
-- The solar array is an assembly of panels into a powerful array
-- The assembly can deliver more energy than the individual panel because
-- of the transformer unit which converts the panel output variations into
-- a stable supply.
-- Solar arrays are not able to store large amounts of energy.
-- The LV arrays are used to make medium voltage arrays.
minetest.register_craft({
    output = 'technic:solar_array_lv 1',
    recipe = {
        {'technic:solar_panel', 'technic:solar_panel',    'technic:solar_panel'},
        {'default:steel_ingot', 'technic:lv_transformer', 'default:steel_ingot'},
        {'',                    'technic:lv_cable0',      ''},
    }
})
technic.register_solar_array({tier="LV", power=10})
technic/machines/LV/solar_panel.lua
New file
@@ -0,0 +1,70 @@
-- Solar panels are the building blocks of LV solar arrays
-- They can however also be used separately but with reduced efficiency due to the missing transformer.
-- Individual panels are less efficient than when the panels are combined into full arrays.
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},
    sounds = default.node_sound_wood_defaults(),
        description="Solar Panel",
    active = false,
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,
    node_box = {
        type = "fixed",
        fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
    },
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_int("LV_EU_supply", 0)
        meta:set_string("infotext", "LV Solar Panel")
    end,
})
minetest.register_craft({
    output = 'technic:solar_panel',
    recipe = {
        {'technic:doped_silicon_wafer', 'technic:doped_silicon_wafer', 'technic:doped_silicon_wafer'},
        {'default:steel_ingot',         'technic:lv_cable0',           'default:steel_ingot'},
    }
})
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 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", "Solar Panel is active ("..charge_to_give.."EU)")
            meta:set_int("LV_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", "Solar Panel is inactive");
            meta:set_int("LV_EU_supply", 0)
        end
    end,
})
technic.register_machine("LV", "technic:solar_panel", technic.producer)
technic/machines/LV/water_mill.lua
New file
@@ -0,0 +1,101 @@
-- A water mill produces LV EUs by exploiting flowing water across it
-- It is a LV EU supplyer and fairly low yield (max 120EUs)
-- It is a little under half as good as the thermal generator.
minetest.register_alias("water_mill", "technic:water_mill")
minetest.register_craft({
    output = 'technic:water_mill',
    recipe = {
        {'default:stone', 'default:stone',        'default:stone'},
        {'group:wood',    'default:diamond',      'group:wood'},
        {'default:stone', 'default:copper_ingot', 'default:stone'},
    }
})
minetest.register_node("technic:water_mill", {
    description = "Water Mill",
    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", "Water Mill")
        meta:set_int("LV_EU_supply", 0)
    end,
})
minetest.register_node("technic:water_mill_active", {
    description = "Water Mill",
    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
       node.name == "default:water_source" then
        return true
    end
    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 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",
            "Water Mill ("..production_level.."%)")
        if production_level > 0 and
           minetest.get_node(pos).name == "technic:water_mill" then
            hacky_swap_node (pos, "technic:water_mill_active")
            meta:set_int("LV_EU_supply", 0)
            return
        end
        if production_level == 0 then
            hacky_swap_node(pos, "technic:water_mill")
        end
    end
})
technic.register_machine("LV", "technic:water_mill",        technic.producer)
technic.register_machine("LV", "technic:water_mill_active", technic.producer)
technic/machines/MV/alloy_furnace.lua
New file
@@ -0,0 +1,14 @@
-- MV alloy furnace
minetest.register_craft({
    output = 'technic:mv_alloy_furnace',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:lv_alloy_furnace', 'technic:stainless_steel_ingot'},
        {'pipeworks:tube_000000',         'technic:mv_transformer',   'pipeworks:tube_000000'},
        {'technic:stainless_steel_ingot', 'technic:mv_cable0',        'technic:stainless_steel_ingot'},
    }
})
technic.register_alloy_furnace({tier="MV", cook_time=4, upgrade=1, tube=1, demand={3000, 2000, 1000}})
technic/machines/MV/battery_box.lua
New file
@@ -0,0 +1,20 @@
-- MV Battery box
minetest.register_craft({
    output = 'technic:mv_battery_box0',
    recipe = {
        {'technic:lv_battery_box0', 'technic:lv_battery_box0', 'technic:lv_battery_box0'},
        {'technic:lv_battery_box0', 'technic:mv_transformer',  'technic:lv_battery_box0'},
        {'',                        'technic:mv_cable0',       ''},
    }
})
technic.register_battery_box({
    tier           = "MV",
    max_charge     = 300000,
    charge_rate    = 20000,
    discharge_rate = 80000,
    charge_step    = 2000,
    discharge_step = 8000,
})
technic/machines/MV/cables.lua
New file
@@ -0,0 +1,14 @@
minetest.register_alias("mv_cable", "technic:mv_cable0")
minetest.register_craft({
    output = 'technic:mv_cable0 3',
    recipe ={
        {'technic:rubber',    'technic:rubber',    'technic:rubber'},
        {'technic:lv_cable0', 'technic:lv_cable0', 'technic:lv_cable0'},
        {'technic:rubber',    'technic:rubber',    'technic:rubber'},
    }
})
technic.register_cable("MV", 2.5/16)
technic/machines/MV/electric_furnace.lua
New file
@@ -0,0 +1,18 @@
-- MV Electric Furnace
-- This is a faster version of the stone furnace which runs on EUs
-- In addition to this it can be upgraded with microcontrollers and batteries
-- This new version uses the batteries to lower the power consumption of the machine
-- Also in addition this furnace can be attached to the pipe system from the pipeworks mod.
-- FIXME: kpoppel I'd like to introduce an induction heating element here also
minetest.register_craft({
    output = 'technic:mv_electric_furnace',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:lv_electric_furnace', 'technic:stainless_steel_ingot'},
        {'pipeworks:tube_000000',         'technic:mv_transformer',      'pipeworks:tube_000000'},
        {'technic:stainless_steel_ingot', 'technic:mv_cable0',           'technic:stainless_steel_ingot'},
    }
})
technic.register_electric_furnace({tier="MV", upgrade=1, tube=1, demand={2000, 1000, 500}, speed=4})
technic/machines/MV/grinder.lua
New file
@@ -0,0 +1,13 @@
-- MV grinder
minetest.register_craft({
    output = 'technic:mv_grinder',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:lv_grinder',     'technic:stainless_steel_ingot'},
        {'pipeworks:tube_000000',         'technic:mv_transformer', 'pipeworks:tube_000000'},
        {'technic:stainless_steel_ingot', 'technic:mv_cable0',      'technic:stainless_steel_ingot'},
    }
})
technic.register_grinder({tier="MV", demand={600, 450, 300}, speed=2, upgrade=1, tube=1})
technic/machines/MV/init.lua
File was renamed from technic/machines/mv/init.lua
@@ -1,11 +1,16 @@
local path = technic.modpath.."/machines/mv"
dofile(path.."/wires.lua")
dofile(path.."/battery_box.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/electric_furnace.lua")
technic.register_tier("MV", "Medium Voltage")
local path = technic.modpath.."/machines/MV"
dofile(path.."/alloy_furnace.lua")
dofile(path.."/battery_box.lua")
dofile(path.."/cables.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/grinder.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/tool_workshop.lua")
dofile(path.."/wind_mill.lua")
-- The power radiator supplies appliances with inductive coupled power:
-- Lighting and associated textures is taken directly from VanessaE's homedecor and made electric.
technic/machines/MV/lighting.lua
File was renamed from technic/machines/mv/lighting.lua
@@ -6,20 +6,20 @@
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if (minetest.get_modpath("intllib")) then
    dofile(minetest.get_modpath("intllib").."/intllib.lua")
    S = intllib.Getter(minetest.get_current_modname())
    dofile(minetest.get_modpath("intllib").."/intllib.lua")
    S = intllib.Getter(minetest.get_current_modname())
else
    S = function ( s ) return s end
    S = function (s) return s end
end
function technic_homedecor_node_is_owned(pos, placer)
        local ownername = false
        if type(IsPlayerNodeOwner) == "function" then                                   -- node_ownership mod
                if HasOwner(pos, placer) then                                           -- returns true if the node is owned
        if type(IsPlayerNodeOwner) == "function" then -- node_ownership mod
                if HasOwner(pos, placer) then
                        if not IsPlayerNodeOwner(pos, placer:get_player_name()) then
                                if type(getLastOwner) == "function" then                -- ...is an old version
                                if type(getLastOwner) == "function" then -- ...is an old version
                                        ownername = getLastOwner(pos)
                                elseif type(GetNodeOwnerName) == "function" then        -- ...is a recent version
                                elseif type(GetNodeOwnerName) == "function" then -- ...is a recent version
                                        ownername = GetNodeOwnerName(pos)
                                else
                                        ownername = S("someone")
@@ -27,38 +27,38 @@
                        end
                end
        elseif type(isprotect)=="function" then                                         -- glomie's protection mod
        elseif type(isprotect) == "function" then -- glomie's protection mod
                if not isprotect(5, pos, placer) then
                        ownername = S("someone")
                end
        elseif type(protector)=="table" and type(protector.can_dig)=="function" then                                    -- Zeg9's protection mod
        elseif type(protector) == "table" and type(protector.can_dig) == "function" then -- Zeg9's protection mod
                if not protector.can_dig(5, pos, placer) then
                        ownername = S("someone")
                end
        end
        if ownername ~= false then
                minetest.chat_send_player( placer:get_player_name(), S("Sorry, %s owns that spot."):format(ownername) )
                minetest.chat_send_player(placer:get_player_name(), S("Sorry, %s owns that spot."):format(ownername) )
                return true
        else
                return false
        end
end
local dirs1 = { 20, 23, 22, 21 }
local dirs2 = { 9, 18, 7, 12 }
local dirs1 = {20, 23, 22, 21}
local dirs2 = {9,  18,  7, 12}
local technic_homedecor_rotate_and_place = function(itemstack, placer, pointed_thing)
    if not technic_homedecor_node_is_owned(pointed_thing.under, placer) 
       and not technic_homedecor_node_is_owned(pointed_thing.above, placer) then
        local node = minetest.env:get_node(pointed_thing.under)
        local node = minetest.get_node(pointed_thing.under)
        if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].on_rightclick then
            local above = pointed_thing.above
            local under = pointed_thing.under
            local pitch = placer:get_look_pitch()
            local pname = minetest.env:get_node(under).name
            local node = minetest.env:get_node(above)
            local pname = minetest.get_node(under).name
            local node = minetest.get_node(above)
            local fdir = minetest.dir_to_facedir(placer:get_look_dir())
            local wield_name = itemstack:get_name()
@@ -74,14 +74,14 @@
                    iswall = false
                end
                if not minetest.registered_nodes[minetest.env:get_node(pos1).name]["buildable_to"] then return end
                if not minetest.registered_nodes[minetest.get_node(pos1).name]["buildable_to"] then return end
                if iswall then 
                    minetest.env:add_node(pos1, {name = wield_name, param2 = dirs2[fdir+1] }) -- place wall variant
                    minetest.add_node(pos1, {name = wield_name, param2 = dirs2[fdir+1] }) -- place wall variant
                elseif isceiling then
                    minetest.env:add_node(pos1, {name = wield_name, param2 = 20 }) -- place upside down variant
                    minetest.add_node(pos1, {name = wield_name, param2 = 20 }) -- place upside down variant
                else
                    minetest.env:add_node(pos1, {name = wield_name, param2 = 0 }) -- place right side up
                    minetest.add_node(pos1, {name = wield_name, param2 = 0 }) -- place right side up
                end
                if not homedecor_expect_infinite_stacks then
technic/machines/MV/power_radiator.lua
New file
@@ -0,0 +1,220 @@
-- The power radiator fuctions like an inductive charger
-- only better in the game setting.
-- The purpose is to allow small appliances to receive power
-- without the overhead of the wiring needed for larger machines.
--
-- The power radiator will consume power corresponding to the
-- sum(power rating of the attached appliances)/0.06
-- Using inductive power transfer is very inefficient so this is
-- set to the factor 0.06.
--
-- Punching the radiator will toggle the power state of all attached appliances.
local power_radius = 12
------------------------------------------------------------------
-- API for inductive powered nodes:
-- Use the functions below to set the corresponding callbacks
-- Also two nodes are needed: The inactive and the active one. The active must be called <name>_active .
------------------------------------------------------------------
-- Register a new appliance using this function
technic.inductive_nodes = {}
technic.register_inductive_machine = function(name)
    table.insert(technic.inductive_nodes, name)
    table.insert(technic.inductive_nodes, name.."_active")
end
-- Appliances:
--  has_supply: pos of supply node if the appliance has a power radiator near with sufficient power for the demand else ""
--  EU_demand: The power demand of the device.
--  EU_charge: Actual use. set to EU_demand if active==1
--  active: set to 1 if the device is on
technic.inductive_on_construct = function(pos, eu_demand, infotext)
    local meta = minetest.get_meta(pos)
    meta:set_string("infotext", infotext)
    meta:set_int("technic_inductive_power_machine", 1)
    meta:set_int("EU_demand", eu_demand)     -- The power demand of this appliance
    meta:set_int("EU_charge", 0)       -- The actual power draw of this appliance
    meta:set_string("has_supply", "") -- Register whether we are powered or not. For use with several radiators.
    meta:set_int("active", 0)    -- If the appliance can be turned on and off by using it use this.
end
technic.inductive_on_punch_off = function(pos, eu_charge, swapnode)
    local meta = minetest.get_meta(pos)
    if meta:get_string("has_supply") ~= "" then
        hacky_swap_node(pos, swapnode)
        meta:set_int("active", 1)
        meta:set_int("EU_charge",eu_charge)
        --print("-----------")
        --print("Turn on:")
        --print("EU_charge: "..meta:get_int("EU_charge"))
        --print("has_supply: "..meta:get_string("has_supply"))
        --print("<----------->")
    end
end
technic.inductive_on_punch_on = function(pos, eu_charge, swapnode)
    local meta = minetest.get_meta(pos)
    hacky_swap_node(pos, swapnode)
    meta:set_int("active", 0)
    meta:set_int("EU_charge",eu_charge)
    --print("-----------")
    --print("Turn off:")
    --print("EU_charge: "..meta:get_int("EU_charge"))
    --print("has_supply: "..meta:get_string("has_supply"))
    --print("<---------->")
end
local shutdown_inductive_appliances = function(pos)
    -- The supply radius
    local rad = power_radius
    -- If the radiator is removed. turn off all appliances in region
    -- If another radiator is near it will turn on the appliances again
    local positions = minetest.find_nodes_in_area(
        {x=pos.x-rad, y=pos.y-rad, z=pos.z-rad},
        {x=pos.x+rad, y=pos.y+rad, z=pos.z+rad},
        technic.inductive_nodes)
    for _, pos1 in pairs(positions) do
        local meta1 = minetest.get_meta(pos1)
        -- If the appliance is belonging to this node
        if meta1:get_string("has_supply") == pos.x..pos.y..pos.z then
            local nodename = minetest.get_node(pos1).name
            -- Swap the node and make sure it is off and unpowered
            if string.sub(nodename, -7) == "_active" then
                hacky_swap_node(pos1, string.sub(nodename, 1, -8))
                meta1:set_int("active", 0)
                meta1:set_int("EU_charge", 0)
            end
            meta1:set_string("has_supply", "")
        end
    end
end
local toggle_on_off_inductive_appliances = function(pos, node, puncher)
    if pos == nil then return end
    -- The supply radius
    local rad = power_radius
    local positions = minetest.find_nodes_in_area(
        {x=pos.x-rad, y=pos.y-rad, z=pos.z-rad},
        {x=pos.x+rad, y=pos.y+rad, z=pos.z+rad},
        technic.inductive_nodes)
    for _, pos1 in pairs(positions) do
        local meta1 = minetest.get_meta(pos1)
        if meta1:get_string("has_supply") == pos.x..pos.y..pos.z then
            minetest.punch_node(pos1)
        end
    end
end
minetest.register_node("technic:power_radiator", {
    description = "Power Radiator",
    tiles  = {"technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png",
              "technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
    sounds = default.node_sound_wood_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,
    node_box = {
        type = "fixed",
        fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
    },
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_int("MV_EU_demand",1)               -- Demand on the primary side when idle
        meta:set_int("connected_EU_demand",0)        -- Potential demand of connected appliances
        meta:set_string("infotext", "Power Radiator")
    end,
    on_dig = function(pos, node, digger)
        shutdown_inductive_appliances(pos)
        return minetest.node_dig(pos, node, digger)
    end,
    on_punch = function(pos, node, puncher)
        toggle_on_off_inductive_appliances(pos, node, puncher)
    end
})
minetest.register_craft({
    output = 'technic:power_radiator 1',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'technic:copper_coil',           'technic:mv_transformer',        'technic:copper_coil'},
        {'technic:rubber',                'technic:mv_cable0',       'technic:rubber'},
    }
})
minetest.register_abm({
    nodenames = {"technic:power_radiator"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta             = minetest.env:get_meta(pos)
        local eu_input  = meta:get_int("MV_EU_input")
        local eu_demand = meta:get_int("MV_EU_demand")
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "MV")
        if eu_input == 0 then
            -- No power
            meta:set_string("infotext", "Power Radiator is unpowered");
            -- meta:set_int("active", 1) -- used for setting textures someday maybe
            shutdown_inductive_appliances(pos)
            meta:set_int("connected_EU_demand", 0)
            meta:set_int("MV_EU_demand",1)
        elseif eu_input == eu_demand then
            -- Powered and ready
            -- The maximum EU sourcing a single radiator can provide.
            local max_charge          = 30000 -- == the max EU demand of the radiator
            local connected_EU_demand = meta:get_int("connected_EU_demand")
            -- Efficiency factor
            local eff_factor = 0.06
            -- The supply radius
            local rad = power_radius
            local meta1            = nil
            local pos1             = {}
            local used_charge      = 0
            -- Index all nodes within supply range
            local positions = minetest.find_nodes_in_area(
                {x=pos.x-rad, y=pos.y-rad, z=pos.z-rad},
                {x=pos.x+rad, y=pos.y+rad, z=pos.z+rad},
                technic.inductive_nodes)
            for _, pos1 in pairs(positions) do
                local meta1 = minetest.get_meta(pos1)
                -- If not supplied see if this node can handle it.
                if meta1:get_string("has_supply") == "" then
                    -- if demand surpasses the capacity of this node, don't bother adding it.
                    local app_eu_demand = math.floor(meta1:get_int("EU_demand") / eff_factor)
                    if connected_EU_demand + app_eu_demand <= max_charge then
                        -- We can power the appliance. Register, and spend power if it is on.
                        connected_EU_demand = connected_EU_demand + app_eu_demand
                        meta1:set_string("has_supply", pos.x..pos.y..pos.z)
                        --Always 0: used_charge = math.floor(used_charge + meta1:get_int("EU_charge") / eff_factor)
                    end
                elseif meta1:get_string("has_supply") == pos.x..pos.y..pos.z then
                    -- The appliance has power from this node. Spend power if it is on.
                    used_charge = used_charge + math.floor(meta1:get_int("EU_charge") / eff_factor)
                end
                meta:set_string("infotext", "Power Radiator is powered ("
                    ..math.floor(used_charge / max_charge * 100)
                    .."% of maximum power)");
                if used_charge == 0 then
                    meta:set_int("MV_EU_demand", 1) -- Still idle
                else
                    meta:set_int("MV_EU_demand", used_charge)
                end
            end
            -- Save state
            meta:set_int("connected_EU_demand", connected_EU_demand)
        end
    end,
})
technic.register_machine("MV", "technic:power_radiator", technic.receiver)
technic/machines/MV/solar_array.lua
New file
@@ -0,0 +1,12 @@
minetest.register_craft({
    output = 'technic:solar_array_mv 1',
    recipe = {
        {'technic:solar_array_lv', 'technic:solar_array_lv', 'technic:solar_array_lv'},
        {'default:steel_ingot',    'technic:mv_transformer', 'default:steel_ingot'},
        {'',                       'technic:mv_cable0',      ''},
    }
})
technic.register_solar_array({tier="MV", power=30})
technic/machines/MV/tool_workshop.lua
New file
@@ -0,0 +1,90 @@
-- LV Tool workshop
-- This machine repairs tools.
minetest.register_alias("tool_workshop", "technic:tool_workshop")
minetest.register_craft({
    output = 'technic:tool_workshop',
    recipe = {
        {'group:wood',    'group:wood',           'group:wood'},
        {'group:wood',    'default:diamond',      'group:wood'},
        {'default:stone', 'default:copper_ingot', 'default:stone'},
    }
})
local workshop_formspec =
    "invsize[8,9;]"..
    "list[current_name;src;3,1;1,1;]"..
    "label[0,0;Tool Workshop]"..
    "list[current_player;main;0,5;8,4;]"
minetest.register_node("technic:tool_workshop", {
    description = "Tool Workshop",
    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},
    sounds = default.node_sound_wood_defaults(),
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "Tool Workshop")
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", workshop_formspec)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
    end,
    can_dig = function(pos,player)
        local meta = minetest.get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            minetest.chat_send_player(player:get_player_name(),
                "Machine cannot be removed because it is not empty");
            return false
        end
        return true
    end,
})
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 = "Tool Workshop"
        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")
        srcstack = inv:get_stack("src", 1)
        if inv:is_empty("src") or
           srcstack:get_wear() == 0 or
           srcstack:get_name() == "technic:water_can" or
           srcstack:get_name() == "technic:lava_can" then
            meta:set_string("infotext", machine_name.." Idle")
            meta:set_int("MV_EU_demand", 0)
            return
        end
        if eu_input < demand then
            meta:set_string("infotext", machine_name.." Unpowered")
        elseif eu_input >= demand then
            meta:set_string("infotext", machine_name.." Active")
            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
New file
@@ -0,0 +1,88 @@
minetest.register_craft({
    output = 'technic:wind_mill_frame 5',
    recipe = {
        {'default:steel_ingot', '',                    'default:steel_ingot'},
        {'',                    'default:steel_ingot', ''},
        {'default:steel_ingot', '',                    'default:steel_ingot'},
    }
})
minetest.register_craft({
    output = 'technic:wind_mill',
    recipe = {
        {'',                    'default:steel_ingot', ''},
        {'default:steel_ingot', 'technic:motor',       'default:steel_ingot'},
        {'',                    'default:steelblock',  ''},
    }
})
minetest.register_node("technic:wind_mill_frame", {
    description = "Wind Mill Frame",
    drawtype = "glasslike_framed",
    tiles = {"default_steel_block.png", "default_glass.png"},
    sunlight_propagates = true,
    groups = {cracky=3},
    sounds = default.node_sound_stone_defaults(),
    paramtype = "light",
})
minetest.register_node("technic:wind_mill", {
    description = "Wind Mill",
    tiles = {"default_steel_block.png"},
    paramtype2 = "facedir",
    groups = {cracky=1},
    sounds = default.node_sound_stone_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
    node_box = {
        type = "fixed",
        fixed = {
            {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, -- Main box
            {-0.1, -0.1, -0.5,  0.1, 0.1, -0.6}, -- Shaft
            {-0.1, -1,   -0.6,  0.1, 1,   -0.7}, -- Vertical blades
            {-1,   -0.1, -0.6,  1,   0.1, -0.7}, -- Horizontal blades
        }
    },
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "Wind Mill")
        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 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", "Wind Mill Inproperly Placed")
            return
        else
            meta:set_int("MV_EU_supply", power)
        end
        meta:set_string("infotext", "Wind Mill ("..power.."EU)")
    end
})
technic.register_machine("MV", "technic:wind_mill", technic.producer)
technic/machines/alloy_furnaces_commons.lua
File was deleted
technic/machines/battery_boxes_commons.lua
File was deleted
technic/machines/grinder_gloopores.lua
File was deleted
technic/machines/hv/battery_box.lua
File was deleted
technic/machines/hv/forcefield.lua
File was deleted
technic/machines/hv/init.lua
File was deleted
technic/machines/hv/nuclear_reactor.lua
File was deleted
technic/machines/hv/solar_array.lua
File was deleted
technic/machines/hv/wires.lua
File was deleted
technic/machines/init.lua
@@ -1,11 +1,14 @@
local path = technic.modpath.."/machines"
dofile(path.."/register/init.lua")
-- Tiers
dofile(path.."/LV/init.lua")
dofile(path.."/MV/init.lua")
dofile(path.."/HV/init.lua")
dofile(path.."/switching_station.lua")
dofile(path.."/supply_converter.lua")
dofile(path.."/alloy_furnaces_commons.lua")
dofile(path.."/battery_boxes_commons.lua")
dofile(path.."/lv/init.lua")
dofile(path.."/mv/init.lua")
dofile(path.."/hv/init.lua")
dofile(path.."/other/init.lua")
technic/machines/lv/alloy_furnace.lua
File was deleted
technic/machines/lv/battery_box.lua
File was deleted
technic/machines/lv/cnc.lua
File was deleted
technic/machines/lv/cnc_api.lua
File was deleted
technic/machines/lv/cnc_nodes.lua
File was deleted
technic/machines/lv/compressor.lua
File was deleted
technic/machines/lv/electric_furnace.lua
File was deleted
technic/machines/lv/extractor.lua
File was deleted
technic/machines/lv/generator.lua
File was deleted
technic/machines/lv/geothermal.lua
File was deleted
technic/machines/lv/grinder.lua
File was deleted
technic/machines/lv/music_player.lua
File was deleted
technic/machines/lv/solar_array.lua
File was deleted
technic/machines/lv/solar_panel.lua
File was deleted
technic/machines/lv/tool_workshop.lua
File was deleted
technic/machines/lv/water_mill.lua
File was deleted
technic/machines/lv/wires.lua
File was deleted
technic/machines/mv/alloy_furnace.lua
File was deleted
technic/machines/mv/battery_box.lua
File was deleted
technic/machines/mv/electric_furnace.lua
File was deleted
technic/machines/mv/grinder.lua
File was deleted
technic/machines/mv/power_radiator.lua
File was deleted
technic/machines/mv/solar_array.lua
File was deleted
technic/machines/mv/wires.lua
File was deleted
technic/machines/other/constructor.lua
@@ -20,7 +20,7 @@
})
mk1_on = function(pos, node)
    local meta = minetest.env:get_meta(pos)
    local meta = minetest.get_meta(pos)
    local inv = meta:get_inventory()
    local pos1={}
    pos1.x=pos.x
@@ -34,7 +34,7 @@
    if node.name == "technic:constructor_mk1_off" then
        hacky_swap_node(pos,"technic:constructor_mk1_on")
        nodeupdate(pos)
        local node1=minetest.env:get_node(pos1)
        local node1=minetest.get_node(pos1)
        deploy_node (inv,"slot1",pos1,node1,node)
    end
end
@@ -57,7 +57,7 @@
    mesecons= {effector={action_on=mk1_on}},
    sounds = default.node_sound_stone_defaults(),
    on_construct = function(pos)
    local meta = minetest.env:get_meta(pos)
    local meta = minetest.get_meta(pos)
    meta:set_string("formspec",
                "invsize[8,9;]"..
                "label[0,0;Constructor MK1]"..
@@ -70,7 +70,7 @@
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos)
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        return inv:is_empty("slot1")
    end,    
@@ -91,7 +91,7 @@
--Constructor MK2
mk2_on = function(pos, node)
    local meta = minetest.env:get_meta(pos)
    local meta = minetest.get_meta(pos)
    local inv = meta:get_inventory()
    local pos1={}
    local pos2={}
@@ -109,9 +109,9 @@
    if node.name == "technic:constructor_mk2_off" then
        hacky_swap_node(pos,"technic:constructor_mk2_on")
        nodeupdate(pos)
        local node1=minetest.env:get_node(pos1)
        local node1=minetest.get_node(pos1)
        deploy_node (inv,"slot1",pos1,node1,node)
        local node1=minetest.env:get_node(pos2)
        local node1=minetest.get_node(pos2)
        deploy_node (inv,"slot2",pos2,node1,node)
    end
end
@@ -133,7 +133,7 @@
    mesecons= {effector={action_on=mk2_on}},
    sounds = default.node_sound_stone_defaults(),
    on_construct = function(pos)
    local meta = minetest.env:get_meta(pos)
    local meta = minetest.get_meta(pos)
    meta:set_string("formspec",
                "invsize[8,9;]"..
                "label[0,0;Constructor MK2]"..
@@ -149,7 +149,7 @@
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos)
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        if inv:is_empty("slot1")==false or inv:is_empty("slot2")==false then return false end
        return true
@@ -170,7 +170,7 @@
-- Constructor MK3
mk3_on = function(pos, node)
    local meta = minetest.env:get_meta(pos)
    local meta = minetest.get_meta(pos)
    local inv = meta:get_inventory()
    
    local pos1={}
@@ -202,13 +202,13 @@
    if node.name == "technic:constructor_mk3_off" then
        hacky_swap_node(pos,"technic:constructor_mk3_on")
        nodeupdate(pos)
        local node1=minetest.env:get_node(pos1)
        local node1=minetest.get_node(pos1)
        deploy_node (inv,"slot1",pos1,node1,node)
        local node1=minetest.env:get_node(pos2)
        local node1=minetest.get_node(pos2)
        deploy_node (inv,"slot2",pos2,node1,node)
        local node1=minetest.env:get_node(pos3)
        local node1=minetest.get_node(pos3)
        deploy_node (inv,"slot3",pos3,node1,node)
        local node1=minetest.env:get_node(pos4)
        local node1=minetest.get_node(pos4)
        deploy_node (inv,"slot4",pos4,node1,node)
    end
end
@@ -230,7 +230,7 @@
    mesecons= {effector={action_on=mk3_on}},
    sounds = default.node_sound_stone_defaults(),
    on_construct = function(pos)
    local meta = minetest.env:get_meta(pos)
    local meta = minetest.get_meta(pos)
    meta:set_string("formspec",
                "invsize[8,9;]"..
                "label[0,0;Constructor MK2]"..
@@ -253,7 +253,7 @@
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos)
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        if inv:is_empty("slot1")==false or inv:is_empty("slot2")==false or inv:is_empty("slot3")==false or inv:is_empty("slot4")==false then return false end
        return true
@@ -279,7 +279,7 @@
            local def = stack1[1]:get_definition()
            if def.type == "node" then
                node_to_be_placed={name=stack1[1]:get_name(), param1=0, param2=node.param2}
                minetest.env:set_node(pos1,node_to_be_placed)
                minetest.set_node(pos1,node_to_be_placed)
                stack1[1]:take_item()
                inv:set_stack(slot_name, 1, stack1[1])
            elseif def.type == "craft" then
@@ -334,10 +334,10 @@
                end
                loop = loop + 1
            end
            minetest.env:remove_node(pos1)
            minetest.remove_node(pos1)
        elseif type(drop) == "string" then
            inv:add_item(slot_name,drop)
            minetest.env:remove_node(pos1)
            minetest.remove_node(pos1)
        end
    end
technic/machines/register/alloy_furnace.lua
New file
@@ -0,0 +1,284 @@
-- Register alloy recipes
technic.alloy_recipes = {}
-- Register recipe in a table
technic.register_alloy_recipe = function(metal1, count1, metal2, count2, result, count3)
    in1 = {
        name  = metal1,
        count = count1,
    }
    in2 = {
        name  = metal2,
        count = count2,
    }
    -- Sort the inputs alphebetically
    if in1.name > in2.name then
        local temp = in1
        in1 = in2
        in2 = temp
    end
    technic.alloy_recipes[in1.name.." "..in2.name] = {
        input = {in1, in2},
        output = {
            name = result,
            count = count3,
        },
    }
    if unified_inventory then
        unified_inventory.register_craft({
            type = "alloy",
            output = result.." "..count3,
            items = {metal1.." "..count1, metal2.." "..count2},
            width = 2,
        })
    end
end
-- Retrieve a recipe given the input metals.
function technic.get_alloy_recipe(stack1, stack2)
    -- Sort the stacks alphebetically
    if stack1:get_name() > stack2:get_name() then
        local temp = stack1
        stack1 = stack2
        stack2 = temp
    end
    for _, recipe in pairs(technic.alloy_recipes) do
        if recipe.input[1].name == stack1:get_name() and
           recipe.input[2].name == stack2:get_name() and
           stack1:get_count() >= recipe.input[1].count and
           stack2:get_count() >= recipe.input[2].count then
            return recipe
        end
    end
end
technic.register_alloy_recipe("technic:copper_dust",   3, "technic:tin_dust",       1, "technic:bronze_dust",           4)
technic.register_alloy_recipe("default:copper_ingot",  3, "moreores:tin_ingot",     1, "moreores:bronze_ingot",         4)
technic.register_alloy_recipe("technic:iron_dust",     3, "technic:chromium_dust",  1, "technic:stainless_steel_dust",  4)
technic.register_alloy_recipe("default:steel_ingot",   3, "technic:chromium_ingot", 1, "technic:stainless_steel_ingot", 4)
technic.register_alloy_recipe("technic:copper_dust",   2, "technic:zinc_dust",      1, "technic:brass_dust",            3)
technic.register_alloy_recipe("default:copper_ingot",  2, "technic:zinc_ingot",     1, "technic:brass_ingot",           3)
technic.register_alloy_recipe("default:sand",          2, "technic:coal_dust",      2, "technic:silicon_wafer",         1)
technic.register_alloy_recipe("technic:silicon_wafer", 1, "technic:gold_dust",      1, "technic:doped_silicon_wafer",   1)
function technic.register_alloy_furnace(data)
    local tier = data.tier
    local ltier = string.lower(tier)
    local tube_side_texture = data.tube and "technic_"..ltier.."_alloy_furnace_side_tube.png"
            or "technic_"..ltier.."_alloy_furnace_side.png"
    local groups = {cracky=2}
    local active_groups = {cracky=2, not_in_creative_inventory=1}
    if data.tube then
        groups.tubedevice = 1
        groups.tubedevice_receiver = 1
        active_groups.tubedevice = 1
        active_groups.tubedevice_receiver = 1
    end
    local formspec =
        "invsize[8,10;]"..
        "label[0,0;"..tier.." Alloy Furnace]"..
        "list[current_name;src;3,1;1,2;]"..
        "list[current_name;dst;5,1;2,2;]"..
        "list[current_player;main;0,6;8,4;]"
    if data.upgrade then
        formspec = formspec..
            "list[current_name;upgrade1;1,4;1,1;]"..
            "list[current_name;upgrade2;2,4;1,1;]"..
            "label[1,5;Upgrade Slots]"
    end
    data.formspec = formspec
    local tube = {
        insert_object = function(pos, node, stack, direction)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            return inv:add_item("src", stack)
        end,
        can_insert = function(pos, node, stack, direction)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            return inv:room_for_item("src", stack)
        end,
        connect_sides = {left=1, right=1, back=1, top=1, bottom=1},
    }
    minetest.register_node("technic:"..ltier.."_alloy_furnace", {
        description = tier.." Alloy Furnace",
        tiles = {"technic_"..ltier.."_alloy_furnace_top.png",
                 "technic_"..ltier.."_alloy_furnace_bottom.png",
             tube_side_texture,
                 tube_side_texture,
             "technic_"..ltier.."_alloy_furnace_side.png",
                 "technic_"..ltier.."_alloy_furnace_front.png"},
        paramtype2 = "facedir",
        groups = groups,
        tube = tube,
        technic = data,
        legacy_facedir_simple = true,
        sounds = default.node_sound_stone_defaults(),
        on_construct = function(pos)
            local meta = minetest.get_meta(pos)
            local name = minetest.get_node(pos).name
            local data = minetest.registered_nodes[name].technic
            meta:set_string("infotext", data.tier.." Alloy furnace")
            meta:set_string("formspec", data.formspec)
            meta:set_int("tube_time",  0)
            local inv = meta:get_inventory()
            inv:set_size("src", 2)
            inv:set_size("dst", 4)
            inv:set_size("upgrade1", 1)
            inv:set_size("upgrade2", 1)
        end,
        can_dig = function(pos, player)
            local meta = minetest.get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("src") or not inv:is_empty("dst") or
               not inv:is_empty("upgrade1") or not inv:is_empty("upgrade2") then
                minetest.chat_send_player(player:get_player_name(),
                    "Machine cannot be removed because it is not empty");
                return false
            else
                return true
            end
        end,
    })
    minetest.register_node("technic:"..ltier.."_alloy_furnace_active",{
        description = tier.." Alloy Furnace",
        tiles = {"technic_"..ltier.."_alloy_furnace_top.png",
                 "technic_"..ltier.."_alloy_furnace_bottom.png",
             tube_side_texture,
                 tube_side_texture,
             "technic_"..ltier.."_alloy_furnace_side.png",
                 "technic_"..ltier.."_alloy_furnace_front_active.png"},
        paramtype2 = "facedir",
        light_source = 8,
        drop = "technic:"..ltier.."_alloy_furnace",
        groups = active_groups,
        tube = tube,
        technic = data,
        legacy_facedir_simple = true,
        sounds = default.node_sound_stone_defaults(),
        can_dig = function(pos, player)
            local meta = minetest.get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("src") or not inv:is_empty("dst") or
               not inv:is_empty("upgrade1") or not inv:is_empty("upgrade2") then
                minetest.chat_send_player(player:get_player_name(),
                    "Machine cannot be removed because it is not empty");
                return false
            else
                return true
            end
        end,
        -- These three makes sure upgrades are not moved in or out while the furnace is active.
        allow_metadata_inventory_put = function(pos, listname, index, stack, player)
            if listname == "src" or listname == "dst" then
                return stack:get_count()
            else
                return 0 -- Disallow the move
            end
        end,
        allow_metadata_inventory_take = function(pos, listname, index, stack, player)
            if listname == "src" or listname == "dst" then
                return stack:get_count()
            else
                return 0 -- Disallow the move
            end
        end,
        allow_metadata_inventory_move = function(pos, from_list, to_list, to_list, to_index, count, player)
            return 0
        end,
    })
    minetest.register_abm({
        nodenames = {"technic:"..ltier.."_alloy_furnace", "technic:"..ltier.."_alloy_furnace_active"},
        interval = 1,
        chance = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            local data         = minetest.registered_nodes[node.name].technic
            local meta         = minetest.get_meta(pos)
            local inv          = meta:get_inventory()
            local eu_input     = meta:get_int(data.tier.."_EU_input")
            -- Machine information
            local machine_name   = data.tier.." Alloy Furnace"
            local machine_node   = "technic:"..string.lower(data.tier).."_alloy_furnace"
            local machine_demand = data.demand
            -- Setup meta data if it does not exist.
            if not eu_input then
                meta:set_int(data.tier.."_EU_demand", machine_demand[1])
                meta:set_int(data.tier.."_EU_input", 0)
            end
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, data.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
            -- Get what to cook if anything
            local srcstack  = inv:get_stack("src", 1)
            local src2stack = inv:get_stack("src", 2)
            local recipe = technic.get_alloy_recipe(srcstack, src2stack)
            local result = recipe and ItemStack(recipe.output) or nil
            -- Sort the stacks alphabetically
            if srcstack:get_name() > src2stack:get_name() then
                local temp = srcstack
                srcstack = src2stack
                src2stack = temp
            end
            if not result then
                hacky_swap_node(pos, machine_node)
                meta:set_string("infotext", machine_name.." Idle")
                meta:set_int(data.tier.."_EU_demand", 0)
                return
            end
            if eu_input < machine_demand[EU_upgrade+1] then
                -- Unpowered - go idle
                hacky_swap_node(pos, machine_node)
                meta:set_string("infotext", machine_name.." Unpowered")
                next_state = 1
            elseif eu_input >= machine_demand[EU_upgrade+1] then
                -- Powered
                hacky_swap_node(pos, machine_node.."_active")
                meta:set_string("infotext", machine_name.." Active")
                meta:set_int("src_time", meta:get_int("src_time") + 1)
                if meta:get_int("src_time") == data.cook_time then
                    meta:set_int("src_time", 0)
                    -- check if there's room for output and that we have the materials
                    if inv:room_for_item("dst", result) then
                        srcstack:take_item(recipe.input[1].count)
                        inv:set_stack("src", 1, srcstack)
                        src2stack:take_item(recipe.input[2].count)
                        inv:set_stack("src", 2, src2stack)
                        -- Put result in "dst" list
                        inv:add_item("dst", result)
                    else
                        next_state = 1
                    end
                end
            end
            meta:set_int(data.tier.."_EU_demand", machine_demand[EU_upgrade+1])
        end,
    })
    technic.register_machine(tier, "technic:"..ltier.."_alloy_furnace",        technic.receiver)
    technic.register_machine(tier, "technic:"..ltier.."_alloy_furnace_active", technic.receiver)
end -- End registration
technic/machines/register/battery_box.lua
New file
@@ -0,0 +1,216 @@
technic.battery_box_formspec =
    "invsize[8,9;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "list[current_name;src;3,1;1,1;]"..
    "image[4,1;1,1;technic_battery_reload.png]"..
    "list[current_name;dst;5,1;1,1;]"..
    "label[0,0;Battery Box]"..
    "label[3,0;Charge]"..
    "label[5,0;Discharge]"..
    "label[1,3;Power level]"..
    "list[current_player;main;0,5;8,4;]"
function technic.register_battery_box(data)
    local tier = data.tier
    local ltier = string.lower(tier)
    for i = 0, 8 do
        local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}
        if i ~= 0 then
            groups.not_in_creative_inventory = 1
        end
        minetest.register_node("technic:"..ltier.."_battery_box"..i, {
            description = tier.." Battery Box",
            tiles = {"technic_"..ltier.."_battery_box_top.png",
                     "technic_"..ltier.."_battery_box_bottom.png",
                 "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png",
                 "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png",
                 "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png",
                 "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png"},
            groups = groups,
            sounds = default.node_sound_wood_defaults(),
            drop = "technic:"..ltier.."_battery_box0",
            technic = data,
            on_construct = function(pos)
                local meta = minetest.get_meta(pos)
                local inv = meta:get_inventory()
                local node = minetest.get_node(pos)
                local data = minetest.registered_nodes[node.name].technic
                meta:set_string("infotext", data.tier.." Battery Box")
                meta:set_string("formspec", battery_box_formspec)
                meta:set_int(data.tier.."_EU_demand", 0)
                meta:set_int(data.tier.."_EU_supply", 0)
                meta:set_int(data.tier.."_EU_input",  0)
                meta:set_float("internal_EU_charge", 0)
                inv:set_size("src", 1)
                inv:set_size("dst", 1)
            end,
            can_dig = function(pos,player)
                local meta = minetest.get_meta(pos);
                local inv = meta:get_inventory()
                if not inv:is_empty("src") or not inv:is_empty("dst") then
                    minetest.chat_send_player(player:get_player_name(),
                        "Machine cannot be removed because it is not empty");
                    return false
                else
                    return true
                end
            end,
        })
    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 data           = minetest.registered_nodes[node.name].technic
            local meta           = minetest.get_meta(pos)
            local eu_input       = meta:get_int(data.tier.."_EU_input")
            local current_charge = meta:get_int("internal_EU_charge")
            local max_charge     = data.max_charge
            local charge_rate    = data.charge_rate
            local discharge_rate = data.discharge_rate
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, data.tier)
            -- 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
            current_charge = technic.charge_tools(meta,
                    current_charge, data.charge_step)
            current_charge = technic.discharge_tools(meta,
                    current_charge, data.discharge_step, max_charge)
            -- We allow batteries to charge on less than the demand
            meta:set_int(data.tier.."_EU_demand",
                    math.min(charge_rate, max_charge - current_charge))
            meta:set_int(data.tier.."_EU_supply",
                    math.min(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
                hacky_swap_node(pos,"technic:"..string.lower(data.tier).."_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",
                technic.battery_box_formspec..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"
                ..charge_percent..":technic_power_meter_fg.png]")
            local infotext = data.tier.." battery box: "
                    ..current_charge.."/"..max_charge
            if eu_input == 0 then
                infotext = infotext.." (idle)"
            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
    for i = 0, 8 do
        technic.register_machine(tier, "technic:"..ltier.."_battery_box"..i, technic.battery)
    end
end -- End registration
function technic.charge_tools(meta, charge, charge_step)
    --charge registered power tools
    local inv = meta:get_inventory()
    if not inv:is_empty("src") then
        local srcstack = inv:get_stack("src", 1)
        local src_item = srcstack:to_table()
        local src_meta = get_item_meta(src_item["metadata"])
        local toolname = src_item["name"]
        if technic.power_tools[toolname] ~= nil then
            -- Set meta data for the tool if it didn't do it itself :-(
            src_meta = get_item_meta(src_item["metadata"])
            src_meta = src_meta or {}
            if src_meta["charge"] == nil then
                src_meta["charge"] = 0
            end
            -- Do the charging
            local item_max_charge = technic.power_tools[toolname]
            local tool_charge     = src_meta["charge"]
            if tool_charge < item_max_charge and charge > 0 then
                if charge - charge_step < 0 then
                    charge_step = charge
                end
                if tool_charge + charge_step > item_max_charge then
                    charge_step = item_max_charge - tool_charge
                end
                tool_charge = tool_charge + charge_step
                charge = charge - charge_step
                technic.set_RE_wear(src_item, tool_charge, item_max_charge)
                src_meta["charge"]   = tool_charge
                src_item["metadata"] = set_item_meta(src_meta)
                inv:set_stack("src", 1, src_item)
            end
        end
    end
    return charge -- return the remaining charge in the battery
end
function technic.discharge_tools(meta, charge, charge_step, max_charge)
    -- discharging registered power tools
    local inv = meta:get_inventory()
    if not inv:is_empty("dst") then
        srcstack = inv:get_stack("dst", 1)
        src_item = srcstack:to_table()
        local src_meta = get_item_meta(src_item["metadata"])
        local toolname = src_item["name"]
        if technic.power_tools[toolname] ~= nil then
            -- Set meta data for the tool if it didn't do it itself :-(
            src_meta = get_item_meta(src_item["metadata"])
            src_meta = src_meta or {}
            if src_meta["charge"] == nil then
                src_meta["charge"] = 0
            end
            -- Do the discharging
            local item_max_charge = technic.power_tools[toolname]
            local tool_charge     = src_meta["charge"]
            if tool_charge > 0 and charge < max_charge then
                if charge + charge_step > max_charge then
                    charge_step = max_charge - charge
                end
                if tool_charge - charge_step < 0 then
                    charge_step = charge
                end
                tool_charge = tool_charge - charge_step
                charge = charge + charge_step
                technic.set_RE_wear(src_item, tool_charge, item_max_charge)
                src_meta["charge"] = tool_charge
                src_item["metadata"] = set_item_meta(src_meta)
                inv:set_stack("dst", 1, src_item)
            end
        end
    end
    return charge -- return the remaining charge in the battery
end
technic/machines/register/cables.lua
New file
@@ -0,0 +1,170 @@
technic.cables = {}
function technic.register_cable(tier, size)
    local ltier = string.lower(tier)
    for x1 = 0, 1 do
    for x2 = 0, 1 do
    for y1 = 0, 1 do
    for y2 = 0, 1 do
    for z1 = 0, 1 do
    for z2 = 0, 1 do
        local id = technic.get_cable_id({x1, x2, y1, y2, z1, z2})
        technic.cables["technic:"..ltier.."_cable"..id] = tier
        local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}
        if id ~= 0 then
            groups.not_in_creative_inventory = 1
        end
        minetest.register_node("technic:"..ltier.."_cable"..id, {
            description = tier.." Cable",
            tiles = {"technic_"..ltier.."_cable.png"},
            inventory_image = "technic_"..ltier.."_cable_wield.png",
            wield_image = "technic_"..ltier.."_cable_wield.png",
            groups = groups,
            sounds = default.node_sound_wood_defaults(),
            drop = "technic:"..ltier.."_cable0",
            paramtype = "light",
            sunlight_propagates = true,
            drawtype = "nodebox",
            node_box = {
                type = "fixed",
                fixed = technic.gen_cable_nodebox(x1, y1, z1, x2, y2, z2, size)
            },
            after_place_node = function(pos)
                local node = minetest.get_node(pos)
                technic.update_cables(pos, technic.get_cable_tier(node.name))
            end,
            after_dig_node = function(pos, oldnode)
                local tier = technic.get_cable_tier(oldnode.name)
                technic.update_cables(pos, tier, true)
            end
        })
    end
    end
    end
    end
    end
    end
end
minetest.register_on_placenode(function(pos, node)
    for tier, machine_list in pairs(technic.machines) do
        for machine_name, _ in pairs(machine_list) do
            if node.name == machine_name then
                technic.update_cables(pos, tier, true)
            end
        end
    end
end)
minetest.register_on_dignode(function(pos, node)
    for tier, machine_list in pairs(technic.machines) do
        for machine_name, _ in pairs(machine_list) do
            if node.name == machine_name then
                technic.update_cables(pos, tier, true)
            end
        end
    end
end)
function technic.get_cable_id(links)
    return (links[6] * 1) + (links[5] * 2)
            + (links[4] * 4)  + (links[3] * 8)
            + (links[2] * 16) + (links[1] * 32)
end
function technic.update_cables(pos, tier, no_set, secondrun)
    local link_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+1, z=pos.z},
        {x=pos.x,   y=pos.y-1, z=pos.z},
        {x=pos.x,   y=pos.y,   z=pos.z+1},
        {x=pos.x,   y=pos.y,   z=pos.z-1}}
    local links = {0, 0, 0, 0, 0, 0}
    for i, link_pos in pairs(link_positions) do
        local connect_type = technic.cables_should_connect(pos, link_pos, tier)
        if connect_type then
            links[i] = 1
            -- Have cables next to us update theirselves,
            -- but only once. (We don't want to update the entire
            -- network or start an infinite loop of updates)
            if not secondrun and connect_type == "cable" then
                technic.update_cables(link_pos, tier, false, true)
            end
        end
    end
    -- We don't want to set ourselves if we have been removed or we are
    -- updating a machine
    if not no_set then
        minetest.set_node(pos, {name="technic:"..string.lower(tier)
                .."_cable"..technic.get_cable_id(links)})
    end
end
function technic.is_tier_cable(name, tier)
    return technic.cables[name] and technic.cables[name] == tier
end
function technic.get_cable_tier(name)
    return technic.cables[name]
end
function technic.cables_should_connect(pos1, pos2, tier)
    local name = minetest.get_node(pos2).name
    if technic.is_tier_cable(name, tier) then
        return "cable"
    elseif technic.machines[tier][name] then
        return "machine"
    end
    return false
end
function technic.gen_cable_nodebox(x1, y1, z1, x2, y2, z2, size)
    -- Nodeboxes
    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_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-
    local box = {box_center}
    if x1 == 1 then
        table.insert(box, box_x1)
    end
    if y1 == 1 then
        table.insert(box, box_y1)
    end
    if z1 == 1 then
        table.insert(box, box_z1)
    end
    if x2 == 1 then
        table.insert(box, box_x2)
    end
    if y2 == 1 then
        table.insert(box, box_y2)
    end
    if z2 == 1 then
        table.insert(box, box_z2)
    end
    return box
end
technic/machines/register/common.lua
New file
@@ -0,0 +1,111 @@
function technic.handle_machine_upgrades(meta)
    -- Get the names of the upgrades
    local inv = meta:get_inventory()
    local upg_item1
    local upg_item2
    local srcstack = inv:get_stack("upgrade1", 1)
    if srcstack then
        upg_item1 = srcstack:to_table()
    end
    srcstack = inv:get_stack("upgrade2", 1)
    if srcstack then
        upg_item2 = srcstack:to_table()
    end
    -- Save some power by installing battery upgrades.
    -- Tube loading speed can be upgraded using control logic units.
    local EU_upgrade = 0
    local tube_upgrade = 0
    if upg_item1 then
        if     upg_item1.name == "technic:battery" then
            EU_upgrade = EU_upgrade + 1
        elseif upg_item1.name == "technic:control_logic_unit" then
            tube_upgrade = tube_upgrade + 1
        end
    end
    if upg_item2 then
        if     upg_item2.name == "technic:battery" then
            EU_upgrade = EU_upgrade + 1
        elseif upg_item2.name == "technic:control_logic_unit" then
            tube_upgrade = tube_upgrade + 1
        end
    end
    return EU_upgrade, tube_upgrade
end
function technic.send_items(pos, x_velocity, z_velocity)
    -- Send items on their way in the pipe system.
    local meta = minetest.get_meta(pos)
    local inv = meta:get_inventory()
    local i = 0
    for _, stack in ipairs(inv:get_list("dst")) do
        i = i + 1
        if stack then
            local item0 = stack:to_table()
            if item0 then
                item0["count"] = "1"
                local item1 = tube_item({x=pos.x, y=pos.y, z=pos.z}, item0)
                item1:get_luaentity().start_pos = {x=pos.x, y=pos.y, z=pos.z}
                item1:setvelocity({x=x_velocity, y=0, z=z_velocity})
                item1:setacceleration({x=0, y=0, z=0})
                stack:take_item(1)
                inv:set_stack("dst", i, stack)
                return
            end
        end
    end
end
function technic.smelt_item(meta, result, speed)
    local inv = meta:get_inventory()
    meta:set_int("cook_time", meta:get_int("cook_time") + 1)
    if meta:get_int("cook_time") < result.time / speed then
        return
    end
    local result = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")})
    if result and result.item then
        meta:set_int("cook_time", 0)
        -- check if there's room for output in "dst" list
        if inv:room_for_item("dst", result) then
            srcstack = inv:get_stack("src", 1)
            srcstack:take_item()
            inv:set_stack("src", 1, srcstack)
            inv:add_item("dst", result.item)
        end
    end
end
function technic.handle_machine_pipeworks(pos, tube_upgrade)
    local node = minetest.get_node(pos)
    local meta = minetest.get_meta(pos)
    local inv = meta:get_inventory()
    local pos1 = vector.new(pos)
    local x_velocity = 0
    local z_velocity = 0
    -- Output is on the left side of the furnace
    if node.param2 == 3 then pos1.z = pos1.z - 1  z_velocity = -1 end
    if node.param2 == 2 then pos1.x = pos1.x - 1  x_velocity = -1 end
    if node.param2 == 1 then pos1.z = pos1.z + 1  z_velocity =  1 end
    if node.param2 == 0 then pos1.x = pos1.x + 1  x_velocity =  1 end
    local output_tube_connected = false
    local meta1 = minetest.get_meta(pos1)
    if meta1:get_int("tubelike") == 1 then
        output_tube_connected = true
    end
    tube_time = meta:get_int("tube_time")
    tube_time = tube_time + tube_upgrade
    if tube_time > 3 then
        tube_time = 0
        if output_tube_connected then
            technic.send_items(pos, x_velocity, z_velocity)
        end
    end
    meta:set_int("tube_time", tube_time)
end
technic/machines/register/electric_furnace.lua
New file
@@ -0,0 +1,203 @@
function technic.register_electric_furnace(data)
    local tier = data.tier
    local ltier = string.lower(tier)
    local tube_side_texture = data.tube and "technic_"..ltier.."_electric_furnace_side_tube.png"
            or "technic_"..ltier.."_electric_furnace_side.png"
    local tube = {
        insert_object = function(pos, node, stack, direction)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            return inv:add_item("src",stack)
        end,
        can_insert = function(pos, node, stack, direction)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            return inv:room_for_item("src", stack)
        end,
        connect_sides = {left=1, right=1, back=1, top=1, bottom=1},
    }
    local formspec =
        "invsize[8,10;]"..
        "list[current_name;src;3,1;1,1;]"..
        "list[current_name;dst;5,1;2,2;]"..
        "list[current_player;main;0,6;8,4;]"..
        "label[0,0;"..tier.." Electric Furnace]"
    if data.upgrade then
        formspec = formspec..
            "list[current_name;upgrade1;1,4;1,1;]"..
            "list[current_name;upgrade2;2,4;1,1;]"..
            "label[1,5;Upgrade Slots]"
    end
    data.formspec = formspec
    minetest.register_node("technic:"..ltier.."_electric_furnace", {
        description = tier.." Electric furnace",
        tiles = {"technic_"..ltier.."_electric_furnace_top.png",
                 "technic_"..ltier.."_electric_furnace_bottom.png",
                 tube_side_texture,
             tube_side_texture,
             "technic_"..ltier.."_electric_furnace_side.png",
                 "technic_"..ltier.."_electric_furnace_front.png"},
        paramtype2 = "facedir",
        groups = {cracky=2, tubedevice=1, tubedevice_receiver=1},
        legacy_facedir_simple = true,
        sounds = default.node_sound_stone_defaults(),
        tube = tube,
        technic = data,
        on_construct = function(pos)
            local meta = minetest.get_meta(pos)
            local name = minetest.get_node(pos).name
            local data = minetest.registered_nodes[name].technic
            meta:set_string("infotext", data.tier.." Electric furnace")
            meta:set_int("tube_time",  0)
            meta:set_string("formspec", data.formspec)
            local inv = meta:get_inventory()
            inv:set_size("src", 1)
            inv:set_size("dst", 4)
            inv:set_size("upgrade1", 1)
            inv:set_size("upgrade2", 1)
        end,
        can_dig = function(pos,player)
            local meta = minetest.get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("src") or not inv:is_empty("dst") or
               not inv:is_empty("upgrade1") or not inv:is_empty("upgrade2") then
                minetest.chat_send_player(player:get_player_name(),
                    "Machine cannot be removed because it is not empty");
                return false
            else
                return true
            end
        end,
    })
    minetest.register_node("technic:"..ltier.."_electric_furnace_active", {
        description = tier.." Electric furnace",
        tiles = {"technic_"..ltier.."_electric_furnace_top.png",
                 "technic_"..ltier.."_electric_furnace_bottom.png",
                 tube_side_texture,
                 tube_side_texture,
                 "technic_"..ltier.."_electric_furnace_side.png",
                 "technic_"..ltier.."_electric_furnace_front_active.png"},
        paramtype2 = "facedir",
        groups = {cracky=2, tubedevice=1, tubedevice_receiver=1, not_in_creative_inventory=1},
        light_source = 8,
        legacy_facedir_simple = true,
        sounds = default.node_sound_stone_defaults(),
        tube = tube,
        technic = data,
        on_construct = function(pos)
            local meta = minetest.get_meta(pos)
            local name = minetest.get_node(pos).name
            local data = minetest.registered_nodes[name].technic
            meta:set_string("infotext", data.tier.." Electric furnace")
            meta:set_int("tube_time",  0)
            meta:set_string("formspec", data.formspec)
            local inv = meta:get_inventory()
            inv:set_size("src", 1)
            inv:set_size("dst", 4)
            inv:set_size("upgrade1", 1)
            inv:set_size("upgrade2", 1)
        end,
        can_dig = function(pos,player)
            local meta = minetest.get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("src") or not inv:is_empty("dst") or
               not inv:is_empty("upgrade1") or not inv:is_empty("upgrade2") then
                minetest.chat_send_player(player:get_player_name(),
                    "Machine cannot be removed because it is not empty");
                return false
            else
                return true
            end
        end,
        -- These three makes sure upgrades are not moved in or out while the furnace is active.
        allow_metadata_inventory_put = function(pos, listname, index, stack, player)
            if listname == "src" or listname == "dst" then
                return stack:get_stack_max()
            else
                return 0 -- Disallow the move
            end
        end,
        allow_metadata_inventory_take = function(pos, listname, index, stack, player)
            if listname == "src" or listname == "dst" then
                return stack:get_stack_max()
            else
                return 0 -- Disallow the move
            end
        end,
        allow_metadata_inventory_move = function(pos, from_list, to_list, to_list, to_index, count, player)
            return 0
        end,
    })
    minetest.register_abm({
        nodenames = {"technic:"..ltier.."_electric_furnace",
                     "technic:"..ltier.."_electric_furnace_active"},
        interval = 1,
        chance   = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            local data     = minetest.registered_nodes[node.name].technic
            local meta     = minetest.get_meta(pos)
            local inv      = meta:get_inventory()
            local eu_input = meta:get_int(data.tier.."_EU_input")
            -- Machine information
            local machine_name   = data.tier.." Electric Furnace"
            local machine_node   = "technic:"..string.lower(data.tier).."_electric_furnace"
            local machine_demand = data.demand
            -- Setup meta data if it does not exist. state is used as an indicator of this
            if not eu_input then
                meta:set_int(data.tier.."_EU_demand", machine_demand[1])
                meta:set_int(data.tier.."_EU_input", 0)
            end
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, data.tier)
            -- Check upgrade slots
            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 = minetest.get_craft_result({
                    method = "cooking",
                    width = 1,
                    items = inv:get_list("src")})
            if not result or result.time == 0 then
                meta:set_int(data.tier.."_EU_demand", 0)
                hacky_swap_node(pos, machine_node)
                meta:set_string("infotext", machine_name.." Idle")
                return
            end
            if eu_input < machine_demand[EU_upgrade+1] then
                -- Unpowered - go idle
                hacky_swap_node(pos, machine_node)
                meta:set_string("infotext", machine_name.." Unpowered")
            elseif eu_input >= machine_demand[EU_upgrade+1] then
                -- Powered
                hacky_swap_node(pos, machine_node.."_active")
                meta:set_string("infotext", machine_name.." Active")
                technic.smelt_item(meta, result, data.speed)
            end
            meta:set_int(data.tier.."_EU_demand", machine_demand[EU_upgrade+1])
        end,
    })
    technic.register_machine(tier, "technic:"..ltier.."_electric_furnace",        technic.receiver)
    technic.register_machine(tier, "technic:"..ltier.."_electric_furnace_active", technic.receiver)
end -- End registration
technic/machines/register/grinder.lua
New file
@@ -0,0 +1,184 @@
function technic.register_grinder(data)
    local tier = data.tier
    local ltier = string.lower(tier)
    local tube = {
        insert_object = function(pos, node, stack, direction)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            return inv:add_item("src", stack)
        end,
        can_insert = function(pos, node, stack, direction)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            return inv:room_for_item("src", stack)
        end,
        connect_sides = {left=1, right=1, back=1, top=1, bottom=1},
    }
    local formspec =
        "invsize[8,10;]"..
        "list[current_name;src;3,1;1,1;]"..
        "list[current_name;dst;5,1;2,2;]"..
        "list[current_player;main;0,6;8,4;]"..
        "label[0,0;"..tier.." Grinder]"
    if data.upgrade then
        formspec = formspec..
            "list[current_name;upgrade1;1,4;1,1;]"..
            "list[current_name;upgrade2;2,4;1,1;]"..
            "label[1,5;Upgrade Slots]"
    end
    data.formspec = formspec
    minetest.register_node("technic:"..ltier.."_grinder", {
        description = tier.." Grinder",
        tiles = {"technic_"..ltier.."_grinder_top.png",  "technic_"..ltier.."_grinder_bottom.png",
             "technic_"..ltier.."_grinder_side.png", "technic_"..ltier.."_grinder_side.png",
             "technic_"..ltier.."_grinder_side.png", "technic_"..ltier.."_grinder_front.png"},
        paramtype2 = "facedir",
        groups = {cracky=2, tubedevice=1, tubedevice_receiver=1},
        technic = data,
        tube = tube,
        legacy_facedir_simple = true,
        sounds = default.node_sound_wood_defaults(),
        on_construct = function(pos)
            local node = minetest.get_node(pos)
            local meta = minetest.get_meta(pos)
            local data = minetest.registered_nodes[node.name].technic
            meta:set_string("infotext", data.tier.." Grinder")
            meta:set_int("tube_time",  0)
            meta:set_string("formspec", data.formspec)
            local inv = meta:get_inventory()
            inv:set_size("src", 1)
            inv:set_size("dst", 4)
            inv:set_size("upgrade1", 1)
            inv:set_size("upgrade2", 1)
        end,
        can_dig = function(pos,player)
            local meta = minetest.get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("src") or not inv:is_empty("dst") or
               not inv:is_empty("upgrade1") or not inv:is_empty("upgrade2") then
                minetest.chat_send_player(player:get_player_name(),
                        "Machine cannot be removed because it is not empty");
                return false
            else
                return true
            end
        end,
    })
    minetest.register_node("technic:"..ltier.."_grinder_active",{
        description = tier.." Grinder",
        tiles = {"technic_"..ltier.."_grinder_top.png",  "technic_"..ltier.."_grinder_bottom.png",
             "technic_"..ltier.."_grinder_side.png", "technic_"..ltier.."_grinder_side.png",
             "technic_"..ltier.."_grinder_side.png", "technic_"..ltier.."_grinder_front_active.png"},
        paramtype2 = "facedir",
        groups = {cracky=2, tubedevice=1, tubedevice_receiver=1, not_in_creative_inventory=1},
        legacy_facedir_simple = true,
        sounds = default.node_sound_wood_defaults(),
        technic = data,
        tube = tube,
        can_dig = function(pos,player)
            local meta = minetest.get_meta(pos)
            local inv = meta:get_inventory()
            if not inv:is_empty("src") or not inv:is_empty("dst") or
               not inv:is_empty("upgrade1") or not inv:is_empty("upgrade2") then
                minetest.chat_send_player(player:get_player_name(),
                        "Machine cannot be removed because it is not empty");
                return false
            else
                return true
            end
        end,
        -- These three makes sure upgrades are not moved in or out while the grinder is active.
        allow_metadata_inventory_put = function(pos, listname, index, stack, player)
            if listname == "src" or listname == "dst" then
                return stack:get_stack_max()
            else
                return 0 -- Disallow the move
            end
        end,
        allow_metadata_inventory_take = function(pos, listname, index, stack, player)
            if listname == "src" or listname == "dst" then
                return stack:get_stack_max()
            else
                return 0 -- Disallow the move
            end
        end,
        allow_metadata_inventory_move = function(pos, from_list, to_list, to_list, to_index, count, player)
            return 0
        end,
    })
    minetest.register_abm({
        nodenames = {"technic:"..ltier.."_grinder","technic:"..ltier.."_grinder_active"},
        interval = 1,
        chance   = 1,
        action = function(pos, node, active_object_count, active_object_count_wider)
            local data         = minetest.registered_nodes[node.name].technic
            local meta         = minetest.get_meta(pos)
            local inv    = meta:get_inventory()
            local eu_input     = meta:get_int(data.tier.."_EU_input")
            local machine_name   = data.tier.." Grinder"
            local machine_node   = "technic:"..string.lower(data.tier).."_grinder"
            local machine_demand = data.demand
            -- Setup meta data if it does not exist.
            if not eu_input then
                meta:set_int(data.tier.."_EU_demand", machine_demand[1])
                meta:set_int(data.tier.."_EU_input", 0)
                return
            end
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, data.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_grinder_recipe(inv:get_stack("src", 1))
            if not result then
                hacky_swap_node(pos, machine_node)
                meta:set_string("infotext", machine_name.." Idle")
                meta:set_int(data.tier.."_EU_demand", 0)
                return
            end
            if eu_input < machine_demand[EU_upgrade+1] then
                -- Unpowered - go idle
                hacky_swap_node(pos, machine_node)
                meta:set_string("infotext", machine_name.." Unpowered")
            elseif eu_input >= machine_demand[EU_upgrade+1] then
                -- Powered
                hacky_swap_node(pos, machine_node.."_active")
                meta:set_string("infotext", machine_name.." Active")
                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
                        srcstack = inv:get_stack("src", 1)
                        srcstack:take_item()
                        inv:set_stack("src", 1, srcstack)
                        inv:add_item("dst", result_stack)
                    end
                end
            end
            meta:set_int(data.tier.."_EU_demand", machine_demand[EU_upgrade+1])
        end
    })
    technic.register_machine(tier, "technic:"..ltier.."_grinder",        technic.receiver)
    technic.register_machine(tier, "technic:"..ltier.."_grinder_active", technic.receiver)
end -- End registration
technic/machines/register/grinder_recipes.lua
New file
@@ -0,0 +1,94 @@
technic.grinder_recipes = {}
function technic.register_grinder_recipe(data)
    data.time = data.time or 3
    technic.grinder_recipes[data.input] = data
    if unified_inventory then
        unified_inventory.register_craft({
            type = "grinding",
            output = data.output,
            items = {data.input},
            width = 0,
        })
    end
end
-- Receive an ItemStack of result by an ItemStack input
function technic.get_grinder_recipe(itemstack)
    return technic.grinder_recipes[itemstack:get_name()]
end
-- Sorted alphebeticaly
local recipes = {
    {"default:bronze_ingot",    "technic:bronze_dust 1"},
    {"default:coal_lump",       "technic:coal_dust 2"},
    {"default:cobble",          "default:gravel"},
    {"default:copper_ingot",    "technic:copper_dust 1"},
    {"default:copper_lump",     "technic:copper_dust 2"},
    {"default:desert_stone",    "default:desert_sand"},
    {"default:gold_ingot",      "technic:gold_dust 1"},
    {"default:gold_lump",       "technic:gold_dust 2"},
    {"default:gravel",          "default:dirt"},
    {"default:iron_lump",       "technic:iron_dust 2"},
    {"default:steel_ingot",     "technic:iron_dust 1"},
    {"default:stone",           "default:sand"},
    {"gloopores:alatro_lump",   "technic:alatro_dust 2"},
    {"gloopores:kalite_lump",   "technic:kalite_dust 2"},
    {"gloopores:arol_lump",     "technic:arol_dust 2"},
    {"gloopores:talinite_lump", "technic:talinite_dust 2"},
    {"gloopores:akalin_lump",   "technic:akalin_dust 2"},
    {"moreores:mithril_ingot",  "technic:mithril_dust 1"},
    {"moreores:mithril_lump",   "technic:mithril_dust 2"},
    {"moreores:silver_ingot",   "technic:silver_dust 1"},
    {"moreores:silver_lump",    "technic:silver_dust 2"},
    {"moreores:tin_ingot",      "technic:tin_dust 1"},
    {"moreores:tin_lump",       "technic:tin_dust 2"},
    {"technic:chromium_ingot",  "technic:chromium_dust 1"},
    {"technic:chromium_lump",   "technic:chromium_dust 2"},
    {"technic:zinc_lump",       "technic:zinc_dust 2"},
}
if minetest.get_modpath("homedecor") then
    table.insert(recipes, {"home_decor:brass_ingot", "technic:brass_dust 1"})
end
for _, data in pairs(recipes) do
    technic.register_grinder_recipe({input=data[1], output=data[2]})
end
local function register_dust(name, ingot)
    local lname = string.lower(name)
    lname = string.gsub(lname, ' ', '_')
    minetest.register_craftitem("technic:"..lname.."_dust", {
        description = name.." Dust",
        inventory_image = "technic_"..lname.."_dust.png",
        on_place_on_ground = minetest.craftitem_place_item,
    })
    if ingot then
        minetest.register_craft({
            type = "cooking",
            recipe = "technic:"..lname.."_dust",
            output = ingot,
        })
    end
end
-- Sorted alphibeticaly
register_dust("Akalin",          "glooptest:akalin_ingot")
register_dust("Alatro",          "glooptest:alatro_ingot")
register_dust("Arol",            "glooptest:arol_ingot")
register_dust("Brass",           "technic:brass_ingot")
register_dust("Bronze",          "default:bronze_ingot")
register_dust("Chromium",        "technic:chromium_ingot")
register_dust("Coal",            nil)
register_dust("Copper",          "default:copper_ingot")
register_dust("Gold",            "default:gold_ingot")
register_dust("Iron",            "default:steel_ingot")
register_dust("Mithril",         "moreores:mithril_ingot")
register_dust("Silver",          "moreores:silver_ingot")
register_dust("Stainless Steel", "technic:stainless_steel_ingot")
register_dust("Talinite",        "glooptest:talinite_ingot")
register_dust("Tin",             "moreores:tin_ingot")
register_dust("Zinc",            "technic:zinc_ingot")
technic/machines/register/init.lua
New file
@@ -0,0 +1,11 @@
local path = technic.modpath.."/machines/register"
dofile(path.."/alloy_furnace.lua")
dofile(path.."/battery_box.lua")
dofile(path.."/cables.lua")
dofile(path.."/common.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/grinder.lua")
dofile(path.."/grinder_recipes.lua")
dofile(path.."/solar_array.lua")
technic/machines/register/solar_array.lua
New file
@@ -0,0 +1,69 @@
function technic.register_solar_array(data)
    local tier = data.tier
    local ltier = string.lower(tier)
    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},
        sounds = default.node_sound_wood_defaults(),
        description = tier.." Solar Array",
        active = false,
        drawtype = "nodebox",
        paramtype = "light",
        node_box = {
            type = "fixed",
            fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
        },
        technic = data,
        on_construct = function(pos)
            local meta = minetest.get_meta(pos)
            local name = minetest.get_node(pos).name
            local tier = minetest.registered_nodes[name].technic.tier
            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 = {}
            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
            local data = minetest.registered_nodes[node.name].technic
            -- 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", "Solar Array is active ("..charge_to_give.."EU)")
                meta:set_int(data.tier.."_EU_supply", charge_to_give)
            else
                meta:set_string("infotext", "Solar Array is inactive");
                meta:set_int(data.tier.."_EU_supply", 0)
            end
        end,
    })
    technic.register_machine(tier, "technic:solar_array_"..ltier, technic.producer)
end
technic/machines/supply_converter.lua
@@ -1,232 +1,79 @@
-- The supply converter is a generic device which can convert from
-- LV to MV and back, and HV to MV and back.
-- The machine will not convert from HV directly to LV.
-- The machine is configured by the wiring below and above it.
-- It is prepared for an upgrade slot if this is to be implemented later.
--
-- The conversion factor is a constant and the conversion is a lossy operation.
--
-- It works like this:
--   The top side is setup as the "RE" side, the bottom as the "PR" side.
--   Once the RE side is powered it will deliver power to the other side.
--   The top side is setup as the receiver side, the bottom as the producer side.
--   Once the receiver side is powered it will deliver power to the other side.
--   Unused power is wasted just like any other producer!
--
minetest.register_node(
   "technic:supply_converter", {
      description = "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},
      sounds = default.node_sound_wood_defaults(),
      drawtype = "nodebox",
      paramtype = "light",
      is_ground_content = true,
      node_box = {
     type = "fixed",
     fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
      },
      selection_box = {
     type = "fixed",
     fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
      },
      on_construct = function(pos)
            local meta = minetest.env:get_meta(pos)
            meta:set_float("technic_hv_power_machine", 1)
            meta:set_float("technic_mv_power_machine", 1)
            meta:set_float("technic_power_machine", 1)
            meta:set_string("infotext", "Supply Converter")
              meta:set_float("active", false)
               end,
   })
minetest.register_node("technic:supply_converter", {
    description = "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},
    sounds = default.node_sound_wood_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
    node_box = {
        type = "fixed",
        fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
    },
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Supply Converter")
        meta:set_float("active", false)
    end,
})
minetest.register_craft({
    output = 'technic:supply_converter 1',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot','technic:stainless_steel_ingot'},
        {'technic:mv_transformer',        'technic:mv_cable',             'technic:lv_transformer'},
        {'technic:mv_cable',              'technic:rubber',               'technic:lv_cable'},
        {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
        {'technic:mv_transformer',        'technic:mv_cable0',             '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)
         -- Conversion factors (a picture of V*A - loss) Asymmetric.
         local lv_mv_factor  = 5 -- division (higher is less efficient)
         local mv_lv_factor  = 4 -- multiplication (higher is more efficient)
         local mv_hv_factor  = 5 -- division
         local hv_mv_factor  = 4 -- multiplication
         local max_lv_demand = 2000 -- The increment size power supply tier. Determines how many are needed
         local max_mv_demand = 2000 -- -""-
         local max_hv_demand = 2000 -- -""-
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  = "Supply Converter"
        local meta          = minetest.get_meta(pos)
         -- Machine information
         local machine_name  = "Supply Converter"
         local meta          = minetest.env:get_meta(pos)
         local upgrade       = "" -- Replace with expansion slot later??
         -- High voltage on top, low at bottom regardless of converter direction
         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 meta_up       = minetest.env:get_meta(pos_up)
         local meta_down     = minetest.env:get_meta(pos_down)
         local convert_MV_LV = 0
         local convert_LV_MV = 0
         local convert_MV_HV = 0
         local convert_HV_MV = 0
         -- check cabling
         if meta_up:get_float("mv_cablelike") == 1 and meta_down:get_float("cablelike") == 1 then
            convert_MV_LV = 1
            upgrade = "MV-LV step down"
         end
         if meta_up:get_float("cablelike") == 1 and meta_down:get_float("mv_cablelike") == 1 then
            convert_LV_MV = 1
            upgrade = "LV-MV step up"
         end
         if meta_up:get_float("mv_cablelike") == 1 and meta_down:get_float("hv_cablelike") == 1 then
            convert_MV_HV = 1
            upgrade = "MV-HV step up"
         end
         if meta_up:get_float("hv_cablelike") == 1 and meta_down:get_float("mv_cablelike") == 1 then
            convert_HV_MV = 1
            upgrade = "HV-MV step down"
         end
         --print("Cabling:"..convert_MV_LV.."|"..convert_LV_MV.."|"..convert_HV_MV.."|"..convert_MV_HV)
        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
         if convert_MV_LV == 0 and convert_LV_MV == 0 and convert_HV_MV == 0 and convert_MV_HV == 0 then
            meta:set_string("infotext", machine_name.." has bad cabling")
            meta:set_int("LV_EU_demand", 0)
            meta:set_int("LV_EU_supply", 0)
            meta:set_int("LV_EU_input",  0)
            meta:set_int("MV_EU_demand", 0)
            meta:set_int("MV_EU_supply", 0)
            meta:set_int("MV_EU_input",  0)
            meta:set_int("HV_EU_demand", 0)
            meta:set_int("HV_EU_supply", 0)
            meta:set_int("HV_EU_input",  0)
            return
         end
        local from = technic.get_cable_tier(name_up)
        local to   = technic.get_cable_tier(name_down)
         -- The node is programmed with an upgrade slot
         -- containing a MV-LV step down, LV-MV step up, HV-MV step down or MV-HV step up unit
        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", machine_name.." has bad cabling")
            return
        end
         if upgrade == "" then
            meta:set_string("infotext", machine_name.." has an empty converter slot");
            technic.unregister_LV_machine("technic:supply_converter")
            technic.unregister_MV_machine("technic:supply_converter")
            technic.unregister_HV_machine("technic:supply_converter")
            meta:set_int("LV_EU_demand", 0)
            meta:set_int("LV_EU_supply", 0)
            meta:set_int("LV_EU_input",  0)
            meta:set_int("MV_EU_demand", 0)
            meta:set_int("MV_EU_supply", 0)
            meta:set_int("MV_EU_input",  0)
            meta:set_int("HV_EU_demand", 0)
            meta:set_int("HV_EU_supply", 0)
            meta:set_int("HV_EU_input",  0)
            return
         end
         -- State machine
         if upgrade == "MV-LV step down" and convert_MV_LV then
            -- Register machine type
            technic.register_LV_machine("technic:supply_converter","PR")
            technic.register_MV_machine("technic:supply_converter","RE")
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, "MV")
            local eu_input  = meta:get_int("MV_EU_input")
            if eu_input == 0 then
               -- Unpowered - go idle
               --hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Unpowered")
               meta:set_int("LV_EU_supply", 0)
               meta:set_int("MV_EU_supply", 0)
               meta:set_int("LV_EU_demand", 0)
               meta:set_int("MV_EU_demand", max_mv_demand)
            else
               -- MV side has got power to spare
               meta:set_string("infotext", machine_name.." is active (MV:"..max_mv_demand.."->LV:"..eu_input*mv_lv_factor..")");
               meta:set_int("LV_EU_supply", eu_input*mv_lv_factor)
            end
            ---------------------------------------------------
         elseif upgrade == "LV-MV step up"   and convert_LV_MV then
            -- Register machine type
            technic.register_LV_machine("technic:supply_converter","RE")
            technic.register_MV_machine("technic:supply_converter","PR")
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, "LV")
            local eu_input  = meta:get_int("LV_EU_input")
            if eu_input == 0 then
               -- Unpowered - go idle
               --hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Unpowered")
               meta:set_int("LV_EU_supply", 0)
               meta:set_int("MV_EU_supply", 0)
               meta:set_int("LV_EU_demand", max_lv_demand)
               meta:set_int("MV_EU_demand", 0)
            else
               -- LV side has got power to spare
               meta:set_string("infotext", machine_name.." is active (LV:"..max_lv_demand.."->MV:"..eu_input/lv_mv_factor..")");
               meta:set_int("MV_EU_supply", eu_input/lv_mv_factor)
            end
            ---------------------------------------------------
         elseif upgrade == "HV-MV step down" and convert_HV_MV then
            -- Register machine type
            technic.register_MV_machine("technic:supply_converter","PR")
            technic.register_HV_machine("technic:supply_converter","RE")
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, "HV")
            local eu_input  = meta:get_int("HV_EU_input")
            if eu_input == 0 then
               -- Unpowered - go idle
               --hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Unpowered")
               meta:set_int("MV_EU_supply", 0)
               meta:set_int("HV_EU_supply", 0)
               meta:set_int("MV_EU_demand", 0)
               meta:set_int("HV_EU_demand", max_hv_demand)
            else
               -- HV side has got power to spare
               meta:set_string("infotext", machine_name.." is active (HV:"..max_hv_demand.."->MV:"..eu_input*hv_mv_factor..")");
               meta:set_int("MV_EU_supply", eu_input*hv_mv_factor)
            end
            ---------------------------------------------------
         elseif upgrade == "MV-HV step up"   and convert_MV_HV then
            -- Register machine type
            technic.register_MV_machine("technic:supply_converter","RE")
            technic.register_HV_machine("technic:supply_converter","PR")
            -- Power off automatically if no longer connected to a switching station
            technic.switching_station_timeout_count(pos, "MV")
            local eu_input  = meta:get_int("MV_EU_input")
            if eu_input == 0 then
               -- Unpowered - go idle
               --hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Unpowered")
               meta:set_int("MV_EU_supply", 0)
               meta:set_int("HV_EU_supply", 0)
               meta:set_int("MV_EU_demand", max_mv_demand)
               meta:set_int("HV_EU_demand", 0)
            else
               -- MV side has got power to spare
               meta:set_string("infotext", machine_name.." is active (MV:"..max_mv_demand.."->HV:"..eu_input/mv_hv_factor..")");
               meta:set_int("HV_EU_supply", eu_input/mv_hv_factor)
            end
            ---------------------------------------------------
         end
    end,
})
for tier, machines in pairs(technic.machines) do
    technic.register_machine(tier, "technic:supply_converter", technic.battery)
end
technic/machines/switching_station.lua
@@ -30,323 +30,256 @@
technic.DBG = 1
local dprint = technic.dprint
minetest.register_craft(
   {
      output = 'technic:switching_station 1',
      recipe = {
     {'technic:lv_transformer', 'technic:mv_transformer', 'technic:hv_transformer'},
     {'technic:lv_transformer', 'technic:mv_transformer', 'technic:hv_transformer'},
     {'technic:lv_cable',       'technic:mv_cable',       'technic:hv_cable'},
      }
   })
minetest.register_craft({
    output = "technic:switching_station",
    recipe = {
        {"default:steel_ingot",  "technic:lv_transformer", "default:steel_ingot"},
        {"default:copper_ingot", "technic:lv_cable0",      "default:copper_ingot"},
        {"default:steel_ingot",  "technic:lv_cable0",      "default:steel_ingot"}
    }
})
minetest.register_node(
   "technic:switching_station",
   {description = "Switching Station",
    tiles  = {"technic_water_mill_top_active.png", "technic_water_mill_top_active.png", "technic_water_mill_top_active.png",
          "technic_water_mill_top_active.png", "technic_water_mill_top_active.png", "technic_water_mill_top_active.png"},
    groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
    sounds = default.node_sound_wood_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,
    node_box = {
     type = "fixed",
       fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
    },
    selection_box = {
       type = "fixed",
       fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
    },
    on_construct = function(pos)
              local meta = minetest.env:get_meta(pos)
              meta:set_string("infotext", "Switching Station")
--            minetest.chat_send_player(puncher:get_player_name(), "Switching station constructed. Punch the station to shut down the network.");
--            meta:set_int("active", 1)
           end,
--      on_punch = function(pos, node, puncher)
--            local meta   = minetest.env:get_meta(pos)
--            local active = meta:get_int("active")
--            if active == 1 then
--               meta:set_int("active", 0)
--               minetest.chat_send_player(puncher:get_player_name(), "Electrical network shut down. Punch again to turn it on.");
--            else
--               meta:set_int("active", 1)
--               minetest.chat_send_player(puncher:get_player_name(), "Electrical network turned on. Punch again to shut it down.");
--            end
--         end
 })
minetest.register_node("technic:switching_station",{
    description = "Switching Station",
    tiles  = {"technic_water_mill_top_active.png", "technic_water_mill_top_active.png",
                  "technic_water_mill_top_active.png", "technic_water_mill_top_active.png",
              "technic_water_mill_top_active.png", "technic_water_mill_top_active.png"},
    groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
    sounds = default.node_sound_wood_defaults(),
    drawtype = "nodebox",
    paramtype = "light",
    node_box = {
        type = "fixed",
        fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
    },
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        meta:set_string("infotext", "Switching Station")
    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
technic.switching_station_timeout_count = function(pos, machine_tier)
                         local meta = minetest.env:get_meta(pos)
                         timeout =  meta:get_int(machine_tier.."_EU_timeout")
                         --print("Counting timeout "..timeout)
                         if timeout == 0 then
                        --print("OFF")
                        meta:set_int(machine_tier.."_EU_input", 0)
                         else
                        --print("ON")
                        meta:set_int(machine_tier.."_EU_timeout", timeout-1)
                         end
                      end
function technic.switching_station_timeout_count(pos, tier)
    local meta = minetest.get_meta(pos)
    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
--------------------------------------------------
-- Add a wire node to the LV/MV/HV network
local add_new_cable_node = function(nodes,pos)
                  local i = 1
                  repeat
                 if nodes[i]==nil then break end
                 if pos.x==nodes[i].x and pos.y==nodes[i].y and pos.z==nodes[i].z then return false end
                 i=i+1
                  until false
                  nodes[i] = {x=pos.x, y=pos.y, z=pos.z, visited=1} -- copy position
                  return true
               end
local add_new_cable_node = function(nodes, pos)
    -- Ignore if the node has already been added
    for i = 1, #nodes do
        if pos.x == nodes[i].x and
           pos.y == nodes[i].y and
           pos.z == nodes[i].z then
            return false
        end
    end
    table.insert(nodes, {x=pos.x, y=pos.y, z=pos.z, visited=1})
    return true
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,cablename)
               local meta = minetest.env:get_meta(pos)
               local name = minetest.env:get_node(pos).name
               if meta:get_float(cablename)==1 then
                  add_new_cable_node(all_nodes,pos)
               elseif machines[name] then
                  --dprint(name.." is a "..machines[name])
                  if     machines[name] == "PR" then
                 add_new_cable_node(PR_nodes,pos)
                  elseif machines[name] == "RE" then
                 add_new_cable_node(RE_nodes,pos)
                  elseif machines[name] == "BA" then
                 add_new_cable_node(BA_nodes,pos)
                  end
                  if cablename == "cablelike" then
                 meta:set_int("LV_EU_timeout", 2) -- Touch node
                  elseif cablename == "mv_cablelike" then
                 meta:set_int("MV_EU_timeout", 2) -- Touch node
                  elseif cablename == "hv_cablelike" then
                 meta:set_int("HV_EU_timeout", 2) -- Touch node
                  end
               end
            end
local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, all_nodes, pos, machines, tier)
    local meta = minetest.get_meta(pos)
    local name = minetest.get_node(pos).name
    if technic.is_tier_cable(name, tier) then
        add_new_cable_node(all_nodes, pos)
    elseif machines[name] then
        --dprint(name.." is a "..machines[name])
        if     machines[name] == technic.producer then
            add_new_cable_node(PR_nodes, pos)
        elseif machines[name] == technic.receiver then
            add_new_cable_node(RE_nodes, pos)
        elseif machines[name] == technic.battery then
            add_new_cable_node(BA_nodes, pos)
        end
        meta:set_int(tier.."_EU_timeout", 2) -- Touch node
    end
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, cablename)
                local pos = {x=all_nodes[i].x, y=all_nodes[i].y, z=all_nodes[i].z} -- copy position
                pos.x=pos.x+1
                check_node_subp(PR_nodes,RE_nodes,BA_nodes,all_nodes,pos, machines, cablename)
                pos.x=pos.x-2
                check_node_subp(PR_nodes,RE_nodes,BA_nodes,all_nodes,pos, machines, cablename)
                pos.x=pos.x+1
                pos.y=pos.y+1
                check_node_subp(PR_nodes,RE_nodes,BA_nodes,all_nodes,pos, machines, cablename)
                pos.y=pos.y-2
                check_node_subp(PR_nodes,RE_nodes,BA_nodes,all_nodes,pos, machines, cablename)
                pos.y=pos.y+1
                pos.z=pos.z+1
                check_node_subp(PR_nodes,RE_nodes,BA_nodes,all_nodes,pos, machines, cablename)
                pos.z=pos.z-2
                check_node_subp(PR_nodes,RE_nodes,BA_nodes,all_nodes,pos, machines, cablename)
                pos.z=pos.z+1
              end
local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, all_nodes, i, machines, tier)
    local pos = all_nodes[i]
    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+1, z=pos.z},
        {x=pos.x,   y=pos.y-1, z=pos.z},
        {x=pos.x,   y=pos.y,   z=pos.z+1},
        {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)
    end
end
----------------------------------------------
-- The action code for the switching station
----------------------------------------------
minetest.register_abm(
    {nodenames = {"technic:switching_station"},
-----------------------------------------------
-- The action code for the switching station --
-----------------------------------------------
minetest.register_abm({
    nodenames = {"technic:switching_station"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
            local meta             = minetest.env:get_meta(pos)
            local meta1            = nil
            local pos1             = {}
            local PR_EU            = 0 -- EUs from PR nodes
            local BA_PR_EU         = 0 -- EUs from BA nodes (discharching)
            local BA_RE_EU         = 0 -- EUs to BA nodes (charging)
            local RE_EU            = 0 -- EUs to RE nodes
        local meta             = minetest.get_meta(pos)
        local meta1            = nil
        local pos1             = {}
        local PR_EU            = 0 -- EUs from PR nodes
        local BA_PR_EU         = 0 -- EUs from BA nodes (discharching)
        local BA_RE_EU         = 0 -- EUs to BA nodes (charging)
        local RE_EU            = 0 -- EUs to RE nodes
            local network   = ""
            local all_nodes = {}
            local PR_nodes  = {}
            local BA_nodes  = {}
            local RE_nodes  = {}
        local tier      = ""
        local all_nodes = {}
        local PR_nodes  = {}
        local BA_nodes  = {}
        local RE_nodes  = {}
--            -- Possible to turn off the entire network
--            if meta:get_int("active") == 0 then
--               for _,pos1 in pairs(RE_nodes) do
--              meta1  = minetest.env:get_meta(pos1)
--              meta1:set_int("EU_input", 0)
--               end
--               for _,pos1 in pairs(BA_nodes) do
--              meta1  = minetest.env:get_meta(pos1)
--              meta1:set_int("EU_input", 0)
--               end
--               return
--            end
        -- Which kind of network are we on:
        pos1 = {x=pos.x, y=pos.y-1, z=pos.z}
        all_nodes[1] = pos1
            -- Which kind of network are we on:
            pos1 = {x=pos.x, y=pos.y-1, z=pos.z}
            all_nodes[1] = pos1
        local name = minetest.get_node(pos1).name
        local tier = technic.get_cable_tier(name)
        if tier then
            local i = 1
            repeat
                traverse_network(PR_nodes, RE_nodes, BA_nodes, all_nodes,
                        i, technic.machines[tier], tier)
                i = i + 1
            until all_nodes[i] == nil
        else
            --dprint("Not connected to a network")
            meta:set_string("infotext", "Switching Station - no network")
            return
        end
        --dprint("nodes="..table.getn(all_nodes)
        --        .." PR="..table.getn(PR_nodes)
        --        .." BA="..table.getn(BA_nodes)
        --        .." RE="..table.getn(RE_nodes))
            meta1  = minetest.env:get_meta(pos1)
            if meta1:get_float("cablelike") ==1 then
               -- LV type
               --dprint("LV type")
               network = "LV"
               local table_index = 1
               repeat
              traverse_network(PR_nodes,RE_nodes,BA_nodes,all_nodes,table_index, technic.LV_machines, "cablelike")
              table_index = table_index + 1
              if all_nodes[table_index] == nil then break end
               until false
            elseif meta1:get_float("mv_cablelike") ==1 then
               -- MV type
               --dprint("MV type")
               network = "MV"
               local table_index = 1
               repeat
              traverse_network(PR_nodes,RE_nodes,BA_nodes,all_nodes,table_index, technic.MV_machines, "mv_cablelike")
              table_index = table_index + 1
              if all_nodes[table_index] == nil then break end
               until false
            elseif meta1:get_float("hv_cablelike") ==1 then
               -- HV type
               --dprint("HV type")
               network = "HV"
               local table_index = 1
               repeat
              traverse_network(PR_nodes,RE_nodes,BA_nodes,all_nodes,table_index, technic.HV_machines, "hv_cablelike")
              table_index = table_index + 1
              if all_nodes[table_index] == nil then break end
               until false
            else
               -- No type :-)
               --dprint("Not connected to a network")
               meta:set_string("infotext", "Switching Station - no network")
               return
            end
            --dprint("nodes="..table.getn(all_nodes).." PR="..table.getn(PR_nodes).." BA="..table.getn(BA_nodes).." RE="..table.getn(RE_nodes))
        -- Strings for the meta data
        local eu_demand_str    = tier.."_EU_demand"
        local eu_input_str     = tier.."_EU_input"
        local eu_supply_str    = tier.."_EU_supply"
            -- Strings for the meta data
            local eu_demand_str    = network.."_EU_demand"
            local eu_input_str     = network.."_EU_input"
            local eu_supply_str    = network.."_EU_supply"
            local eu_from_fuel_str = network.."_EU_from_fuel"
        -- Get all the power from the PR nodes
        local PR_eu_supply = 0 -- Total power
        for _, pos1 in pairs(PR_nodes) do
            meta1 = minetest.get_meta(pos1)
            PR_eu_supply = PR_eu_supply + meta1:get_int(eu_supply_str)
        end
        --dprint("Total PR supply:"..PR_eu_supply)
            -- Get all the power from the PR nodes
            local PR_eu_supply = 0 -- Total power
            for _,pos1 in pairs(PR_nodes) do
               meta1  = minetest.env:get_meta(pos1)
               PR_eu_supply = PR_eu_supply + meta1:get_int(eu_supply_str)
            end
            --dprint("Total PR supply:"..PR_eu_supply)
        -- Get all the demand from the RE nodes
        local RE_eu_demand = 0
        for _, pos1 in pairs(RE_nodes) do
            meta1 = minetest.get_meta(pos1)
            RE_eu_demand = RE_eu_demand + meta1:get_int(eu_demand_str)
        end
        --dprint("Total RE demand:"..RE_eu_demand)
            -- Get all the demand from the RE nodes
            local RE_eu_demand = 0
            for _,pos1 in pairs(RE_nodes) do
               meta1  = minetest.env:get_meta(pos1)
               RE_eu_demand = RE_eu_demand + meta1:get_int(eu_demand_str)
            end
            --dprint("Total RE demand:"..RE_eu_demand)
        -- Get all the power from the BA nodes
        local BA_eu_supply = 0
        for _, pos1 in pairs(BA_nodes) do
            meta1 = minetest.get_meta(pos1)
            BA_eu_supply = BA_eu_supply + meta1:get_int(eu_supply_str)
        end
        --dprint("Total BA supply:"..BA_eu_supply)
            -- Get all the power from the BA nodes
            local BA_eu_supply = 0
            for _,pos1 in pairs(BA_nodes) do
               meta1  = minetest.env:get_meta(pos1)
               BA_eu_supply = BA_eu_supply + meta1:get_int(eu_supply_str)
            end
            --dprint("Total BA supply:"..BA_eu_supply)
        -- Get all the demand from the BA nodes
        local BA_eu_demand = 0
        for _, pos1 in pairs(BA_nodes) do
            meta1 = minetest.get_meta(pos1)
            BA_eu_demand = BA_eu_demand + meta1:get_int(eu_demand_str)
        end
        --dprint("Total BA demand:"..BA_eu_demand)
            -- Get all the demand from the BA nodes
            local BA_eu_demand = 0
            for _,pos1 in pairs(BA_nodes) do
               meta1  = minetest.env:get_meta(pos1)
               BA_eu_demand = BA_eu_demand + meta1:get_int(eu_demand_str)
            end
            --dprint("Total BA demand:"..BA_eu_demand)
        meta:set_string("infotext",
                "Switching Station. Supply: "..PR_eu_supply
                .." Demand: "..RE_eu_demand)
            meta:set_string("infotext", "Switching Station. PR("..(PR_eu_supply+BA_eu_supply)..") RE("..(RE_eu_demand+BA_eu_demand)..")")
        -- If the PR supply is enough for the RE demand supply them all
        if PR_eu_supply >= RE_eu_demand then
        --dprint("PR_eu_supply"..PR_eu_supply.." >= RE_eu_demand"..RE_eu_demand)
            for _, pos1 in pairs(RE_nodes) do
                meta1 = minetest.get_meta(pos1)
                local eu_demand = meta1:get_int(eu_demand_str)
                meta1:set_int(eu_input_str, eu_demand)
            end
            -- We have a surplus, so distribute the rest equally to the BA nodes
            -- Let's calculate the factor of the demand
            PR_eu_supply = PR_eu_supply - RE_eu_demand
            local charge_factor = 0 -- Assume all batteries fully charged
            if BA_eu_demand > 0 then
                charge_factor = PR_eu_supply / BA_eu_demand
            end
            for n, pos1 in pairs(BA_nodes) do
                meta1 = minetest.get_meta(pos1)
                local eu_demand = meta1:get_int(eu_demand_str)
                meta1:set_int(eu_input_str, math.floor(eu_demand * charge_factor))
                --dprint("Charging battery:"..math.floor(eu_demand*charge_factor))
            end
            return
        end
            -- If the PR supply is enough for the RE demand supply them all
            if PR_eu_supply >= RE_eu_demand then
               --dprint("PR_eu_supply"..PR_eu_supply.." >= RE_eu_demand"..RE_eu_demand)
               for _,pos1 in pairs(RE_nodes) do
              meta1  = minetest.env:get_meta(pos1)
              local eu_demand = meta1:get_int(eu_demand_str)
              meta1:set_int(eu_input_str, eu_demand)
               end
               -- We have a surplus, so distribute the rest equally to the BA nodes
               -- Let's calculate the factor of the demand
               PR_eu_supply = PR_eu_supply - RE_eu_demand
               local charge_factor = 0 -- Assume all batteries fully charged
               if BA_eu_demand > 0 then
              charge_factor = PR_eu_supply / BA_eu_demand
               end
               for n,pos1 in pairs(BA_nodes) do
              meta1  = minetest.env:get_meta(pos1)
              local eu_demand = meta1:get_int(eu_demand_str)
              meta1:set_int(eu_input_str, math.floor(eu_demand*charge_factor))
              --dprint("Charging battery:"..math.floor(eu_demand*charge_factor))
               end
               -- If still a surplus we can start giving back to the fuel burning generators
               -- Only full EU packages are given back. The rest is wasted.
               if BA_eu_demand == 0 then
              for _,pos1 in pairs(PR_nodes) do
                 meta1  = minetest.env:get_meta(pos1)
                 if meta1:get_int(eu_from_fuel_str) == 1 then
        -- If the PR supply is not enough for the RE demand we will discharge the batteries too
        if PR_eu_supply + BA_eu_supply >= RE_eu_demand then
            --dprint("PR_eu_supply "..PR_eu_supply.."+BA_eu_supply "..BA_eu_supply.." >= RE_eu_demand"..RE_eu_demand)
            for _, pos1 in pairs(RE_nodes) do
                meta1  = minetest.get_meta(pos1)
                local eu_demand = meta1:get_int(eu_demand_str)
                meta1:set_int(eu_input_str, eu_demand)
            end
            -- We have a deficit, so distribute to the BA nodes
            -- Let's calculate the factor of the supply
            local charge_factor = 0 -- Assume all batteries depleted
            if BA_eu_supply > 0 then
                charge_factor = (PR_eu_supply - RE_eu_demand) / BA_eu_supply
            end
            for n,pos1 in pairs(BA_nodes) do
                meta1 = minetest.get_meta(pos1)
                local eu_supply = meta1:get_int(eu_supply_str)
                if PR_eu_supply < eu_supply then
                   break
                else
                   -- Set the supply to 0 if we did not require it.
                   meta1:set_int(eu_supply_str, 0)
                   PR_eu_supply = PR_eu_supply - eu_supply
                end
                 end
              end
               end
               return
            end
                meta1:set_int(eu_input_str, math.floor(eu_supply * charge_factor))
                --dprint("Discharging battery:"..math.floor(eu_supply*charge_factor))
            end
            return
        end
            -- If the PR supply is not enough for the RE demand we will discharge the batteries too
            if PR_eu_supply+BA_eu_supply >= RE_eu_demand then
               --dprint("PR_eu_supply "..PR_eu_supply.."+BA_eu_supply "..BA_eu_supply.." >= RE_eu_demand"..RE_eu_demand)
               for _,pos1 in pairs(RE_nodes) do
              meta1  = minetest.env:get_meta(pos1)
              local eu_demand = meta1:get_int(eu_demand_str)
              meta1:set_int(eu_input_str, eu_demand)
               end
               -- We have a deficit, so distribute to the BA nodes
               -- Let's calculate the factor of the supply
               local charge_factor = 0 -- Assume all batteries depleted
               if BA_eu_supply > 0 then
              charge_factor = (PR_eu_supply - RE_eu_demand) / BA_eu_supply
               end
               for n,pos1 in pairs(BA_nodes) do
              meta1  = minetest.env:get_meta(pos1)
              local eu_supply = meta1:get_int(eu_supply_str)
              meta1:set_int(eu_input_str, math.floor(eu_supply*charge_factor))
              --dprint("Discharging battery:"..math.floor(eu_supply*charge_factor))
               end
               return
            end
            -- If the PR+BA supply is not enough for the RE demand: Shut everything down!
            -- Note: another behaviour could also be imagined: provide the average power for all and let the node decide what happens.
            -- This is much simpler though: Not enough power for all==no power for all
            --print("NO POWER")
            for _,pos1 in pairs(RE_nodes) do
               meta1  = minetest.env:get_meta(pos1)
               meta1:set_int(eu_input_str, 0)
            end
        -- If the PR+BA supply is not enough for the RE demand: Power only the batteries
        local charge_factor = 0 -- Assume all batteries fully charged
        if BA_eu_demand > 0 then
            charge_factor = PR_eu_supply / BA_eu_demand
        end
        for n, pos1 in pairs(BA_nodes) do
            meta1 = minetest.get_meta(pos1)
            local eu_demand = meta1:get_int(eu_demand_str)
            meta1:set_int(eu_input_str, math.floor(eu_demand * charge_factor))
        end
        for n, pos1 in pairs(RE_nodes) do
            meta1 = minetest.get_meta(pos1)
            meta1:set_int(eu_input_str, 0)
        end
    end,
})
for tier, machines in pairs(technic.machines) do
    -- SPECIAL will not be traversed
    technic.register_machine(tier, "technic:switching_station", "SPECIAL")
end
technic/register.lua
New file
@@ -0,0 +1,48 @@
-- This file includes the functions and data structures for registering machines and tools for LV, MV, HV types.
-- We use the technic namespace for these functions and data to avoid eventual conflict.
technic.receiver = "RE"
technic.producer = "PR"
technic.battery  = "BA"
technic.machines    = {}
technic.power_tools = {}
function technic.register_tier(tier, description)
    technic.machines[tier]    = {}
    technic.cables[tier]      = {}
end
function technic.register_machine(tier, nodename, machine_type)
    if not technic.machines[tier] then
        return
    end
    technic.machines[tier][nodename] = machine_type
end
function technic.register_power_tool(craftitem, max_charge)
    technic.power_tools[craftitem] = max_charge
end
-- Utility functions. Not sure exactly what they do.. water.lua uses the two first.
function technic.get_RE_item_load(load1, max_load)
    if load1 == 0 then load1 = 65535 end
    local temp = 65536 - load1
    temp = temp / 65535 * max_load
    return math.floor(temp + 0.5)
end
function technic.set_RE_item_load(load1, max_load)
    if load1 == 0 then return 65535 end
    local temp = load1 / max_load * 65535
    temp = 65536 - temp
    return math.floor(temp)
end
-- Wear down a tool depending on the remaining charge.
function technic.set_RE_wear(item_stack, item_load, max_load)
    local temp = 65536 - math.floor(item_load / max_load * 65535)
    item_stack.wear = tostring(temp)
    return item_stack
end
technic/register_machine_and_tool.lua
File was deleted
technic/rubber.lua
File was deleted
technic/textures/technic_hv_battery_box_side.png

technic/textures/technic_lv_alloy_furnace_bottom.png
technic/textures/technic_lv_alloy_furnace_front.png

technic/textures/technic_lv_alloy_furnace_front_active.png

technic/textures/technic_lv_alloy_furnace_side.png

technic/textures/technic_lv_alloy_furnace_top.png

technic/textures/technic_lv_battery_box_bottom.png

technic/textures/technic_lv_battery_box_side.png

technic/textures/technic_lv_battery_box_top.png

technic/textures/technic_lv_electric_furnace_bottom.png

technic/textures/technic_lv_electric_furnace_front.png

technic/textures/technic_lv_electric_furnace_front_active.png

technic/textures/technic_lv_electric_furnace_side.png

technic/textures/technic_lv_electric_furnace_top.png

technic/textures/technic_mv_battery_box_side.png

technic/textures/technic_power_meter0.png
technic/textures/technic_uranium_fuel.png
technic/tools/chainsaw.lua
@@ -3,7 +3,7 @@
local chainsaw_charge_per_node = 12    -- 12    - Gives 2500 nodes on a single charge (about 50 complete normal trees)
local chainsaw_leaves          = true  -- true  - Cut down entire trees, leaves and all
technic.register_power_tool ("technic:chainsaw",chainsaw_max_charge)
technic.register_power_tool("technic:chainsaw", chainsaw_max_charge)
minetest.register_tool("technic:chainsaw", {
        description = "Chainsaw",
@@ -50,6 +50,16 @@
        timber_nodenames["default:leaves"] = true
end
-- technic_worldgen defines rubber trees if moretrees isn't installed
if minetest.get_modpath("technic_worldgen") or
   minetest.get_modpath("moretrees") then
    timber_nodenames["moretrees:rubber_tree_trunk_empty"] = true
    timber_nodenames["moretrees:rubber_tree_trunk"]       = true
    if chainsaw_leaves then
                timber_nodenames["moretrees:rubber_tree_leaves"] = true
    end
end
-- Support moretrees if it is there
if( minetest.get_modpath("moretrees") ~= nil ) then
        timber_nodenames["moretrees:apple_tree_trunk"]                 = true
@@ -66,9 +76,7 @@
        timber_nodenames["moretrees:palm_trunk_sideways"]              = true
        timber_nodenames["moretrees:pine_trunk"]                       = true
        timber_nodenames["moretrees:pine_trunk_sideways"]              = true
        timber_nodenames["moretrees:rubber_tree_trunk"]                = true
        timber_nodenames["moretrees:rubber_tree_trunk_sideways"]       = true
        timber_nodenames["moretrees:rubber_tree_trunk_empty"]          = true
        timber_nodenames["moretrees:rubber_tree_trunk_sideways_empty"] = true
        timber_nodenames["moretrees:sequoia_trunk"]                    = true
        timber_nodenames["moretrees:sequoia_trunk_sideways"]           = true
@@ -79,7 +87,7 @@
        timber_nodenames["moretrees:jungletree_trunk"]                 = true
        timber_nodenames["moretrees:jungletree_trunk_sideways"]        = true
        if chainsaw_leaves == true then
        if chainsaw_leaves then
                timber_nodenames["moretrees:apple_tree_leaves"]        = true
                timber_nodenames["moretrees:oak_leaves"]               = true
                timber_nodenames["moretrees:sequoia_leaves"]           = true
@@ -90,7 +98,6 @@
                timber_nodenames["moretrees:spruce_leaves"]            = true
                timber_nodenames["moretrees:pine_leaves"]              = true
                timber_nodenames["moretrees:willow_leaves"]            = true
                timber_nodenames["moretrees:rubber_tree_leaves"]       = true
                timber_nodenames["moretrees:jungletree_leaves_green"]  = true
                timber_nodenames["moretrees:jungletree_leaves_yellow"] = true
                timber_nodenames["moretrees:jungletree_leaves_red"]    = true
technic/tools/flashlight.lua
@@ -1,7 +1,7 @@
-- original code comes from walkin_light mod by Echo http://minetest.net/forum/viewtopic.php?id=2621
local flashlight_max_charge=30000
technic.register_power_tool ("technic:flashlight",flashlight_max_charge)
local flashlight_max_charge = 30000
technic.register_power_tool("technic:flashlight", flashlight_max_charge)
      
minetest.register_tool("technic:flashlight", {
    description = "Flashlight",
@@ -14,9 +14,9 @@
minetest.register_craft({
output = "technic:flashlight",
recipe = {
    {"technic:rubber","glass","technic:rubber"},
    {"technic:stainless_steel_ingot","technic:battery","technic:stainless_steel_ingot"},
    {"","technic:battery",""}
        {"technic:rubber",                "glass",           "technic:rubber"},
        {"technic:stainless_steel_ingot", "technic:battery", "technic:stainless_steel_ingot"},
        {"",                              "technic:battery", ""}
    }
})
@@ -33,87 +33,80 @@
    table.insert(players, player_name)
    local pos = player:getpos()
    local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)}
    player_positions[player_name] = {}
    player_positions[player_name]["x"] = rounded_pos.x;
    player_positions[player_name]["y"] = rounded_pos.y;
    player_positions[player_name]["z"] = rounded_pos.z;
    player_positions[player_name] = rounded_pos
end)
minetest.register_on_leaveplayer(function(player)
    local player_name = player:get_player_name()
    for i,v in ipairs(players) do
    for i, v in ipairs(players) do
        if v == player_name then 
            table.remove(players, i)
            last_wielded[player_name] = nil
            -- Neuberechnung des Lichts erzwingen
            local pos = player:getpos()
            local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)}
            minetest.env:add_node(rounded_pos,{type="node",name="technic:light_off"})
            minetest.env:add_node(rounded_pos,{type="node",name="air"})
            player_positions[player_name]["x"] = nil
            player_positions[player_name]["y"] = nil
            player_positions[player_name]["z"] = nil
            player_positions[player_name]["m"] = nil
            player_positions[player_name] = nil
            local nodename = minetest.get_node(rounded_pos).name
            if nodename == "technic:light_off" or nodename == "technic:light" then
                minetest.remove_node(rounded_pos)
            end
            if player_positions[player_name] then
                player_positions[player_name] = nil
            end
        end
    end
end)
minetest.register_globalstep(function(dtime)
    for i,player_name in ipairs(players) do
        local player = minetest.env:get_player_by_name(player_name)
    for i, player_name in ipairs(players) do
        local player = minetest.get_player_by_name(player_name)
        if player then
        flashlight_weared=check_for_flashlight(player)
        local pos = player:getpos()
        local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)}
        local old_pos = {x=player_positions[player_name]["x"], y=player_positions[player_name]["y"], z=player_positions[player_name]["z"]}
        if last_wielded[player_name] and not flashlight_weared then --remove light, flashlight weared out or was removed from hotbar
            local node=minetest.env:get_node_or_nil(old_pos)
            if node then
            if node.name=="technic:light" then
                  minetest.env:add_node(old_pos,{type="node",name="technic:light_off"})
                minetest.env:add_node(old_pos,{type="node",name="air"})
              last_wielded[player_name]=false
              end
            end
            end
            flashlight_weared = check_for_flashlight(player)
            local pos = player:getpos()
            local rounded_pos = {x=round(pos.x), y=round(pos.y)+1, z=round(pos.z)}
            local old_pos = vector.new(player_positions[player_name])
            if last_wielded[player_name] and not flashlight_weared then --remove light, flashlight weared out or was removed from hotbar
                local node = minetest.get_node_or_nil(old_pos)
                if node and node.name == "technic:light" then
                    minetest.add_node(old_pos,{name="air"})
                    last_wielded[player_name] = false
                end
        player_moved=not(old_pos.x==rounded_pos.x and old_pos.y==rounded_pos.y and old_pos.z==rounded_pos.z)
        if player_moved and last_wielded[player_name] and flashlight_weared  then
            local node=minetest.env:get_node_or_nil(rounded_pos)
            if node then
            if node.name=="air" then
                  minetest.env:add_node(rounded_pos,{type="node",name="technic:light"})
              end
                player_moved = not(old_pos.x == rounded_pos.x and old_pos.y == rounded_pos.y and old_pos.z == rounded_pos.z)
                if player_moved and last_wielded[player_name] and flashlight_weared  then
                    local node=minetest.env:get_node_or_nil(rounded_pos)
                    if node then
                        if node.name=="air" then
                            minetest.env:add_node(rounded_pos,{type="node",name="technic:light"})
                        end
                    end
                    local node=minetest.env:get_node_or_nil(old_pos)
                    if node then
                        if node.name=="technic:light" then
                            minetest.env:add_node(old_pos,{type="node",name="technic:light_off"})
                            minetest.env:add_node(old_pos,{type="node",name="air"})
                        end
                    end
                    player_positions[player_name]["x"] = rounded_pos.x
                    player_positions[player_name]["y"] = rounded_pos.y
                    player_positions[player_name]["z"] = rounded_pos.z
                elseif not last_wielded[player_name] and flashlight_weared then
                    local node=minetest.env:get_node_or_nil(rounded_pos)
                    if node then
                        if node.name=="air" then
                            minetest.env:add_node(rounded_pos,{type="node",name="technic:light"})
                        end
                    end
                    player_positions[player_name]["x"] = rounded_pos.x
                    player_positions[player_name]["y"] = rounded_pos.y
                    player_positions[player_name]["z"] = rounded_pos.z
                    last_wielded[player_name]=true
                end
            end
            local node=minetest.env:get_node_or_nil(old_pos)
            if node then
              if node.name=="technic:light" then
                  minetest.env:add_node(old_pos,{type="node",name="technic:light_off"})
                minetest.env:add_node(old_pos,{type="node",name="air"})
              end
            end
            player_positions[player_name]["x"] = rounded_pos.x
            player_positions[player_name]["y"] = rounded_pos.y
            player_positions[player_name]["z"] = rounded_pos.z
        else if not last_wielded[player_name] and flashlight_weared then
            local node=minetest.env:get_node_or_nil(rounded_pos)
            if node then
            if node.name=="air" then
                  minetest.env:add_node(rounded_pos,{type="node",name="technic:light"})
              end
            end
            player_positions[player_name]["x"] = rounded_pos.x
            player_positions[player_name]["y"] = rounded_pos.y
            player_positions[player_name]["z"] = rounded_pos.z
            last_wielded[player_name]=true
            end
    end
    end
        end
    end
end)
@@ -160,7 +153,7 @@
            if meta["charge"]==nil then return false end
            charge=meta["charge"]
            if charge-2>0 then
             charge =charge-2;
             charge =charge-2;
            technic.set_RE_wear(item,charge,flashlight_max_charge)
            meta["charge"]=charge
            item["metadata"]=set_item_meta(meta)
technic/tools/init.lua
@@ -1,12 +1,12 @@
local path = technic.modpath.."/tools"
if technic.config:getBool("enable_mining_drill") then
if technic.config:get_bool("enable_mining_drill") then
    dofile(path.."/mining_drill.lua")
end
if technic.config:getBool("enable_mining_laser") then
if technic.config:get_bool("enable_mining_laser") then
    dofile(path.."/mining_laser_mk1.lua")
end
if technic.config:getBool("enable_flashlight") then
if technic.config:get_bool("enable_flashlight") then
    dofile(path.."/flashlight.lua")
end
dofile(path.."/cans.lua")
technic/tools/mining_drill.lua
@@ -1,9 +1,9 @@
local mining_drill_max_charge=60000
local mining_drill_mk2_max_charge=240000
local mining_drill_mk3_max_charge=960000
local mining_drill_power_usage=200
local mining_drill_mk2_power_usage=600
local mining_drill_mk3_power_usage=1800
local mining_drill_max_charge      = 60000
local mining_drill_mk2_max_charge  = 240000
local mining_drill_mk3_max_charge  = 960000
local mining_drill_power_usage     = 200
local mining_drill_mk2_power_usage = 600
local mining_drill_mk3_power_usage = 1800
minetest.register_craft({
    output = 'technic:mining_drill',
@@ -30,14 +30,14 @@
    }
})
for i=1,4,1 do
minetest.register_craft({
    output = 'technic:mining_drill_mk3',
    recipe = {
        {'technic:diamond_drill_head' ,        'technic:diamond_drill_head' ,    'technic:diamond_drill_head' },
        {'technic:stainless_steel_ingot',    'technic:mining_drill_mk2_'..i, 'technic:stainless_steel_ingot' },
        {'',                    'technic:blue_energy_crystal',     ''},
    }
})
    minetest.register_craft({
        output = 'technic:mining_drill_mk3',
        recipe = {
            {'technic:diamond_drill_head',    'technic:diamond_drill_head',   'technic:diamond_drill_head'},
            {'technic:stainless_steel_ingot', 'technic:mining_drill_mk2_'..i, 'technic:stainless_steel_ingot'},
            {'',                              'technic:blue_energy_crystal',  ''},
        }
    })
end
function drill_dig_it (pos, player,drill_type,mode)
@@ -220,7 +220,7 @@
    drill_dig_it0 (pos,player)
end
technic.register_power_tool ("technic:mining_drill",mining_drill_max_charge)
technic.register_power_tool("technic:mining_drill", mining_drill_max_charge)
minetest.register_tool("technic:mining_drill", {
    description = "Mining Drill Mk1",
    inventory_image = "technic_mining_drill.png",
@@ -253,20 +253,21 @@
    return itemstack
    end,
})
technic.register_power_tool ("technic:mining_drill_mk2",mining_drill_mk2_max_charge)
technic.register_power_tool("technic:mining_drill_mk2", mining_drill_mk2_max_charge)
for i=1,4,1 do
technic.register_power_tool ("technic:mining_drill_mk2_"..i,mining_drill_mk2_max_charge)
minetest.register_tool("technic:mining_drill_mk2_"..i, {
    description = "Mining Drill Mk2 in Mode "..i,
    inventory_image = "technic_mining_drill_mk2.png^technic_tool_mode"..i..".png",
    wield_image = "technic_mining_drill_mk2.png",
    groups = {not_in_creative_inventory=1},
    on_use = function(itemstack, user, pointed_thing)
    mining_drill_mk2_handler(itemstack,user,pointed_thing)
    return itemstack
    end,
})
    technic.register_power_tool("technic:mining_drill_mk2_"..i, mining_drill_mk2_max_charge)
    minetest.register_tool("technic:mining_drill_mk2_"..i, {
        description = "Mining Drill Mk2 in Mode "..i,
        inventory_image = "technic_mining_drill_mk2.png^technic_tool_mode"..i..".png",
        wield_image = "technic_mining_drill_mk2.png",
        groups = {not_in_creative_inventory=1},
        on_use = function(itemstack, user, pointed_thing)
            mining_drill_mk2_handler(itemstack, user, pointed_thing)
            return itemstack
        end,
    })
end
minetest.register_tool("technic:mining_drill_mk3", {
@@ -277,20 +278,21 @@
    return itemstack
    end,
})
technic.register_power_tool ("technic:mining_drill_mk3",mining_drill_mk3_max_charge)
technic.register_power_tool("technic:mining_drill_mk3", mining_drill_mk3_max_charge)
for i=1,5,1 do
technic.register_power_tool ("technic:mining_drill_mk3_"..i,mining_drill_mk3_max_charge)
minetest.register_tool("technic:mining_drill_mk3_"..i, {
    description = "Mining Drill Mk3 in Mode "..i,
    inventory_image = "technic_mining_drill_mk3.png^technic_tool_mode"..i..".png",
    wield_image = "technic_mining_drill_mk3.png",
    groups = {not_in_creative_inventory=1},
    on_use = function(itemstack, user, pointed_thing)
    mining_drill_mk3_handler(itemstack,user,pointed_thing)
    return itemstack
    end,
})
    technic.register_power_tool("technic:mining_drill_mk3_"..i, mining_drill_mk3_max_charge)
    minetest.register_tool("technic:mining_drill_mk3_"..i, {
        description = "Mining Drill Mk3 in Mode "..i,
        inventory_image = "technic_mining_drill_mk3.png^technic_tool_mode"..i..".png",
        wield_image = "technic_mining_drill_mk3.png",
        groups = {not_in_creative_inventory=1},
        on_use = function(itemstack, user, pointed_thing)
        mining_drill_mk3_handler(itemstack,user,pointed_thing)
        return itemstack
        end,
    })
end
function mining_drill_mk2_handler (itemstack,user,pointed_thing)
@@ -392,3 +394,4 @@
    itemstack:replace(item)
    return itemstack
end
technic/tools/mining_laser_mk1.lua
@@ -1,5 +1,5 @@
local laser_mk1_max_charge=40000
technic.register_power_tool ("technic:laser_mk1",laser_mk1_max_charge)
local laser_mk1_max_charge = 40000
technic.register_power_tool("technic:laser_mk1", laser_mk1_max_charge)
local laser_shoot = function(itemstack, player, pointed_thing)
                local laser_straight_mode=0
technic/tools/sonic_screwdriver.lua
@@ -1,5 +1,5 @@
local sonic_screwdriver_max_charge=15000
technic.register_power_tool ("technic:sonic_screwdriver",sonic_screwdriver_max_charge)
local sonic_screwdriver_max_charge = 15000
technic.register_power_tool("technic:sonic_screwdriver", sonic_screwdriver_max_charge)
minetest.register_tool("technic:sonic_screwdriver", {
            description = "Sonic Screwdriver",
technic/tools/tree_tap.lua
@@ -1,53 +1,60 @@
    minetest.register_tool("technic:treetap", {
            description = "Tree Tap",
            inventory_image = "technic_tree_tap.png",
            on_use = function(itemstack,user,pointed_thing)
                    if pointed_thing.type~="node" then return end
                    if user:get_inventory():room_for_item("main",ItemStack("technic:raw_latex")) then
                            local pos=minetest.get_pointed_thing_position(pointed_thing,above)
                            local node=minetest.env:get_node(pos)
                            local node_name=node.name
                            if node_name == "moretrees:rubber_tree_trunk" then
                                    node.name = "moretrees:rubber_tree_trunk_empty"
                                    user:get_inventory():add_item("main",ItemStack("technic:raw_latex"))
                                    minetest.env:set_node(pos,node)
                                    local item=itemstack:to_table()
                                    local item_wear=tonumber((item["wear"]))
                                    item_wear=item_wear+819
                                    if item_wear>65535 then itemstack:clear() return itemstack end
                                    item["wear"]=tostring(item_wear)
                                    itemstack:replace(item)
                                    return itemstack
                                    else
                                    return itemstack
                                    end
                           else return end
                    end,
    })
minetest.register_tool("technic:treetap", {
    description = "Tree Tap",
    inventory_image = "technic_tree_tap.png",
    on_use = function(itemstack,user,pointed_thing)
        if pointed_thing.type ~= "node" then
            return
        end
        if user:get_inventory():room_for_item("main",ItemStack("technic:raw_latex")) then
            local pos = minetest.get_pointed_thing_position(pointed_thing,above)
            local node = minetest.env:get_node(pos)
            local node_name = node.name
            if node_name == "moretrees:rubber_tree_trunk" then
                node.name = "moretrees:rubber_tree_trunk_empty"
                user:get_inventory():add_item("main", ItemStack("technic:raw_latex"))
                minetest.set_node(pos,node)
                local item = itemstack:to_table()
                local item_wear = tonumber((item["wear"]))
                item_wear = item_wear + 819
                if item_wear > 65535 then
                    itemstack:clear()
                    return itemstack
                end
                item["wear"] = tostring(item_wear)
                itemstack:replace(item)
                return itemstack
            else
                return itemstack
            end
        else
            return
        end
    end,
})
     
    minetest.register_craft({
            output = "technic:treetap",
            recipe = {
                    {"pipeworks:tube", "default:wood", "default:stick"},
                    {"", "default:stick", "default:stick"}
            },
    })
minetest.register_craft({
    output = "technic:treetap",
    recipe = {
        {"pipeworks:tube", "group:wood",    "default:stick"},
        {"",               "default:stick", "default:stick"}
    },
})
     
    minetest.register_craftitem("technic:raw_latex", {
            description = "Raw Latex",
            inventory_image = "technic_raw_latex.png",
    })
minetest.register_craftitem("technic:raw_latex", {
    description = "Raw Latex",
    inventory_image = "technic_raw_latex.png",
})
     
    minetest.register_craft({
            type = "cooking",
            output = "technic:rubber",
            recipe = "technic:raw_latex",
    })
    minetest.register_craftitem("technic:rubber", {
            description = "Rubber Fiber",
            inventory_image = "technic_rubber.png",
    })
minetest.register_craft({
    type = "cooking",
    output = "technic:rubber",
    recipe = "technic:raw_latex",
})
minetest.register_craftitem("technic:rubber", {
    description = "Rubber Fiber",
    inventory_image = "technic_rubber.png",
})
minetest.register_abm({
    nodenames = {"moretrees:rubber_tree_trunk_empty"},
@@ -55,6 +62,7 @@
    chance = 15,
    action = function(pos, node)
        node.name = "moretrees:rubber_tree_trunk"
        minetest.env:set_node(pos, node)
        minetest.set_node(pos, node)
    end
})
technic_worldgen/crafts.lua
@@ -1,109 +1,68 @@
minetest.register_craftitem( ":technic:uranium", {
minetest.register_craftitem(":technic:uranium", {
    description = "Uranium",
    inventory_image = "technic_uranium.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craftitem( ":technic:chromium_lump", {
minetest.register_craftitem(":technic:chromium_lump", {
    description = "Chromium Lump",
    inventory_image = "technic_chromium_lump.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craftitem( ":technic:chromium_ingot", {
minetest.register_craftitem(":technic:chromium_ingot", {
    description = "Chromium Ingot",
    inventory_image = "technic_chromium_ingot.png",
    on_place_on_ground = minetest.craftitem_place_item,
})
minetest.register_craftitem( ":technic:zinc_lump", {
minetest.register_craftitem(":technic:zinc_lump", {
    description = "Zinc Lump",
    inventory_image = "technic_zinc_lump.png",
})
minetest.register_craftitem( ":technic:zinc_ingot", {
minetest.register_craftitem(":technic:zinc_ingot", {
    description = "Zinc Ingot",
    inventory_image = "technic_zinc_ingot.png",
})
minetest.register_craftitem( ":technic:stainless_steel_ingot", {
minetest.register_craftitem(":technic:stainless_steel_ingot", {
    description = "Stainless Steel Ingot",
    inventory_image = "technic_stainless_steel_ingot.png",
})
minetest.register_craftitem( ":group:brass_ingot", {
    description = "Brass Ingot",
    inventory_image = "technic_brass_ingot.png",
})
local function register_block(block, ingot)
    minetest.register_craft({
        output = block,
        recipe = {
            {ingot, ingot, ingot},
            {ingot, ingot, ingot},
            {ingot, ingot, ingot},
        }
    })
minetest.register_craft({
    output = "node technic:uranium_block",
    recipe = {{"technic:uranium", "technic:uranium", "technic:uranium"},
          {"technic:uranium", "technic:uranium", "technic:uranium"},
          {"technic:uranium", "technic:uranium", "technic:uranium"}}
})
    minetest.register_craft({
        output = ingot.." 9",
        recipe = {
            {block}
        }
    })
end
minetest.register_craft({
    output = "craft technic:uranium 9",
    recipe = {{"technic:uranium_block"}}
})
minetest.register_craft({
    output = "node technic:chromium_block",
    recipe = {{"technic:chromium_ingot", "technic:chromium_ingot", "technic:chromium_ingot"},
          {"technic:chromium_ingot", "technic:chromium_ingot", "technic:chromium_ingot"},
          {"technic:chromium_ingot", "technic:chromium_ingot", "technic:chromium_ingot"}}
})
minetest.register_craft({
    output = "craft technic:chromium_ingot 9",
    recipe = {{"technic:chromium_block"}}
})
minetest.register_craft({
    output = "node technic:zinc_block",
    recipe = {{"technic:zinc_ingot", "technic:zinc_ingot", "technic:zinc_ingot"},
          {"technic:zinc_ingot", "technic:zinc_ingot", "technic:zinc_ingot"},
          {"technic:zinc_ingot", "technic:zinc_ingot", "technic:zinc_ingot"}}
})
minetest.register_craft({
    output = "craft technic:zinc_ingot 9",
    recipe = {{"technic:zinc_block"}}
})
minetest.register_craft({
    output = "node technic:stainless_steel_block",
    recipe = {{"technic:stainless_steel_ingot", "technic:stainless_steel_ingot", "technic:stainless_steel_ingot"},
          {"technic:stainless_steel_ingot", "technic:stainless_steel_ingot", "technic:stainless_steel_ingot"},
          {"technic:stainless_steel_ingot", "technic:stainless_steel_ingot", "technic:stainless_steel_ingot"}}
})
minetest.register_craft({
    output = "craft technic:stainless_steel_ingot 9",
    recipe = {{"technic:stainless_steel_block"}}
})
minetest.register_craft({
    output = "node group:brass_block",
    recipe = {{"group:brass_ingot", "group:brass_ingot", "group:brass_ingot"},
          {"group:brass_ingot", "group:brass_ingot", "group:brass_ingot"},
          {"group:brass_ingot", "group:brass_ingot", "group:brass_ingot"}}
})
minetest.register_craft({
    output = "craft group:brass_ingot 9",
    recipe = {{"group:brass_block"}}
})
register_block("technic:uranium_block", "technic:uranium")
register_block("technic:chromium_block", "technic:chromium_ingot")
register_block("technic:zinc_block", "technic:zinc_ingot")
register_block("technic:stainless_steel_block", "technic:stainless_steel_ingot")
minetest.register_craft({
    type = 'cooking',
    recipe = "technic:zinc_lump",
    output = "technic:zinc_ingot",
    recipe = "technic:zinc_lump"
})
minetest.register_craft({
    type = 'cooking',
    recipe = "technic:chromium_lump",
    output = "technic:chromium_ingot",
    recipe = "technic:chromium_lump"
})
technic_worldgen/init.lua
@@ -1,7 +1,11 @@
-- Minetest 0.4.6 : technic_worldgen
modpath=minetest.get_modpath("technic_worldgen")
local modpath = minetest.get_modpath("technic_worldgen")
dofile(modpath.."/nodes.lua")
dofile(modpath.."/oregen.lua")
dofile(modpath.."/crafts.lua")
-- Rubber trees, moretrees also supplies these
if not minetest.get_modpath("moretrees") then
    dofile(modpath.."/rubber.lua")
end
technic_worldgen/oregen.lua
@@ -8,6 +8,7 @@
    height_min     = -300,
    height_max     = -80,
})
minetest.register_ore({
    ore_type       = "scatter",
    ore            = "technic:mineral_chromium",
@@ -18,6 +19,7 @@
    height_min     = -31000,
    height_max     = -100,
})
minetest.register_ore({
    ore_type       = "scatter",
    ore            = "technic:mineral_zinc",
@@ -28,7 +30,8 @@
    height_min     = -31000,
    height_max     = 2,
})
if technic.config:getBool("enable_marble_generation") then
if technic.config:get_bool("enable_marble_generation") then
minetest.register_ore({
    ore_type       = "sheet",
    ore            = "technic:marble",
@@ -42,7 +45,8 @@
    noise_params = {offset=0, scale=15, spread={x=150, y=150, z=150}, seed=23, octaves=3, persist=0.70}
})
end
if technic.config:getBool("enable_granite_generation") then
if technic.config:get_bool("enable_granite_generation") then
minetest.register_ore({
    ore_type       = "sheet",
    ore            = "technic:granite",
technic_worldgen/rubber.lua
New file
@@ -0,0 +1,104 @@
-- Code of rubber tree by PilzAdam
minetest.register_node(":moretrees:rubber_tree_sapling", {
    description = "Rubber Tree Sapling",
    drawtype = "plantlike",
    tiles = {"technic_rubber_sapling.png"},
    inventory_image = "technic_rubber_sapling.png",
    wield_image = "technic_rubber_sapling.png",
    paramtype = "light",
    walkable = false,
    groups = {dig_immediate=3, flammable=2},
    sounds = default.node_sound_defaults(),
})
minetest.register_craft({
    type = "fuel",
    recipe = "moretrees:rubber_tree_sapling",
    burntime = 10
})
minetest.register_node(":moretrees:rubber_tree_trunk", {
    description = "Rubber Tree",
    tiles = {"default_tree_top.png", "default_tree_top.png",
        "technic_rubber_tree_full.png"},
    groups = {tree=1, snappy=1, choppy=2, oddly_breakable_by_hand=1,
        flammable=2},
    drop = "default:tree",
    sounds = default.node_sound_wood_defaults(),
})
minetest.register_node(":moretrees:rubber_tree_trunk_empty", {
    tiles = {"default_tree_top.png", "default_tree_top.png",
        "technic_rubber_tree_empty.png"},
    groups = {tree=1, snappy=1, choppy=2, oddly_breakable_by_hand=1,
            flammable=2, not_in_creative_inventory=1},
    drop = "default:tree",
    sounds = default.node_sound_wood_defaults(),
})
minetest.register_abm({
    nodenames = {"moretrees:rubber_tree_trunk_empty"},
    interval = 60,
    chance = 15,
    action = function(pos, node)
        minetest.set_node(pos, {name="moretrees:rubber_tree_trunk"})
    end
})
minetest.register_node(":moretrees:rubber_tree_leaves", {
    drawtype = "allfaces_optional",
    visual_scale = 1.3,
    tiles = {"technic_rubber_leaves.png"},
    paramtype = "light",
    groups = {snappy=3, leafdecay=3, flammable=2, not_in_creative_inventory=1},
    drop = {
        max_items = 1,
        items = {{
            items = {"moretrees:rubber_tree_sapling"},
            rarity = 20,
        }}
    },
    sounds = default.node_sound_leaves_defaults(),
})
technic.rubber_tree_model={
    axiom = "FFFFA",
    rules_a = "[&FFBFA]////[&BFFFA]////[&FBFFA]",
    rules_b = "[&FFA]////[&FFA]////[&FFA]",
    trunk = "moretrees:rubber_tree_trunk",
    leaves = "moretrees:rubber_tree_leaves",
    angle = 35,
    iterations = 3,
    random_level = 1,
    trunk_type = "double",
    thin_branches = true
}
minetest.register_abm({
    nodenames = {"moretrees:rubber_tree_sapling"},
    interval = 60,
    chance = 20,
    action = function(pos, node)
        minetest.remove_node(pos)
        minetest.spawn_tree(pos, technic.rubber_tree_model)
    end
})
if technic.config:get_bool("enable_rubber_tree_generation") then
    minetest.register_on_generated(function(minp, maxp, blockseed)
        if math.random(1, 100) > 5 then
            return
        end
        local tmp = {
                x = (maxp.x - minp.x) / 2 + minp.x,
                y = (maxp.y - minp.y) / 2 + minp.y,
                z = (maxp.z - minp.z) / 2 + minp.z}
        local pos = minetest.find_node_near(tmp, maxp.x - minp.x,
                {"default:dirt_with_grass"})
        if pos ~= nil then
            minetest.spawn_tree({x=pos.x, y=pos.y+1, z=pos.z}, technic.rubber_tree_model)
        end
    end)
end
unified_inventory/api.lua
@@ -22,15 +22,7 @@
unified_inventory.home_filename = minetest.get_worldpath()..'/unified_inventory_home'
-- Create detached creative inventory after loading all mods
-- Also 2nd attempt to disable default creative mod
minetest.after(0.01, function()
    if creative_inventory then
        creative_inventory.set_creative_formspec = function(player, start_i, pagenum)
        return
        end
    end
    unified_inventory.items_list = {}
    for name,def in pairs(minetest.registered_items) do
        if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0)
unified_inventory/bags.lua
@@ -1,20 +1,15 @@
--[[
-- Bags for Minetest
Bags for Minetest
-- Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
-- License: GPLv3
Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
Source Code: https://github.com/cornernote/minetest-particles
License: GPLv3
]]--
-- register_on_joinplayer
minetest.register_on_joinplayer(function(player)
    local player_inv = player:get_inventory()
    local bags_inv = minetest.create_detached_inventory(player:get_player_name().."_bags",{
        on_put = function(inv, listname, index, stack, player)
            player:get_inventory():set_stack(listname, index, stack)
            player:get_inventory():set_size(listname.."contents", stack:get_definition().groups.bagslots)
            player:get_inventory():set_size(listname.."contents",
                    stack:get_definition().groups.bagslots)
        end,
        on_take = function(inv, listname, index, stack, player)
            player:get_inventory():set_stack(listname, index, nil)
@@ -41,7 +36,7 @@
        local bag = "bag"..i
        player_inv:set_size(bag, 1)
        bags_inv:set_size(bag, 1)
        bags_inv:set_stack(bag,1,player_inv:get_stack(bag,1))
        bags_inv:set_stack(bag, 1, player_inv:get_stack(bag, 1))
    end
end)
@@ -51,11 +46,13 @@
    inventory_image = "bags_small.png",
    groups = {bagslots=8},
})
minetest.register_tool("unified_inventory:bag_medium", {
    description = "Medium Bag",
    inventory_image = "bags_medium.png",
    groups = {bagslots=16},
})
minetest.register_tool("unified_inventory:bag_large", {
    description = "Large Bag",
    inventory_image = "bags_large.png",
@@ -66,24 +63,27 @@
minetest.register_craft({
    output = "unified_inventory:bag_small",
    recipe = {
        {"", "default:stick", ""},
        {"default:wood", "default:wood", "default:wood"},
        {"default:wood", "default:wood", "default:wood"},
    },
        {"",           "default:stick", ""},
        {"group:wood", "group:wood",    "group:wood"},
        {"group:wood", "group:wood",    "group:wood"},
    },
})
minetest.register_craft({
    output = "unified_inventory:bag_medium",
    recipe = {
        {"", "default:stick", ""},
        {"unified_inventory:bag_small", "unified_inventory:bag_small", "unified_inventory:bag_small"},
        {"unified_inventory:bag_small", "unified_inventory:bag_small", "unified_inventory:bag_small"},
    },
        {"",              "",                            ""},
        {"default:stick", "unified_inventory:bag_small", "default:stick"},
        {"default:stick", "unified_inventory:bag_small", "default:stick"},
    },
})
minetest.register_craft({
    output = "unified_inventory:bag_large",
    recipe = {
        {"", "default:stick", ""},
        {"unified_inventory:bag_medium", "unified_inventory:bag_medium", "unified_inventory:bag_medium"},
        {"unified_inventory:bag_medium", "unified_inventory:bag_medium", "unified_inventory:bag_medium"},
        {"",              "",                             ""},
        {"default:stick", "unified_inventory:bag_medium", "default:stick"},
        {"default:stick", "unified_inventory:bag_medium", "default:stick"},
    },
})
unified_inventory/depends.txt
@@ -1 +1 @@
creative?