ShadowNinja
2013-07-08 19c9a0443b17176a27329b69ee16fe28d7be6fd8
Merge branch 'indev'

Conflicts:
technic/alloy_furnace.lua
technic/alloy_furnaces_commons.lua
technic/battery_box.lua
technic/battery_box_hv.lua
technic/battery_box_mv.lua
technic/chainsaw.lua
technic/cnc.lua
technic/cnc_nodes.lua
technic/electric_furnace.lua
technic/grinder.lua
technic/init.lua
technic/solar_array_hv.lua
technic/solar_array_lv.lua
technic/solar_array_mv.lua
technic/solar_panel.lua
unified_inventory/api.lua
unified_inventory/depends.txt
26 files added
10 files deleted
36 files modified
7933 ■■■■■ changed files
.gitignore 4 ●●●● patch | view | raw | blame | history
README.md 5 ●●●●● patch | view | raw | blame | history
technic/alloy_furnace.lua 507 ●●●● patch | view | raw | blame | history
technic/alloy_furnace_mv.lua 641 ●●●●● patch | view | raw | blame | history
technic/alloy_furnaces_commons.lua 98 ●●●● patch | view | raw | blame | history
technic/battery_box.lua 536 ●●●●● patch | view | raw | blame | history
technic/battery_box_hv.lua 404 ●●●●● patch | view | raw | blame | history
technic/battery_box_mv.lua 398 ●●●●● patch | view | raw | blame | history
technic/cans.lua 16 ●●●● patch | view | raw | blame | history
technic/chainsaw.lua 9 ●●●●● patch | view | raw | blame | history
technic/cnc.lua 427 ●●●● patch | view | raw | blame | history
technic/electric_furnace.lua 307 ●●●● patch | view | raw | blame | history
technic/electric_furnace_mv.lua 551 ●●●● patch | view | raw | blame | history
technic/extractor.lua 220 ●●●●● patch | view | raw | blame | history
technic/flashlight.lua 6 ●●●● patch | view | raw | blame | history
technic/forcefield.lua 203 ●●●● patch | view | raw | blame | history
technic/generator.lua 222 ●●●● patch | view | raw | blame | history
technic/geothermal.lua 228 ●●●● patch | view | raw | blame | history
technic/grinder.lua 583 ●●●● patch | view | raw | blame | history
technic/grinder_gloopores.lua 10 ●●●● patch | view | raw | blame | history
technic/init.lua 68 ●●●●● patch | view | raw | blame | history
technic/items.lua 21 ●●●●● patch | view | raw | blame | history
technic/lighting.lua 590 ●●●●● patch | view | raw | blame | history
technic/mining_drill.lua 28 ●●●● patch | view | raw | blame | history
technic/mining_laser_mk1.lua 8 ●●●● patch | view | raw | blame | history
technic/music_player.lua 246 ●●●●● patch | view | raw | blame | history
technic/power_radiator.lua 226 ●●●●● patch | view | raw | blame | history
technic/register_machine_and_tool.lua 70 ●●●●● patch | view | raw | blame | history
technic/solar_array_hv.lua 63 ●●●●● patch | view | raw | blame | history
technic/solar_array_lv.lua 78 ●●●●● patch | view | raw | blame | history
technic/solar_array_mv.lua 75 ●●●●● patch | view | raw | blame | history
technic/solar_panel.lua 27 ●●●● patch | view | raw | blame | history
technic/solar_panel_mv.lua 78 ●●●●● patch | view | raw | blame | history
technic/sonic_screwdriver.lua 6 ●●●● patch | view | raw | blame | history
technic/supply_converter.lua 232 ●●●●● patch | view | raw | blame | history
technic/switching_station.lua 352 ●●●●● patch | view | raw | blame | history
technic/textures/technic_enriched_uranium.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_cube_white_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_cube_white_sides_ceiling.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_cube_white_tb.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_cube_yellow_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_cube_yellow_sides_ceiling.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_cube_yellow_tb.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thick_white_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thick_white_wall_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thick_yellow_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thick_yellow_wall_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thin_white_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thin_white_wall_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thin_yellow_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_thin_yellow_wall_sides.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_white_tb.png patch | view | raw | blame | history
technic/textures/technic_homedecor_glowlight_yellow_tb.png patch | view | raw | blame | history
technic/textures/technic_mv_solar_panel_bottom.png patch | view | raw | blame | history
technic/textures/technic_mv_solar_panel_side.png patch | view | raw | blame | history
technic/textures/technic_mv_solar_panel_top.png patch | view | raw | blame | history
technic/textures/technic_mv_solarpanel_bottom.png patch | view | raw | blame | history
technic/textures/technic_mv_solarpanel_side.png patch | view | raw | blame | history
technic/textures/technic_mv_solarpanel_top.png patch | view | raw | blame | history
technic/textures/technic_supply_converter_bottom.png patch | view | raw | blame | history
technic/textures/technic_supply_converter_side.png patch | view | raw | blame | history
technic/textures/technic_supply_converter_top.png patch | view | raw | blame | history
technic/textures/technicx32/technic_mv_solar_panel_bottom.png patch | view | raw | blame | history
technic/textures/technicx32/technic_mv_solar_panel_side.png patch | view | raw | blame | history
technic/textures/technicx32/technic_mv_solar_panel_top.png patch | view | raw | blame | history
technic/tool_workshop.lua 182 ●●●●● patch | view | raw | blame | history
technic/water_mill.lua 187 ●●●● patch | view | raw | blame | history
technic_worldgen/depends.txt 1 ●●●● patch | view | raw | blame | history
technic_worldgen/nodes.lua 2 ●●●●● patch | view | raw | blame | history
technic_worldgen/oregen.lua 4 ●●●● patch | view | raw | blame | history
unified_inventory/api.lua 13 ●●●● patch | view | raw | blame | history
unified_inventory/depends.txt 1 ●●●● patch | view | raw | blame | history
.gitignore
@@ -161,3 +161,7 @@
# Mac crap
.DS_Store
#gedit backup files
*~
README.md
@@ -1,12 +1,13 @@
technic 0.4.6
technic 0.4.7
Technic mod for Minetest 0.4.6
Technic mod for Minetest 0.4.7
Credits for contributing to the project:
Nekogloop
ShadowNinja
VanessaE
Nore/Novatux
kpoppel
And many others for ideas/inspiring 
Licences:
technic/alloy_furnace.lua
@@ -1,12 +1,14 @@
-- LV Alloy furnace
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', 'default:brick', 'default:brick'},
    }
})
-- FIXME: kpoppel: I'd like to introduce an induction heating element here...
minetest.register_craft({
    output = 'technic:alloy_furnace',
    recipe = {
@@ -16,190 +18,178 @@
    }
})
-- LV alloy furnace
local alloy_furnace_formspec =
   "invsize[8,9;]"..
   "list[current_name;src;3,1;1,1;]"..
   "list[current_name;src2;3,2;1,1;]"..
   "list[current_name;dst;5,1;2,2;]"..
   "list[current_player;main;0,5;8,4;]"..
   "label[0,0;Electric Alloy Furnace]"
alloy_furnace_formspec =
    "invsize[8,9;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "list[current_name;src;3,1;1,1;]"..
    "list[current_name;src2;3,2;1,1;]"..
    "list[current_name;dst;5,1;2,2;]"..
    "list[current_player;main;0,5;8,4;]"..
    "label[0,0;LV Electric Alloy Furnace]"..
    "label[1,3;Power level]"..
    "background[-0.19,-0.25;8.4,9.75;ui_form_bg.png]"..
    "background[0,0;8,4;ui_lv_alloy_furnace.png]"..
    "background[0,5;8,4;ui_main_inventory.png]"
minetest.register_node("technic:alloy_furnace", {
    description = "LV Electric alloy furnace",
    tiles = {"technic_alloy_furnace_top.png", "technic_machine_bottom.png", "technic_alloy_furnace_side.png",
        "technic_alloy_furnace_side.png", "technic_alloy_furnace_side.png", "technic_alloy_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2},
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", alloy_furnace_formspec)
        meta:set_string("infotext", "Electric Alloy furnace")
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("src2", 1)
        inv:set_size("dst", 4)
        local EU_used  = 0
        local furnace_is_cookin = 0
        local cooked = nil
        meta:set_float("internal_EU_buffer",0)
        meta:set_float("internal_EU_buffer_size",2000)
        meta:set_float("tube_time", 0)
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false end
        if not inv:is_empty("src") then
            return false end
        if not inv:is_empty("src2") then
            return false end
        return true
    end,
minetest.register_node(
   "technic:alloy_furnace",
   {
      description = "Electric alloy furnace",
      tiles = {"technic_alloy_furnace_top.png", "technic_machine_bottom.png", "technic_alloy_furnace_side.png",
           "technic_alloy_furnace_side.png", "technic_alloy_furnace_side.png", "technic_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("infotext", "Electric Alloy furnace")
            meta:set_float("technic_power_machine", 1)
            meta:set_string("formspec", alloy_furnace_formspec)
            local inv = meta:get_inventory()
            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("src") or not inv:is_empty("src2") 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:alloy_furnace_active", {
    description = "Alloy Furnace",
    tiles = {"technic_alloy_furnace_top.png", "technic_machine_bottom.png", "technic_alloy_furnace_side.png",
        "technic_alloy_furnace_side.png", "technic_alloy_furnace_side.png", "technic_alloy_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:alloy_furnace",
    groups = {cracky=2,not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    technic_power_machine=1,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false
        elseif not inv:is_empty("src") then
            return false
        end
        return true
    end,
})
minetest.register_node(
   "technic:alloy_furnace_active",
   {
      description = "Alloy Furnace",
      tiles = {"technic_alloy_furnace_top.png", "technic_machine_bottom.png", "technic_alloy_furnace_side.png",
           "technic_alloy_furnace_side.png", "technic_alloy_furnace_side.png", "technic_alloy_furnace_front_active.png"},
      paramtype2 = "facedir",
      light_source = 8,
      drop = "technic: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("src") or not inv:is_empty("src2") 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:alloy_furnace","technic:alloy_furnace_active"},
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
minetest.register_abm(
   { nodenames = {"technic:alloy_furnace","technic:alloy_furnace_active"},
     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("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
        local meta = minetest.env:get_meta(pos)
        internal_EU_buffer=meta:get_float("internal_EU_buffer")
        internal_EU_buffer_size=meta:get_float("internal_EU_buffer")
        local load = math.floor(internal_EU_buffer/2000 * 100)
        meta:set_string("formspec",
                alloy_furnace_formspec..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]")
         -- Machine information
         local machine_name         = "Electric Alloy Furnace"
         local machine_node         = "technic:alloy_furnace"
         local machine_state_demand = { 50, 600 }
        local inv = meta:get_inventory()
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            meta:set_int("LV_EU_input", 0)
            meta:set_int("tube_time", 0)
            return
         end
         -- Power off automatically if no longer connected to a switching station
         technic.switching_station_timeout_count(pos, "LV")
         -- State machine
         if eu_input == 0 then
            -- Unpowered - go idle
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            -- Execute always if powered logic
            local inv    = meta:get_inventory()
            local empty  = 1
            local recipe = nil
            local result = nil
        local furnace_is_cookin = meta:get_int("furnace_is_cookin")
            -- Get what to cook if anything
            local srcstack  = inv:get_stack("src", 1)
            local src2stack = inv:get_stack("src2", 1)
            local src_item1 = nil
            local src_item2 = nil
            if srcstack and src2stack then
               src_item1 = srcstack:to_table()
               src_item2 = src2stack:to_table()
               empty     = 0
            end
            if src_item1 and src_item2 then
               recipe = technic.get_alloy_recipe(src_item1,src_item2)
            end
            if recipe then
               result = { name=recipe.dst_name, count=recipe.dst_count}
            end
        local srclist = inv:get_list("src")
        local srclist2 = inv:get_list("src2")
            if recipe then
               print("recipe "..recipe.dst_name.." : result "..result.name.." : empty "..empty.." : src_item1 "..src_item1.name.." : src_item2 "..src_item2.name)
            end
        srcstack = inv:get_stack("src", 1)
        if srcstack then src_item1=srcstack:to_table() end
        srcstack = inv:get_stack("src2", 1)
        if srcstack then src_item2=srcstack:to_table() end
        dst_index=nil
            if state == 1 then
               hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Idle")
               if empty == 0 and recipe and inv:room_for_item("dst", result) then
              meta:set_string("infotext", machine_name.." Active")
              meta:set_string("src_time", 0)
              next_state = 2
               end
        if src_item1 and src_item2 then
                dst_index=get_cook_result(src_item1,src_item2)
                end
            elseif state == 2 then
               hacky_swap_node(pos, machine_node.."_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_string("src_time", 0)
              -- check if there's room for output in "dst" list and that we have the materials
              if recipe and inv:room_for_item("dst", result) then
                 -- Take stuff from "src" list
                 srcstack:take_item(recipe.src1_count)
                 inv:set_stack("src", 1, srcstack)
                 src2stack:take_item(recipe.src2_count)
                 inv:set_stack("src2", 1, src2stack)
               -- Put result in "dst" list
                 inv:add_item("dst",result)
              else
                 next_state = 1
              end
               end
            end
            -- Change state?
            if next_state ~= state then
               meta:set_int("LV_EU_demand", machine_state_demand[next_state])
               meta:set_int("state", next_state)
            end
         end
          end,
  })
technic.register_LV_machine ("technic:alloy_furnace","RE")
technic.register_LV_machine ("technic:alloy_furnace_active","RE")
        if (furnace_is_cookin == 1) then
            if internal_EU_buffer>=150 then
            internal_EU_buffer=internal_EU_buffer-150;
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
            meta:set_float("src_time", meta:get_float("src_time") + 1)
            if dst_index and meta:get_float("src_time") >= 4 then
                -- check if there's room for output in "dst" list
                dst_stack={}
                dst_stack["name"]=alloy_recipes[dst_index].dst_name
                dst_stack["count"]=alloy_recipes[dst_index].dst_count
                if inv:room_for_item("dst",dst_stack) then
                    -- Put result in "dst" list
                    inv:add_item("dst",dst_stack)
                    -- take stuff from "src" list
                    for i=1,alloy_recipes[dst_index].src1_count,1 do
                        srcstack = inv:get_stack("src", 1)
                        srcstack:take_item()
                        inv:set_stack("src", 1, srcstack)
                        end
                    for i=1,alloy_recipes[dst_index].src2_count,1 do
                        srcstack = inv:get_stack("src2", 1)
                        srcstack:take_item()
                        inv:set_stack("src2", 1, srcstack)
                        end
                else
                    print("Furnace inventory full!")
                end
                meta:set_string("src_time", 0)
            end
            end
        end
        if dst_index and meta:get_int("furnace_is_cookin")==0 then
            hacky_swap_node(pos,"technic:alloy_furnace_active")
            meta:set_string("infotext","Electric Alloy Furnace active")
            meta:set_int("furnace_is_cookin",1)
            meta:set_string("src_time", 0)
            return
            end
        if meta:get_int("furnace_is_cookin")==0 or dst_index==nil then
            hacky_swap_node(pos,"technic:alloy_furnace")
            meta:set_string("infotext","Electric Alloy Furnace inactive")
            meta:set_int("furnace_is_cookin",0)
            meta:set_string("src_time", 0)
        end
end,
})
function get_cook_result(src_item1, src_item2)
local counter=registered_recipes_count-1
for i=1, counter,1 do
if    alloy_recipes[i].src1_name==src_item1["name"] and
    alloy_recipes[i].src2_name==src_item2["name"] and
    alloy_recipes[i].src1_count<=src_item1["count"] and
    alloy_recipes[i].src2_count<=src_item2["count"]
    then return i end
end
return nil
end
register_LV_machine ("technic:alloy_furnace","RE")
register_LV_machine ("technic:alloy_furnace_active","RE")
--coal driven alloy furnace:
--------------------------------------------------
-- coal driven alloy furnace. This uses no EUs:
--------------------------------------------------
coal_alloy_furnace_formspec =
    "size[8,9]"..
    "label[0,0;Alloy Furnace]"..
@@ -209,7 +199,7 @@
    "list[current_name;src2;3,1;1,1;]"..
    "list[current_name;dst;5,1;2,2;]"..
    "list[current_player;main;0,5;8,4;]"
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",
@@ -227,9 +217,6 @@
        inv:set_size("src", 1)
        inv:set_size("src2", 1)
        inv:set_size("dst", 4)
        local furnace_is_cookin = 0
        local dst_index = nil
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
@@ -265,10 +252,10 @@
    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.env:get_meta(pos)
        for i, name in ipairs({
        for i, name in pairs({
                "fuel_totaltime",
                "fuel_time",
                "src_totaltime",
@@ -279,108 +266,102 @@
            end
        end
        local inv = meta:get_inventory()
        local inv    = meta:get_inventory()
        local recipe = nil
        -- Get what to cook if anything
        local srcstack = inv:get_stack("src", 1)
        if srcstack then src_item1=srcstack:to_table() end
        local src2stack = inv:get_stack("src2", 1)
        if src2stack then src_item2=src2stack:to_table() end
        if src_item1 and src_item2 then
           recipe = technic.get_alloy_recipe(src_item1,src_item2)
        end
        local was_active = false
        if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then
           was_active = true
           meta:set_float("fuel_time", meta:get_float("fuel_time") + 1)
           meta:set_float("src_time", meta:get_float("src_time") + 1)
           if recipe and meta:get_float("src_time") == 6 then
              -- check if there's room for output in "dst" list
              local dst_stack = { name=recipe.dst_name, count=recipe.dst_count}
              if inv:room_for_item("dst",dst_stack) then
             -- Take stuff from "src" list
             srcstack:take_item(recipe.src1_count)
             inv:set_stack("src", 1, srcstack)
             src2stack:take_item(recipe.src2_count)
             inv:set_stack("src2", 1, src2stack)
             -- Put result in "dst" list
             inv:add_item("dst",dst_stack)
              else
             print("Furnace inventory full!") -- Silly code...
              end
              meta:set_string("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)
        if srcstack then src_item1=srcstack:to_table() end
        srcstack = inv:get_stack("src2", 1)
        if srcstack then src_item2=srcstack:to_table() end
        dst_index=nil
        if src_item1 and src_item2 then
                dst_index=get_cook_result(src_item1,src_item2)
                end
        local was_active = false
        if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then
            was_active = true
            meta:set_float("fuel_time", meta:get_float("fuel_time") + 1)
            meta:set_float("src_time", meta:get_float("src_time") + 1)
            if dst_index and meta:get_float("src_time") >= 5 then
                -- check if there's room for output in "dst" list
                dst_stack={}
                dst_stack["name"]=alloy_recipes[dst_index].dst_name
                dst_stack["count"]=alloy_recipes[dst_index].dst_count
                if inv:room_for_item("dst",dst_stack) then
                    -- Put result in "dst" list
                    inv:add_item("dst", dst_stack)
                    -- take stuff from "src" list
                    for i=1,alloy_recipes[dst_index].src1_count,1 do
                        srcstack = inv:get_stack("src", 1)
                        srcstack:take_item()
                        inv:set_stack("src", 1, srcstack)
                        end
                    for i=1,alloy_recipes[dst_index].src2_count,1 do
                        srcstack = inv:get_stack("src2", 1)
                        srcstack:take_item()
                        inv:set_stack("src2", 1, srcstack)
                        end
                else
                    print("Furnace inventory full!")
                end
                meta:set_string("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
        if src_item1 and src_item2 then
           recipe = technic.get_alloy_recipe(src_item1,src_item2)
        end
        if recipe==nil then
           if was_active then
              meta:set_string("infotext","Furnace is empty")
              hacky_swap_node(pos,"technic:coal_alloy_furnace")
              meta:set_string("formspec", coal_alloy_furnace_formspec)
           end
           return
        end
        -- Next take a hard look at the fuel situation
        local fuel = nil
        local fuellist = inv:get_list("fuel")
        srcstack = inv:get_stack("src", 1)
        if srcstack then src_item1=srcstack:to_table() end
        srcstack = inv:get_stack("src2", 1)
        if srcstack then src_item2=srcstack:to_table() end
        dst_index=nil
        if src_item1 and src_item2 then
                dst_index=get_cook_result(src_item1,src_item2)
                end
        if fuellist then
            fuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
           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", coal_alloy_furnace_formspec)
            return
        end
        if dst_index==nil then
            if was_active then
                meta:set_string("infotext","Furnace is empty")
                hacky_swap_node(pos,"technic:coal_alloy_furnace")
                meta:set_string("formspec", coal_alloy_furnace_formspec)
            end
            return
           meta:set_string("infotext","Furnace out of fuel")
           hacky_swap_node(pos,"technic:coal_alloy_furnace")
           meta:set_string("formspec", coal_alloy_furnace_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,
})
         end,
     })
technic/alloy_furnace_mv.lua
@@ -9,262 +9,451 @@
    }
})
MV_alloy_furnace_formspec =
local mv_alloy_furnace_formspec =
    "invsize[8,10;]"..
    "label[0,0;MV Alloy Furnace]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "label[1,2.8;Power level]"..
    "list[current_name;src;3,1;1,2;]"..
        "list[current_name;src;3,1;1,2;]"..
    "list[current_name;dst;5,1;2,2;]"..
    "list[current_player;main;0,6;8,4;]"..
    "list[current_name;upgrade1;1,4;1,1;]"..
    "list[current_name;upgrade2;2,4;1,1;]"..
    "label[1,5;Upgrade Slots]"
    
minetest.register_node("technic:mv_alloy_furnace", {
    description = "MV Alloy Furnace",
    tiles = {"technic_mv_alloy_furnace_top.png", "technic_mv_alloy_furnace_bottom.png", "technic_mv_alloy_furnace_side_tube.png",
        "technic_mv_alloy_furnace_side_tube.png", "technic_mv_alloy_furnace_side.png", "technic_mv_alloy_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1},
    tube={insert_object=function(pos,node,stack,direction)
            local meta=minetest.env:get_meta(pos)
            local inv=meta:get_inventory()
                return inv:add_item("src",stack)
        end,
        can_insert=function(pos,node,stack,direction)
minetest.register_node(
   "technic:mv_alloy_furnace",
   {description = "MV Alloy Furnace",
    tiles = {"technic_mv_alloy_furnace_top.png", "technic_mv_alloy_furnace_bottom.png", "technic_mv_alloy_furnace_side_tube.png",
         "technic_mv_alloy_furnace_side_tube.png", "technic_mv_alloy_furnace_side.png", "technic_mv_alloy_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1},
    tube={insert_object=function(pos,node,stack,direction)
               local meta=minetest.env: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.env:get_meta(pos)
            local inv=meta:get_inventory()
            return inv:room_for_item("src",stack)
        end,
        },
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", mv_alloy_furnace_formspec)
        meta:set_string("infotext", "MV Electric Alloy furnace")
        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)
        local EU_used  = 0
        local furnace_is_cookin = 0
        local cooked = nil
        meta:set_float("internal_EU_buffer",0)
        meta:set_float("internal_EU_buffer_size",2000)
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false end
        if not inv:is_empty("src") then
            return false end
        if not inv:is_empty("upgrade1") then
            return false end
        if not inv:is_empty("upgrade2") then
            return false end
        return true
    end,
             end,
       },
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    on_construct = function(pos)
              local meta = minetest.env:get_meta(pos)
              meta:set_string("infotext", "MV Alloy furnace")
              meta:set_float("technic_mv_power_machine", 1)
              meta:set_int("tube_time",  0)
              meta:set_string("formspec", mv_alloy_furnace_formspec)
              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.env: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:mv_alloy_furnace_active", {
    description = "MV Alloy Furnace",
    tiles = {"technic_mv_alloy_furnace_top.png", "technic_mv_alloy_furnace_bottom.png", "technic_mv_alloy_furnace_side_tube.png",
        "technic_mv_alloy_furnace_side_tube.png", "technic_mv_alloy_furnace_side.png", "technic_mv_alloy_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:mv_alloy_furnace",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1,not_in_creative_inventory=1},
    tube={insert_object=function(pos,node,stack,direction)
            local meta=minetest.env:get_meta(pos)
            local inv=meta:get_inventory()
                return inv:add_item("src",stack)
        end,
        can_insert=function(pos,node,stack,direction)
minetest.register_node(
   "technic:mv_alloy_furnace_active",
   {description = "MV Alloy Furnace",
    tiles = {"technic_mv_alloy_furnace_top.png", "technic_mv_alloy_furnace_bottom.png", "technic_mv_alloy_furnace_side_tube.png",
         "technic_mv_alloy_furnace_side_tube.png", "technic_mv_alloy_furnace_side.png", "technic_mv_alloy_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:mv_alloy_furnace",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1,not_in_creative_inventory=1},
    tube={insert_object=function(pos,node,stack,direction)
               local meta=minetest.env: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.env:get_meta(pos)
            local inv=meta:get_inventory()
            return inv:room_for_item("src",stack)
        end,
        },
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    technic_power_machine=1,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false end
        if not inv:is_empty("src") then
            return false end
        if not inv:is_empty("upgrade1") then
            return false end
        if not inv:is_empty("upgrade2") then
            return false end
        return true
    end,
             end,
       },
    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("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 99
                       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 99
                       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:mv_alloy_furnace","technic:mv_alloy_furnace_active"},
    interval = 1,
    chance = 1,
local send_cooked_items = function(pos,x_velocity,z_velocity)
                 -- Send items on their way in the pipe system.
                 local meta=minetest.env: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
    action = function(pos, node, active_object_count, active_object_count_wider)
        local pos1={}
        pos1.x=pos.x
        pos1.y=pos.y
        pos1.z=pos.z
        local x_velocity=0
        local z_velocity=0
local smelt_item = function(pos)
              local meta=minetest.env:get_meta(pos)
              local inv = meta:get_inventory()
              meta:set_int("src_time", meta:get_int("src_time") + 3) -- Cooking time 3x faster
              local result = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")})
              dst_stack={}
              dst_stack["name"]=alloy_recipes[dst_index].dst_name
              dst_stack["count"]=alloy_recipes[dst_index].dst_count
        -- 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
              if result and result.item and meta:get_int("src_time") >= result.time then
             meta:set_int("src_time", 0)
             -- check if there's room for output in "dst" list
             if inv:room_for_item("dst",result) then
                -- take stuff from "src" list
                srcstack = inv:get_stack("src", 1)
                srcstack:take_item()
                inv:set_stack("src", 1, srcstack)
                -- Put result in "dst" list
                inv:add_item("dst", result.item)
                return 1
             else
                return 0 -- done
             end
              end
              return 0 -- done
           end
        local output_tube_connected = false
        local meta=minetest.env:get_meta(pos1)
        if meta:get_int("tubelike")==1 then output_tube_connected=true end
        meta = minetest.env:get_meta(pos)
        local inv = meta:get_inventory()
        local upg_item1
        local upg_item1_name=""
        local upg_item2
        local upg_item2_name=""
        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
        if upg_item1 then upg_item1_name=upg_item1.name end
        if upg_item2 then upg_item2_name=upg_item2.name end
minetest.register_abm(
   {nodenames = {"technic:mv_alloy_furnace","technic:mv_alloy_furnace_active"},
    interval = 1,
    chance = 1,
        local speed=0
        if upg_item1_name=="technic:control_logic_unit" then speed=speed+1 end
        if upg_item2_name=="technic:control_logic_unit" then speed=speed+1 end
        tube_time=meta:get_float("tube_time")
        tube_time=tube_time+speed
        if tube_time>3 then
            tube_time=0
            if output_tube_connected then send_cooked_alloys(pos,x_velocity,z_velocity) end
        end
        meta:set_float("tube_time", tube_time)
    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 state        = meta:get_int("state")
        local next_state   = state
        local extra_buffer_size = 0
        if upg_item1_name=="technic:battery" then extra_buffer_size =extra_buffer_size + 10000 end
        if upg_item2_name=="technic:battery" then extra_buffer_size =extra_buffer_size + 10000 end
        local internal_EU_buffer_size=2000+extra_buffer_size
        meta:set_float("internal_EU_buffer_size",internal_EU_buffer_size)
        internal_EU_buffer=meta:get_float("internal_EU_buffer")
        if internal_EU_buffer > internal_EU_buffer_size then internal_EU_buffer = internal_EU_buffer_size end
        local meta = minetest.env:get_meta(pos)
        local load = math.floor(internal_EU_buffer/internal_EU_buffer_size * 100)
        meta:set_string("formspec",
                MV_alloy_furnace_formspec..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]")
        local inv = meta:get_inventory()
        local furnace_is_cookin = meta:get_int("furnace_is_cookin")
        local srclist = inv:get_list("src")
        local srclist2 = inv:get_list("src2")
        -- Machine information
        local machine_name         = "MV Alloy Furnace"
        local machine_node         = "technic:mv_alloy_furnace"
        local machine_state_demand = { 50, 2000, 1500, 1000 }
        
        srcstack = inv:get_stack("src", 1)
        if srcstack then src_item1=srcstack:to_table() end
        srcstack = inv:get_stack("src", 2)
        if srcstack then src_item2=srcstack:to_table() end
        dst_index=nil
        -- Setup meta data if it does not exist. state is used as an indicator of this
        if state == 0 then
           meta:set_int("state", 1)
           meta:set_int("MV_EU_demand", machine_state_demand[1])
           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")
        -- Execute always logic
        -- CODE HERE --
        if src_item1 and src_item2 then
                dst_index=get_cook_result(src_item1,src_item2)
                end
        -- State machine
        if eu_input == 0 then
           -- Unpowered - go idle
           hacky_swap_node(pos, machine_node)
           meta:set_string("infotext", machine_name.." Unpowered")
           next_state = 1
        elseif eu_input == machine_state_demand[state] then
           -- Powered - do the state specific actions
           -- Execute always if powered logic
           local meta=minetest.env:get_meta(pos)
           -- Get the names of the upgrades
           local meta=minetest.env:get_meta(pos)
           local inv = meta:get_inventory()
           local upg_item1
           local upg_item1_name=""
           local upg_item2
           local upg_item2_name=""
           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
           if upg_item1 then upg_item1_name=upg_item1.name end
           if upg_item2 then upg_item2_name=upg_item2.name end
           -- Save some power by installing battery upgrades. Fully upgraded makes this
           -- furnace use the same amount of power as the LV version
           local EU_saving_upgrade = 0
           if upg_item1_name=="technic:battery" then EU_saving_upgrade = EU_saving_upgrade + 1 end
           if upg_item2_name=="technic:battery" then EU_saving_upgrade = EU_saving_upgrade + 1 end
           -- Tube loading speed can be upgraded using control logic units
           local tube_speed_upgrade = 0
           if upg_item1_name=="technic:control_logic_unit" then tube_speed_upgrade = tube_speed_upgrade + 1 end
           if upg_item2_name=="technic:control_logic_unit" then tube_speed_upgrade = tube_speed_upgrade + 1 end
           -- Handle pipeworks (consumes tube_speed_upgrade)
           local pos1={x=pos.x, y=pos.y, z=pos.z}
           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.env: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_speed_upgrade
           if tube_time > 3 then
              tube_time = 0
              if output_tube_connected then
             send_cooked_items(pos,x_velocity,z_velocity)
              end
           end
           meta:set_int("tube_time", tube_time)
           -- The machine shuts down if we have nothing to smelt and no tube is connected
           -- or if we have nothing to send with a tube connected.
           if    (not output_tube_connected and inv:is_empty("src"))
              or (    output_tube_connected and inv:is_empty("dst")) then
              next_state = 1
           end
           ----------------------
           local empty  = 1
           local recipe = nil
           local result = nil
        if (furnace_is_cookin == 1) then
            if internal_EU_buffer>=150 then
            internal_EU_buffer=internal_EU_buffer-150;
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
            meta:set_float("src_time", meta:get_float("src_time") + 1)
            if dst_index and meta:get_float("src_time") >= 4 then
                -- check if there's room for output in "dst" list
                dst_stack={}
                dst_stack["name"]=alloy_recipes[dst_index].dst_name
                dst_stack["count"]=alloy_recipes[dst_index].dst_count
                if inv:room_for_item("dst",dst_stack) then
                    -- Put result in "dst" list
                    inv:add_item("dst",dst_stack)
                    -- take stuff from "src" list
                    for i=1,alloy_recipes[dst_index].src1_count,1 do
                        srcstack = inv:get_stack("src", 1)
                        srcstack:take_item()
                        inv:set_stack("src", 1, srcstack)
                        end
                    for i=1,alloy_recipes[dst_index].src2_count,1 do
                        srcstack = inv:get_stack("src", 2)
                        srcstack:take_item()
                        inv:set_stack("src", 2, srcstack)
                        end
                else
                    print("Furnace inventory full!")
                end
                meta:set_string("src_time", 0)
            end
            end
           -- Get what to cook if anything
           local srcstack  = inv:get_stack("src", 1)
           local src2stack = inv:get_stack("src", 2)
           local src_item1 = nil
           local src_item2 = nil
           if srcstack and src2stack then
              src_item1 = srcstack:to_table()
              src_item2 = src2stack:to_table()
              empty     = 0
           end
           if src_item1 and src_item2 then
              recipe = technic.get_alloy_recipe(src_item1,src_item2)
           end
           if recipe then
              result = { name=recipe.dst_name, count=recipe.dst_count}
           end
           if state == 1 then
              hacky_swap_node(pos, machine_node)
              meta:set_string("infotext", machine_name.." Idle")
              local meta=minetest.env:get_meta(pos)
              local inv = meta:get_inventory()
              if not inv:is_empty("src") then
             if empty == 0 and recipe and inv:room_for_item("dst", result) then
                meta:set_string("infotext", machine_name.." Active")
                meta:set_int("src_time",     0)
                next_state = 2+EU_saving_upgrade -- Next state is decided by the battery upgrade (state 2= 0 batteries, state 3 = 1 battery, 4 = 2 batteries)
             end
              end
           elseif state == 2 or state == 3 or state == 4 then
              hacky_swap_node(pos, machine_node.."_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_string("src_time", 0)
             -- check if there's room for output in "dst" list and that we have the materials
             if recipe and inv:room_for_item("dst", result) then
                -- Take stuff from "src" list
                srcstack:take_item(recipe.src1_count)
                inv:set_stack("src", 1, srcstack)
                src2stack:take_item(recipe.src2_count)
                inv:set_stack("src2", 1, src2stack)
                -- Put result in "dst" list
                inv:add_item("dst",result)
             else
                next_state = 1
             end
              end
           end
        end
        -- Change state?
        if next_state ~= state then
           meta:set_int("MV_EU_demand", machine_state_demand[next_state])
           meta:set_int("state", next_state)
        end
        if dst_index and meta:get_int("furnace_is_cookin")==0 then
            hacky_swap_node(pos,"technic:mv_alloy_furnace_active")
            meta:set_string("infotext","MV Alloy Furnace active")
            meta:set_int("furnace_is_cookin",1)
            meta:set_string("src_time", 0)
            return
            end
        if meta:get_int("furnace_is_cookin")==0 or dst_index==nil then
            hacky_swap_node(pos,"technic:mv_alloy_furnace")
            meta:set_string("infotext","MV Alloy Furnace inactive")
            meta:set_int("furnace_is_cookin",0)
            meta:set_string("src_time", 0)
        end
end,
})
         ------------------------------------
function send_cooked_alloys (pos,x_velocity,z_velocity)
        local meta=minetest.env: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
--         local pos1={}
--         pos1.x=pos.x
--         pos1.y=pos.y
--         pos1.z=pos.z
--         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 meta=minetest.env:get_meta(pos1)
--         if meta:get_int("tubelike")==1 then output_tube_connected=true end
--         meta = minetest.env:get_meta(pos)
--         local inv = meta:get_inventory()
--         local upg_item1
--         local upg_item1_name=""
--         local upg_item2
--         local upg_item2_name=""
--         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
--         if upg_item1 then upg_item1_name=upg_item1.name end
--         if upg_item2 then upg_item2_name=upg_item2.name end
--
--         local speed=0
--         if upg_item1_name=="technic:control_logic_unit" then speed=speed+1 end
--         if upg_item2_name=="technic:control_logic_unit" then speed=speed+1 end
--         tube_time=meta:get_float("tube_time")
--         tube_time=tube_time+speed
--         if tube_time>3 then
--        tube_time=0
--        if output_tube_connected then send_cooked_items(pos,x_velocity,z_velocity) end
--         end
--         meta:set_float("tube_time", tube_time)
--
--         local extra_buffer_size = 0
--         if upg_item1_name=="technic:battery" then extra_buffer_size =extra_buffer_size + 10000 end
--         if upg_item2_name=="technic:battery" then extra_buffer_size =extra_buffer_size + 10000 end
--         local internal_EU_buffer_size=2000+extra_buffer_size
--         meta:set_float("internal_EU_buffer_size",internal_EU_buffer_size)
--
--         internal_EU_buffer=meta:get_float("internal_EU_buffer")
--         if internal_EU_buffer > internal_EU_buffer_size then internal_EU_buffer = internal_EU_buffer_size end
--         local meta = minetest.env:get_meta(pos)
--         local load = math.floor(internal_EU_buffer/internal_EU_buffer_size * 100)
--         meta:set_string("formspec",
--                 MV_alloy_furnace_formspec..
--                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
--                (load)..":technic_power_meter_fg.png]")
--
--         local inv = meta:get_inventory()
--
--         local furnace_is_cookin = meta:get_int("furnace_is_cookin")
--
--         local srclist = inv:get_list("src")
--         local srclist2 = inv:get_list("src2")
--
--         srcstack = inv:get_stack("src", 1)
--         if srcstack then src_item1=srcstack:to_table() end
--         srcstack = inv:get_stack("src", 2)
--         if srcstack then src_item2=srcstack:to_table() end
--         dst_index=nil
--
--         if src_item1 and src_item2 then
--        dst_index=get_cook_result(src_item1,src_item2)
--         end
--
--
--         if (furnace_is_cookin == 1) then
--        if internal_EU_buffer>=150 then
--           internal_EU_buffer=internal_EU_buffer-150;
--           meta:set_float("internal_EU_buffer",internal_EU_buffer)
--           meta:set_float("src_time", meta:get_float("src_time") + 1)
--           if dst_index and meta:get_float("src_time") >= 4 then
--              -- check if there's room for output in "dst" list
--              dst_stack={}
--              dst_stack["name"]=alloy_recipes[dst_index].dst_name
--              dst_stack["count"]=alloy_recipes[dst_index].dst_count
--              if inv:room_for_item("dst",dst_stack) then
--             -- Put result in "dst" list
--             inv:add_item("dst",dst_stack)
--             -- take stuff from "src" list
--             for i=1,alloy_recipes[dst_index].src1_count,1 do
--                srcstack = inv:get_stack("src", 1)
--                srcstack:take_item()
--                inv:set_stack("src", 1, srcstack)
--             end
--             for i=1,alloy_recipes[dst_index].src2_count,1 do
--                srcstack = inv:get_stack("src", 2)
--                srcstack:take_item()
--                inv:set_stack("src", 2, srcstack)
--             end
--
--              else
--             print("Furnace inventory full!")
--              end
--              meta:set_string("src_time", 0)
--           end
--        end
--         end
--
--         if dst_index and meta:get_int("furnace_is_cookin")==0 then
--        hacky_swap_node(pos,"technic:mv_alloy_furnace_active")
--        meta:set_string("infotext","MV Alloy Furnace active")
--        meta:set_int("furnace_is_cookin",1)
--        meta:set_string("src_time", 0)
--        return
--         end
--
--         if meta:get_int("furnace_is_cookin")==0 or dst_index==nil then
--        hacky_swap_node(pos,"technic:mv_alloy_furnace")
--        meta:set_string("infotext","MV Alloy Furnace inactive")
--        meta:set_int("furnace_is_cookin",0)
--        meta:set_string("src_time", 0)
--         end
--
      end,
 })
register_MV_machine ("technic:mv_alloy_furnace","RE")
register_MV_machine ("technic:mv_alloy_furnace_active","RE")
technic.register_MV_machine ("technic:mv_alloy_furnace","RE")
technic.register_MV_machine ("technic:mv_alloy_furnace_active","RE")
technic/alloy_furnaces_commons.lua
@@ -1,32 +1,77 @@
alloy_recipes ={}
-- Register alloy recipes
technic.alloy_recipes = {}
registered_recipes_count=1
-- Register recipe in a table
technic.register_alloy_recipe = function(metal1, count1, metal2, count2, result, count3)
                   technic.alloy_recipes[metal1..metal2] = { src1_count = count1, src2_count = count2, dst_name = result, dst_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.
-- Input parameters are a table from a StackItem
technic.get_alloy_recipe = function(metal1, metal2)
                  -- Check for both combinations of metals and for the right amount in both
                  if technic.alloy_recipes[metal1.name..metal2.name]
                 and metal1.count >= technic.alloy_recipes[metal1.name..metal2.name].src1_count
                 and metal2.count >= technic.alloy_recipes[metal1.name..metal2.name].src2_count then
                 return technic.alloy_recipes[metal1.name..metal2.name]
                  elseif technic.alloy_recipes[metal2.name..metal1.name]
                 and metal2.count >= technic.alloy_recipes[metal2.name..metal1.name].src1_count
                 and metal1.count >= technic.alloy_recipes[metal2.name..metal1.name].src2_count then
                 return technic.alloy_recipes[metal2.name..metal1.name]
                  else
                 return nil
                  end
               end
technic.register_alloy_recipe("technic:copper_dust",  3, "technic:tin_dust",      1, "technic:bronze_dust",          4)
technic.register_alloy_recipe("moreores: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("moreores: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)
--------------------------------------
-- LEGACY CODE - some other mods might depend on this - Register the same recipes as above...
--------------------------------------
alloy_recipes = {}
registered_recipes_count = 1
function register_alloy_recipe (string1,count1, string2,count2, string3,count3)
alloy_recipes[registered_recipes_count]={}
alloy_recipes[registered_recipes_count].src1_name=string1
alloy_recipes[registered_recipes_count].src1_count=count1
alloy_recipes[registered_recipes_count].src2_name=string2
alloy_recipes[registered_recipes_count].src2_count=count2
alloy_recipes[registered_recipes_count].dst_name=string3
alloy_recipes[registered_recipes_count].dst_count=count3
registered_recipes_count=registered_recipes_count+1
alloy_recipes[registered_recipes_count]={}
alloy_recipes[registered_recipes_count].src1_name=string2
alloy_recipes[registered_recipes_count].src1_count=count2
alloy_recipes[registered_recipes_count].src2_name=string1
alloy_recipes[registered_recipes_count].src2_count=count1
alloy_recipes[registered_recipes_count].dst_name=string3
alloy_recipes[registered_recipes_count].dst_count=count3
registered_recipes_count=registered_recipes_count+1
if unified_inventory then
    unified_inventory.register_craft({
    type = "alloy",
    output = string3.." "..count3,
    items = {string1.." "..count1,string2.." "..count2},
    width = 2,
    })
    end
   alloy_recipes[registered_recipes_count]={}
   alloy_recipes[registered_recipes_count].src1_name=string1
   alloy_recipes[registered_recipes_count].src1_count=count1
   alloy_recipes[registered_recipes_count].src2_name=string2
   alloy_recipes[registered_recipes_count].src2_count=count2
   alloy_recipes[registered_recipes_count].dst_name=string3
   alloy_recipes[registered_recipes_count].dst_count=count3
   registered_recipes_count=registered_recipes_count+1
   alloy_recipes[registered_recipes_count]={}
   alloy_recipes[registered_recipes_count].src1_name=string2
   alloy_recipes[registered_recipes_count].src1_count=count2
   alloy_recipes[registered_recipes_count].src2_name=string1
   alloy_recipes[registered_recipes_count].src2_count=count1
   alloy_recipes[registered_recipes_count].dst_name=string3
   alloy_recipes[registered_recipes_count].dst_count=count3
   registered_recipes_count=registered_recipes_count+1
   if unified_inventory then
      unified_inventory.register_craft({
          type = "alloy",
          output = string3.." "..count3,
          items = {string1.." "..count1,string2.." "..count2},
          width = 2,
           })
   end
end
register_alloy_recipe ("technic:copper_dust",3, "technic:tin_dust",1, "technic:bronze_dust",4)
@@ -37,3 +82,4 @@
register_alloy_recipe ("default:copper_ingot",2, "technic:zinc_ingot",1, "technic:brass_ingot",3)
register_alloy_recipe ("default:sand",2, "technic:coal_dust",2, "technic:silicon_wafer",1)
register_alloy_recipe ("technic:silicon_wafer",1, "technic:gold_dust",1, "technic:doped_silicon_wafer",1)
technic/battery_box.lua
@@ -1,157 +1,201 @@
-- register LV machines here
local LV_machines = {}
function register_LV_machine(string1,string2)
   LV_machines[string1] = string2
end
power_tools ={}
registered_power_tools_count=0
function register_power_tool (string1,max_charge)
   registered_power_tools_count=registered_power_tools_count+1
   power_tools[registered_power_tools_count]={}
   power_tools[registered_power_tools_count].tool_name=string1
   power_tools[registered_power_tools_count].max_charge=max_charge
end
register_power_tool ("technic:battery",10000)
register_power_tool ("technic:red_energy_crystal",100000)
register_power_tool ("technic:green_energy_crystal",250000)
register_power_tool ("technic:blue_energy_crystal",500000)
-- LV Battery box and some other nodes...
technic.register_LV_power_tool("technic:battery",10000)
technic.register_MV_power_tool("technic:red_energy_crystal",100000)
technic.register_HV_power_tool("technic:green_energy_crystal",250000)
technic.register_HV_power_tool("technic:blue_energy_crystal",500000)
minetest.register_craft({
               output = 'technic:battery 1',
               recipe = {
                  {'default:wood', 'default:copper_ingot', 'default:wood'},
                  {'default:wood', 'moreores:tin_ingot', 'default:wood'},
                  {'default:wood', 'default:copper_ingot', 'default:wood'},
               }
            })
    output = 'technic:battery 1',
    recipe = {
        {'default:wood', 'default:copper_ingot', 'default:wood'},
        {'default:wood', 'moreores:tin_ingot',   'default:wood'},
        {'default:wood', 'default:copper_ingot', 'default:wood'},
    }
})
minetest.register_craft({
               output = 'technic:battery_box 1',
               recipe = {
                  {'technic:battery', 'default:wood', 'technic:battery'},
                  {'technic:battery', 'moreores:copper_ingot', 'technic:battery'},
                  {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
               }
            })
minetest.register_tool("technic:battery", {
    description = "RE Battery",
    inventory_image = "technic_battery.png",
    tool_capabilities = {
        load=0,
        max_drop_level=0,
        groupcaps={
            fleshy={times={}, uses=10000, maxlevel=0}
        }
    }
})
minetest.register_tool("technic:battery",
               {description = "RE Battery",
            inventory_image = "technic_battery.png",
            tool_capabilities = {load=0,max_drop_level=0, groupcaps={fleshy={times={}, uses=10000, maxlevel=0}}}})
--------------------------------------------
-- The Battery box
--------------------------------------------
minetest.register_craftitem("technic:battery_box", {
                   description = "Battery box",
                   stack_max = 99,
                })
    description = "Battery box",
    stack_max = 99,
})
minetest.register_craft({
    output = 'technic:battery_box 1',
    recipe = {
        {'technic:battery',     'default:wood',         'technic:battery'},
        {'technic:battery',     'default:copper_ingot', 'technic:battery'},
        {'default:steel_ingot', 'default:steel_ingot',  'default:steel_ingot'},
    }
})
battery_box_formspec =
local 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;LV Battery Box]"..
    "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;]"..
    "background[-0.19,-0.25;8.4,9.75;ui_form_bg.png]"..
    "background[0,0;8,4;ui_lv_battery_box.png]"..
    "background[0,5;8,4;ui_main_inventory.png]"
    "list[current_player;main;0,5;8,4;]"
minetest.register_node(
   "technic:battery_box", {
      description = "LV Battery Box",
      tiles = {"technic_battery_box_top.png", "technic_battery_box_bottom.png", "technic_battery_box_side0.png",
           "technic_battery_box_side0.png", "technic_battery_box_side0.png", "technic_battery_box_side0.png"},
      groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
      sounds = default.node_sound_wood_defaults(),
      drop="technic:battery_box",
      on_construct = function(pos)
                 if pos == nil then return end
                 local meta = minetest.env:get_meta(pos)
                 local inv = meta:get_inventory()
                 meta:set_string("infotext", "Battery box")
                 meta:set_float("technic_power_machine", 1)
                 meta:set_string("formspec", battery_box_formspec)
                 meta:set_float("internal_EU_buffer", 0)
                 meta:set_float("internal_EU_buffer_size", 60000)
                 inv:set_size("src", 1)
                 inv:set_size("dst", 1)
              end,
      can_dig = function(pos,player)
            if pos == nil then return end
            local meta = minetest.env:get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("dst") then
               return false
            elseif not inv:is_empty("src") then
               return false
            end
minetest.register_node("technic:battery_box", {
    description = "LV Battery Box",
    tiles = {"technic_battery_box_top.png", "technic_battery_box_bottom.png",
             "technic_battery_box_side0.png", "technic_battery_box_side0.png",
         "technic_battery_box_side0.png", "technic_battery_box_side0.png"},
    groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
    sounds = default.node_sound_wood_defaults(),
    drop="technic:battery_box",
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        local inv = meta:get_inventory()
        meta:set_string("infotext", "Battery box")
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", battery_box_formspec)
        meta:set_int("LV_EU_demand", 0) -- How much can this node charge
        meta:set_int("LV_EU_supply", 0) -- How much can this node discharge
        meta:set_int("LV_EU_input",  0) -- How much power is this machine getting.
        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.env: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,
})
for i=1,8,1 do
   minetest.register_node(
      "technic:battery_box"..i, {
     description = "LV Battery Box",
     tiles = {"technic_battery_box_top.png", "technic_battery_box_bottom.png", "technic_battery_box_side0.png^technic_power_meter"..i..".png",
          "technic_battery_box_side0.png^technic_power_meter"..i..".png", "technic_battery_box_side0.png^technic_power_meter"..i..".png", "technic_battery_box_side0.png^technic_power_meter"..i..".png"},
     tiles = {"technic_battery_box_top.png", "technic_battery_box_bottom.png",
              "technic_battery_box_side0.png^technic_power_meter"..i..".png",
          "technic_battery_box_side0.png^technic_power_meter"..i..".png",
          "technic_battery_box_side0.png^technic_power_meter"..i..".png",
          "technic_battery_box_side0.png^technic_power_meter"..i..".png"},
     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
     sounds = default.node_sound_wood_defaults(),
     drop="technic:battery_box",
     on_construct = function(pos)
                 if pos == nil then return end
                 local meta = minetest.env:get_meta(pos)
                 local inv = meta:get_inventory()
                 meta:set_string("infotext", "Battery box")
                 meta:set_float("technic_power_machine", 1)
                 meta:set_string("formspec", battery_box_formspec)
                 meta:set_float("internal_EU_buffer", 0)
                 meta:set_float("internal_EU_buffer_size", 60000)
                 inv:set_size("src", 1)
                 inv:set_size("dst", 1)
              end,
     can_dig = function(pos,player)
            if pos == nil then return end
            local meta = minetest.env:get_meta(pos);
            local inv = meta:get_inventory()
            if not inv:is_empty("dst") then
               return false
            elseif not inv:is_empty("src") then
               return false
            end
            return true
             end,
              local meta = minetest.env: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
function 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
local power_tools = technic.LV_power_tools
function 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
local charge_LV_tools = function(meta, charge)
             --charge registered power tools
             local inv = meta:get_inventory()
             if inv:is_empty("src")==false  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 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"])
               if src_meta==nil then
                  src_meta={}
                  src_meta["technic_power_tool"]=true
                  src_meta["charge"]=0
               else
                  if src_meta["technic_power_tool"]==nil then
                 src_meta["technic_power_tool"]=true
                 src_meta["charge"]=0
                  end
               end
               -- Do the charging
               local item_max_charge = power_tools[toolname]
               local load            = src_meta["charge"]
               local load_step       = 1000 -- how much to charge per tick
               if load<item_max_charge and charge>0 then
                  if charge-load_step<0 then load_step=charge end
                  if load+load_step>item_max_charge then load_step=item_max_charge-load end
                  load=load+load_step
                  charge=charge-load_step
                  technic.set_RE_wear(src_item,load,item_max_charge)
                  src_meta["charge"]   = load
                  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 set_RE_wear (item_stack,load1,max_load)
   local temp=65536-math.floor(load1/max_load*65535)
   item_stack["wear"]=tostring(temp)
   return item_stack
end
local discharge_LV_tools = function(meta, charge, max_charge)
            -- discharging registered power tools
            local inv = meta:get_inventory()
            if inv:is_empty("dst") == false 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 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"])
                  if src_meta==nil then
                 src_meta={}
                 src_meta["technic_power_tool"]=true
                 src_meta["charge"]=0
                  else
                 if src_meta["technic_power_tool"]==nil then
                    src_meta["technic_power_tool"]=true
                    src_meta["charge"]=0
                 end
                  end
                  -- Do the discharging
                  local item_max_charge = power_tools[toolname]
                  local load            = src_meta["charge"]
                  local load_step       = 4000 -- how much to discharge per tick
                  if load>0 and charge<max_charge then
                 if charge+load_step>max_charge then load_step=max_charge-charge end
                 if load-load_step<0 then load_step=load end
                 load=load-load_step
                 charge=charge+load_step
                 technic.set_RE_wear(src_item,load,item_max_charge)
                 src_meta["charge"]=load
                 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
minetest.register_abm(
   {nodenames = {"technic:battery_box","technic:battery_box1","technic:battery_box2","technic:battery_box3","technic:battery_box4",
@@ -159,12 +203,39 @@
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta       = minetest.env:get_meta(pos)
        local max_charge = 60000 -- Set maximum charge for the device here
        local charge     = meta:get_int("internal_EU_buffer")
        local meta               = minetest.env:get_meta(pos)
        local max_charge         = 60000 -- Set maximum charge for the device here
        local max_charge_rate    = 1000  -- Set maximum rate of charging
        local max_discharge_rate = 2000  -- Set maximum rate of discharging
        local eu_input           = meta:get_int("LV_EU_input")
        local current_charge     = meta:get_int("internal_EU_charge") -- Battery charge right now
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "LV")
        -- 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 = charge_LV_tools(meta, current_charge)
        current_charge = discharge_LV_tools(meta, current_charge, max_charge)
        -- Set a demand (we allow batteries to charge on less than the demand though)
        meta:set_int("LV_EU_demand", math.min(max_charge_rate, max_charge-current_charge))
        --print("BA:"..max_charge_rate.."|"..max_charge-current_charge.."|"..math.min(max_charge_rate, max_charge-current_charge))
        -- Set how much we can supply
        meta:set_int("LV_EU_supply", math.min(max_discharge_rate, current_charge))
        meta:set_int("internal_EU_charge", current_charge)
        --dprint("BA: input:"..eu_input.." supply="..meta:get_int("LV_EU_supply").." demand="..meta:get_int("LV_EU_demand").." current:"..current_charge)
        -- Select node textures
        local i=math.ceil((charge/max_charge)*8)
        local i=math.ceil((current_charge/max_charge)*8)
        if i > 8 then i = 8 end
        local j = meta:get_float("last_side_shown")
        if i~=j then
@@ -172,224 +243,27 @@
           elseif i==0 then hacky_swap_node(pos,"technic:battery_box") end
           meta:set_float("last_side_shown",i)
        end
        --charge registered power tools
        local inv = meta:get_inventory()
        if inv:is_empty("src")==false  then
           local srcstack = inv:get_stack("src", 1)
           local src_item=srcstack:to_table()
           local src_meta=get_item_meta(src_item["metadata"])
           local item_max_charge=nil
           for i=1,registered_power_tools_count,1 do
              if power_tools[i].tool_name==src_item["name"] then
             src_meta=get_item_meta(src_item["metadata"])
             if src_meta==nil then
                src_meta={}
                src_meta["technic_power_tool"]=true
                src_meta["charge"]=0
             else
                if src_meta["technic_power_tool"]==nil then
                   src_meta["technic_power_tool"]=true
                   src_meta["charge"]=0
                end
             end
             -- Do the charging
             local item_max_charge = power_tools[i].max_charge
             local load1           = src_meta["charge"]
             local load_step       = 1000 -- how much to charge per tick
             if load1<item_max_charge and charge>0 then
                if charge-load_step<0 then load_step=charge end
                if load1+load_step>item_max_charge then load_step=item_max_charge-load1 end
                load1=load1+load_step
                charge=charge-load_step
                set_RE_wear(src_item,load1,item_max_charge)
                src_meta["charge"]=load1
                src_item["metadata"]=set_item_meta(src_meta)
                inv:set_stack("src", 1, src_item)
             end
             meta:set_int("internal_EU_buffer",charge)
             break
              end
           end
        end
        -- discharging registered power tools
        if inv:is_empty("dst") == false then
           srcstack = inv:get_stack("dst", 1)
           src_item=srcstack:to_table()
           local src_meta=get_item_meta(src_item["metadata"])
           local item_max_charge=nil
           for i=1,registered_power_tools_count,1 do
              if power_tools[i].tool_name==src_item["name"] then
             src_meta=get_item_meta(src_item["metadata"])
             if src_meta==nil then
                src_meta={}
                src_meta["technic_power_tool"]=true
                src_meta["charge"]=0
             else
                if src_meta["technic_power_tool"]==nil then
                   src_meta["technic_power_tool"]=true
                   src_meta["charge"]=0
                end
             end
             local item_max_charge = power_tools[i].max_charge
             local load1           = src_meta["charge"]
             local load_step       = 4000 -- how much to discharge per tick
             if load1>0 and charge<max_charge then
                if charge+load_step>max_charge then load_step=max_charge-charge end
                if load1-load_step<0 then load_step=load1 end
                load1=load1-load_step
                charge=charge+load_step
                set_RE_wear(src_item,load1,item_max_charge)
                src_meta["charge"]=load1
                src_item["metadata"]=set_item_meta(src_meta)
                inv:set_stack("dst", 1, src_item)
             end
             meta:set_int("internal_EU_buffer",charge)
             break
              end
           end
        end
        local load = math.floor(charge/60000 * 100)
        local load = math.floor(current_charge/max_charge * 100)
        meta:set_string("formspec",
                battery_box_formspec..
                   "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                   (load)..":technic_power_meter_fg.png]"
                 )
        -- Next index the surrounding network the get the producers and receivers on the power grid
        local pos1={}
        pos1.y=pos.y-1
        pos1.x=pos.x
        pos1.z=pos.z
        meta1 = minetest.env:get_meta(pos1)
        if meta1:get_float("cablelike")~=1 then return end
        local LV_nodes = {}
        local PR_nodes = {}
        local RE_nodes = {}
        local BA_nodes = {}
        LV_nodes[1]={}
        LV_nodes[1].x=pos1.x
        LV_nodes[1].y=pos1.y
        LV_nodes[1].z=pos1.z
        LV_nodes[1].visited=false
        local table_index=1
        repeat
           check_LV_node(PR_nodes,RE_nodes,BA_nodes,LV_nodes,table_index)
           table_index=table_index+1
           if LV_nodes[table_index]==nil then break end
        until false
        -- Get power from all connected producers
        local pr_pos
                for _,pr_pos in ipairs(PR_nodes) do
           local meta1              = minetest.env:get_meta(pr_pos)
           local internal_EU_buffer = meta1:get_float("internal_EU_buffer")
           local charge_to_take     = 200
           if charge<max_charge then
              if internal_EU_buffer-charge_to_take<=0 then
             charge_to_take=internal_EU_buffer
              end
              if charge_to_take>0 then
             charge=charge+charge_to_take
             internal_EU_buffer=internal_EU_buffer-charge_to_take
             meta1:set_float("internal_EU_buffer",internal_EU_buffer)
              end
           end
        if eu_input == 0 then
           meta:set_string("infotext", "LV Battery box: "..current_charge.."/"..max_charge.." (idle)")
        else
           meta:set_string("infotext", "LV Battery box: "..current_charge.."/"..max_charge)
        end
        if charge>max_charge then charge=max_charge end
        -- Provide power to all connected receivers
        local re_pos
                for _,re_pos in ipairs(RE_nodes) do
           local meta1                   = minetest.env:get_meta(re_pos)
           local internal_EU_buffer      = meta1:get_float("internal_EU_buffer")
           local internal_EU_buffer_size = meta1:get_float("internal_EU_buffer_size")
           local charge_to_give          = math.min(200, charge/table.getn(RE_nodes))
           if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
              charge_to_give=internal_EU_buffer_size-internal_EU_buffer
           end
           if charge-charge_to_give<0 then charge_to_give=charge end
           internal_EU_buffer=internal_EU_buffer+charge_to_give
           meta1:set_float("internal_EU_buffer",internal_EU_buffer)
           charge=charge-charge_to_give;
        end
        charge=math.floor(charge)
        meta:set_string("infotext", "LV Battery box: "..charge.."/"..max_charge);
        meta:set_int("internal_EU_buffer",charge)
         end
 })
-- Register as a battery type
-- Battery type machines function as power reservoirs and can both receive and give back power
register_LV_machine("technic:battery_box","BA")
technic.register_LV_machine("technic:battery_box","BA")
for i=1,8,1 do
   register_LV_machine("technic:battery_box"..i,"BA")
   technic.register_LV_machine("technic:battery_box"..i,"BA")
end
function add_new_cable_node (LV_nodes,pos1)
   if LV_nodes == nil then return true end
   local i=1
   repeat
      if LV_nodes[i]==nil then break end
      if pos1.x==LV_nodes[i].x and pos1.y==LV_nodes[i].y and pos1.z==LV_nodes[i].z then return false end
      i=i+1
   until false
   LV_nodes[i]={}
   LV_nodes[i].x=pos1.x
   LV_nodes[i].y=pos1.y
   LV_nodes[i].z=pos1.z
   return true
end
function check_LV_node(PR_nodes,RE_nodes,BA_nodes,LV_nodes,i)
   local pos1={}
   pos1.x=LV_nodes[i].x
   pos1.y=LV_nodes[i].y
   pos1.z=LV_nodes[i].z
   pos1.x=pos1.x+1
   check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   pos1.x=pos1.x-2
   check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   pos1.x=pos1.x+1
   pos1.y=pos1.y+1
   check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   pos1.y=pos1.y-2
   check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   pos1.y=pos1.y+1
   pos1.z=pos1.z+1
   check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   pos1.z=pos1.z-2
   check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   pos1.z=pos1.z+1
   return new_node_added
end
function check_LV_node_subp (PR_nodes,RE_nodes,BA_nodes,LV_nodes,pos1)
   local meta = minetest.env:get_meta(pos1)
   local name = minetest.env:get_node(pos1).name
   if meta:get_float("cablelike")==1 then
      add_new_cable_node(LV_nodes,pos1)
   elseif LV_machines[name] then
      --print(name.." is a "..LV_machines[name])
      if     LV_machines[name] == "PR" then
     add_new_cable_node(PR_nodes,pos1)
      elseif LV_machines[name] == "RE" then
     add_new_cable_node(RE_nodes,pos1)
      elseif LV_machines[name] == "BA" then
     add_new_cable_node(BA_nodes,pos1)
      end
   end
end
technic/battery_box_hv.lua
@@ -1,10 +1,4 @@
-- register MV machines here
technic.HV_machines = {}
local HV_machines = technic.HV_machines
function register_HV_machine(string1,string2)
   technic.HV_machines[string1] = string2
end
-- HV battery box
minetest.register_craft({
               output = 'technic:hv_battery_box 1',
               recipe = {
@@ -14,7 +8,7 @@
               }
            })
hv_battery_box_formspec =
local battery_box_formspec =
   "invsize[8,9;]"..
   "image[1,1;1,2;technic_power_meter_bg.png]"..
   "list[current_name;src;3,1;1,1;]"..
@@ -35,74 +29,176 @@
      sounds = default.node_sound_wood_defaults(),
      drop="technic:hv_battery_box",
      on_construct = function(pos)
            if pos==nil then return end
            local meta = minetest.env:get_meta(pos)
            local inv = meta:get_inventory()
            meta:set_string("infotext", "HV Battery Box")
            meta:set_float("technic_hv_power_machine", 1)
            meta:set_string("formspec", battery_box_formspec)
            meta:set_int("HV_EU_demand", 0) -- How much can this node charge
            meta:set_int("HV_EU_supply", 0) -- How much can this node discharge
            meta:set_int("HV_EU_input",  0) -- How much power is this machine getting.
            meta:set_float("internal_EU_charge", 0)
            inv:set_size("src", 1)
            inv:set_size("dst", 1)
             end,
      can_dig = function(pos,player)
           if pos==nil then return end
           local meta = minetest.env:get_meta(pos);
           local inv = meta:get_inventory()
           if not inv:is_empty("dst") then
           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
           elseif not inv:is_empty("src") then
              return false
           else
              return true
           end
           return true
        end,
   })
for i=1,8,1 do
   minetest.register_node(
      "technic:hv_battery_box"..i, {
     description = "HV Battery Box",
     tiles = {"technic_hv_battery_box_top.png", "technic_hv_battery_box_bottom.png", "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png",
          "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png", "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png", "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png"},
     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
     sounds = default.node_sound_wood_defaults(),
     paramtype="light",
     light_source=9,
     drop="technic:hv_battery_box",
     on_construct = function(pos)
               local meta = minetest.env:get_meta(pos)
               local inv = meta:get_inventory()
               meta:set_string("infotext", "HV Battery box")
               meta:set_float("technic_hv_power_machine", 1)
               meta:set_string("formspec", battery_box_formspec)
               inv:set_size("src", 1)
               inv:set_size("dst", 1)
            end,
     can_dig = function(pos,player)
              local meta = minetest.env:get_meta(pos);
              local inv = meta:get_inventory()
              if not inv:is_empty("dst") then
             return false
              elseif not inv:is_empty("src") then
             return false
              end
              return true
           end,
      })
      "technic:hv_battery_box"..i,
      {description = "HV Battery Box",
       tiles = {"technic_hv_battery_box_top.png", "technic_hv_battery_box_bottom.png", "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png",
        "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png", "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png", "technic_hv_battery_box_side0.png^technic_power_meter"..i..".png"},
       groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
       sounds = default.node_sound_wood_defaults(),
       paramtype="light",
       light_source=9,
       drop="technic:hv_battery_box",
       can_dig = function(pos,player)
            local meta = minetest.env: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
local power_tools = technic.HV_power_tools
local charge_HV_tools = function(meta, charge)
             --charge registered power tools
             local inv = meta:get_inventory()
             if inv:is_empty("src")==false  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 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"])
               if src_meta==nil then
                  src_meta={}
                  src_meta["technic_hv_power_tool"]=true
                  src_meta["charge"]=0
               else
                  if src_meta["technic_hv_power_tool"]==nil then
                 src_meta["technic_hv_power_tool"]=true
                 src_meta["charge"]=0
                  end
               end
               -- Do the charging
               local item_max_charge = power_tools[toolname]
               local load            = src_meta["charge"]
               local load_step       = 1000 -- how much to charge per tick
               if load<item_max_charge and charge>0 then
                  if charge-load_step<0 then load_step=charge end
                  if load+load_step>item_max_charge then load_step=item_max_charge-load end
                  load=load+load_step
                  charge=charge-load_step
                  technic.set_RE_wear(src_item,load,item_max_charge)
                  src_meta["charge"]   = load
                  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
local discharge_HV_tools = function(meta, charge, max_charge)
            -- discharging registered power tools
            local inv = meta:get_inventory()
            if inv:is_empty("dst") == false 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 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"])
                  if src_meta==nil then
                 src_meta={}
                 src_meta["technic_hv_power_tool"]=true
                 src_meta["charge"]=0
                  else
                 if src_meta["technic_hv_power_tool"]==nil then
                    src_meta["technic_hv_power_tool"]=true
                    src_meta["charge"]=0
                 end
                  end
                  -- Do the discharging
                  local item_max_charge = power_tools[toolname]
                  local load            = src_meta["charge"]
                  local load_step       = 4000 -- how much to discharge per tick
                  if load>0 and charge<max_charge then
                 if charge+load_step>max_charge then load_step=max_charge-charge end
                 if load-load_step<0 then load_step=load end
                 load=load-load_step
                 charge=charge+load_step
                 technic.set_RE_wear(src_item,load,item_max_charge)
                 src_meta["charge"]=load
                 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
minetest.register_abm(
   {nodenames = {"technic:hv_battery_box","technic:hv_battery_box1","technic:hv_battery_box2","technic:hv_battery_box3","technic:hv_battery_box4",
         "technic:hv_battery_box5","technic:hv_battery_box6","technic:hv_battery_box7","technic:hv_battery_box8"
          },
    interval = 1,
    chance = 1,
    chance   = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta       = minetest.env:get_meta(pos)
        local max_charge = 1500000
        local charge     = meta:get_int("internal_EU_buffer")
        local meta               = minetest.env:get_meta(pos)
        local max_charge         = 1500000 -- Set maximum charge for the device here
        local max_charge_rate    = 3000    -- Set maximum rate of charging
        local max_discharge_rate = 5000    -- Set maximum rate of discharging (16000)
        local eu_input           = meta:get_int("HV_EU_input")
        local current_charge     = meta:get_int("internal_EU_charge") -- Battery charge right now
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "HV")
        -- 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 = charge_HV_tools(meta, current_charge)
        current_charge = discharge_HV_tools(meta, current_charge, max_charge)
        -- Set a demand (we allow batteries to charge on less than the demand though)
        meta:set_int("HV_EU_demand", math.min(max_charge_rate, max_charge-current_charge))
        -- Set how much we can supply
        meta:set_int("HV_EU_supply", math.min(max_discharge_rate, current_charge))
        meta:set_int("internal_EU_charge", current_charge)
        --dprint("BA: input:"..eu_input.." supply="..meta:get_int("HV_EU_supply").." demand="..meta:get_int("HV_EU_demand").." current:"..current_charge)
        -- Select node textures
        local i = math.ceil((charge/max_charge)*8)
        local i=math.ceil((current_charge/max_charge)*8)
        if i > 8 then i = 8 end
        local j = meta:get_float("last_side_shown")
        if i~=j then
@@ -111,221 +207,25 @@
           meta:set_float("last_side_shown",i)
        end
        --charge registered power tools
        local inv = meta:get_inventory()
        if inv:is_empty("src")==false  then
           local srcstack = inv:get_stack("src", 1)
           local src_item=srcstack:to_table()
           local src_meta=get_item_meta(src_item["metadata"])
           for i=1,registered_power_tools_count,1 do
              if power_tools[i].tool_name==src_item["name"] then
             src_meta=get_item_meta(src_item["metadata"])
             if src_meta==nil then
                src_meta={}
                src_meta["technic_power_tool"]=true
                src_meta["charge"]=0
             else
                if src_meta["technic_power_tool"]==nil then
                   src_meta["technic_power_tool"]=true
                   src_meta["charge"]=0
                end
             end
             -- Do the charging
             local item_max_charge = power_tools[i].max_charge
             local load1           = src_meta["charge"]
             local load_step       = 16000 -- how much to charge per tick
             if load1<item_max_charge and charge>0 then
                if charge-load_step<0 then load_step=charge end
                if load1+load_step>item_max_charge then load_step=item_max_charge-load1 end
                load1=load1+load_step
                charge=charge-load_step
                set_RE_wear(src_item,load1,item_max_charge)
                src_meta["charge"]=load1
                src_item["metadata"]=set_item_meta(src_meta)
                inv:set_stack("src", 1, src_item)
             end
             meta:set_int("internal_EU_buffer",charge)
             break
              end
           end
        end
        -- discharging registered power tools
        if inv:is_empty("dst") == false then
           srcstack = inv:get_stack("dst", 1)
           src_item=srcstack:to_table()
           local src_meta=get_item_meta(src_item["metadata"])
           local item_max_charge=nil
           for i=1,registered_power_tools_count,1 do
              if power_tools[i].tool_name==src_item["name"] then
             src_meta=get_item_meta(src_item["metadata"])
             if src_meta==nil then
                src_meta={}
                src_meta["technic_power_tool"]=true
                src_meta["charge"]=0
             else
                if src_meta["technic_power_tool"]==nil then
                   src_meta["technic_power_tool"]=true
                   src_meta["charge"]=0
                end
             end
             local item_max_charge = power_tools[i].max_charge
             local load1           = src_meta["charge"]
             local load_step       = 16000 -- how much to discharge per tick
             if load1>0 and charge<max_charge then
                if charge+load_step>max_charge then load_step=max_charge-charge end
                if load1-load_step<0 then load_step=load1 end
                load1=load1-load_step
                charge=charge+load_step
                set_RE_wear(src_item,load1,item_max_charge)
                src_meta["charge"]=load1
                src_item["metadata"]=set_item_meta(src_meta)
                inv:set_stack("dst", 1, src_item)
             end
             meta:set_int("internal_EU_buffer",charge)
             break
              end
           end
        end
        local load = math.floor((charge/1500000) * 100)
        local load = math.floor(current_charge/max_charge * 100)
        meta:set_string("formspec",
                hv_battery_box_formspec..
                battery_box_formspec..
                   "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                   (load)..":technic_power_meter_fg.png]"
                 )
        -- Next index the surrounding network the get the producers and receivers on the
        local pos1={}
        pos1.y=pos.y-1
        pos1.x=pos.x
        pos1.z=pos.z
        meta1 = minetest.env:get_meta(pos1)
        if meta1:get_float("hv_cablelike")~=1 then return end
        local HV_nodes = {}
        local PR_nodes = {}
        local RE_nodes = {}
        local BA_nodes = {}
        HV_nodes[1]={}
        HV_nodes[1].x=pos1.x
        HV_nodes[1].y=pos1.y
        HV_nodes[1].z=pos1.z
        HV_nodes[1].visited=false
        local table_index=1
        repeat
           check_HV_node (PR_nodes,RE_nodes,BA_nodes,HV_nodes,table_index)
           table_index=table_index+1
           if HV_nodes[table_index]==nil then break end
        until false
        -- Get power from all connected producers
        local pr_pos
                for _,pr_pos in ipairs(PR_nodes) do
           local meta1              = minetest.env:get_meta(pr_pos)
           local internal_EU_buffer = meta1:get_float("internal_EU_buffer")
           local charge_to_take     = 4000
           if charge<max_charge then
              if internal_EU_buffer-charge_to_take<=0 then
             charge_to_take=internal_EU_buffer
              end
              if charge_to_take>0 then
             charge=charge+charge_to_take
             internal_EU_buffer=internal_EU_buffer-charge_to_take
             meta1:set_float("internal_EU_buffer",internal_EU_buffer)
              end
           end
        if eu_input == 0 then
           meta:set_string("infotext", "HV Battery box: "..current_charge.."/"..max_charge.." (idle)")
        else
           meta:set_string("infotext", "HV Battery box: "..current_charge.."/"..max_charge)
        end
        if charge>max_charge then charge=max_charge end
        -- Provide power to all connected receivers
        local re_pos
                for _,re_pos in ipairs(RE_nodes) do
           local meta1                   = minetest.env:get_meta(re_pos)
           local internal_EU_buffer      = meta1:get_float("internal_EU_buffer")
           local internal_EU_buffer_size = meta1:get_float("internal_EU_buffer_size")
           local charge_to_give          = math.min(4000, charge/table.getn(RE_nodes))
           if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
              charge_to_give=internal_EU_buffer_size-internal_EU_buffer
           end
           if charge-charge_to_give<0 then charge_to_give=charge end
           internal_EU_buffer=internal_EU_buffer+charge_to_give
           meta1:set_float("internal_EU_buffer",internal_EU_buffer)
           charge=charge-charge_to_give;
        end
        charge=math.floor(charge)
        meta:set_string("infotext", "MV Battery box: "..charge.."/"..max_charge);
        meta:set_int("internal_EU_buffer",charge)
         end
 })
-- Register as a battery type
-- Battery type machines function as power reservoirs and can both receive and give back power
register_HV_machine("technic:hv_battery_box","BA")
technic.register_HV_machine("technic:hv_battery_box","BA")
for i=1,8,1 do
   register_HV_machine("technic:hv_battery_box"..i,"BA")
   technic.register_HV_machine("technic:hv_battery_box"..i,"BA")
end
function add_new_HVcable_node (HV_nodes,pos1)
   if HV_nodes == nil then return true end
   local i=1
   repeat
      if HV_nodes[i]==nil then break end
      if pos1.x==HV_nodes[i].x and pos1.y==HV_nodes[i].y and pos1.z==HV_nodes[i].z then return false end
      i=i+1
   until false
   HV_nodes[i]={}
   HV_nodes[i].x=pos1.x
   HV_nodes[i].y=pos1.y
   HV_nodes[i].z=pos1.z
   return true
end
function check_HV_node(PR_nodes,RE_nodes,BA_nodes,HV_nodes,i)
   local pos1={}
   pos1.x=HV_nodes[i].x
   pos1.y=HV_nodes[i].y
   pos1.z=HV_nodes[i].z
   pos1.x=pos1.x+1
   check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   pos1.x=pos1.x-2
   check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   pos1.x=pos1.x+1
   pos1.y=pos1.y+1
   check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   pos1.y=pos1.y-2
   check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   pos1.y=pos1.y+1
   pos1.z=pos1.z+1
   check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   pos1.z=pos1.z-2
   check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   pos1.z=pos1.z+1
end
function check_HV_node_subp (PR_nodes,RE_nodes,BA_nodes,HV_nodes,pos1)
   local meta = minetest.env:get_meta(pos1)
   local name = minetest.env:get_node(pos1).name
   if meta:get_float("hv_cablelike")==1 then
      add_new_HVcable_node(HV_nodes,pos1)
   elseif HV_machines[name] then
      --print(name.." is a "..HV_machines[name])
      if     HV_machines[name] == "PR" then
     add_new_HVcable_node(PR_nodes,pos1)
      elseif HV_machines[name] == "RE" then
     add_new_HVcable_node(RE_nodes,pos1)
      elseif HV_machines[name] == "BA" then
     add_new_HVcable_node(BA_nodes,pos1)
      end
   end
end
technic/battery_box_mv.lua
@@ -1,11 +1,4 @@
-- register MV machines here
technic.MV_machines = {}
--local MV_machines = {}
local MV_machines = technic.MV_machines
function register_MV_machine(string1,string2)
   technic.MV_machines[string1] = string2
end
-- MV Battery box
minetest.register_craft(
   {
      output = 'technic:mv_battery_box 1',
@@ -16,7 +9,7 @@
      }
   })
mv_battery_box_formspec =
local battery_box_formspec =
   "invsize[8,9;]"..
   "image[1,1;1,2;technic_power_meter_bg.png]"..
   "list[current_name;src;3,1;1,1;]"..
@@ -43,73 +36,172 @@
            meta:set_string("infotext", "MV Battery box")
            meta:set_float("technic_mv_power_machine", 1)
            meta:set_string("formspec", battery_box_formspec)
            meta:set_float("internal_EU_buffer", 0)
            meta:set_float("internal_EU_buffer_size", 300000)
            meta:set_int("MV_EU_demand", 0) -- How much can this node charge
            meta:set_int("MV_EU_supply", 0) -- How much can this node discharge
            meta:set_int("MV_EU_input",  0) -- How much power is this machine getting.
            meta:set_float("internal_EU_charge", 0)
            inv:set_size("src", 1)
            inv:set_size("dst", 1)
             end,
      can_dig = function(pos,player)
           if pos==nil then return end
           local meta = minetest.env:get_meta(pos);
           local inv = meta:get_inventory()
           if not inv:is_empty("dst") then
           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
           elseif not inv:is_empty("src") then
              return false
           else
              return true
           end
           return true
        end
        end,
   })
for i=1,8,1 do
   minetest.register_node(
      "technic:mv_battery_box"..i, {
      "technic:mv_battery_box"..i,
      {
     description = "MV Battery Box",
     tiles  = {"technic_mv_battery_box_top.png", "technic_mv_battery_box_bottom.png", "technic_mv_battery_box_side0.png^technic_power_meter"..i..".png",
           "technic_mv_battery_box_side0.png^technic_power_meter"..i..".png", "technic_mv_battery_box_side0.png^technic_power_meter"..i..".png", "technic_mv_battery_box_side0.png^technic_power_meter"..i..".png"},
     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
     sounds = default.node_sound_wood_defaults(),
     drop   = "technic:mv_battery_box",
     on_construct = function(pos)
               if pos==nil then return end
               local meta = minetest.env:get_meta(pos);
               local inv = meta:get_inventory()
               meta:set_string("infotext", "MV Battery box")
               meta:set_float("technic_mv_power_machine", 1)
               meta:set_string("formspec", battery_box_formspec)
               meta:set_float("internal_EU_buffer", 0)
               meta:set_float("internal_EU_buffer_size", 300000)
               inv:set_size("src", 1)
               inv:set_size("dst", 1)
            end,
     can_dig = function(pos,player)
              if pos==nil then return end
              local meta = minetest.env:get_meta(pos);
              local inv = meta:get_inventory()
              if not inv:is_empty("dst") then
              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
              elseif not inv:is_empty("src") then
             return false
              else
             return true
              end
              return true
           end
           end,
      })
end
local power_tools = technic.MV_power_tools
local charge_MV_tools = function(meta, charge)
             --charge registered power tools
             local inv = meta:get_inventory()
             if inv:is_empty("src")==false  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 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"])
               if src_meta==nil then
                  src_meta={}
                  src_meta["technic_mv_power_tool"]=true
                  src_meta["charge"]=0
               else
                  if src_meta["technic_mv_power_tool"]==nil then
                 src_meta["technic_mv_power_tool"]=true
                 src_meta["charge"]=0
                  end
               end
               -- Do the charging
               local item_max_charge = power_tools[toolname]
               local load            = src_meta["charge"]
               local load_step       = 1000 -- how much to charge per tick
               if load<item_max_charge and charge>0 then
                  if charge-load_step<0 then load_step=charge end
                  if load+load_step>item_max_charge then load_step=item_max_charge-load end
                  load=load+load_step
                  charge=charge-load_step
                  technic.set_RE_wear(src_item,load,item_max_charge)
                  src_meta["charge"]   = load
                  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
local discharge_MV_tools = function(meta, charge, max_charge)
            -- discharging registered power tools
            local inv = meta:get_inventory()
            if inv:is_empty("dst") == false 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 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"])
                  if src_meta==nil then
                 src_meta={}
                 src_meta["technic_mv_power_tool"]=true
                 src_meta["charge"]=0
                  else
                 if src_meta["technic_mv_power_tool"]==nil then
                    src_meta["technic_mv_power_tool"]=true
                    src_meta["charge"]=0
                 end
                  end
                  -- Do the discharging
                  local item_max_charge = power_tools[toolname]
                  local load            = src_meta["charge"]
                  local load_step       = 4000 -- how much to discharge per tick
                  if load>0 and charge<max_charge then
                 if charge+load_step>max_charge then load_step=max_charge-charge end
                 if load-load_step<0 then load_step=load end
                 load=load-load_step
                 charge=charge+load_step
                 technic.set_RE_wear(src_item,load,item_max_charge)
                 src_meta["charge"]=load
                 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
minetest.register_abm(
   {nodenames = {"technic:mv_battery_box","technic:mv_battery_box1","technic:mv_battery_box2","technic:mv_battery_box3","technic:mv_battery_box4",
         "technic:mv_battery_box5","technic:mv_battery_box6","technic:mv_battery_box7","technic:mv_battery_box8"
          },
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local meta       = minetest.env:get_meta(pos)
        local max_charge = 300000 -- Set maximum charge for the device here
        local charge     = meta:get_int("internal_EU_buffer")
   {
      nodenames = {"technic:mv_battery_box","technic:mv_battery_box1","technic:mv_battery_box2","technic:mv_battery_box3","technic:mv_battery_box4",
           "technic:mv_battery_box5","technic:mv_battery_box6","technic:mv_battery_box7","technic:mv_battery_box8"
        },
      interval = 1,
      chance   = 1,
      action = function(pos, node, active_object_count, active_object_count_wider)
        local meta               = minetest.env:get_meta(pos)
        local max_charge         = 300000 -- Set maximum charge for the device here
        local max_charge_rate    = 2000   -- Set maximum rate of charging (4000)
        local max_discharge_rate = 3000   -- Set maximum rate of discharging
        local eu_input           = meta:get_int("MV_EU_input")
        local current_charge     = meta:get_int("internal_EU_charge") -- Battery charge right now
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "MV")
        -- 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 = charge_MV_tools(meta, current_charge)
        current_charge = discharge_MV_tools(meta, current_charge, max_charge)
        -- Set a demand (we allow batteries to charge on less than the demand though)
        meta:set_int("MV_EU_demand", math.min(max_charge_rate, max_charge-current_charge))
        -- Set how much we can supply
        meta:set_int("MV_EU_supply", math.min(max_discharge_rate, current_charge))
        meta:set_int("internal_EU_charge", current_charge)
        --dprint("BA: input:"..eu_input.." supply="..meta:get_int("MV_EU_supply").." demand="..meta:get_int("MV_EU_demand").." current:"..current_charge)
        -- Select node textures
        local i = math.ceil((charge/max_charge)*8)
        local i=math.ceil((current_charge/max_charge)*8)
        if i > 8 then i = 8 end
        local j = meta:get_float("last_side_shown")
        if i~=j then
@@ -118,221 +210,25 @@
           meta:set_float("last_side_shown",i)
        end
        --charge registered power tools
        local inv = meta:get_inventory()
        if inv:is_empty("src")==false  then
           local srcstack = inv:get_stack("src", 1)
           local src_item=srcstack:to_table()
           local src_meta=get_item_meta(src_item["metadata"])
           -- Power tools should really be made into a hash table to avoid linear search. But the list is short so okay...
           for i=1,registered_power_tools_count,1 do
              if power_tools[i].tool_name==src_item["name"] then
             -- What is this code doing? Setting tool properties if not set already????
             src_meta=get_item_meta(src_item["metadata"])
             if src_meta==nil then
                src_meta={}
                src_meta["technic_power_tool"]=true
                src_meta["charge"]=0
             else
                if src_meta["technic_power_tool"]==nil then
                   src_meta["technic_power_tool"]=true
                   src_meta["charge"]=0
                end
             end
             -- Do the charging
             local item_max_charge = power_tools[i].max_charge
             local load1           = src_meta["charge"]
             local load_step       = 4000 -- how much to charge per tick
             if load1<item_max_charge and charge>0 then
                if charge-load_step<0 then load_step=charge end
                if load1+load_step>item_max_charge then load_step=item_max_charge-load1 end
                load1=load1+load_step
                charge=charge-load_step
                set_RE_wear(src_item,load1,item_max_charge)
                src_meta["charge"]   = load1
                src_item["metadata"] = set_item_meta(src_meta)
                inv:set_stack("src", 1, src_item)
             end
             meta:set_int("internal_EU_buffer",charge)
             break
              end
           end
        end
        -- discharging registered power tools
        if inv:is_empty("dst") == false then
           srcstack = inv:get_stack("dst", 1)
           src_item=srcstack:to_table()
           local src_meta=get_item_meta(src_item["metadata"])
           local item_max_charge=nil
           for i=1,registered_power_tools_count,1 do
              if power_tools[i].tool_name==src_item["name"] then
             src_meta=get_item_meta(src_item["metadata"])
             if src_meta==nil then
                src_meta={}
                src_meta["technic_power_tool"]=true
                src_meta["charge"]=0
             else
                if src_meta["technic_power_tool"]==nil then
                   src_meta["technic_power_tool"]=true
                   src_meta["charge"]=0
                end
             end
             local item_max_charge = power_tools[i].max_charge
             local load1           = src_meta["charge"]
             local load_step       = 4000 -- how much to discharge per tick
             if load1>0 and charge<max_charge then
                if charge+load_step>max_charge then load_step=max_charge-charge end
                if load1-load_step<0 then load_step=load1 end
                load1=load1-load_step
                charge=charge+load_step
                set_RE_wear(src_item,load1,item_max_charge)
                src_meta["charge"]=load1
                src_item["metadata"]=set_item_meta(src_meta)
                inv:set_stack("dst", 1, src_item)
             end
             meta:set_int("internal_EU_buffer",charge)
             break
              end
           end
        end
        local load = math.floor((charge/300000) * 100)
        local load = math.floor(current_charge/max_charge * 100)
        meta:set_string("formspec",
                mv_battery_box_formspec..
                battery_box_formspec..
                   "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                   (load)..":technic_power_meter_fg.png]"
                 )
        -- Next index the surrounding network the get the producers and receivers on the power grid
        local pos1 = {}
        pos1.y = pos.y-1
        pos1.x = pos.x
        pos1.z = pos.z
        meta1 = minetest.env:get_meta(pos1)
        if meta1:get_float("mv_cablelike")~=1 then return end
        local MV_nodes = {}
        local PR_nodes = {}
        local RE_nodes = {}
        local BA_nodes = {}
        MV_nodes[1]   = {}
        MV_nodes[1].x = pos1.x
        MV_nodes[1].y = pos1.y
        MV_nodes[1].z = pos1.z
        local table_index=1
        repeat
           check_MV_node(PR_nodes,RE_nodes,BA_nodes,MV_nodes,table_index)
           table_index=table_index+1
           if MV_nodes[table_index]==nil then break end
        until false
        -- Get power from all connected producers
        local pr_pos
                for _,pr_pos in ipairs(PR_nodes) do
           local meta1              = minetest.env:get_meta(pr_pos)
           local internal_EU_buffer = meta1:get_float("internal_EU_buffer")
           local charge_to_take     = 1000
           if charge<max_charge then
              if internal_EU_buffer-charge_to_take<=0 then
             charge_to_take=internal_EU_buffer
              end
              if charge_to_take>0 then
             charge=charge+charge_to_take
             internal_EU_buffer=internal_EU_buffer-charge_to_take
             meta1:set_float("internal_EU_buffer",internal_EU_buffer)
              end
           end
        if eu_input == 0 then
           meta:set_string("infotext", "MV Battery box: "..current_charge.."/"..max_charge.." (idle)")
        else
           meta:set_string("infotext", "MV Battery box: "..current_charge.."/"..max_charge)
        end
        if charge>max_charge then charge=max_charge end
        -- Provide power to all connected receivers
        local re_pos
                for _,re_pos in ipairs(RE_nodes) do
           local meta1                   = minetest.env:get_meta(re_pos)
           local internal_EU_buffer      = meta1:get_float("internal_EU_buffer")
           local internal_EU_buffer_size = meta1:get_float("internal_EU_buffer_size")
           local charge_to_give          = math.min(1000, charge/table.getn(RE_nodes))
           if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
              charge_to_give=internal_EU_buffer_size-internal_EU_buffer
           end
           if charge-charge_to_give<0 then charge_to_give=charge end
           internal_EU_buffer=internal_EU_buffer+charge_to_give
           meta1:set_float("internal_EU_buffer",internal_EU_buffer)
           charge=charge-charge_to_give;
        end
        charge=math.floor(charge)
        meta:set_string("infotext", "MV Battery box: "..charge.."/"..max_charge);
        meta:set_int("internal_EU_buffer",charge)
         end
 })
   })
-- Register as a battery type
-- Battery type machines function as power reservoirs and can both receive and give back power
register_MV_machine("technic:mv_battery_box","BA")
technic.register_MV_machine("technic:mv_battery_box","BA")
for i=1,8,1 do
   register_MV_machine("technic:mv_battery_box"..i,"BA")
   technic.register_MV_machine("technic:mv_battery_box"..i,"BA")
end
function add_new_MVcable_node (MV_nodes,pos1)
   if MV_nodes == nil then return true end
   local i=1
   repeat
      if MV_nodes[i]==nil then break end
      if pos1.x==MV_nodes[i].x and pos1.y==MV_nodes[i].y and pos1.z==MV_nodes[i].z then return false end
      i=i+1
   until false
   MV_nodes[i]={}
   MV_nodes[i].x=pos1.x
   MV_nodes[i].y=pos1.y
   MV_nodes[i].z=pos1.z
   return true
end
function check_MV_node(PR_nodes,RE_nodes,BA_nodes,MV_nodes,i)
   local pos1={}
   pos1.x=MV_nodes[i].x
   pos1.y=MV_nodes[i].y
   pos1.z=MV_nodes[i].z
   pos1.x=pos1.x+1
   check_MV_node_subp(PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   pos1.x=pos1.x-2
   check_MV_node_subp(PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   pos1.x=pos1.x+1
   pos1.y=pos1.y+1
   check_MV_node_subp(PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   pos1.y=pos1.y-2
   check_MV_node_subp(PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   pos1.y=pos1.y+1
   pos1.z=pos1.z+1
   check_MV_node_subp(PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   pos1.z=pos1.z-2
   check_MV_node_subp(PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   pos1.z=pos1.z+1
end
function check_MV_node_subp (PR_nodes,RE_nodes,BA_nodes,MV_nodes,pos1)
   local meta = minetest.env:get_meta(pos1)
   local name = minetest.env:get_node(pos1).name
   if meta:get_float("mv_cablelike")==1 then
      add_new_MVcable_node(MV_nodes,pos1)
   elseif MV_machines[name] then
      --print(name.." is a "..MV_machines[name])
      if     MV_machines[name] == "PR" then
     add_new_MVcable_node(PR_nodes,pos1)
      elseif MV_machines[name] == "RE" then
     add_new_MVcable_node(RE_nodes,pos1)
      elseif MV_machines[name] == "BA" then
     add_new_MVcable_node(BA_nodes,pos1)
      end
   end
end
technic/cans.lua
@@ -1,5 +1,5 @@
water_can_max_load = 16
lava_can_max_load = 8
local water_can_max_load = 16
local lava_can_max_load = 8
minetest.register_craft({
    output = 'technic:water_can 1',
@@ -42,7 +42,7 @@
            minetest.env:add_node(pointed_thing.under, {name="air"})
             load=load+1;    
            item["metadata"]=tostring(load)
            set_RE_wear(item,load,water_can_max_load)
            technic.set_RE_wear(item,load,water_can_max_load)
            itemstack:replace(item)
            end
            return itemstack
@@ -54,7 +54,7 @@
            minetest.env:add_node(pointed_thing.under, {name="default:water_source"})
            load=load-1;    
            item["metadata"]=tostring(load)
            set_RE_wear(item,load,water_can_max_load)
            technic.set_RE_wear(item,load,water_can_max_load)
            itemstack:replace(item)
            return itemstack
            end
@@ -64,7 +64,7 @@
            minetest.env:add_node(pointed_thing.above, {name="default:water_source"})
            load=load-1;    
            item["metadata"]=tostring(load)
            set_RE_wear(item,load,water_can_max_load)
            technic.set_RE_wear(item,load,water_can_max_load)
            itemstack:replace(item)
            return itemstack
            end        
@@ -90,7 +90,7 @@
            minetest.env:add_node(pointed_thing.under, {name="air"})
             load=load+1;
            item["metadata"]=tostring(load)
            set_RE_wear(item,load,lava_can_max_load)
            technic.set_RE_wear(item,load,lava_can_max_load)
            itemstack:replace(item)
            end
            return itemstack
@@ -102,7 +102,7 @@
            minetest.env:add_node(pointed_thing.under, {name="default:lava_source"})
            load=load-1;    
            item["metadata"]=tostring(load)
            set_RE_wear(item,load,lava_can_max_load)
            technic.set_RE_wear(item,load,lava_can_max_load)
            itemstack:replace(item)
            return itemstack
            end
@@ -112,7 +112,7 @@
            minetest.env:add_node(pointed_thing.above, {name="default:lava_source"})
            load=load-1;    
            item["metadata"]=tostring(load)
            set_RE_wear(item,load,lava_can_max_load)
            technic.set_RE_wear(item,load,lava_can_max_load)
            itemstack:replace(item)
            return itemstack
            end    
technic/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
register_power_tool ("technic:chainsaw",chainsaw_max_charge)
technic.register_LV_power_tool ("technic:chainsaw",chainsaw_max_charge)
minetest.register_tool("technic:chainsaw", {
        description = "Chainsaw",
@@ -20,7 +20,7 @@
                        if charge < chainsaw_charge_per_node then return end -- only cut if charged
                        charge=chainsaw_dig_it(minetest.get_pointed_thing_position(pointed_thing, above),user,charge)
                        set_RE_wear(item,charge,chainsaw_max_charge)
                        technic.set_RE_wear(item,charge,chainsaw_max_charge)
                        meta["charge"]=charge
                        item["metadata"]=set_item_meta(meta)
                        itemstack:replace(item)
@@ -33,8 +33,8 @@
        output = 'technic:chainsaw',
        recipe = {
                {'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:battery'},
                {'technic:stainless_steel_ingot', 'technic:motor', 'technic:battery'},
                {'','','default:copper_ingot'},
                {'technic:stainless_steel_ingot', 'technic:motor',                 'technic:battery'},
                {'',                               '',                             'default:copper_ingot'},
        }
})
@@ -266,3 +266,4 @@
        -- Nothing sawed down
        return remaining_charge
end
technic/cnc.lua
@@ -1,11 +1,13 @@
-- Technic CNC v1.0 by kpo
-- Technic CNC v1.0 by kpoppel
-- Based on the NonCubic Blocks MOD v1.4 by yves_de_beck
-- Idea:
--   Somehw have a tabbed/paged panel if the number of shapes should expand
--   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,
@@ -31,24 +33,6 @@
   element_t                = 1,
   element_edge             = 2,
}
--cnc_recipes ={}
--registered_cnc_recipes_count=1
--
--function register_cnc_recipe (string1,string2)
--   cnc_recipes[registered_cnc_recipes_count]={}
--   cnc_recipes[registered_cnc_recipes_count].src_name=string1
--   cnc_recipes[registered_cnc_recipes_count].dst_name=string2
--   registered_cnc_recipes_count=registered_cnc_recipes_count+1
--   if unified_inventory then
--      unified_inventory.register_craft({
--                      type = "cnc milling",
--                      output = string2,
--                      items = {string1},
--                      width = 0,
--                       })
--   end
--end
local cnc_formspec =
   "invsize[9,11;]"..
@@ -88,225 +72,222 @@
   
   "list[current_player;main;0,7;8,4;]"
local cnc_power_formspec=
   "label[0,3;Power]"..
   "image[0,1;1,2;technic_power_meter_bg.png]"
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 form_handler = function(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.env: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 -- callback function
            -- 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.env: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 -- callback function
-- 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},
       },
        },
        selection_box = {
       type = "fixed",
       fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
        },
        groups = {cracky=2},
    legacy_facedir_simple = true,
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=5000;
    cnc_time = 0;
    src_time = 0; -- fixme
    on_construct = function(pos)
              local meta = minetest.env:get_meta(pos)
              meta:set_string("infotext", "CNC Machine Inactive")
              meta:set_float("technic_power_machine", 1)
              meta:set_float("internal_EU_buffer", 0)
              meta:set_float("internal_EU_buffer_size", 5000)
              meta:set_string("formspec", cnc_formspec..cnc_power_formspec)
              meta:set_float("cnc_time", 0)
              local inv = meta:get_inventory()
              inv:set_size("src", 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("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,
     })
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},
     },
      },
      selection_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.env: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.env: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.env: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,
})
              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.env: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.env:get_meta(pos)
          local charge= meta:get_float("internal_EU_buffer")
          local max_charge= meta:get_float("internal_EU_buffer_size")
          local cnc_cost=350
          local load = math.floor((charge/max_charge)*100)
          meta:set_string("formspec", cnc_formspec..
                  "image[0,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                  (load)..":technic_power_meter_fg.png]"
                )
          local inv = meta:get_inventory()
          local srclist = inv:get_list("src")
          if inv:is_empty("src") then
             meta:set_float("cnc_on",0)
             meta:set_string("cnc_product", "") -- Reset the program
          end
          if (meta:get_float("cnc_on") == 1) then
             if charge>=cnc_cost then
            charge=charge-cnc_cost;
            meta:set_float("internal_EU_buffer",charge)
            meta:set_float("src_time", meta:get_float("src_time") + 1)
            if meta:get_float("src_time") >= meta:get_float("cnc_time") then
               local product = meta:get_string("cnc_product")
               if inv:room_for_item("dst",product) then
                  -- CNC does the transformation
                  ------------------------------
                  if minetest.registered_nodes[product] ~= nil then
                 inv:add_item("dst",product .. " " .. meta:get_float("cnc_multiplier"))
                 srcstack = inv:get_stack("src", 1)
                 srcstack:take_item()
                 inv:set_stack("src",1,srcstack)
                 if inv:is_empty("src") then
                    meta:set_float("cnc_on",0)
                    meta:set_string("cnc_product", "") -- Reset the program
--                    print("cnc product reset")
                 end
                  else
                 minetest.chat_send_player(meta:get_string("cnc_user"), "CNC machine does not know how to handle this material. Please remove it.");
                  end
               else
                  minetest.chat_send_player(meta:get_string("cnc_user"), "CNC inventory full!")
               end
               meta:set_float("src_time", 0)
            end
             end
          end
   { nodenames = {"technic:cnc","technic:cnc_active"},
     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("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
          if (meta:get_float("cnc_on")==0) then
             if not inv:is_empty("src") then
            local product = meta:get_string("cnc_product")
            if minetest.registered_nodes[product] ~= nil then
               meta:set_float("cnc_on",1)
               hacky_swap_node(pos,"technic:cnc_active")
               meta:set_string("infotext", "CNC Machine Active")
               cnc_time=3
               meta:set_float("cnc_time",cnc_time)
               meta:set_float("src_time", 0)
               return
            end
             else
            hacky_swap_node(pos,"technic:cnc")
            meta:set_string("infotext", "CNC Machine Inactive")
             end
          end
           end
   })
         -- Machine information
         local machine_name         = "CNC"
         local machine_node         = "technic:cnc"
         local machine_state_demand = { 50, 450 }
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            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")
         -- State machine
         if eu_input == 0 then
            -- Unpowered - go idle
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            local inv   = meta:get_inventory()
            local empty = inv:is_empty("src")
register_LV_machine ("technic:cnc","RE")
register_LV_machine ("technic:cnc_active","RE")
            if state == 1 then
               hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Idle")
               local result = meta:get_string("cnc_product")
               if not empty and minetest.registered_nodes[result] ~= nil and inv:room_for_item("dst",result) then
              next_state = 2
               else
              meta:set_string("cnc_product", "") -- Reset the program
               end
               --minetest.chat_send_player(meta:get_string("cnc_user"), "CNC machine does not know how to handle this material. Please remove it.");
            elseif state == 2 then
               hacky_swap_node(pos, machine_node.."_active")
               meta:set_string("infotext", machine_name.." Active")
               if empty then
              next_state = 1
               else
              meta:set_int("src_time", meta:get_int("src_time") + 1)
              if meta:get_int("src_time") >= 3 then -- 3 ticks per output
                 local result = meta:get_string("cnc_product")
                 -- check if there's room for output in "dst" list
                 if inv:room_for_item("dst",result) then
                -- CNC does the transformation
                ------------------------------
                meta:set_int("src_time", 0)
                -- take stuff from "src" list
                srcstack = inv:get_stack("src", 1)
                srcstack:take_item()
                inv:set_stack("src", 1, srcstack)
                -- Put result in "dst" list
                inv:add_item("dst",result .. " " .. meta:get_int("cnc_multiplier"))
                 else
                next_state = 1
                 end
              end
               end
            end
         end
         -- Change state?
         if next_state ~= state then
            meta:set_int("LV_EU_demand", machine_state_demand[next_state])
            meta:set_int("state", next_state)
         end
          end
  })
technic.register_LV_machine ("technic:cnc","RE")
technic.register_LV_machine ("technic:cnc_active","RE")
-------------------------
-- 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'},
               },
            })
-------------------------
    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/electric_furnace.lua
@@ -1,171 +1,160 @@
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'},
    }
})
-- 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'},
    }
 })
electric_furnace_formspec =
    "invsize[8,9;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "list[current_name;src;3,1;1,1;]"..
    "list[current_name;dst;5,1;2,2;]"..
    "list[current_player;main;0,5;8,4;]"..
    "label[0,0;LV Electric Furnace]"..
    "label[1,3;Power level]"..
    "background[-0.19,-0.25;8.4,9.75;ui_form_bg.png]"..
    "background[0,0;8,4;ui_lv_electric_furnace.png]"..
    "background[0,5;8,4;ui_main_inventory.png]"
minetest.register_node("technic:electric_furnace", {
    description = "LV Electric Furnace",
    tiles = {"technic_electric_furnace_top.png", "technic_electric_furnace_bottom.png", "technic_electric_furnace_side.png",
        "technic_electric_furnace_side.png", "technic_electric_furnace_side.png", "technic_electric_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2},
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", electric_furnace_formspec)
        meta:set_string("infotext", "Electric Furnace")
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 4)
        local EU_used  = 0
        local furnace_is_cookin = 0
        local cooked = nil
        meta:set_float("internal_EU_buffer",0)
        meta:set_float("internal_EU_buffer_size",2000)
local electric_furnace_formspec =
   "invsize[8,9;]"..
   "list[current_name;src;3,1;1,1;]"..
   "list[current_name;dst;5,1;2,2;]"..
   "list[current_player;main;0,5;8,4;]"..
   "label[0,0;Electric Furnace]"..
   "label[1,3;Power level]"
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false
        elseif not inv:is_empty("src") then
            return false
        end
        return true
    end,
})
minetest.register_node(
   "technic:electric_furnace",
   {description = "Electric furnace",
    tiles = {"technic_electric_furnace_top.png", "technic_electric_furnace_bottom.png", "technic_electric_furnace_side.png",
         "technic_electric_furnace_side.png", "technic_electric_furnace_side.png", "technic_electric_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("infotext", "Electric Furnace")
              meta:set_float("technic_power_machine", 1)
              meta:set_string("formspec", electric_furnace_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.env: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:electric_furnace_active", {
    description = "LV Electric Furnace",
    tiles = {"technic_electric_furnace_top.png", "technic_electric_furnace_bottom.png", "technic_electric_furnace_side.png",
        "technic_electric_furnace_side.png", "technic_electric_furnace_side.png", "technic_electric_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:electric_furnace",
    groups = {cracky=2, not_in_creative_inventory=1},
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    technic_power_machine=1,
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_string("formspec", electric_furnace_formspec)
        meta:set_string("infotext", "LV Electric Furnace");
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 4)
        local EU_used  = 0
        local furnace_is_cookin = 0
        local cooked = nil
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false
        elseif not inv:is_empty("src") then
            return false
        end
        return true
    end,
})
minetest.register_node(
   "technic:electric_furnace_active",
   {description = "Electric Furnace",
    tiles = {"technic_electric_furnace_top.png", "technic_electric_furnace_bottom.png", "technic_electric_furnace_side.png",
         "technic_electric_furnace_side.png", "technic_electric_furnace_side.png", "technic_electric_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:electric_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("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:electric_furnace","technic:electric_furnace_active"},
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
minetest.register_abm(
   { nodenames = {"technic:electric_furnace","technic:electric_furnace_active"},
     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("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
        local meta = minetest.env:get_meta(pos)
        internal_EU_buffer=meta:get_float("internal_EU_buffer")
        internal_EU_buffer_size=meta:get_float("internal_EU_buffer_size")
        local load = math.floor(internal_EU_buffer/internal_EU_buffer_size * 100)
        meta:set_string("formspec",
                electric_furnace_formspec..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                    (load)..":technic_power_meter_fg.png]")
         -- Machine information
         local machine_name         = "Electric furnace"
         local machine_node         = "technic:electric_furnace"
         local machine_state_demand = { 50, 1000 }
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            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")
         -- State machine
         if eu_input == 0 then
            -- Unpowered - go idle
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            -- Execute always if powered logic
            local inv    = meta:get_inventory()
            local empty  = inv:is_empty("src")
        local inv = meta:get_inventory()
        local furnace_is_cookin = meta:get_float("furnace_is_cookin")
        local srclist = inv:get_list("src")
        local cooked=nil
            if state == 1 then
               hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Idle")
        if srclist then
         cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
        end
        if (furnace_is_cookin == 1) then
            if internal_EU_buffer>=150 then
            internal_EU_buffer=internal_EU_buffer-150;
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
            meta:set_float("src_time", meta:get_float("src_time") + 3)
            if cooked and cooked.item and meta:get_float("src_time") >= cooked.time then
                -- check if there's room for output in "dst" list
                if inv:room_for_item("dst",cooked.item) then
                    -- Put result in "dst" list
                    inv:add_item("dst", cooked.item)
                    -- take stuff from "src" list
                    srcstack = inv:get_stack("src", 1)
                    srcstack:take_item()
                    inv:set_stack("src", 1, srcstack)
                else
                    print("Furnace inventory full!")
                end
                meta:set_string("src_time", 0)
            end
            end
        end
               local result = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")})
               if not empty and result and inv:room_for_item("dst",result) then
              next_state = 2
               end
            elseif state == 2 then
               hacky_swap_node(pos, machine_node.."_active")
               meta:set_string("infotext", machine_name.." Active")
        if srclist then
            cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
            if cooked.time>0 then
            hacky_swap_node(pos,"technic:electric_furnace_active")
            meta:set_string("infotext","Furnace active")
            meta:set_string("furnace_is_cookin",1)
            meta:set_string("src_time", 0)
            return
            end
               if empty then
              next_state = 1
               else
              meta:set_int("src_time", meta:get_int("src_time") + 3) -- Cooking time 3x
              local result = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")})
              if result and result.item and meta:get_int("src_time") >= result.time then
                 -- check if there's room for output in "dst" list
                 meta:set_int("src_time", 0)
                 if inv:room_for_item("dst",result.item) then
                -- take stuff from "src" list
                srcstack = inv:get_stack("src", 1)
                srcstack:take_item()
                inv:set_stack("src", 1, srcstack)
                -- Put result in "dst" list
                inv:add_item("dst", result.item)
                 else
                -- all full: go idle
                next_state = 1
                 end
              end
               end
            end
         end
         -- Change state?
         if next_state ~= state then
            meta:set_int("LV_EU_demand", machine_state_demand[next_state])
            meta:set_int("state", next_state)
         end
          end,
  })
        end
technic.register_LV_machine ("technic:electric_furnace","RE")
technic.register_LV_machine ("technic:electric_furnace_active","RE")
                hacky_swap_node(pos,"technic:electric_furnace")
                meta:set_string("infotext","Furnace inactive")
                meta:set_string("furnace_is_cookin",0)
                meta:set_string("src_time", 0)
end,
})
register_LV_machine ("technic:electric_furnace","RE")
register_LV_machine ("technic:electric_furnace_active","RE")
technic/electric_furnace_mv.lua
@@ -1,279 +1,304 @@
minetest.register_craft({
    output = 'technic:mv_electric_furnace',
    recipe = {
        {'technic:stainless_steel_ingot', 'technic:electric_furnace', 'technic:stainless_steel_ingot'},
        {'pipeworks:tube_000000', 'technic:mv_transformer', 'pipeworks:tube_000000'},
        {'technic:stainless_steel_ingot', 'technic:mv_cable', 'technic:stainless_steel_ingot'},
    }
})
-- 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:electric_furnace', 'technic:stainless_steel_ingot'},
       {'pipeworks:tube_000000', 'technic:mv_transformer', 'pipeworks:tube_000000'},
       {'technic:stainless_steel_ingot', 'technic:mv_cable', 'technic:stainless_steel_ingot'},
    }
 })
mv_electric_furnace_formspec =
    "invsize[8,10;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "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;MV Electric Furnace]"..
    "label[1,2.8;Power level]"..
    "list[current_name;upgrade1;1,4;1,1;]"..
    "list[current_name;upgrade2;2,4;1,1;]"..
    "label[1,5;Upgrade Slots]"
local mv_electric_furnace_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;MV Electric Furnace]"..
   "list[current_name;upgrade1;1,4;1,1;]"..
   "list[current_name;upgrade2;2,4;1,1;]"..
   "label[1,5;Upgrade Slots]"
minetest.register_node("technic:mv_electric_furnace", {
    description = "MV Electric furnace",
    tiles = {"technic_mv_electric_furnace_top.png", "technic_mv_electric_furnace_bottom.png", "technic_mv_electric_furnace_side_tube.png",
        "technic_mv_electric_furnace_side_tube.png", "technic_mv_electric_furnace_side.png", "technic_mv_electric_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1,},
        tube={insert_object=function(pos,node,stack,direction)
            local meta=minetest.env:get_meta(pos)
            local inv=meta:get_inventory()
                return inv:add_item("src",stack)
        end,
        can_insert=function(pos,node,stack,direction)
minetest.register_node(
   "technic:mv_electric_furnace",
   {description = "MV Electric furnace",
    tiles = {"technic_mv_electric_furnace_top.png", "technic_mv_electric_furnace_bottom.png", "technic_mv_electric_furnace_side_tube.png",
         "technic_mv_electric_furnace_side_tube.png", "technic_mv_electric_furnace_side.png", "technic_mv_electric_furnace_front.png"},
    paramtype2 = "facedir",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1,},
    tube={insert_object=function(pos,node,stack,direction)
               local meta=minetest.env: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.env:get_meta(pos)
            local inv=meta:get_inventory()
            return inv:room_for_item("src",stack)
        end,
        },
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_mv_power_machine", 1)
        meta:set_string("formspec", mv_electric_furnace_formspec)
        meta:set_string("infotext", "Electric furnace")
        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)
        local EU_used  = 0
        local furnace_is_cookin = 0
        local cooked = nil
        meta:set_float("internal_EU_buffer",0)
        meta:set_float("internal_EU_buffer_size",2000)
        meta:set_float("tube_time", 0)
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false
        elseif not inv:is_empty("src") then
            return false
        elseif not inv:is_empty("upgrade1") then
            return false
        elseif not inv:is_empty("upgrade2") then
            return false
        end
        return true
    end,
})
             end,
       },
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    on_construct = function(pos)
              local meta = minetest.env:get_meta(pos)
              meta:set_string("infotext", "MV Electric furnace")
              meta:set_float("technic_mv_power_machine", 1)
              meta:set_int("tube_time",  0)
              meta:set_string("formspec", mv_electric_furnace_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.env: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:mv_electric_furnace_active", {
    description = "MV Electric Furnace",
    tiles = {"technic_mv_electric_furnace_top.png", "technic_mv_electric_furnace_bottom.png", "technic_mv_electric_furnace_side_tube.png",
        "technic_mv_electric_furnace_side_tube.png", "technic_mv_electric_furnace_side.png", "technic_mv_electric_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:mv_electric_furnace",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1,not_in_creative_inventory=1},
    tube={insert_object=function(pos,node,stack,direction)
            local meta=minetest.env:get_meta(pos)
            local inv=meta:get_inventory()
                return inv:add_item("src",stack)
        end,
        can_insert=function(pos,node,stack,direction)
minetest.register_node(
   "technic:mv_electric_furnace_active",
   {description = "MV Electric Furnace",
    tiles = {"technic_mv_electric_furnace_top.png", "technic_mv_electric_furnace_bottom.png", "technic_mv_electric_furnace_side_tube.png",
         "technic_mv_electric_furnace_side_tube.png", "technic_mv_electric_furnace_side.png", "technic_mv_electric_furnace_front_active.png"},
    paramtype2 = "facedir",
    light_source = 8,
    drop = "technic:mv_electric_furnace",
    groups = {cracky=2, tubedevice=1,tubedevice_receiver=1,not_in_creative_inventory=1},
    tube={insert_object=function(pos,node,stack,direction)
               local meta=minetest.env: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.env:get_meta(pos)
            local inv=meta:get_inventory()
            return inv:room_for_item("src",stack)
        end,
        },
    legacy_facedir_simple = true,
    sounds = default.node_sound_stone_defaults(),
    internal_EU_buffer=0;
    interal_EU_buffer_size=2000;
    technic_power_machine=1,
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_mv_power_machine", 1)
        meta:set_string("formspec", mv_electric_furnace_formspec)
        meta:set_string("infotext", "Electric furnace");
        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)
        local EU_used  = 0
        local furnace_is_cookin = 0
        local cooked = nil
    end,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("dst") then
            return false
        elseif not inv:is_empty("src") then
            return false
        elseif not inv:is_empty("upgrade1") then
            return false
        elseif not inv:is_empty("upgrade2") then
            return false
        end
        return true
    end,
})
             end,
       },
    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("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 99
                       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 99
                       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:mv_electric_furnace","technic:mv_electric_furnace_active"},
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
        local pos1={}
        pos1.x=pos.x
        pos1.y=pos.y
        pos1.z=pos.z
        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 meta=minetest.env:get_meta(pos1)
        if meta:get_int("tubelike")==1 then output_tube_connected=true end
        meta = minetest.env:get_meta(pos)
        local inv = meta:get_inventory()
        local upg_item1
        local upg_item1_name=""
        local upg_item2
        local upg_item2_name=""
        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
        if upg_item1 then upg_item1_name=upg_item1.name end
        if upg_item2 then upg_item2_name=upg_item2.name end
        local speed=0
        if upg_item1_name=="technic:control_logic_unit" then speed=speed+1 end
        if upg_item2_name=="technic:control_logic_unit" then speed=speed+1 end
        tube_time=meta:get_float("tube_time")
        tube_time=tube_time+speed
        if tube_time>3 then
            tube_time=0
            if output_tube_connected then send_cooked_items(pos,x_velocity,z_velocity) end
        end
        meta:set_float("tube_time", tube_time)
        local extra_buffer_size = 0
        if upg_item1_name=="technic:battery" then extra_buffer_size =extra_buffer_size + 10000 end
        if upg_item2_name=="technic:battery" then extra_buffer_size =extra_buffer_size + 10000 end
        local internal_EU_buffer_size=2000+extra_buffer_size
        meta:set_float("internal_EU_buffer_size",internal_EU_buffer_size)
        internal_EU_buffer=meta:get_float("internal_EU_buffer")
        if internal_EU_buffer > internal_EU_buffer_size then internal_EU_buffer = internal_EU_buffer_size end
        local load = math.floor(internal_EU_buffer/(internal_EU_buffer_size) * 100)
        meta:set_string("formspec",
                "invsize[8,10;]"..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                    (load)..":technic_power_meter_fg.png]"..
                "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;MV Electric Furnace]"..
                "label[1,2.8;Power level]"..
                "list[current_name;upgrade1;1,4;1,1;]"..
                "list[current_name;upgrade2;2,4;1,1;]"..
                "label[1,5;Upgrade Slots]")
        local furnace_is_cookin = meta:get_float("furnace_is_cookin")
        local srclist = inv:get_list("src")
        local cooked=nil
        if srclist then
         cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
        end
        if (furnace_is_cookin == 1) then
            if internal_EU_buffer>=150 then
            internal_EU_buffer=internal_EU_buffer-150;
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
            meta:set_float("src_time", meta:get_float("src_time") + 3)
            if cooked and cooked.item and meta:get_float("src_time") >= cooked.time then
                -- check if there's room for output in "dst" list
                if inv:room_for_item("dst",cooked.item) then
                    -- Put result in "dst" list
                    inv:add_item("dst", cooked.item)
                    -- take stuff from "src" list
                    srcstack = inv:get_stack("src", 1)
                    srcstack:take_item()
                    inv:set_stack("src", 1, srcstack)
                else
                    print("Furnace inventory full!")
local send_cooked_items = function(pos,x_velocity,z_velocity)
                 -- Send items on their way in the pipe system.
                 local meta=minetest.env: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
                meta:set_string("src_time", 0)
            end
            end
                 end
              end
               end
local smelt_item = function(pos)
              local meta=minetest.env:get_meta(pos)
              local inv = meta:get_inventory()
              meta:set_int("src_time", meta:get_int("src_time") + 3) -- Cooking time 3x faster
              local result = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")})
              if result and result.item and meta:get_int("src_time") >= result.time then
             meta:set_int("src_time", 0)
             -- check if there's room for output in "dst" list
             if inv:room_for_item("dst",result) then
                -- take stuff from "src" list
                srcstack = inv:get_stack("src", 1)
                srcstack:take_item()
                inv:set_stack("src", 1, srcstack)
                -- Put result in "dst" list
                inv:add_item("dst", result.item)
                return 1
             else
                return 0 -- done
             end
              end
              return 0 -- done
           end
minetest.register_abm(
   {nodenames = {"technic:mv_electric_furnace","technic:mv_electric_furnace_active"},
    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 state        = meta:get_int("state")
        local next_state   = state
        -- Machine information
        local machine_name         = "MV Electric Furnace"
        local machine_node         = "technic:mv_electric_furnace"
        local machine_state_demand = { 50, 2000, 1500, 1000 }
        -- Setup meta data if it does not exist. state is used as an indicator of this
        if state == 0 then
           meta:set_int("state", 1)
           meta:set_int("MV_EU_demand", machine_state_demand[1])
           meta:set_int("MV_EU_input", 0)
           return
        end
        if srclist then
            cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
            if cooked.time>0 then
            hacky_swap_node(pos,"technic:mv_electric_furnace_active")
            meta:set_string("infotext","Furnace active")
            meta:set_string("furnace_is_cookin",1)
            meta:set_string("src_time", 0)
            return
            end
        -- Power off automatically if no longer connected to a switching station
        technic.switching_station_timeout_count(pos, "MV")
        -- Execute always logic
        -- CODE HERE --
        -- State machine
        if eu_input == 0 then
           -- Unpowered - go idle
           hacky_swap_node(pos, machine_node)
           meta:set_string("infotext", machine_name.." Unpowered")
           next_state = 1
        elseif eu_input == machine_state_demand[state] then
           -- Powered - do the state specific actions
           -- Execute always if powered logic
           local meta=minetest.env:get_meta(pos)
           -- Get the names of the upgrades
           local meta=minetest.env:get_meta(pos)
           local inv = meta:get_inventory()
           local upg_item1
           local upg_item1_name=""
           local upg_item2
           local upg_item2_name=""
           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
           if upg_item1 then upg_item1_name=upg_item1.name end
           if upg_item2 then upg_item2_name=upg_item2.name end
           -- Save some power by installing battery upgrades. Fully upgraded makes this
           -- furnace use the same amount of power as the LV version
           local EU_saving_upgrade = 0
           if upg_item1_name=="technic:battery" then EU_saving_upgrade = EU_saving_upgrade + 1 end
           if upg_item2_name=="technic:battery" then EU_saving_upgrade = EU_saving_upgrade + 1 end
           -- Tube loading speed can be upgraded using control logic units
           local tube_speed_upgrade = 0
           if upg_item1_name=="technic:control_logic_unit" then tube_speed_upgrade = tube_speed_upgrade + 1 end
           if upg_item2_name=="technic:control_logic_unit" then tube_speed_upgrade = tube_speed_upgrade + 1 end
           -- Handle pipeworks (consumes tube_speed_upgrade)
           local pos1={x=pos.x, y=pos.y, z=pos.z}
           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.env: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_speed_upgrade
           if tube_time > 3 then
              tube_time = 0
              if output_tube_connected then
             send_cooked_items(pos,x_velocity,z_velocity)
              end
           end
           meta:set_int("tube_time", tube_time)
           -- The machine shuts down if we have nothing to smelt and no tube is connected
           -- or if we have nothing to send with a tube connected.
           if    (not output_tube_connected and inv:is_empty("src"))
           or (    output_tube_connected and inv:is_empty("dst")) then
           next_state = 1
        end
                hacky_swap_node(pos,"technic:mv_electric_furnace")
                meta:set_string("infotext","Furnace inactive")
                meta:set_string("furnace_is_cookin",0)
                meta:set_string("src_time", 0)
end,
})
function send_cooked_items (pos,x_velocity,z_velocity)
        local meta=minetest.env: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
        ----------------------
        if state == 1 then
           hacky_swap_node(pos, machine_node)
           meta:set_string("infotext", machine_name.." Idle")
           local meta=minetest.env:get_meta(pos)
           local inv = meta:get_inventory()
           if not inv:is_empty("src") then
              local result = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")})
              if result then
             meta:set_string("infotext", machine_name.." Active")
             meta:set_int("src_time",     0)
             next_state = 2+EU_saving_upgrade -- Next state is decided by the battery upgrade (state 2= 0 batteries, state 3 = 1 battery, 4 = 2 batteries)
              end
           else
              meta:set_string("infotext", "Electric Furnace Idle")
           end
        elseif state == 2 or state == 3 or state == 4 then
           hacky_swap_node(pos, machine_node.."_active")
           meta:set_string("infotext", machine_name.." Active")
           result = smelt_item(pos, data)
           if result == 0 then
              next_state = 1
           end
        end
end
         end
         -- Change state?
         if next_state ~= state then
        meta:set_int("MV_EU_demand", machine_state_demand[next_state])
        meta:set_int("state", next_state)
         end
      end,
 })
register_MV_machine ("technic:mv_electric_furnace","RE")
register_MV_machine ("technic:mv_electric_furnace_active","RE")
technic.register_MV_machine ("technic:mv_electric_furnace","RE")
technic.register_MV_machine ("technic:mv_electric_furnace_active","RE")
technic/extractor.lua
New file
@@ -0,0 +1,220 @@
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_cable', 'technic:treetap'},
                  {'','',''},
               }
            })
minetest.register_craftitem("technic:extractor", {
                   description = "Extractor",
                   stack_max = 99,
                })
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.env:get_meta(pos)
            meta:set_string("infotext", "Extractor")
            meta:set_float("technic_power_machine", 1)
            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.env: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.env: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)
         -- Run a machine through its states. Takes the same arguments as the ABM action
         -- and adds the machine's states and any extra data which is needed by the machine.
         -- A machine is characterized by running through a set number of states (usually 2:
         -- Idle and active) in some order. A state decides when to move to the next one
         -- and the machine only changes state if it is powered correctly.
         -- The machine will automatically shut down if disconnected from power in some fashion.
         local meta         = minetest.env:get_meta(pos)
         local eu_input     = meta:get_int("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
         -- Machine information
         local machine_name         = "Extractor"
         local machine_node         = "technic:extractor"
         local machine_state_demand = { 50, 300 }
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            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")
         -- State machine
         if eu_input == 0 then
            -- unpowered - go idle
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            local inv    = meta:get_inventory()
            local empty  = inv:is_empty("src")
            local srcstack  = inv:get_stack("src", 1)
            local src_item = nil
            local recipe = nil
            local result = nil
            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 state == 1 then
               hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Idle")
               if not empty and result and inv:room_for_item("dst",result) then
              meta:set_int("src_time", 0)
              next_state = 2
               end
            elseif state == 2 then
               hacky_swap_node(pos, machine_node.."_active")
               meta:set_string("infotext", machine_name.." Active")
               if empty then
              next_state = 1
               else
              meta:set_int("src_time", meta:get_int("src_time") + 1)
              if meta:get_int("src_time") == 4 then -- 4 ticks per output
                 -- check if there's room for output in "dst" list
                 meta:set_int("src_time", 0)
                 if recipe and inv:room_for_item("dst",result) then
                -- take stuff from "src" list
                srcstack:take_item(recipe.src_count)
                    inv:set_stack("src", 1, srcstack)
                -- Put result in "dst" list
                inv:add_item("dst", result)
                 else
                -- all full: go idle
                next_state = 1
                 end
              end
               end
            end
         end
         -- Change state?
         if next_state ~= state then
            meta:set_int("LV_EU_demand", machine_state_demand[next_state])
            meta:set_int("state", next_state)
         end
          end
  })
technic.register_LV_machine ("technic:extractor","RE")
technic.register_LV_machine ("technic:extractor_active","RE")
technic/flashlight.lua
@@ -1,7 +1,7 @@
-- original code comes from walkin_light mod by Echo http://minetest.net/forum/viewtopic.php?id=2621
flashlight_max_charge=30000
register_power_tool ("technic:flashlight",flashlight_max_charge)
local flashlight_max_charge=30000
technic.register_LV_power_tool ("technic:flashlight",flashlight_max_charge)
      
minetest.register_tool("technic:flashlight", {
    description = "Flashlight",
@@ -161,7 +161,7 @@
            charge=meta["charge"]
            if charge-2>0 then
             charge =charge-2;    
            set_RE_wear(item,charge,flashlight_max_charge)
            technic.set_RE_wear(item,charge,flashlight_max_charge)
            meta["charge"]=charge
            item["metadata"]=set_item_meta(meta)
            hotbar[i]:replace(item)
technic/forcefield.lua
@@ -1,7 +1,11 @@
--Forcefield mod by ShadowNinja
-- Forcefield mod by ShadowNinja
-- Modified by kpoppel
--
-- Forcefields are powerful barriers but they consume huge amounts of power.
-- Forcefield Generator is a HV machine.
local forcefield_emitter_buffer_size = 10000
local forcefield_emitter_power_consumption = 0.8
-- How expensive is the generator? Leaves room for upgrades lowering the power drain?
local forcefield_power_drain     = 10 -- default 10
local forcefield_update_interval = 1
minetest.register_craft({
@@ -13,22 +17,13 @@
    }
})
local function get_forcefield_count(range)
    local count = 0
    for x=-range,range do
    for y=-range,range do
    for z=-range,range do
        if ((x*x+y*y+z*z) <= (range * range + range)) then
            if (y == 0) or ((range-1) * (range-1) + (range-1) <= x*x+y*y+z*z) then
                count = count + 1
            end
        end
    end
    end
    end
    return count
end
-- Idea: Let forcefields have different colors by upgrade slot.
-- Idea: Let forcefields add up by detecting if one hits another.
--    ___   __
--   /   \/   \
--  |          |
--   \___/\___/
--
local function add_forcefield(pos, range)
    for x=-range,range do
    for y=-range,range do
@@ -66,69 +61,90 @@
    end
end
forcefield_receive_fields = function(pos, formname, fields, sender)
    local meta = minetest.env:get_meta(pos)
    local range = meta:get_int("range")
    if fields.add then range = range + 1 end
    if fields.subtract then range = range - 1 end
    if fields.toggle then
        if meta:get_int("enabled") == 1 then
            meta:set_int("enabled", 0)
        else
            meta:set_int("enabled", 1)
        end
    end
    if range <= 20 and range >= 0 and meta:get_int("range") ~= range then
        remove_forcefield(pos, meta:get_int("range"))
        meta:set_int("range", range)
        local buffer = meta:get_float("internal_EU_buffer")
        local buffer_size = meta:get_float("internal_EU_buffer_size")
        local load = math.floor(buffer / buffer_size * 100)
        meta:set_string("formspec", get_forcefield_formspec(range, 0))
    end
end
function get_forcefield_formspec(range, load)
    if not load then load = 0 end
    return "invsize[8,9;]"..
local get_forcefield_formspec = function(range)
   --    return "invsize[8,9;]"..  (if upgrades added later - colors for instance)
    return "invsize[3,4;]"..
    "label[0,0;Forcefield emitter]"..
    "label[1,3;Power level]"..
    "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
    load..":technic_power_meter_fg.png]"..
    "label[4,1;Range]"..
    "label[4,2;"..range.."]"..
    "button[3,2;1,1;add;+]"..
    "button[5,2;1,1;subtract;-]"..
    "button[3,3;3,1;toggle;Enable/Disable]"..
    "list[current_player;main;0,5;8,4;]"
    "label[1,1;Range]"..
    "label[1,2;"..range.."]"..
    "button[0,2;1,1;subtract;-]"..
    "button[2,2;1,1;add;+]"..
    "button[0,3;3,1;toggle;Enable/Disable]" -- ..
--    "list[current_player;main;0,5;8,4;]"
end
local function forcefield_check(pos)
    local meta = minetest.env:get_meta(pos)
    local node = minetest.env:get_node(pos)
    local internal_EU_buffer=meta:get_float("internal_EU_buffer")
    local internal_EU_buffer_size=meta:get_float("internal_EU_buffer_size")
local forcefield_receive_fields = function(pos, formname, fields, sender)
                     local meta = minetest.env:get_meta(pos)
                     local range = meta:get_int("range")
                     if fields.add then range = range + 1 end
                     if fields.subtract then range = range - 1 end
                     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.
                     if range < 5  then range = 5 end
                     if range > 20 then range = 20 end
    local load = math.floor(internal_EU_buffer/internal_EU_buffer_size * 100)
    meta:set_string("formspec", get_forcefield_formspec(meta:get_int("range"), load))
                     if range <= 20 and range >= 5 and meta:get_int("range") ~= range then
                    remove_forcefield(pos, meta:get_int("range"))
                    meta:set_int("range", range)
                    meta:set_string("formspec", get_forcefield_formspec(range))
                     end
                  end
    local power_requirement = get_forcefield_count(meta:get_int("range")) * forcefield_emitter_power_consumption
    if meta:get_int("enabled") == 1 and internal_EU_buffer >= power_requirement then
        if node.name == "technic:forcefield_emitter_off" then
            hacky_swap_node(pos, "technic:forcefield_emitter_on")
        end
        internal_EU_buffer=internal_EU_buffer-power_requirement;
        meta:set_float("internal_EU_buffer", internal_EU_buffer)
        add_forcefield(pos, meta:get_int("range"))
    else
        if node.name == "technic:forcefield_emitter_on" then
            remove_forcefield(pos, meta:get_int("range"))
            hacky_swap_node(pos, "technic:forcefield_emitter_off")
        end
    end
    return true
local forcefield_check = function(pos)
                local meta = minetest.env:get_meta(pos)
                local node = minetest.env:get_node(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")
end
                local power_requirement
                if enabled == 1 then
                   power_requirement = math.floor(4*math.pi*math.pow(meta:get_int("range"), 2)) * forcefield_power_drain
                else
                   power_requirement = eu_demand
                end
                if eu_input == 0 then
                   meta:set_string("infotext", "Forcefield Generator Unpowered")
                   meta:set_int("HV_EU_demand", 100)
                   meta:set_int("enabled", 0)
                   if node.name == "technic:forcefield_emitter_on" then
                  remove_forcefield(pos, meta:get_int("range"))
                  hacky_swap_node(pos, "technic:forcefield_emitter_off")
                   end
                elseif eu_input == power_requirement then
                   if meta:get_int("enabled") == 1 then
                  if node.name == "technic:forcefield_emitter_off" then
                     hacky_swap_node(pos, "technic:forcefield_emitter_on")
                     meta:set_string("infotext", "Forcefield Generator Active")
                     add_forcefield(pos, meta:get_int("range"))
                  else
                     -- Range updated. Move the forcefield.
                     add_forcefield(pos, meta:get_int("range"))
                  end
                   else
                  if node.name == "technic:forcefield_emitter_on" then
                     remove_forcefield(pos, meta:get_int("range"))
                     hacky_swap_node(pos, "technic:forcefield_emitter_off")
                     meta:set_int("HV_EU_demand", 100)
                     meta:set_string("infotext", "Forcefield Generator Idle")
                  end
                   end
                else
                   meta:set_int("HV_EU_demand", power_requirement)
                end
                return true
             end
local mesecons = {effector = {
    action_on = function(pos, node)
@@ -145,18 +161,17 @@
    tiles = {"technic_forcefield_emitter_off.png"},
    is_ground_content = true,
    groups = {cracky = 1},
    technic_power_machine=1,
    on_timer = forcefield_check,
    on_receive_fields = forcefield_receive_fields,
    on_construct = function(pos)
        minetest.env:get_node_timer(pos):start(forcefield_update_interval)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", forcefield_emitter_buffer_size)
        meta:set_float("technic_hv_power_machine", 1)
        meta:set_int("HV_EU_input", 0)
        meta:set_int("HV_EU_demand", 0)
        meta:set_int("range", 10)
        meta:set_int("enabled", 1)
        meta:set_string("formspec", get_forcefield_formspec(meta:get_int("range", 0)))
        meta:set_int("enabled", 0)
        meta:set_string("formspec", get_forcefield_formspec(meta:get_int("range")))
        meta:set_string("infotext", "Forcefield emitter");
    end,
    mesecons = mesecons
@@ -173,19 +188,18 @@
    on_construct = function(pos) 
        minetest.env:get_node_timer(pos):start(forcefield_update_interval)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", forcefield_emitter_buffer_size)
        meta:set_int("range", 10)
        meta:set_int("enabled", 1)
        meta:set_string("formspec", get_forcefield_formspec(meta:get_int("range"), 0))
        meta:set_string("infotext", "Forcefield emitter");
--        meta:set_float("technic_hv_power_machine", 1)
--        meta:set_float("HV_EU_input", 0)
--        meta:set_float("HV_EU_demand", 0)
--        meta:set_int("range", 10)
--        meta:set_int("enabled", 1)
        meta:set_string("formspec", get_forcefield_formspec(meta:get_int("range")))
--        meta:set_string("infotext", "Forcefield emitter");
    end,
    on_dig = function(pos, node, digger)    
        remove_forcefield(pos, minetest.env:get_meta(pos):get_int("range"))
        return minetest.node_dig(pos, node, digger)
    end,
    technic_power_machine=1,
    mesecons = mesecons
})
@@ -193,6 +207,7 @@
    description = "Forcefield (you hacker you)",
    sunlight_propagates = true,
    drop = '',
        light_source = 8,
    tiles = {{name="technic_forcefield_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}}},
    is_ground_content = true,
    groups = {not_in_creative_inventory=1, unbreakable=1},
@@ -206,9 +221,5 @@
    },
})
register_MV_machine ("technic:forcefield_emitter_on","RE")
register_MV_machine ("technic:forcefield_emitter_off","RE")
technic.register_HV_machine("technic:forcefield_emitter_on","RE")
technic.register_HV_machine("technic:forcefield_emitter_off","RE")
technic/generator.lua
@@ -1,3 +1,7 @@
-- Th coal driven EU generator.
-- A simple device to get started on the electric machines.
-- Inefficient and expensive in coal (200EU 16 ticks)
-- Also only allows for LV machinery to run.
minetest.register_alias("generator", "technic:generator")
minetest.register_alias("generator", "technic:generator_active")
@@ -15,7 +19,7 @@
    stack_max = 99,
}) 
generator_formspec =
local generator_formspec =
    "invsize[8,9;]"..
    "image[0,0;5,5;technic_generator_menu.png]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
@@ -26,124 +30,118 @@
    "list[current_player;main;0,5;8,4;]"
    
minetest.register_node("technic:generator", {
    description = "Coal Driven 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(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=5000;
    burn_time=0;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Generator")
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 5000)
        meta:set_string("formspec", generator_formspec)
        meta:set_float("burn_time", 0)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
minetest.register_node(
   "technic:generator",
   {
      description = "Coal Driven 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.env:get_meta(pos)
            meta:set_string("infotext", "Coal Electric Generator")
            meta:set_float("technic_power_machine", 1)
            meta:set_int("LV_EU_supply", 0)
            meta:set_int("LV_EU_from_fuel", 1) -- Signal to the switching station that this device burns some sort of fuel and needs special handling
            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.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            return false
        end
        return true
      can_dig = function(pos,player)
           local meta = minetest.env: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 = "Coal Driven 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",
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=0;
    burn_time=0;
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            return false
        end
        return true
minetest.register_node(
   "technic:generator_active",
   {
      description = "Coal Driven 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.env: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)
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.env:get_meta(pos)
          local burn_time= meta:get_int("burn_time")
    local meta = minetest.env:get_meta(pos)
    local burn_time= meta:get_float("burn_time")
    local charge= meta:get_float("internal_EU_buffer")
    local max_charge= meta:get_float("internal_EU_buffer_size")
    local burn_charge=200
          -- If more to burn and the energy produced was used: produce some more
          if burn_time>0 then
             if meta:get_int("LV_EU_supply") == 0 then
            -- We did not use the power
            meta:set_int("LV_EU_supply", 200) -- Give 200EUs
             else
            burn_time = burn_time - 1
            meta:set_int("burn_time",burn_time)
             end
          end
    if burn_time>0 then
        if charge+burn_charge>max_charge then
        burn_charge=max_charge-charge
        end
        if burn_charge>0 then
        burn_time=burn_time-1
        meta:set_float("burn_time",burn_time)
        charge=charge+burn_charge
        meta:set_float("internal_EU_buffer",charge)
        end
    end
    if burn_time==0 then
        local inv = meta:get_inventory()
        if inv:is_empty("src")==false  then
        local srcstack = inv:get_stack("src", 1)
        src_item=srcstack:to_table()
        if src_item["name"]== "default:coal_lump" then
        srcstack:take_item()
        inv:set_stack("src", 1, srcstack)
        burn_time=16
        meta:set_float("burn_time",burn_time)
        hacky_swap_node (pos,"technic:generator_active")
        end
        end
    end
          -- Burn another piece of coal
          if burn_time==0 then
             local inv = meta:get_inventory()
             if inv:is_empty("src") == false  then
            local srcstack = inv:get_stack("src", 1)
            src_item=srcstack:to_table()
            if src_item["name"] == "default:coal_lump" then
               srcstack:take_item()
               inv:set_stack("src", 1, srcstack)
               burn_time=16
               meta:set_int("burn_time",burn_time)
               hacky_swap_node (pos,"technic:generator_active")
               meta:set_int("LV_EU_supply", 200) -- Give 200EUs
            end
             end
          end
    local load = math.floor((charge/max_charge)*100)
    local percent = math.floor((burn_time/16)*100)
    meta:set_string("formspec",
                "invsize[8,9;]"..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]"..
                "label[0,0;Generator]"..
                "label[1,3;Power level]"..
                "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;]"
                )
          local load = 8 -- math.floor((charge/max_charge)*100)
          local percent = math.floor((burn_time/16)*100)
          meta:set_string("formspec",
                  "invsize[8,9;]"..
                     "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                     (load)..":technic_power_meter_fg.png]"..
                  "label[0,0;Generator]"..
                  "label[1,3;Power level]"..
                  "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;]"
             )
    if burn_time==0 then
        hacky_swap_node (pos,"technic:generator")
    end
          if burn_time==0 then
             hacky_swap_node (pos,"technic:generator")
          end
           end
   })
    end
})
register_LV_machine ("technic:generator","PR")
register_LV_machine ("technic:generator_active","PR")
technic.register_LV_machine ("technic:generator","PR")
technic.register_LV_machine ("technic:generator_active","PR")
technic/geothermal.lua
@@ -1,3 +1,7 @@
-- 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({
@@ -14,7 +18,7 @@
    stack_max = 99,
}) 
geothermal_formspec =
local geothermal_formspec =
    "invsize[8,4;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "label[0,0;Geothermal Generator]"..
@@ -22,117 +26,131 @@
    "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(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=5000;
    burn_time=0;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Geothermal Generator")
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 2000)
        meta:set_string("formspec", geothermal_formspec)
        end,
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.env: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",
   })
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",
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=0;
})
local check_node_around = function(pos)
                 local node=minetest.env: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)
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.env:get_meta(pos)
          local water_nodes      = 0
          local lava_nodes       = 0
          local production_level = 0
          local eu_supply        = 0
    local meta = minetest.env:get_meta(pos)
    local charge= meta:get_float("internal_EU_buffer")
    local max_charge= meta:get_float("internal_EU_buffer_size")
    local water_nodes = 0
    local lava_nodes = 0
    local production_level=0
    local load_step=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
          pos.x=pos.x+1
          local check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          pos.y=pos.y-1
          local check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
    pos.x=pos.x+1
    local check=check_node_around (pos)
    if check==1 then water_nodes=water_nodes+1 end
    if check==2 then lava_nodes=lava_nodes+1 end
    pos.x=pos.x-2
    check=check_node_around (pos)
    if check==1 then water_nodes=water_nodes+1 end
    if check==2 then lava_nodes=lava_nodes+1 end
    pos.x=pos.x+1
    pos.z=pos.z+1
    check=check_node_around (pos)
    if check==1 then water_nodes=water_nodes+1 end
    if check==2 then lava_nodes=lava_nodes+1 end
    pos.z=pos.z-2
    check=check_node_around (pos)
    if check==1 then water_nodes=water_nodes+1 end
    if check==2 then lava_nodes=lava_nodes+1 end
    pos.z=pos.z+1
          pos.x=pos.x-2
          check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          pos.y=pos.y+1
          check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          pos.x=pos.x+1
          pos.z=pos.z+1
          check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          pos.y=pos.y-1
          check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          pos.z=pos.z-2
          check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          pos.y=pos.y+1
          check=check_node_around(pos)
          if check==1 then water_nodes=water_nodes+1 end
          if check==2 then lava_nodes=lava_nodes+1 end
          -- Back to (0,0,0)
          pos.z=pos.z+1
    
    if water_nodes==1 and lava_nodes==1 then production_level=50 load_step=30 end
    if water_nodes==2 and lava_nodes==1 then production_level=75 load_step=45 end
    if water_nodes==1 and lava_nodes==2 then production_level=75 load_step=45 end
    if water_nodes==2 and lava_nodes==2 then production_level=100 load_step=60 end
    if water_nodes==3 and lava_nodes==1 then production_level=25 load_step=15 end
    if water_nodes==1 and lava_nodes==3 then production_level=25 load_step=15 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
        if charge+load_step>max_charge then
        load_step=max_charge-charge
        end
        if load_step>0 then
        charge=charge+load_step
        meta:set_float("internal_EU_buffer",charge)
        end
    end
          if production_level>0 then
             meta:set_int("LV_EU_supply", eu_supply)
          end
    local load = math.floor((charge/max_charge)*100)
    meta:set_string("formspec",
                "invsize[8,4;]"..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]"..
                "label[0,0;Geothermal Generator]"..
                "label[1,3;Power level]"..
                "label[4,0;Production at "..tostring(production_level).."%]"
                )
          local load = 1 -- math.floor((charge/max_charge)*100)
          meta:set_string("formspec",
                  "invsize[8,4;]"..
                     "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                     (load)..":technic_power_meter_fg.png]"..
                  "label[0,0;Geothermal Generator]"..
                  "label[1,3;Power level]"..
                  "label[4,0;Production at "..tostring(production_level).."%]"
                )
                
    if production_level>0 and minetest.env: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") end
end
})
          if production_level>0 and minetest.env: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
   })
function check_node_around (pos)
local node=minetest.env: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
register_LV_machine ("technic:geothermal","PR")
register_LV_machine ("technic:geothermal_active","PR")
technic.register_LV_machine ("technic:geothermal","PR")
technic.register_LV_machine ("technic:geothermal_active","PR")
technic/grinder.lua
@@ -1,349 +1,352 @@
grinder_recipes ={}
technic.grinder_recipes ={}
registered_grinder_recipes_count=1
technic.register_grinder_recipe = function(src, dst)
                   technic.grinder_recipes[src] = dst
                   if unified_inventory then
                      unified_inventory.register_craft(
                     {
                        type = "grinding",
                        output = dst,
                        items = {src},
                        width = 0,
                     })
                   end
                end
function register_grinder_recipe (string1,string2)
grinder_recipes[registered_grinder_recipes_count]={}
grinder_recipes[registered_grinder_recipes_count].src_name=string1
grinder_recipes[registered_grinder_recipes_count].dst_name=string2
registered_grinder_recipes_count=registered_grinder_recipes_count+1
if unified_inventory then
    unified_inventory.register_craft({
    type = "grinding",
    output = string2,
    items = {string1},
    width = 0,
    })
    end
end
-- Receive an ItemStack of result by an ItemStack input
technic.get_grinder_recipe = function(itemstack)
                local src_item  = itemstack:to_table()
                if src_item == nil then
                   return nil
                end
                local item_name = src_item["name"]
                if technic.grinder_recipes[item_name] then
                   return ItemStack(technic.grinder_recipes[item_name])
                else
                   return nil
                end
                 end
register_grinder_recipe("default:stone","default:sand")
register_grinder_recipe("default:cobble","default:gravel")
register_grinder_recipe("default:gravel","default:dirt")
register_grinder_recipe("default:desert_stone","default:desert_sand")
register_grinder_recipe("default:iron_lump","technic:iron_dust 2")
register_grinder_recipe("default:steel_ingot","technic:iron_dust 1")
register_grinder_recipe("default:coal_lump","technic:coal_dust 2")
register_grinder_recipe("default:copper_lump","technic:copper_dust 2")
register_grinder_recipe("default:copper_ingot","technic:copper_dust 1")
register_grinder_recipe("default:gold_lump","technic:gold_dust 2")
register_grinder_recipe("default:gold_ingot","technic:gold_dust 1")
--register_grinder_recipe("default:bronze_ingot","technic:bronze_dust 1")  -- Dust does not exist yet
register_grinder_recipe("moreores:tin_lump","technic:tin_dust 2")
register_grinder_recipe("moreores:tin_ingot","technic:tin_dust 1")
register_grinder_recipe("moreores:silver_lump","technic:silver_dust 2")
register_grinder_recipe("moreores:silver_ingot","technic:silver_dust 1")
register_grinder_recipe("moreores:mithril_lump","technic:mithril_dust 2")
register_grinder_recipe("moreores:mithril_ingot","technic:mithril_dust 1")
register_grinder_recipe("technic:chromium_lump","technic:chromium_dust 2")
register_grinder_recipe("technic:chromium_ingot","technic:chromium_dust 1")
register_grinder_recipe("technic:stainless_steel_ingot","stainless_steel_dust 1")
register_grinder_recipe("technic:brass_ingot","technic:brass_dust 1")
register_grinder_recipe("homedecor:brass_ingot","technic:brass_dust 1")
register_grinder_recipe("technic:zinc_lump","technic:zinc_dust 2")
register_grinder_recipe("technic:zinc_ingot","technic:zinc_dust 1")
register_grinder_recipe("technic:coal_dust","dye:black 2")
register_grinder_recipe("default:cactus","dye:green 2")
register_grinder_recipe("default:dry_shrub","dye:brown 2")
register_grinder_recipe("flowers:flower_geranium","dye:blue 2")
register_grinder_recipe("flowers:flower_dandelion_white","dye:white 2")
register_grinder_recipe("flowers:flower_dandelion_yellow","dye:yellow 2")
register_grinder_recipe("flowers:flower_tulip","dye:orange 2")
register_grinder_recipe("flowers:flower_rose","dye:red 2")
register_grinder_recipe("flowers:flower_viola","dye:violet 2")
technic.register_grinder_recipe("default:stone","default:sand")
technic.register_grinder_recipe("default:cobble","default:gravel")
technic.register_grinder_recipe("default:gravel","default:dirt")
technic.register_grinder_recipe("default:desert_stone","default:desert_sand")
technic.register_grinder_recipe("default:iron_lump","technic:iron_dust 2")
technic.register_grinder_recipe("default:steel_ingot","technic:iron_dust 1")
technic.register_grinder_recipe("default:coal_lump","technic:coal_dust 2")
technic.register_grinder_recipe("default:copper_lump","technic:copper_dust 2")
technic.register_grinder_recipe("default:copper_ingot","technic:copper_dust 1")
technic.register_grinder_recipe("default:gold_lump","technic:gold_dust 2")
technic.register_grinder_recipe("default:gold_ingot","technic:gold_dust 1")
--technic.register_grinder_recipe("default:bronze_ingot","technic:bronze_dust 1")  -- Dust does not exist yet
--technic.register_grinder_recipe("home_decor:brass_ingot","technic:brass_dust 1") -- needs check for the mod
technic.register_grinder_recipe("moreores:tin_lump","technic:tin_dust 2")
technic.register_grinder_recipe("moreores:tin_ingot","technic:tin_dust 1")
technic.register_grinder_recipe("moreores:silver_lump","technic:silver_dust 2")
technic.register_grinder_recipe("moreores:silver_ingot","technic:silver_dust 1")
technic.register_grinder_recipe("moreores:mithril_lump","technic:mithril_dust 2")
technic.register_grinder_recipe("moreores:mithril_ingot","technic:mithril_dust 1")
technic.register_grinder_recipe("technic:chromium_lump","technic:chromium_dust 2")
technic.register_grinder_recipe("technic:chromium_ingot","technic:chromium_dust 1")
technic.register_grinder_recipe("technic:stainless_steel_ingot","stainless_steel_dust 1")
technic.register_grinder_recipe("technic:brass_ingot","technic:brass_dust 1")
technic.register_grinder_recipe("technic:zinc_lump","technic:zinc_dust 2")
technic.register_grinder_recipe("technic:zinc_ingot","technic:zinc_dust 1")
minetest.register_craftitem( "technic:coal_dust", {
    description = "Coal Dust",
    inventory_image = "technic_coal_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Coal Dust",
                inventory_image = "technic_coal_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craftitem( "technic:iron_dust", {
    description = "Iron Dust",
    inventory_image = "technic_iron_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Iron Dust",
                inventory_image = "technic_iron_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "default:steel_ingot",
    recipe = "technic:iron_dust",
})
               type = "cooking",
               output = "default:steel_ingot",
               recipe = "technic:iron_dust",
            })
minetest.register_craftitem( "technic:copper_dust", {
    description = "Copper Dust",
    inventory_image = "technic_copper_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Copper Dust",
                inventory_image = "technic_copper_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "default:copper_ingot",
    recipe = "technic:copper_dust",
})
               type = "cooking",
               output = "moreores:copper_ingot",
               recipe = "technic:copper_dust",
            })
minetest.register_craftitem( "technic:tin_dust", {
    description = "Tin Dust",
    inventory_image = "technic_tin_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Tin Dust",
                inventory_image = "technic_tin_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "moreores:tin_ingot",
    recipe = "technic:tin_dust",
})
               type = "cooking",
               output = "moreores:tin_ingot",
               recipe = "technic:tin_dust",
            })
minetest.register_craftitem( "technic:silver_dust", {
    description = "Silver Dust",
    inventory_image = "technic_silver_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Silver Dust",
                inventory_image = "technic_silver_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "moreores:silver_ingot",
    recipe = "technic:silver_dust",
})
               type = "cooking",
               output = "moreores:silver_ingot",
               recipe = "technic:silver_dust",
            })
minetest.register_craftitem( "technic:gold_dust", {
    description = "Gold Dust",
    inventory_image = "technic_gold_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Gold Dust",
                inventory_image = "technic_gold_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "default:gold_ingot",
    recipe = "technic:gold_dust",
})
               type = "cooking",
               output = "default:gold_ingot",
               recipe = "technic:gold_dust",
            })
minetest.register_craftitem( "technic:mithril_dust", {
    description = "Mithril Dust",
    inventory_image = "technic_mithril_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Mithril Dust",
                inventory_image = "technic_mithril_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "moreores:mithril_ingot",
    recipe = "technic:mithril_dust",
})
               type = "cooking",
               output = "moreores:mithril_ingot",
               recipe = "technic:mithril_dust",
            })
minetest.register_craftitem( "technic:chromium_dust", {
    description = "Chromium Dust",
    inventory_image = "technic_chromium_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Chromium Dust",
                inventory_image = "technic_chromium_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "technic:chromium_ingot",
    recipe = "technic:chromium_dust",
})
               type = "cooking",
               output = "technic:chromium_ingot",
               recipe = "technic:chromium_dust",
            })
minetest.register_craftitem( "technic:bronze_dust", {
    description = "Bronze Dust",
    inventory_image = "technic_bronze_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Bronze Dust",
                inventory_image = "technic_bronze_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "default:bronze_ingot",
    recipe = "technic:bronze_dust",
})
               type = "cooking",
               output = "default:bronze_ingot",
               recipe = "technic:bronze_dust",
            })
minetest.register_craftitem( "technic:brass_dust", {
    description = "Brass Dust",
    inventory_image = "technic_brass_dust.png",
    on_place_on_ground = minetest.craftitem_place_item,
    })
                description = "Brass Dust",
                inventory_image = "technic_brass_dust.png",
                on_place_on_ground = minetest.craftitem_place_item,
                 })
minetest.register_craft({
    type = "cooking",
    output = "technic:brass_ingot",
    recipe = "technic:brass_dust",
})
               type = "cooking",
               output = "technic:brass_ingot",
               recipe = "technic:brass_dust",
            })
minetest.register_craftitem( "technic:stainless_steel_dust", {
    description = "Stainless Steel Dust",
    inventory_image = "technic_stainless_steel_dust.png",
    })
                description = "Stainless Steel Dust",
                inventory_image = "technic_stainless_steel_dust.png",
                 })
minetest.register_craft({
    type = "cooking",
    output = "technic:stainless_steel_ingot",
    recipe = "technic:stainless_steel_dust",
})
               type = "cooking",
               output = "technic:stainless_steel_ingot",
               recipe = "technic:stainless_steel_dust",
            })
minetest.register_craftitem( "technic:zinc_dust", {
    description = "Zinc Dust",
    inventory_image = "technic_zinc_dust.png",
    })
                description = "Zinc Dust",
                inventory_image = "technic_zinc_dust.png",
                 })
minetest.register_craft({
    type = "cooking",
    output = "technic:zinc_ingot",
    recipe = "technic:zinc_dust",
})
               type = "cooking",
               output = "technic:zinc_ingot",
               recipe = "technic:zinc_dust",
            })
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', 'default:copper_ingot', 'default:stone'},
    }
})
               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'},
               }
            })
minetest.register_craftitem("technic:grinder", {
    description = "Grinder",
    stack_max = 99,
})
                   description = "Grinder",
                   stack_max = 99,
                })
grinder_formspec =
    "invsize[8,9;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "label[0,0;LV Grinder]"..
    "label[1,3;Power level]"..
    "list[current_name;src;3,1;1,1;]"..
    "list[current_name;dst;5,1;2,2;]"..
    "list[current_player;main;0,5;8,4;]"..
    "background[-0.19,-0.25;8.4,9.75;ui_form_bg.png]"..
    "background[0,0;8,4;ui_lv_grinder.png]"..
    "background[0,5;8,4;ui_main_inventory.png]"
local grinder_formspec =
   "invsize[8,9;]"..
   "label[0,0;Grinder]"..
   "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:grinder", {
    description = "LV Grinder",
    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(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=5000;
    grind_time=0;
    grinded = nil;
    src_time = 0;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Grinder")
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 5000)
        meta:set_string("formspec", grinder_formspec)
        meta:set_float("grind_time", 0)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 4)
minetest.register_node(
   "technic:grinder",
   {
      description = "Grinder",
      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.env:get_meta(pos)
            meta:set_string("infotext", "Grinder")
            meta:set_float("technic_power_machine", 1)
            meta:set_string("formspec", grinder_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.env: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,
    can_dig = function(pos,player)
        local meta = minetest.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            return false
        end
        if not inv:is_empty("dst") then
            return false
        end
        return true
   })
minetest.register_node(
   "technic:grinder_active",
   {
      description = "Grinder",
      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.env: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:grinder_active", {
    description = "Grinder",
    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.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            return false
        end
        if not inv:is_empty("dst") then
            return false
        end
        return true
        end,
})
minetest.register_abm(
   { nodenames = {"technic:grinder","technic:grinder_active"},
     interval = 1,
     chance   = 1,
     action = function(pos, node, active_object_count, active_object_count_wider)
         -- Run a machine through its states. Takes the same arguments as the ABM action
         -- and adds the machine's states and any extra data which is needed by the machine.
         -- A machine is characterized by running through a set number of states (usually 2:
         -- Idle and active) in some order. A state decides when to move to the next one
         -- and the machine only changes state if it is powered correctly.
         -- The machine will automatically shut down if disconnected from power in some fashion.
         local meta         = minetest.env:get_meta(pos)
         local eu_input     = meta:get_int("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
minetest.register_abm({
    nodenames = {"technic:grinder","technic:grinder_active"},
    interval = 1,
    chance = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
         -- Machine information
         local machine_name         = "Grinder"
         local machine_node         = "technic:grinder"
         local machine_state_demand = { 50, 300 }
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            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")
         -- State machine
         if eu_input == 0 then
            -- unpowered - go idle
            hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            local inv    = meta:get_inventory()
            local empty  = inv:is_empty("src")
    local meta = minetest.env:get_meta(pos)
    local charge= meta:get_float("internal_EU_buffer")
    local max_charge= meta:get_float("internal_EU_buffer_size")
    local grind_cost=200
            if state == 1 then
               hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Idle")
    local load = math.floor((charge/max_charge)*100)
    meta:set_string("formspec",
                grinder_formspec..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]")
               local result = technic.get_grinder_recipe(inv:get_stack("src", 1))
               if not empty and result and inv:room_for_item("dst",result) then
              meta:set_int("src_time", 0)
              next_state = 2
               end
        local inv = meta:get_inventory()
        local srclist = inv:get_list("src")
        if inv:is_empty("src") then meta:set_float("grinder_on",0) end
            elseif state == 2 then
               hacky_swap_node(pos, machine_node.."_active")
               meta:set_string("infotext", machine_name.." Active")
        if (meta:get_float("grinder_on") == 1) then
            if charge>=grind_cost then
            charge=charge-grind_cost;
            meta:set_float("internal_EU_buffer",charge)
            meta:set_float("src_time", meta:get_float("src_time") + 1)
            if meta:get_float("src_time") >= meta:get_float("grind_time") then
                -- check if there's room for output in "dst" list
                grinded = get_grinded_item (inv:get_stack("src", 1))
                if inv:room_for_item("dst",grinded) then
                    -- Put result in "dst" list
                    inv:add_item("dst", grinded)
                    -- take stuff from "src" list
                    srcstack = inv:get_stack("src", 1)
                    srcstack:take_item()
                    inv:set_stack("src", 1, srcstack)
                    if inv:is_empty("src") then meta:set_float("grinder_on",0) end
                else
                    print("Grinder inventory full!")
                end
                meta:set_float("src_time", 0)
            end
            end
        end
        if (meta:get_float("grinder_on")==0) then
        local grinded=nil
        if not inv:is_empty("src") then
            grinded = get_grinded_item (inv:get_stack("src", 1))
            if grinded then
                meta:set_float("grinder_on",1)
                hacky_swap_node(pos,"technic:grinder_active")
                meta:set_string("infotext", "Grinder Active")
                grind_time=4
                meta:set_float("grind_time",grind_time)
                meta:set_float("src_time", 0)
                return
            end
            else
                hacky_swap_node(pos,"technic:grinder")
                meta:set_string("infotext", "Grinder Inactive")
        end
        end
    end
})
               if empty then
              next_state = 1
               else
              meta:set_int("src_time", meta:get_int("src_time") + 1)
              if meta:get_int("src_time") == 4 then -- 4 ticks per output
                 -- check if there's room for output in "dst" list
                 local result = technic.get_grinder_recipe(inv:get_stack("src", 1))
function get_grinded_item (items)
new_item =nil
src_item=items:to_table()
item_name=src_item["name"]
                 meta:set_int("src_time", 0)
                 if inv:room_for_item("dst",result) then
                -- take stuff from "src" list
                srcstack = inv:get_stack("src", 1)
                srcstack:take_item()
                inv:set_stack("src", 1, srcstack)
                -- Put result in "dst" list
                inv:add_item("dst", result)
                 else
                -- all full: go idle
                next_state = 1
                 end
              end
               end
            end
         end
         -- Change state?
         if next_state ~= state then
            meta:set_int("LV_EU_demand", machine_state_demand[next_state])
            meta:set_int("state", next_state)
         end
          end
  })
local counter=registered_grinder_recipes_count-1
for i=1, counter,1 do
    if    grinder_recipes[i].src_name==item_name then return ItemStack(grinder_recipes[i].dst_name) end
end
return nil
end
technic.register_LV_machine ("technic:grinder","RE")
technic.register_LV_machine ("technic:grinder_active","RE")
register_LV_machine ("technic:grinder","RE")
register_LV_machine ("technic:grinder_active","RE")
technic/grinder_gloopores.lua
@@ -1,8 +1,8 @@
register_grinder_recipe("gloopores:alatro_lump","technic:alatro_dust 2")
register_grinder_recipe("gloopores:kalite_lump","technic:kalite_dust 2")
register_grinder_recipe("gloopores:arol_lump","technic:arol_dust 2")
register_grinder_recipe("gloopores:talinite_lump","technic:talinite_dust 2")
register_grinder_recipe("gloopores:akalin_lump","technic:akalin_dust 2")
technic.register_grinder_recipe("gloopores:alatro_lump","technic:alatro_dust 2")
technic.register_grinder_recipe("gloopores:kalite_lump","technic:kalite_dust 2")
technic.register_grinder_recipe("gloopores:arol_lump","technic:arol_dust 2")
technic.register_grinder_recipe("gloopores:talinite_lump","technic:talinite_dust 2")
technic.register_grinder_recipe("gloopores:akalin_lump","technic:akalin_dust 2")
 
minetest.register_craftitem("technic:alatro_dust", {
  Â  Â  Â  description = "Alatro Dust",
technic/init.lua
@@ -4,7 +4,13 @@
technic = {}
modpath=minetest.get_modpath("technic")
technic.dprint = function(string)
    if technic.DBG == 1 then
        print(string)
    end
end
local modpath = minetest.get_modpath("technic")
--Read technic config file
dofile(modpath.."/config.lua")
@@ -14,38 +20,55 @@
--items 
dofile(modpath.."/items.lua")
-- Register functions
dofile(modpath.."/register_machine_and_tool.lua")
dofile(modpath.."/alloy_furnaces_commons.lua") -- Idea: Let the LV, MV, HV version of the furnace support different alloys
-- Switching station LV,MV,HV
dofile(modpath.."/switching_station.lua")
dofile(modpath.."/supply_converter.lua")
--LV machines
dofile(modpath.."/wires.lua")
dofile(modpath.."/battery_box.lua")
dofile(modpath.."/alloy_furnaces_commons.lua")
dofile(modpath.."/alloy_furnace.lua")
dofile(modpath.."/solar_panel.lua")
dofile(modpath.."/solar_array_lv.lua")
dofile(modpath.."/geothermal.lua")
dofile(modpath.."/water_mill.lua")
dofile(modpath.."/generator.lua")
dofile(modpath.."/electric_furnace.lua")
dofile(modpath.."/tool_workshop.lua")
dofile(modpath.."/music_player.lua")
dofile(modpath.."/generator.lua")
dofile(modpath.."/grinder.lua")
dofile(modpath.."/cnc.lua")
dofile(modpath.."/cnc_api.lua")
dofile(modpath.."/cnc_nodes.lua")
dofile(modpath.."/extractor.lua")
--MV machines
dofile(modpath.."/wires_mv.lua")
dofile(modpath.."/battery_box_mv.lua")
dofile(modpath.."/solar_array_mv.lua")
dofile(modpath.."/down_converter_mv.lua")
--dofile(modpath.."/down_converter_mv.lua")
dofile(modpath.."/electric_furnace_mv.lua")
dofile(modpath.."/alloy_furnace_mv.lua")
dofile(modpath.."/forcefield.lua")
---- The power radiator supplies appliances with inductive coupled power:
---- lighting and associated textures is taken directly from VanessaE's homedecor and made electric.
dofile(modpath.."/power_radiator.lua")
dofile(modpath.."/lighting.lua")
--
----HV machines
dofile(modpath.."/wires_hv.lua")
dofile(modpath.."/battery_box_hv.lua")
dofile(modpath.."/solar_array_hv.lua")
--HV machines
dofile(modpath.."/wires_hv.lua")
dofile(modpath.."/battery_box_hv.lua")
dofile(modpath.."/solar_array_hv.lua")
dofile(modpath.."/down_converter_hv.lua")
--dofile(modpath.."/down_converter_hv.lua")
--Tools
if technic.config:getBool("enable_mining_drill") then dofile(modpath.."/mining_drill.lua") end
@@ -55,8 +78,8 @@
dofile(modpath.."/chainsaw.lua")
dofile(modpath.."/tree_tap.lua")
dofile(modpath.."/sonic_screwdriver.lua")
-- mesecons and tubes related
--
---- mesecons and tubes related
dofile(modpath.."/injector.lua")
dofile(modpath.."/node_breaker.lua")
dofile(modpath.."/deployer.lua")
@@ -64,24 +87,23 @@
dofile(modpath.."/frames.lua")
function has_locked_chest_privilege(meta, player)
    if player:get_player_name() ~= meta:get_string("owner") then
        return false
    end
    return true
   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)
    local meta = minetest.env:get_meta(pos)
    local meta0 = meta:to_table()
    if node.name == name then
        return nil
    end
    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
   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
end
technic/items.lua
@@ -10,6 +10,12 @@
    on_place_on_ground = minetest.craftitem_place_item,
})
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({
@@ -175,6 +181,21 @@
    }
})
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",
technic/lighting.lua
New file
@@ -0,0 +1,590 @@
-- NOTE: The code is takes directly from VanessaE's homedecor mod.
-- I just made it the lights into indictive appliances for this mod.
-- This file supplies electric powered glowlights
-- 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())
else
    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 not IsPlayerNodeOwner(pos, placer:get_player_name()) then
                                if type(getLastOwner) == "function" then                -- ...is an old version
                                        ownername = getLastOwner(pos)
                                elseif type(GetNodeOwnerName) == "function" then        -- ...is a recent version
                                        ownername = GetNodeOwnerName(pos)
                                else
                                        ownername = S("someone")
                                end
                        end
                end
        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
                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) )
                return true
        else
                return false
        end
end
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)
        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 fdir = minetest.dir_to_facedir(placer:get_look_dir())
            local wield_name = itemstack:get_name()
            if not minetest.registered_nodes[pname]
                or not minetest.registered_nodes[pname].on_rightclick then
                local iswall = (above.x ~= under.x) or (above.z ~= under.z)
                local isceiling = (above.x == under.x) and (above.z == under.z) and (pitch > 0)
                local pos1 = above
                if minetest.registered_nodes[pname]["buildable_to"] then
                    pos1 = under
                    iswall = false
                end
                if not minetest.registered_nodes[minetest.env: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
                elseif isceiling then
                    minetest.env: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
                end
                if not homedecor_expect_infinite_stacks then
                    itemstack:take_item()
                    return itemstack
                end
            end
        else
            minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack)
        end
    end
end
-- Yellow -- Half node
minetest.register_node('technic:homedecor_glowlight_half_yellow', {
    description = S("Yellow Glowlight (thick)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3 },
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thick)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_half_yellow_active")
           end
})
minetest.register_node('technic:homedecor_glowlight_half_yellow_active', {
    description = S("Yellow Glowlight (thick)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png',
        'technic_homedecor_glowlight_thick_yellow_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    light_source = LIGHT_MAX,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3, not_in_creative_inventory=1},
    drop="technic:homedecor_glowlight_half_yellow",
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thick)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_half_yellow")
           end
})
-- Yellow -- Quarter node
minetest.register_node('technic:homedecor_glowlight_quarter_yellow', {
    description = S("Yellow Glowlight (thin)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3 },
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thin)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_quarter_yellow_active")
           end
})
minetest.register_node('technic:homedecor_glowlight_quarter_yellow_active', {
    description = S("Yellow Glowlight (thin)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_yellow_tb.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png',
        'technic_homedecor_glowlight_thin_yellow_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    light_source = LIGHT_MAX-1,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3, not_in_creative_inventory=1},
    drop="technic:homedecor_glowlight_quarter_yellow",
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thin)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_quarter_yellow")
           end
})
-- White -- half node
minetest.register_node('technic:homedecor_glowlight_half_white', {
    description = S("White Glowlight (thick)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_thick_white_sides.png',
        'technic_homedecor_glowlight_thick_white_sides.png',
        'technic_homedecor_glowlight_thick_white_sides.png',
        'technic_homedecor_glowlight_thick_white_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3 },
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "White Glowlight (thick)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_half_white_active")
           end
})
minetest.register_node('technic:homedecor_glowlight_half_white_active', {
    description = S("White Glowlight (thick)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_thick_white_sides.png',
        'technic_homedecor_glowlight_thick_white_sides.png',
        'technic_homedecor_glowlight_thick_white_sides.png',
        'technic_homedecor_glowlight_thick_white_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    light_source = LIGHT_MAX,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3, not_in_creative_inventory=1},
    drop="technic:homedecor_glowlight_half_white",
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "White Glowlight (thick)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_half_white")
           end
})
-- White -- Quarter node
minetest.register_node('technic:homedecor_glowlight_quarter_white', {
    description = S("White Glowlight (thin)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_thin_white_sides.png',
        'technic_homedecor_glowlight_thin_white_sides.png',
        'technic_homedecor_glowlight_thin_white_sides.png',
        'technic_homedecor_glowlight_thin_white_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3 },
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "White Glowlight (thin)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_quarter_white_active")
           end
})
minetest.register_node('technic:homedecor_glowlight_quarter_white_active', {
    description = S("White Glowlight (thin)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_white_tb.png',
        'technic_homedecor_glowlight_thin_white_sides.png',
        'technic_homedecor_glowlight_thin_white_sides.png',
        'technic_homedecor_glowlight_thin_white_sides.png',
        'technic_homedecor_glowlight_thin_white_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    light_source = LIGHT_MAX-1,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3, not_in_creative_inventory=1},
    drop="technic:homedecor_glowlight_quarter_white",
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 100, "White Glowlight (thin)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_quarter_white")
           end
})
-- Glowlight "cubes" - yellow
minetest.register_node('technic:homedecor_glowlight_small_cube_yellow', {
    description = S("Yellow Glowlight (small cube)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_cube_yellow_tb.png',
        'technic_homedecor_glowlight_cube_yellow_tb.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3 },
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 50, "Yellow Glowlight (small cube)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_off(pos, 50, "technic:homedecor_glowlight_small_cube_yellow_active")
           end
})
minetest.register_node('technic:homedecor_glowlight_small_cube_yellow_active', {
    description = S("Yellow Glowlight (small cube)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_cube_yellow_tb.png',
        'technic_homedecor_glowlight_cube_yellow_tb.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png',
        'technic_homedecor_glowlight_cube_yellow_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    light_source = LIGHT_MAX-1,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3, not_in_creative_inventory=1},
    drop="technic:homedecor_glowlight_small_cube_yellow",
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 50, "Yellow Glowlight (small cube)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_small_cube_yellow")
           end
})
-- Glowlight "cubes" - white
minetest.register_node('technic:homedecor_glowlight_small_cube_white', {
    description = S("White Glowlight (small cube)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_cube_white_tb.png',
        'technic_homedecor_glowlight_cube_white_tb.png',
        'technic_homedecor_glowlight_cube_white_sides.png',
        'technic_homedecor_glowlight_cube_white_sides.png',
        'technic_homedecor_glowlight_cube_white_sides.png',
        'technic_homedecor_glowlight_cube_white_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3 },
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 50, "White Glowlight (small cube)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_off(pos, 50, "technic:homedecor_glowlight_small_cube_white_active")
           end
})
minetest.register_node('technic:homedecor_glowlight_small_cube_white_active', {
    description = S("White Glowlight (small cube)"),
    drawtype = "nodebox",
    tiles = {
        'technic_homedecor_glowlight_cube_white_tb.png',
        'technic_homedecor_glowlight_cube_white_tb.png',
        'technic_homedecor_glowlight_cube_white_sides.png',
        'technic_homedecor_glowlight_cube_white_sides.png',
        'technic_homedecor_glowlight_cube_white_sides.png',
        'technic_homedecor_glowlight_cube_white_sides.png'
    },
        selection_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
        node_box = {
                type = "fixed",
                fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 }
        },
    sunlight_propagates = false,
    paramtype = "light",
    paramtype2 = "facedir",
    walkable = true,
    light_source = LIGHT_MAX-1,
    sounds = default.node_sound_wood_defaults(),
    groups = { snappy = 3, not_in_creative_inventory=1},
    drop="technic:homedecor_glowlight_small_cube_white",
    on_place = function(itemstack, placer, pointed_thing)
        technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing)
        return itemstack
         end,
    on_construct = function(pos)
              technic.inductive_on_construct(pos, 50, "White Glowlight (small cube)")
               end,
    on_punch = function(pos, node, puncher)
              technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_small_cube_white")
           end
})
technic.register_inductive_machine("technic:homedecor_glowlight_half_yellow")
technic.register_inductive_machine("technic:homedecor_glowlight_half_white")
technic.register_inductive_machine("technic:homedecor_glowlight_quarter_yellow")
technic.register_inductive_machine("technic:homedecor_glowlight_quarter_white")
technic.register_inductive_machine("technic:homedecor_glowlight_small_cube_yellow")
technic.register_inductive_machine("technic:homedecor_glowlight_small_cube_white")
technic/mining_drill.lua
@@ -1,9 +1,9 @@
mining_drill_max_charge=60000
mining_drill_mk2_max_charge=240000
mining_drill_mk3_max_charge=960000
mining_drill_power_usage=200
mining_drill_mk2_power_usage=600
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',
@@ -210,7 +210,7 @@
    drill_dig_it0 (pos,player)
end
register_power_tool ("technic:mining_drill",mining_drill_max_charge)
technic.register_MV_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",
@@ -227,7 +227,7 @@
            charge =charge-mining_drill_power_usage;
            meta["charge"]=charge
            item["metadata"]=set_item_meta(meta)
            set_RE_wear(item,charge,mining_drill_max_charge)
            technic.set_RE_wear(item,charge,mining_drill_max_charge)
            itemstack:replace(item)
            end
        return itemstack
@@ -243,10 +243,10 @@
    return itemstack
    end,
})
register_power_tool ("technic:mining_drill_mk2",mining_drill_mk2_max_charge)
technic.register_HV_power_tool ("technic:mining_drill_mk2",mining_drill_mk2_max_charge)
for i=1,4,1 do
register_power_tool ("technic:mining_drill_mk2_"..i,mining_drill_mk2_max_charge)
technic.register_HV_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",
@@ -267,10 +267,10 @@
    return itemstack
    end,
})
register_power_tool ("technic:mining_drill_mk3",mining_drill_mk3_max_charge)
technic.register_HV_power_tool ("technic:mining_drill_mk3",mining_drill_mk3_max_charge)
for i=1,5,1 do
register_power_tool ("technic:mining_drill_mk3_"..i,mining_drill_mk3_max_charge)
technic.register_HV_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",
@@ -299,7 +299,7 @@
        if charge<0 then charge=0 end
        meta["charge"]=charge
        item["metadata"]=set_item_meta(meta)
        set_RE_wear(item,charge,mining_drill_mk2_max_charge)
        technic.set_RE_wear(item,charge,mining_drill_mk2_max_charge)
        itemstack:replace(item)
    end
    return itemstack
@@ -321,7 +321,7 @@
        if charge<0 then charge=0 end
        meta["charge"]=charge
        item["metadata"]=set_item_meta(meta)
        set_RE_wear(item,charge,mining_drill_mk3_max_charge)
        technic.set_RE_wear(item,charge,mining_drill_mk3_max_charge)
        itemstack:replace(item)
    end
    return itemstack
technic/mining_laser_mk1.lua
@@ -1,5 +1,5 @@
laser_mk1_max_charge=40000
register_power_tool ("technic:laser_mk1",laser_mk1_max_charge)
local laser_mk1_max_charge=40000
technic.register_LV_power_tool ("technic:laser_mk1",laser_mk1_max_charge)
local laser_shoot = function(itemstack, player, pointed_thing)
                local laser_straight_mode=0
@@ -62,8 +62,8 @@
        charge=meta["charge"]
        if charge-400>0 then
         laser_shoot(item, user, pointed_thing)
         charge =charge-400;
        set_RE_wear(item,charge,laser_mk1_max_charge)
         charge = charge-400;
        technic.set_RE_wear(item,charge,laser_mk1_max_charge)
        meta["charge"]=charge
        item["metadata"]=set_item_meta(meta)
        itemstack:replace(item)
technic/music_player.lua
@@ -1,3 +1,5 @@
-- LV Music player.
-- The playe can play music. But it is high ampage!
minetest.register_alias("music_player", "technic:music_player")
minetest.register_craft({
    output = 'technic:music_player',
@@ -11,112 +13,144 @@
minetest.register_craftitem("technic:music_player", {
    description = "Music Player",
    stack_max = 99,
})
music_player_formspec =
    "invsize[8,9;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "label[0,0;Music Player]"..
    "label[1,3;Power level]"..
    "button[5,2;1,1;track1;1]"..
    "button[6,2;1,1;track2;2]"
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(),
    technic_power_machine=1,
    internal_EU_buffer=0,
    internal_EU_buffer_size=5000,
    music_player_on=0,
    music_playing =0,
    music_handle = 0,
    music_player_current_track =1,
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Music Player")
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 1)
        meta:set_float("internal_EU_buffer_size", 5000)
        meta:set_string("formspec", music_player_formspec)
        meta:set_float("music_player_on", 0)
        meta:set_float("music_player_current_track", 1)
        end,
    on_receive_fields = function(pos, formanme, fields, sender)
    local meta = minetest.env:get_meta(pos)
    player_on=meta:get_float("music_player_on")
    music_handle=meta:get_float("music_handle")
    music_player_current_track=meta:get_float("music_player_current_track")
    if fields.track1 then music_player_current_track=1 end
    if fields.track2 then music_player_current_track=2 end
    if fields.track3 then music_player_current_track=3 end
    if fields.track4 then music_player_current_track=4 end
    if fields.track5 then music_player_current_track=5 end
    if fields.track6 then music_player_current_track=6 end
    if fields.track7 then music_player_current_track=7 end
    if fields.track8 then music_player_current_track=8 end
    if fields.track9 then music_player_current_track=9 end
    meta:set_float("music_player_current_track",music_player_current_track)
    if fields.play and player_on==1 then
    if music_handle then minetest.sound_stop(music_handle) end
    music_handle=minetest.sound_play("technic_track"..music_player_current_track, {pos = pos, gain = 1.0,loop = true, max_hear_distance = 72,})
    meta:set_float("music_playing",1)
    end
    if fields.stop then
    meta:set_float("music_playing",0)
    if music_handle then minetest.sound_stop(music_handle) end
    end
    meta:set_float("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.env:get_meta(pos)
    local charge= meta:get_float("internal_EU_buffer")
    local max_charge= meta:get_float("internal_EU_buffer_size")
    player_on=meta:get_float("music_player_on")
    music_player_current_track=meta:get_float("music_player_current_track")
    local play_cost=80
    if charge>play_cost then
        if meta:get_float("music_playing")==1 then charge=charge-play_cost end
            meta:set_float("internal_EU_buffer",charge)
        meta:set_float("music_player_on",1)
    else
        meta:set_float("music_playing",0)
        meta:set_float("music_player_on",0)
        if music_handle then minetest.sound_stop(music_handle) end
    end
    local load = math.floor((charge/max_charge)*100)
    meta:set_string("formspec",
                "invsize[8,9;]"..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]"..
                "label[0,0;Music Player]"..
                "label[1,3;Power level]"..
                "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 "..tostring(music_player_current_track).."]"
                )
    end
})
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 --]"
register_LV_machine ("technic:music_player","RE")
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.env:get_meta(pos)
            meta:set_string("infotext", "Music Player")
            meta:set_float("technic_power_machine", 1)
            meta:set_int("active",     0) -- Is the device on?
            meta:set_int("music_player_current_track", 1)
            meta:set_string("formspec", music_player_formspec)
             end,
      on_receive_fields = function(pos, formanme, fields, sender)
                 local meta                 = minetest.env:get_meta(pos)
                 music_handle               = meta:get_int("music_handle")
                 music_player_current_track = meta:get_int("music_player_current_track")
                 if fields.track1 then music_player_current_track = 1 end
                 if fields.track2 then music_player_current_track = 2 end
                 if fields.track3 then music_player_current_track = 3 end
                 if fields.track4 then music_player_current_track = 4 end
                 if fields.track5 then music_player_current_track = 5 end
                 if fields.track6 then music_player_current_track = 6 end
                 if fields.track7 then music_player_current_track = 7 end
                 if fields.track8 then music_player_current_track = 8 end
                 if fields.track9 then music_player_current_track = 9 end
                 meta:set_int("music_player_current_track",music_player_current_track)
                 if fields.play and meta:get_int("active") == 0 then
                if music_handle then minetest.sound_stop(music_handle) end
                music_handle = minetest.sound_play("technic_track"..music_player_current_track, {pos = pos, gain = 1.0,loop = true, max_hear_distance = 72,})
                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.env:get_meta(pos)
         local eu_input     = meta:get_int("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
         -- Machine information
         local machine_name         = "Music Player"
         local machine_node         = "technic:music_player"
         local machine_state_demand = { 10, 150 }
         local music_handle         = meta:get_int("music_handle")
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            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")
         -- State machine
         if eu_input == 0 then
            -- unpowered - go idle
            -- hacky_swap_node(pos, machine_node) -- if someday two nodes for this
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            if state == 1 then
               -- hacky_swap_node(pos, machine_node) -- if someday two nodes for this
               meta:set_string("infotext", machine_name.." Idle")
               if meta:get_int("active") == 1 then
              next_state = 2
               end
            elseif state == 2 then
               -- hacky_swap_node(pos, machine_node.."_active") -- if someday two nodes for this
               meta:set_string("infotext", machine_name.." Active")
               music_player_current_track=meta:get_int("music_player_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 "..tostring(music_player_current_track).."]"
                    )
               if meta:get_int("active") == 0 then
              if music_handle then minetest.sound_stop(music_handle) end
              next_state = 1
               end
            end
         end
         -- Change state?
         if next_state ~= state then
            meta:set_int("LV_EU_demand", machine_state_demand[next_state])
            meta:set_int("state", next_state)
         end
          end
   })
technic.register_LV_machine ("technic:music_player","RE")
technic/power_radiator.lua
New file
@@ -0,0 +1,226 @@
-- 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.6
-- Using inductive power transfer is very inefficient so this is
-- set to the factor 0.6.
--
-- Punching the radiator will toggle the power state of all attached appliances.
--
local power_radius = 6
------------------------------------------------------------------
-- 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.env: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.env: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("EUcha:"..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.env: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("EUcha:"..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.env: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.env: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.env: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.env: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.env:get_meta(pos1)
                         if meta1:get_string("has_supply") == pos.x..pos.y..pos.z then
                            minetest.env: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},
      },
      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_int("technic_mv_power_machine", 1)  -- MV machine
            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")
--            meta:set_int("active", 0)
             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_cable',              '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          = 3000 -- == the max EU demand of the radiator
           local connected_EU_demand = meta:get_int("connected_EU_demand")
           -- Efficiency factor
           local eff_factor = 0.6
           -- 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.env: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.env: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
                --print("I can supply this:"..connected_EU_demand.."|"..app_eu_demand.."<="..max_charge.."|act:"..meta1:get_int("EU_charge"))
                -- 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)
             --print("My Lamp ("..pos.x..","..pos.y..","..pos.z..") Used:"..used_charge.."Max:"..max_charge)
              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
--              meta:set_int("active",1) -- used for setting textures someday maybe
           end
           -- Save state
           meta:set_int("connected_EU_demand",connected_EU_demand)
        else
           -- This is the case where input ~= demand. Overloaded or underpowered!
--           --If demand surpasses actual supply turn off everything - we are out of power
--           if used_charge>eu_input then
--              meta:set_string("infotext", "Power Radiator is overloaded ("..math.floor(used_charge/eu_input*100).."% of available power)");
----              meta:set_int("active",1) -- used for setting textures someday maybe
--              shutdown_inductive_appliances(pos)
--              connected_EU_demand = 0
        end
         end,
 })
technic.register_MV_machine ("technic:power_radiator","RE")
technic/register_machine_and_tool.lua
New file
@@ -0,0 +1,70 @@
-- This file includes the functions and data structures for registering machines and tools for LV, MV, HV types.
-- We use the technioc namespace for these functions and data to avoid eventual conflict.
-- register LV machines here
technic.LV_machines    = {}
technic.LV_power_tools = {}
technic.register_LV_machine = function(nodename,type)
                 technic.LV_machines[nodename] = type
                  end
technic.unregister_LV_machine = function(nodename,type)
                   technic.LV_machines[nodename] = nil
                end
technic.register_LV_power_tool = function(craftitem,max_charge)
                    technic.LV_power_tools[craftitem] = max_charge
                 end
-- register MV machines here
technic.MV_machines    = {}
technic.MV_power_tools = {}
technic.register_MV_machine = function(nodename,type)
                 technic.MV_machines[nodename] = type
                  end
technic.unregister_MV_machine = function(nodename)
                   technic.MV_machines[nodename] = nil
                end
technic.register_MV_power_tool = function(craftitem,max_charge)
                    technic.MV_power_tools[craftitem] = max_charge
                 end
-- register HV machines here
technic.HV_machines    = {}
technic.HV_power_tools = {}
technic.register_HV_machine = function(nodename,type)
                 technic.HV_machines[nodename] = type
                  end
technic.unregister_HV_machine = function(nodename)
                   technic.HV_machines[nodename] = nil
                end
technic.register_HV_power_tool = function(craftitem,max_charge)
                    technic.HV_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,load,max_load)
   local temp=65536-math.floor(load/max_load*65535)
   item_stack["wear"]=tostring(temp)
   return item_stack
end
technic/solar_array_hv.lua
@@ -10,9 +10,6 @@
    sounds = default.node_sound_wood_defaults(),
        description="HV Solar Array",
    active = false,
    technic_hv_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=3000;
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,    
@@ -27,29 +24,25 @@
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_hv_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 3000)
        meta:set_int("HV_EU_supply", 0)
        meta:set_string("infotext", "HV Solar Array")
        meta:set_float("active", false)
    end,
})
minetest.register_craft({
    output = 'technic:solar_array_hv 1',
    recipe = {
        {'technic:solar_array_mv', 'technic:solar_array_mv','technic:solar_array_mv'},
        {'technic:solar_array_mv', 'technic:hv_transformer','technic:solar_array_mv'},
        {'default:steel_ingot',    'technic:hv_cable',      'default:steel_ingot'},
    }
})
minetest.register_craft(
   {output = 'technic:solar_array_hv 1',
    recipe = {
       {'technic:solar_array_mv', 'technic:solar_array_mv','technic:solar_array_mv'},
       {'technic:solar_array_mv', 'technic:hv_transformer','technic:solar_array_mv'},
       {'default:steel_ingot',    'technic:hv_cable',      'default:steel_ingot'},
    }
 })
minetest.register_abm(
    {nodenames = {"technic:solar_array_hv"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
   {nodenames = {"technic:solar_array_hv"},
    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.
@@ -62,7 +55,6 @@
        pos1.y=pos.y+1
        pos1.x=pos.x
        pos1.z=pos.z
        local light = minetest.env:get_node_light(pos1, nil)
        local time_of_day = minetest.env:get_timeofday()
        local meta = minetest.env:get_meta(pos)
@@ -70,24 +62,17 @@
        -- 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 > -10 then
            local internal_EU_buffer      = meta:get_float("internal_EU_buffer")
            local internal_EU_buffer_size = meta:get_float("internal_EU_buffer_size")
            local charge_to_give          = math.floor(light*(light*9.6+pos1.y/130*48))
            if charge_to_give<0   then charge_to_give=0 end
            if charge_to_give>2880 then charge_to_give=2880 end
            if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
               charge_to_give=internal_EU_buffer_size-internal_EU_buffer
            end
            meta:set_string("infotext", "Solar Array is active ("..charge_to_give.."EU)")
            meta:set_float("active",1)
            internal_EU_buffer=internal_EU_buffer+charge_to_give
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
           local charge_to_give          = math.floor(light*(light*9.6+pos1.y/130*48))
           if charge_to_give<0   then charge_to_give=0 end
           if charge_to_give>160 then charge_to_give=160 end
           meta:set_string("infotext", "Solar Array is active ("..charge_to_give.."EU)")
           meta:set_int("HV_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", "Solar Array is inactive");
            meta:set_float("active",0)
           meta:set_string("infotext", "Solar Array is inactive");
           meta:set_int("HV_EU_supply", 0)
        end
    end,
})
         end,
 })
register_HV_machine ("technic:solar_array_hv","PR")
technic.register_HV_machine ("technic:solar_array_hv","PR")
technic/solar_array_lv.lua
@@ -10,10 +10,6 @@
    groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
    sounds = default.node_sound_wood_defaults(),
        description="LV Solar Array",
    active = false,
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=1000;
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,    
@@ -27,68 +23,56 @@
        },
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 1000)
        meta:set_int("technic_power_machine", 1)
        meta:set_int("LV_EU_supply", 0)
        meta:set_string("infotext", "LV Solar Array")
        meta:set_float("active", false)
    end,
})
minetest.register_craft({
    output = 'technic:solar_array_lv 1',
    recipe = {
        {'technic:solar_panel', 'technic:solar_panel',    'technic:solar_panel'},
        {'technic:solar_panel', 'technic:lv_transformer', 'technic:solar_panel'},
        {'default:steel_ingot', 'technic:lv_cable',       'default:steel_ingot'},
    }
})
minetest.register_craft(
   {output = 'technic:solar_array_lv 1',
    recipe = {
       {'technic:solar_panel', 'technic:solar_panel',    'technic:solar_panel'},
       {'technic:solar_panel', 'technic:lv_transformer', 'technic:solar_panel'},
       {'default:steel_ingot', 'technic:lv_cable',       'default:steel_ingot'},
    }
 })
minetest.register_abm(
    {nodenames = {"technic:solar_array_lv"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
   {nodenames = {"technic:solar_array_lv"},
    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 160EU 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 arrays do not work outside daylight hours or if
                -- built below -10m
        -- Height gives 1/4 of the effect, light 3/4. Max. effect is 160EU 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 arrays 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.env:get_node_light(pos1, nil)
        local time_of_day = minetest.env:get_timeofday()
        local meta = minetest.env:get_meta(pos)
        if light == nil then light = 0 end
        -- turn on array only during day time and if sufficient light
                -- I know this is counter intuitive when cheating by using other light sources.
        -- 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 > -10 then
            local internal_EU_buffer      = meta:get_float("internal_EU_buffer")
            local internal_EU_buffer_size = meta:get_float("internal_EU_buffer_size")
            local charge_to_give          = math.floor(light*(light*0.5333+pos1.y/130*2.6667))
            if charge_to_give<0   then charge_to_give=0 end
            if charge_to_give>160 then charge_to_give=160 end
            if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
               charge_to_give=internal_EU_buffer_size-internal_EU_buffer
            end
            meta:set_string("infotext", "Solar Array is active ("..charge_to_give.."EU)")
            meta:set_float("active",1)
            internal_EU_buffer=internal_EU_buffer+charge_to_give
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
           local charge_to_give = math.floor(light*(light*0.5333+pos1.y/130*2.6667))
           if charge_to_give<0   then charge_to_give=0 end
           if charge_to_give>160 then charge_to_give=160 end
           meta:set_string("infotext", "Solar Array is active ("..charge_to_give.."EU)")
           meta:set_int("LV_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", "Solar Array is inactive");
            meta:set_float("active",0)
           meta:set_string("infotext", "Solar Array is inactive");
           meta:set_int("LV_EU_supply", 0)
        end
    end,
})
         end,
 })
register_LV_machine ("technic:solar_array_lv","PR")
technic.register_LV_machine ("technic:solar_array_lv","PR")
technic/solar_array_mv.lua
@@ -11,9 +11,6 @@
    sounds = default.node_sound_wood_defaults(),
        description="MV Solar Array",
    active = false,
    technic_mv_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=1000;
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,    
@@ -28,37 +25,34 @@
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_mv_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 1000)
        meta:set_int("MV_EU_supply", 0)
        meta:set_string("infotext", "MV Solar Array")
        meta:set_float("active", false)
    end,
})
minetest.register_craft({
    output = 'technic:solar_array_mv 1',
    recipe = {
        {'technic:solar_array_lv', 'technic:solar_array_lv','technic:solar_array_lv'},
        {'technic:solar_array_lv', 'technic:mv_transformer','technic:solar_array_lv'},
        {'default:steel_ingot',    'technic:mv_cable',      'default:steel_ingot'},
    }
minetest.register_craft(
   {
      output = 'technic:solar_array_mv 1',
      recipe = {
     {'technic:solar_array_lv', 'technic:solar_array_lv','technic:solar_array_lv'},
     {'technic:solar_array_lv', 'technic:mv_transformer','technic:solar_array_lv'},
     {'default:steel_ingot',    'technic:mv_cable',      'default:steel_ingot'},
      }
})
minetest.register_abm(
    {nodenames = {"technic:solar_array_mv"},
    interval   = 1,
    chance     = 1,
    action = function(pos, node, active_object_count, active_object_count_wider)
   {nodenames = {"technic:solar_array_mv"},
    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 720EU 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
        -- Height gives 1/4 of the effect, light 3/4. Max. effect is 720EU 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
@@ -69,27 +63,20 @@
        local meta = minetest.env:get_meta(pos)
        if light == nil then light = 0 end
        -- turn on array only during day time and if sufficient light
                -- I know this is counter intuitive when cheating by using other light sources.
        -- 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 > -10 then
            local internal_EU_buffer      = meta:get_float("internal_EU_buffer")
            local internal_EU_buffer_size = meta:get_float("internal_EU_buffer_size")
            local charge_to_give          = math.floor(light*(light*2.4+pos1.y/130*12))
            if charge_to_give<0   then charge_to_give=0 end
            if charge_to_give>720 then charge_to_give=720 end
            if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
               charge_to_give=internal_EU_buffer_size-internal_EU_buffer
            end
            meta:set_string("infotext", "Solar Array is active ("..charge_to_give.."EU)")
            meta:set_float("active",1)
            internal_EU_buffer=internal_EU_buffer+charge_to_give
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
            -- Idea: How about letting solar panels provide power without battery boxes?
            -- This could provide an even distribution to all receivers.
           local charge_to_give = math.floor(light*(light*2.4+pos1.y/130*12))
           if charge_to_give<0   then charge_to_give=0 end
           if charge_to_give>160 then charge_to_give=160 end
           meta:set_string("infotext", "Solar Array is active ("..charge_to_give.."EU)")
           --            meta:set_float("active",1)
           meta:set_int("MV_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", "Solar Array is inactive");
            meta:set_float("active",0)
           meta:set_string("infotext", "Solar Array is inactive");
           meta:set_int("MV_EU_supply", 0)
        end
    end,
})
         end,
 })
register_MV_machine ("technic:solar_array_mv","PR")
technic.register_MV_machine ("technic:solar_array_mv","PR")
technic/solar_panel.lua
@@ -8,9 +8,6 @@
    sounds = default.node_sound_wood_defaults(),
        description="Solar Panel",
    active = false,
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=160;
    drawtype = "nodebox",
    paramtype = "light",
    is_ground_content = true,    
@@ -24,12 +21,9 @@
        },
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 160)
        meta:set_string("infotext", "Solar Panel")
        meta:set_float("active", false)
        meta:set_int("technic_power_machine", 1)
        meta:set_int("LV_EU_supply", 0)
        meta:set_string("infotext", "LV Solar Panel")
    end,
})
@@ -68,24 +62,17 @@
        -- 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 internal_EU_buffer=meta:get_float("internal_EU_buffer")
            local internal_EU_buffer_size=meta:get_float("internal_EU_buffer_size")
            local charge_to_give=math.floor(light*(light*0.0867+pos1.y/130*0.4333))
            if charge_to_give<0 then charge_to_give=0 end
            if charge_to_give>26 then charge_to_give=26 end
            if internal_EU_buffer+charge_to_give>internal_EU_buffer_size then
               charge_to_give=internal_EU_buffer_size-internal_EU_buffer
            end
            meta:set_string("infotext", "Solar Panel is active ("..charge_to_give.."EU)")
            meta:set_float("active",1)
            internal_EU_buffer=internal_EU_buffer+charge_to_give
            meta:set_float("internal_EU_buffer",internal_EU_buffer)
            meta:set_int("LV_EU_supply", charge_to_give)
        else
            meta:set_string("infotext", "Solar Panel is inactive");
            meta:set_float("active",0)
            meta:set_int("LV_EU_supply", 0)
        end
    end,
}) 
register_LV_machine ("technic:solar_panel","PR")
technic.register_LV_machine ("technic:solar_panel","PR")
technic/solar_panel_mv.lua
File was deleted
technic/sonic_screwdriver.lua
@@ -1,5 +1,5 @@
sonic_screwdriver_max_charge=15000
register_power_tool ("technic:sonic_screwdriver",sonic_screwdriver_max_charge)
local sonic_screwdriver_max_charge=15000
technic.register_HV_power_tool ("technic:sonic_screwdriver",sonic_screwdriver_max_charge)
minetest.register_tool("technic:sonic_screwdriver", {
            description = "Sonic Screwdriver",
@@ -38,7 +38,7 @@
                        charge=charge-100;  
                        meta1["charge"]=charge
                        item["metadata"]=set_item_meta(meta1)
                        set_RE_wear(item,charge,sonic_screwdriver_max_charge)
                        technic.set_RE_wear(item,charge,sonic_screwdriver_max_charge)
                        itemstack:replace(item)
                        end
                        return itemstack
technic/supply_converter.lua
New file
@@ -0,0 +1,232 @@
-- 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.
--   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_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'},
    }
})
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 -- -""-
         -- 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)
         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
         -- 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 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,
})
technic/switching_station.lua
New file
@@ -0,0 +1,352 @@
-- SWITCHING STATION
-- The switching station is the center of all power distribution on an electric network.
-- The station will collect all produced power from producers (PR) and batteries (BA)
-- and distribute it to receivers (RE) and depleted batteries (BA).
--
-- It works like this:
--  All PR,BA,RE nodes are indexed and tagged with the switching station.
-- The tagging is to allow more stations to be built without allowing a cheat
-- with duplicating power.
--  All the RE nodes are queried for their current EU demand. Those which are off
-- would require no or a small standby EU demand, while those which are on would
-- require more.
-- If the total demand is less than the available power they are all updated with the
-- demand number.
-- If any surplus exists from the PR nodes the batteries will be charged evenly with this.
-- If the total demand requires draw on the batteries they will be discharged evenly.
--
-- If the total demand is more than the available power all RE nodes will be shut down.
-- We have a brown-out situation.
--
-- Hence all the power distribution logic resides in this single node.
--
--  Nodes connected to the network will have one or more of these parameters as meta data:
--   <LV|MV|HV>_EU_supply : Exists for PR and BA node types. This is the EU value supplied by the node. Output
--   <LV|MV|HV>_EU_demand : Exists for RE and BA node types. This is the EU value the node requires to run. Output
--   <LV|MV|HV>_EU_input  : Exists for RE and BA node types. This is the actual EU value the network can give the node. Input
--
--  The reason the LV|MV|HV type is prepended toe meta data is because some machine could require several supplies to work.
--  This way the supplies are separated per network.
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_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
 })
--------------------------------------------------
-- 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
--------------------------------------------------
-- 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
-- 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
-- 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
----------------------------------------------
-- 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 network   = ""
            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
            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    = 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.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.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.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.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. 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.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
                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
            -- 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
    end,
})
technic/textures/technic_enriched_uranium.png
technic/textures/technic_homedecor_glowlight_cube_white_sides.png
technic/textures/technic_homedecor_glowlight_cube_white_sides_ceiling.png
technic/textures/technic_homedecor_glowlight_cube_white_tb.png
technic/textures/technic_homedecor_glowlight_cube_yellow_sides.png
technic/textures/technic_homedecor_glowlight_cube_yellow_sides_ceiling.png
technic/textures/technic_homedecor_glowlight_cube_yellow_tb.png
technic/textures/technic_homedecor_glowlight_thick_white_sides.png
technic/textures/technic_homedecor_glowlight_thick_white_wall_sides.png
technic/textures/technic_homedecor_glowlight_thick_yellow_sides.png
technic/textures/technic_homedecor_glowlight_thick_yellow_wall_sides.png
technic/textures/technic_homedecor_glowlight_thin_white_sides.png
technic/textures/technic_homedecor_glowlight_thin_white_wall_sides.png
technic/textures/technic_homedecor_glowlight_thin_yellow_sides.png
technic/textures/technic_homedecor_glowlight_thin_yellow_wall_sides.png
technic/textures/technic_homedecor_glowlight_white_tb.png
technic/textures/technic_homedecor_glowlight_yellow_tb.png
technic/textures/technic_mv_solar_panel_bottom.png
Binary files differ
technic/textures/technic_mv_solar_panel_side.png
Binary files differ
technic/textures/technic_mv_solar_panel_top.png
Binary files differ
technic/textures/technic_mv_solarpanel_bottom.png
Binary files differ
technic/textures/technic_mv_solarpanel_side.png
Binary files differ
technic/textures/technic_mv_solarpanel_top.png
Binary files differ
technic/textures/technic_supply_converter_bottom.png
technic/textures/technic_supply_converter_side.png
technic/textures/technic_supply_converter_top.png
technic/textures/technicx32/technic_mv_solar_panel_bottom.png
Binary files differ
technic/textures/technicx32/technic_mv_solar_panel_side.png
Binary files differ
technic/textures/technicx32/technic_mv_solar_panel_top.png
Binary files differ
technic/tool_workshop.lua
@@ -1,3 +1,5 @@
-- LV Tool workshop
-- This machine repairs tools.
minetest.register_alias("tool_workshop", "technic:tool_workshop")
minetest.register_craft({
    output = 'technic:tool_workshop',
@@ -13,88 +15,108 @@
    stack_max = 99,
}) 
workshop_formspec =
    "invsize[8,9;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "list[current_name;src;3,1;1,1;]"..
    "label[0,0;Tool Workshop]"..
    "label[1,3;Power level]"..
    "list[current_player;main;0,5;8,4;]"
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(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=2000;
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.env: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.env: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,
   })
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Tool Workshop")
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 1)
        meta:set_float("internal_EU_buffer_size", 2000)
        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.env:get_meta(pos);
        local inv = meta:get_inventory()
        if not inv:is_empty("src") then
            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.env:get_meta(pos)
         local eu_input     = meta:get_int("LV_EU_input")
         local state        = meta:get_int("state")
         local next_state   = state
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.env:get_meta(pos)
    local charge= meta:get_float("internal_EU_buffer")
    local max_charge= meta:get_float("internal_EU_buffer_size")
    local load_step=2000
    local load_cost=200
        local inv = meta:get_inventory()
        if inv:is_empty("src")==false  then
            srcstack = inv:get_stack("src", 1)
            src_item=srcstack:to_table()
            if (src_item["name"]=="technic:water_can" or src_item["name"]=="technic:lava_can") then
                load_step=0
                load_cost=0
                end
            local load1=tonumber((src_item["wear"]))
            if charge>load_cost then
                if load1>1 then
                    if load1-load_step<0 then load_step=load1 load1=1
                    else load1=load1-load_step end
                    charge=charge-load_cost
                    src_item["wear"]=tostring(load1)
                    inv:set_stack("src", 1, src_item)
                end
            end
        end
    meta:set_float("internal_EU_buffer",charge)
    local load = math.floor((charge/max_charge)*100)
    meta:set_string("formspec",
                "invsize[8,9;]"..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]"..
                "list[current_name;src;3,1;1,1;]"..
                "label[0,0;Tool Workshop]"..
                "label[1,3;Power level]"..
                "list[current_player;main;0,5;8,4;]")
    end
})
         -- Machine information
         local machine_name         = "Tool Workshop"
         local machine_node         = "technic:tool_workshop"
         local machine_state_demand = { 50, 150 }
         -- Setup meta data if it does not exist. state is used as an indicator of this
         if state == 0 then
            meta:set_int("state", 1)
            meta:set_int("LV_EU_demand", machine_state_demand[1])
            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")
         -- State machine
         if eu_input == 0 then
            -- Unpowered - go idle
            --hacky_swap_node(pos, machine_node)
            meta:set_string("infotext", machine_name.." Unpowered")
            next_state = 1
         elseif eu_input == machine_state_demand[state] then
            -- Powered - do the state specific actions
            local inv = meta:get_inventory()
            if state == 1 then
               --hacky_swap_node(pos, machine_node)
               meta:set_string("infotext", machine_name.." Idle")
               if not inv:is_empty("src") then
              next_state = 2
               end
            elseif state == 2 then
               --hacky_swap_node(pos, machine_node.."_active")
               meta:set_string("infotext", machine_name.." Active")
register_LV_machine ("technic:tool_workshop","RE")
               if inv:is_empty("src") then
              next_state = 1
               else
              srcstack = inv:get_stack("src", 1)
              src_item=srcstack:to_table()
              -- Cannot charge cans
              if (src_item["name"]=="technic:water_can" or src_item["name"]=="technic:lava_can") then
                 return
              end
              local wear=tonumber(src_item["wear"])
              wear = math.max(1, wear-2000) -- Improve the tool this much every tick
              src_item["wear"]=tostring(wear)
              inv:set_stack("src", 1, src_item)
               end
            end
         end
         -- Change state?
         if next_state ~= state then
            meta:set_int("LV_EU_demand", machine_state_demand[next_state])
            meta:set_int("state", next_state)
         end
          end
   })
technic.register_LV_machine ("technic:tool_workshop","RE")
technic/water_mill.lua
@@ -1,3 +1,6 @@
-- 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({
@@ -14,7 +17,7 @@
    stack_max = 99,
}) 
water_mill_formspec =
local water_mill_formspec =
    "invsize[8,4;]"..
    "image[1,1;1,2;technic_power_meter_bg.png]"..
    "label[0,0;Water Mill]"..
@@ -22,110 +25,98 @@
    "list[current_player;main;0,5;8,4;]"
    
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(),
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=5000;
    burn_time=0;
    on_construct = function(pos)
        local meta = minetest.env:get_meta(pos)
        meta:set_string("infotext", "Water Mill")
        meta:set_float("technic_power_machine", 1)
        meta:set_float("internal_EU_buffer", 0)
        meta:set_float("internal_EU_buffer_size", 3000)
        meta:set_string("formspec", water_mill_formspec)
        end,
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.env:get_meta(pos)
            meta:set_string("infotext", "Water Mill")
            meta:set_float("technic_power_machine", 1)
            meta:set_int("LV_EU_supply", 0)
            meta:set_string("formspec", water_mill_formspec)
             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",
})
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",
    technic_power_machine=1,
    internal_EU_buffer=0;
    internal_EU_buffer_size=0;
})
local check_node_around_mill = function(pos)
                  local node=minetest.env:get_node(pos)
                  if node.name=="default:water_flowing" then return 1 end
                  return 0
                   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)
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.env:get_meta(pos)
          local water_nodes      = 0
          local lava_nodes       = 0
          local production_level = 0
          local eu_supply        = 0
    local meta = minetest.env:get_meta(pos)
    local charge= meta:get_float("internal_EU_buffer")
    local max_charge= meta:get_float("internal_EU_buffer_size")
    local water_nodes = 0
    local lava_nodes = 0
    local production_level=0
    local load_step=0
    pos.x=pos.x+1
    local check=check_node_around_mill (pos)
    if check==1 then water_nodes=water_nodes+1 end
    pos.x=pos.x-2
    check=check_node_around_mill (pos)
    if check==1 then water_nodes=water_nodes+1 end
    pos.x=pos.x+1
    pos.z=pos.z+1
    check=check_node_around_mill (pos)
    if check==1 then water_nodes=water_nodes+1 end
    pos.z=pos.z-2
    check=check_node_around_mill (pos)
    if check==1 then water_nodes=water_nodes+1 end
    pos.z=pos.z+1
          pos.x=pos.x+1
          local check=check_node_around_mill (pos)
          if check==1 then water_nodes=water_nodes+1 end
          pos.x=pos.x-2
          check=check_node_around_mill (pos)
          if check==1 then water_nodes=water_nodes+1 end
          pos.x=pos.x+1
          pos.z=pos.z+1
          check=check_node_around_mill (pos)
          if check==1 then water_nodes=water_nodes+1 end
          pos.z=pos.z-2
          check=check_node_around_mill (pos)
          if check==1 then water_nodes=water_nodes+1 end
          pos.z=pos.z+1
    
    if water_nodes==1 then production_level=25 load_step=30 end
    if water_nodes==2 then production_level=50 load_step=60 end
    if water_nodes==3 then production_level=75 load_step=90 end
    if water_nodes==4 then production_level=100 load_step=120 end
          if water_nodes==1 then production_level =  25; eu_supply =  30 end
          if water_nodes==2 then production_level =  50; eu_supply =  60 end
          if water_nodes==3 then production_level =  75; eu_supply =  90 end
          if water_nodes==4 then production_level = 100; eu_supply = 120 end
        if production_level>0 then
        if charge+load_step>max_charge then
        load_step=max_charge-charge
        end
        if load_step>0 then
        charge=charge+load_step
        meta:set_float("internal_EU_buffer",charge)
        end
    end
          if production_level>0 then
             meta:set_int("LV_EU_supply", eu_supply)
          end
    local load = math.floor((charge/max_charge)*100)
    meta:set_string("formspec",
                "invsize[8,4;]"..
                "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                        (load)..":technic_power_meter_fg.png]"..
                "label[0,0;Water Mill]"..
                "label[1,3;Power level]"..
                "label[4,0;Production at "..tostring(production_level).."%]"
                )
          local load = 1 -- math.floor((charge/max_charge)*100)
          meta:set_string("formspec",
                  "invsize[8,4;]"..
                     "image[1,1;1,2;technic_power_meter_bg.png^[lowpart:"..
                     (load)..":technic_power_meter_fg.png]"..
                  "label[0,0;Water Mill]"..
                  "label[1,3;Power level]"..
                  "label[4,0;Production at "..tostring(production_level).."%]"
                )
                
    if production_level>0 and minetest.env:get_node(pos).name=="technic:water_mill" then
        hacky_swap_node (pos,"technic:water_mill_active")
        return
    end
    if production_level==0 then hacky_swap_node (pos,"technic:water_mill") end
end
})
          if production_level>0 and minetest.env: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
   })
function check_node_around_mill (pos)
local node=minetest.env:get_node(pos)
if node.name=="default:water_flowing"  then return 1 end
return 0
end
register_LV_machine ("technic:water_mill","PR")
register_LV_machine ("technic:water_mill_active","PR")
technic.register_LV_machine ("technic:water_mill","PR")
technic.register_LV_machine ("technic:water_mill_active","PR")
technic_worldgen/depends.txt
@@ -1 +1,2 @@
default
technic
technic_worldgen/nodes.lua
@@ -96,3 +96,5 @@
        {'technic:marble','technic:marble'}
    }
})
minetest.register_alias("technic:diamond_block", "default:diamondblock")
technic_worldgen/oregen.lua
@@ -28,6 +28,7 @@
    height_min     = -31000,
    height_max     = 2,
})
if technic.config:getBool("enable_marble_generation") then
minetest.register_ore({
    ore_type       = "sheet",
    ore            = "technic:marble",
@@ -40,6 +41,8 @@
    noise_threshhold = 0.4,
    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
minetest.register_ore({
    ore_type       = "sheet",
    ore            = "technic:granite",
@@ -52,4 +55,5 @@
    noise_threshhold = 0.4,
    noise_params = {offset=0, scale=15, spread={x=130, y=130, z=130}, seed=24, octaves=3, persist=0.70}
})
end
unified_inventory/api.lua
@@ -230,7 +230,10 @@
                end    
                if craft.type == "alloy" then
                method="Alloy cooking"
                end
                end
                if craft.type == "extracting" then
                method="Extracting"
                end
                formspec = formspec.."label[6,3;"..method.."]"
            end
            
@@ -557,8 +560,12 @@
    local craft = crafts[alternate]
    inv:set_stack("output", 1, craft.output)
    local items=craft.items
    -- cook, fuel, grinding recipes
    if craft.type == "cooking" or craft.type == "fuel" or craft.type == "grinding" then
    -- cooking, fuel, grinding, and extracting recipes
    if craft.type == "cooking" or
       craft.type == "fuel" or
       craft.type == "grinding" or
       craft.type == "extracting" then
        def=unified_inventory.find_item_def(craft["items"][1])
        if def then
            inv:set_stack("build", 1, def)
unified_inventory/depends.txt
@@ -1 +1,2 @@
creative