code:
# Braziliam portuguese translation for technic
# Tradução portuguesa brasileira para technic
# By Sires

## Misc
[Technic] Loaded in %f seconds = [Technic] Carregado em %f segundos

## Items
Silicon Wafer = Pastilha de Silício
Doped Silicon Wafer = Pastilha de Silício Dopada
Enriched Uranium = Urânio Enriquecido
Uranium Fuel = Combustivel de Urânio
Diamond Drill Head = Cabeça de Broca de Diamante
Blue Energy Crystal = Cristal de Energia Azul
Green Energy Crystal = Cristal de Energia Verde
Red Energy Crystal = Cristal de Energia Vermelho
Fine Copper Wire = Fio Fino de Cobre
Copper Coil = Bobina de Cobre
Electric Motor = Motor Elétrico
Low Voltage Transformer = Transformador de Baixa Voltagem
Medium Voltage Transformer = Transformador de Média Voltagem
High Voltage Transformer = Transformador de Alta Voltagem
Control Logic Unit = Unidade de Controle Lógico
Mixed Metal Ingot = Lingote de Metal Misturado
Composite Plate = Placa Composta
Copper Plate = Placa de Cobre
Carbon Plate = Placa de Carbono
Graphite = Grafite
Carbon Cloth = Recido de Carbono
Raw Latex = Latex bruto
Rubber Fiber = Fibra de Borracha
%.1f%%-Fissile Uranium Ingot = Lingote de Urânio %.1f%%-Físsil
%.1f%%-Fissile Uranium Block = Bloco de Urânio %.1f%%-Físsil

## Machine Misc
Machine cannot be removed because it is not empty = A máquina não pode ser removida porque ela não está vazia
Inventory move disallowed due to protection = Movimento de inventário não permitido pela proteção
# $1: Machine name (includes tier)
@1 Active (@2 EU) = @1 Ativo (@2 EU)
%s Active = %s Ativo
%s Disabled = %s Ativado
%s Enabled = %s Desativado
%s Idle = Ócio
%s Improperly Placed = %s Colocado Inapropriadamente
%s is empty = %s está vazio
%s Unpowered = %s Sem energia
%s Out Of Fuel = %s Sem Combustível
%s Has Bad Cabling = %s Tem Cabeamento Ruim
%s (Slave) = %s (Servo)
%s Has No Network = %s Não Tem Rede
%s Finished = %s Acabou
Enable/Disable = Ativar/Desativar
Range = Alcance
Upgrade Slots = Lugares para Melhoria
In: = Entrada:
Out: = Saída:
Slot %d = Lugar %d
Itemwise = Por item
Stackwise = Por pilha
Ignoring Mesecon Signal = Ignorar Sinaal de Mesecon
Controlled by Mesecon Signal = Controlado por Sinal de Mesecon
Owner: = Dono:
Unlocked = Destravado
Locked = Travado
Radius: = Raio:
Enabled = Ativado
Disabled = Desativado

## Machine names
# $1: Tier
%s Alloy Furnace = Fornalha de Liga %s
%s Battery Box = Caixa de Bateria %s
%s Cable = Cabo %s
%s CNC Machine = Máquina CNC %s
%s Centrifuge = Centrifuga %s
%s Compressor = Compresso %s
%s Extractor = Extrator %s
%s Forcefield Emitter = Emissor de Campo de Força %s
%s Furnace = Fornalha %s
%s Grinder = Triturador %s
%s Music Player = Tocador de Música %s
%s Quarry = Pedreira %s
%s Tool Workshop = Oficina de Ferramentas %s
Arrayed Solar %s Generator = Gerador Solar Equipado %s
Fuel-Fired %s Generator = Gerador Alimentado-por-Combustível %s
Geothermal %s Generator = Gerador Geotermal %s
Hydro %s Generator = Gerador Hidráulico %s
Nuclear %s Generator Core = Núcleo de Gerador Nuclear %s
Small Solar %s Generator = Gerador Solar Pequeno %s
Wind %s Generator = Gerador de Energia Eólica %s
Self-Contained Injector = Injetor Auto-Contido
Constructor Mk%d = Construtor Nv%d
Frame = Armação
Frame Motor = Motor de Armação
Template = Modelo
Template (replacing) = Modelo (recolocando)
Template Motor = Modelo de Motor
Template Tool = Modelo de Ferramenta
Battery Box = Caixa de Bateria
Supply Converter = Conversor de Energia
Switching Station = Estação de Comutação
Fuel-Fired Alloy Furnace = Fornalha de Liga Alimentada-por-Combustível
Fuel-Fired Furnace = Fornalha Alimentada-por-Combustível
Wind Mill Frame = Armação de Moinho de Vento
Forcefield = Campo de Força
Nuclear Reactor Rod Compartment = Compartimento de Barra do Reator Nuclear
Administrative World Anchor = Âncora de Mundo Administrativa

## Machine-specific
# $1: Pruduced EU
Charge = Carregar
Discharge = Descarregar
Power level = Nível de Energia
# $1: Tier $2: current_charge $3: max_charge
@1 Battery Box: @2/@3 = Caixa de Baterias @1: @2/@3
# $1: Machine name $2: Supply $3: Demand
@1. Supply: @2 Demand: @3 = @1. Suprimento: @2 Demanda: @3
Production at %d%% = Produção em %d%%
Choose Milling Program: = Escolha o Programa de Serragem:
Slim Elements half / normal height: = Metade de Elementos Finos / altura normal:
Current track %s = Música Atual %s
Stopped = Parado
Keeping %d/%d map blocks loaded = Mantendo %d/%d blocos de mapa carregados
Digging not started = Escavação não começada
Digging finished = Escavação terminada
Digging %d m above machine = Escavando %d m acima da máquina
Digging %d m below machine = Escavando %d m abaixo da máquina
@1 (@2 @3 -> @4 @5) = @1 (@2 @3 -> @4 @5)

## CNC
Cylinder = Cilindro
Element Cross = Cruz do Elemento
Element Cross Double = Cruz Dupla do Elemento
Element Edge = Borda do Elemento
Element Edge Double = Borda Dupla do Elemento
Element End = Final do Elemento
Element End Double = Final Duplo do Elemento
Element Straight = Elemento Contínuo
Element Straight Double = Elemento Contínuo duplo
Element T = Elemento em T
Element T Double = Elemento em T Duplo
Horizontal Cylinder = Cilindro Horizontal
One Curved Edge Block = Uma Borda de Bloco Curvada
Pyramid = Pirâmide
Slope = Ladeira
Slope Edge = Canto de Ladeira
Slope Inner Edge = Canto de Dentro de Ladeira
Slope Lying = Ladeira Deitada
Slope Upside Down = Ladeira de Cabeça para Baixo
Slope Upside Down Edge = Cande de Ladeira de Cabeça para Baixo
Slope Upside Down Inner Edge = Canto de Dentro de Ladeira de Cabeça para Baixo
Sphere = Esfera
Spike = Espinho
Stick = Graveto
Two Curved Edge Block = Bloco de Duas Bordas Curvadas
Brick = Tijolo
Cobble = Pedregulho
Dirt = Terra
Leaves = Folhas
Sandstone = Arenito
Stone = Pedra
Tree = Árvore
Wooden = de Madeira

## Grinder Recipes
# $1: Name
%s Dust = Pó de %s
Akalin = Akalin
Alatro = Alatro
Arol = Arol
Brass = Latão
Bronze = Bronze
Carbon Steel = Aço Carbono
Cast Iron = Ferro Fundido
Chromium = Crômio
Coal = Carvão
Copper = Cobre
Gold = Ouro
Mithril = Mithril
Silver = Prata
Stainless Steel = Aço Inoxidável
Talinite = Talinite
Tin = Estanho
Wrought Iron = Ferro Forjado
Zinc = Zinco
%.1f%%-Fissile Uranium = Urânio %.1f%%-Físsil

## Tools
RE Battery = Bateria RE
Water Can = Lata de Água
Lava Can = Lata de Lava
Chainsaw = Motosserra
Flashlight = Lanterna
3 nodes deep. = 3 nodes de profundidade.
3 nodes tall. = 3 nodes de altura.
3 nodes wide. = 3 nodes de largura.
3x3 nodes. = 3x3 nodes.
Use while sneaking to change Mining Drill Mk%d modes. = Use enquanto esgueirando para mudar os modos da Broca de Mineração Nv%d.
Mining Drill Mk%d Mode %d = Broca de Mineração Nv%d Modo %d
Mining Drill Mk%d = Broca de Mineração Nv%d
Mining Laser Mk%d = Laser de Mineração Nv%d
Single node. = Unico node.
Sonic Screwdriver = Chave de Fenda Sônica.
Tree Tap = Torneira de Árvore

## Craft descriptions
Alloy cooking = Cozinhando em liga
Grinding = Triturando
Compressing = Comprimindo
Extracting = Extraindo
Separating = Separando


code:
# template.txt
# Template for translations of Technic

## Misc
[Technic] Loaded in %f seconds =

## Items
Silicon Wafer =
Doped Silicon Wafer =
Enriched Uranium =
Uranium Fuel =
Diamond Drill Head =
Blue Energy Crystal =
Green Energy Crystal =
Red Energy Crystal =
Fine Copper Wire =
Fine Gold Wire =
Fine Silver Wire =
Copper Coil =
Electric Motor =
Low Voltage Transformer =
Medium Voltage Transformer =
High Voltage Transformer =
Control Logic Unit =
Mixed Metal Ingot =
Composite Plate =
Copper Plate =
Carbon Plate =
Graphite =
Carbon Cloth =
Raw Latex =
Rubber Fiber =
%.1f%%-Fissile Uranium Ingot =
%.1f%%-Fissile Uranium Block =

## Machine misc
Machine cannot be removed because it is not empty =
Inventory move disallowed due to protection =
# $1: Machine name (Includes tier)
@1 Active (@2 EU) =
%s Active =
%s Disabled =
%s Enabled =
%s Idle =
%s Improperly Placed =
%s is empty =
%s Unpowered =
%s Out Of Fuel =
%s Has Bad Cabling =
%s (Slave) =
%s Has No Network =
%s Finished =
Enable/Disable =
Range =
Upgrade Slots =
In: =
Out: =
Slot %d =
Itemwise =
Stackwise =
Ignoring Mesecon Signal =
Controlled by Mesecon Signal =
Owner: =
Unlocked =
Locked =
Radius: =
Enabled =
Disabled =

## Machine names
# $1: Tier
%s Alloy Furnace =
%s Battery Box =
%s Cable =
%s Centrifuge =
%s Compressor =
%s Extractor =
%s Forcefield Emitter =
%s Furnace =
%s Grinder =
%s Music Player =
%s Quarry =
%s Tool Workshop =
Arrayed Solar %s Generator =
Fuel-Fired %s Generator =
Geothermal %s Generator =
Hydro %s Generator =
Nuclear %s Generator Core =
Small Solar %s Generator =
Wind %s Generator =
Self-Contained Injector =
Constructor Mk%d =
Frame =
Frame Motor =
Template =
Template (replacing) =
Template Motor =
Template Tool =
Battery Box =
Supply Converter =
Switching Station =
Fuel-Fired Alloy Furnace =
Fuel-Fired Furnace =
Wind Mill Frame =
Forcefield =
Nuclear Reactor Rod Compartment =
Administrative World Anchor =

## Machine-specific
# $1: Pruduced EU
Charge =
Discharge =
Power level =
# $1: Tier $2: current_charge $3: max_charge
@1 Battery Box: @2/@3 =
# $1: Machine name $2: Supply $3: Demand
@1. Supply: @2 Demand: @3 =
Production at %d%% =
Choose Milling Program: =
Slim Elements half / normal height: =
Current track %s =
Stopped =
Keeping %d/%d map blocks loaded =
Digging not started =
Digging finished =
Digging %d m above machine =
Digging %d m below machine =
@1 (@2 @3 -> @4 @5) =

## Grinder Recipes
# $1: Name
%s Dust =
Akalin =
Alatro =
Arol =
Brass =
Bronze =
Carbon Steel =
Cast Iron =
Chromium =
Coal =
Copper =
Gold =
Mithril =
Silver =
Stainless Steel =
Talinite =
Tin =
Wrought Iron =
Zinc =
%.1f%%-Fissile Uranium =

## Tools
RE Battery =
Water Can =
Lava Can =
Chainsaw =
Flashlight =
3 nodes deep. =
3 nodes tall. =
3 nodes wide. =
3x3 nodes. =
Use while sneaking to change Mining Drill Mk%d modes. =
Mining Drill Mk%d Mode %d =
Mining Drill Mk%d =
Mining Laser Mk%d =
Single node. =
Sonic Screwdriver =
Tree Tap =

## Craft descriptions
Alloy cooking =
Grinding =
Compressing =
Extracting =
Separating =

repo_name: Desour/PlayMinetestServer

license: mit


code:
-- HV battery box

minetest.register_craft({
	output = 'technic:hv_battery_box0',
	recipe = {
		{'technic:mv_battery_box0', 'technic:mv_battery_box0', 'technic:mv_battery_box0'},
		{'technic:mv_battery_box0', 'technic:hv_transformer',  'technic:mv_battery_box0'},
		{'',                        'technic:hv_cable',        ''},
	}
})

technic.register_battery_box({
	tier           = "HV",
	max_charge     = 1000000,
	charge_rate    = 100000,
	discharge_rate = 400000,
	charge_step    = 10000,
	discharge_step = 40000,
	upgrade        = 1,
	tube           = 1,
})


code:
minetest.register_craft({
	output = 'technic:hv_cable 3',
	recipe = {
		{'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting'},
		{'technic:mv_cable',           'technic:mv_cable',           'technic:mv_cable'},
		{'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting'},
	}
})

technic.register_cable("HV", 3/16)

if minetest.get_modpath("digilines") then

	local S = technic.getter

	if minetest.get_modpath("digistuff") then
		minetest.register_craft({
			output = 'technic:hv_digi_cable 1',
			type = "shapeless",
			recipe = {'digistuff:digimese', 'technic:hv_cable'}
		})
	else
		minetest.register_craft({
			output = 'technic:hv_digi_cable 1',
			recipe = {
				{'digilines:wire_std_00000000', 'digilines:wire_std_00000000', 'digilines:wire_std_00000000'},
				{'digilines:wire_std_00000000', 'technic:hv_cable',            'digilines:wire_std_00000000'},
				{'digilines:wire_std_00000000', 'digilines:wire_std_00000000', 'digilines:wire_std_00000000'},
			}
		})
	end

	technic.register_cable("HV", 3/16, S("HV Cable (digiline)"), "_digi", {
		digiline = {
			wire = {
				rules = {
					{x = 1, y = 0, z = 0},
					{x =-1, y = 0, z = 0},
					{x = 0, y = 1, z = 0},
					{x = 0, y =-1, z = 0},
					{x = 0, y = 0, z = 1},
					{x = 0, y = 0, z =-1}
				}
			}
		}
	})
end


code:
-- HV compressor

minetest.register_craft({
	output = 'technic:hv_compressor',
	recipe = {
		{'technic:carbon_plate',          'technic:mv_compressor',   'technic:composite_plate'},
		{'pipeworks:tube_1',              'technic:hv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:hv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_compressor({tier = "HV", demand = {1500, 1000, 750}, speed = 5, upgrade = 1, tube = 1})


code:
-- 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:hv_electric_furnace',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:mv_electric_furnace', 'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:hv_transformer',      'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:hv_cable',            'technic:stainless_steel_ingot'},
	}
})

technic.register_electric_furnace({tier="HV", upgrade=1, tube=1, demand={4000, 2500, 1500}, speed=12})


code:
--- Forcefield generator.
-- @author ShadowNinja
--
-- Forcefields are powerful barriers but they consume huge amounts of power.
-- The forcefield Generator is an HV machine.

-- How expensive is the generator?
-- Leaves room for upgrades lowering the power drain?
local digilines_path = minetest.get_modpath("digilines")

local forcefield_power_drain   = 10

local S = technic.getter

local cable_entry = "^technic_cable_connection_overlay.png"

minetest.register_craft({
	output = "technic:forcefield_emitter_off",
	recipe = {
		{"default:mese",         "basic_materials:motor",          "default:mese"        },
		{"technic:deployer_off", "technic:machine_casing", "technic:deployer_off"},
		{"default:mese",         "technic:hv_cable",       "default:mese"        },
	}
})

local replaceable_cids = {}

minetest.after(0, function()
	for name, ndef in pairs(minetest.registered_nodes) do
		if ndef.buildable_to == true and name ~= "ignore" then
			replaceable_cids[minetest.get_content_id(name)] = true
		end
	end
end)

-- Idea: Let forcefields have different colors by upgrade slot.
-- Idea: Let forcefields add up by detecting if one hits another.
--    ___   __
--   /   \/   \
--  |          |
--   \___/\___/

local function update_forcefield(pos, meta, active)

	if active then
		-- rate limit by chance
		if math.floor(math.random()*4) ~= 0 then
			return
		end
	end

	local shape = meta:get_int("shape")
	local range = meta:get_int("range")
	local vm = VoxelManip()
	local MinEdge, MaxEdge = vm:read_from_map(vector.subtract(pos, range),
			vector.add(pos, range))
	local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
	local data = vm:get_data()

	local c_air = minetest.get_content_id("air")
	local c_field = minetest.get_content_id("technic:forcefield")

	for z = -range, range do
	for y = -range, range do
	local vi = area:index(pos.x + (-range), pos.y + y, pos.z + z)
	for x = -range, range do
		local relevant
		if shape == 0 then
			local squared = x * x + y * y + z * z
			relevant =
				squared <= range       *  range      +  range and
				squared >= (range - 1) * (range - 1) + (range - 1)
		else
			relevant =
				x == -range or x == range or
				y == -range or y == range or
				z == -range or z == range
		end
		if relevant then
			local cid = data[vi]
			if active and replaceable_cids[cid] then
				data[vi] = c_field
			elseif not active and cid == c_field then
				data[vi] = c_air
			end
		end
		vi = vi + 1
	end
	end
	end

	vm:set_data(data)
	vm:update_liquids()
	vm:write_to_map()
end

local function set_forcefield_formspec(meta)
	local formspec
	if digilines_path then
		formspec = "size[5,3.25]"..
			"field[0.3,3;5,1;channel;Digiline Channel;"..meta:get_string("channel").."]"
	else
		formspec = "size[5,2.25]"
	end
	formspec = formspec..
		"field[0.3,0.5;2,1;range;"..S("Range")..";"..meta:get_int("range").."]"
	-- The names for these toggle buttons are explicit about which
	-- state they'll switch to, so that multiple presses (arising
	-- from the ambiguity between lag and a missed press) only make
	-- the single change that the user expects.
	if meta:get_int("shape") == 0 then
		formspec = formspec.."button[3,0.2;2,1;shape1;"..S("Sphere").."]"
	else
		formspec = formspec.."button[3,0.2;2,1;shape0;"..S("Cube").."]"
	end
	if meta:get_int("mesecon_mode") == 0 then
		formspec = formspec.."button[0,1;5,1;mesecon_mode_1;"..S("Ignoring Mesecon Signal").."]"
	else
		formspec = formspec.."button[0,1;5,1;mesecon_mode_0;"..S("Controlled by Mesecon Signal").."]"
	end
	if meta:get_int("enabled") == 0 then
		formspec = formspec.."button[0,1.75;5,1;enable;"..S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
	else
		formspec = formspec.."button[0,1.75;5,1;disable;"..S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
	end
	meta:set_string("formspec", formspec)
end

local forcefield_receive_fields = function(pos, formname, fields, sender)
	local player_name = sender:get_player_name()
	if minetest.is_protected(pos, player_name) then
		minetest.chat_send_player(player_name, "You are not allowed to edit this!")
		minetest.record_protection_violation(pos, player_name)
		return
	end
	local meta = minetest.get_meta(pos)
	local range = nil
	if fields.range then
		range = tonumber(fields.range) or 0
		-- Smallest field is 5. Anything less is asking for trouble.
		-- Largest is 20. It is a matter of pratical node handling.
		-- At the maximim range updating the forcefield takes about 0.2s
		range = math.max(range, 5)
		range = math.min(range, 20)
		if range == meta:get_int("range") then range = nil end
	end
	if fields.shape0 or fields.shape1 or range then
		update_forcefield(pos, meta, false)
	end
	if range then meta:set_int("range", range) end
	if fields.channel then meta:set_string("channel", fields.channel) end
	if fields.shape0  then meta:set_int("shape", 0) end
	if fields.shape1  then meta:set_int("shape", 1) end
	if fields.enable  then meta:set_int("enabled", 1) end
	if fields.disable then meta:set_int("enabled", 0) end
	if fields.mesecon_mode_0 then meta:set_int("mesecon_mode", 0) end
	if fields.mesecon_mode_1 then meta:set_int("mesecon_mode", 1) end
	set_forcefield_formspec(meta)
end

local mesecons = {
	effector = {
		action_on = function(pos, node)
			minetest.get_meta(pos):set_int("mesecon_effect", 1)
		end,
		action_off = function(pos, node)
			minetest.get_meta(pos):set_int("mesecon_effect", 0)
		end
	}
}

local digiline_def = {
	receptor = {
		rules = technic.digilines.rules,
		action = function() end
	},
	effector = {
		rules = technic.digilines.rules,
		action = function(pos, node, channel, msg)
			local meta = minetest.get_meta(pos)
			if channel ~= meta:get_string("channel") then
				return
			end
			local msgt = type(msg)
			if msgt == "string" then
				local smsg = msg:lower()
				msg = {}
				if smsg == "get" then
					msg.command = "get"
				elseif smsg == "off" then
					msg.command = "off"
				elseif smsg == "on" then
					msg.command = "on"
				elseif smsg == "toggle" then
					msg.command = "toggle"
				elseif smsg:sub(1, 5) == "range" then
					msg.command = "range"
					msg.value = tonumber(smsg:sub(7))
				elseif smsg:sub(1, 5) == "shape" then
					msg.command = "shape"
					msg.value = smsg:sub(7):lower()
					msg.value = tonumber(msg.value) or msg.value
				end
			elseif msgt ~= "table" then
				return
			end
			if msg.command == "get" then
				digilines.receptor_send(pos, technic.digilines.rules, channel, {
					enabled = meta:get_int("enabled"),
					range   = meta:get_int("range"),
					shape   = meta:get_int("shape")
				})
				return
			elseif msg.command == "off" then
				meta:set_int("enabled", 0)
			elseif msg.command == "on" then
				meta:set_int("enabled", 1)
			elseif msg.command == "toggle" then
				local onn = meta:get_int("enabled")
				onn = 1-onn -- Mirror onn with pivot 0.5, so switch between 1 and 0.
				meta:set_int("enabled", onn)
			elseif msg.command == "range" then
				if type(msg.value) ~= "number" then
					return
				end
				msg.value = math.max(msg.value, 5)
				msg.value = math.min(msg.value, 20)
				update_forcefield(pos, meta, false)
				meta:set_int("range", msg.value)
			elseif msg.command == "shape" then
				local valuet = type(msg.value)
				if valuet == "string" then
					if msg.value == "sphere" then
						msg.value = 0
					elseif msg.value == "cube" then
						msg.value = 1
					end
				elseif valuet ~= "number" then
					return
				end
				if not msg.value then
					return
				end
				update_forcefield(pos, meta, false)
				meta:set_int("shape", msg.value)
			else
				return
			end
			set_forcefield_formspec(meta)
		end
	},
}

local function run(pos, node)
	local meta = minetest.get_meta(pos)
	local eu_input   = meta:get_int("HV_EU_input")
	local enabled = meta:get_int("enabled") ~= 0 and
		(meta:get_int("mesecon_mode") == 0 or meta:get_int("mesecon_effect") ~= 0)
	local machine_name = S("%s Forcefield Emitter"):format("HV")

	local range = meta:get_int("range")
	local power_requirement
	if meta:get_int("shape") == 0 then
		power_requirement = math.floor(4 * math.pi * range * range)
	else
		power_requirement = 24 * range * range
	end
	power_requirement = power_requirement * forcefield_power_drain

	if not enabled then
		if node.name == "technic:forcefield_emitter_on" then
			update_forcefield(pos, meta, false)
			technic.swap_node(pos, "technic:forcefield_emitter_off")
			meta:set_string("infotext", S("%s Disabled"):format(machine_name))
		end
		meta:set_int("HV_EU_demand", 0)
		return
	end
	meta:set_int("HV_EU_demand", power_requirement)
	if eu_input < power_requirement then
		meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
		if node.name == "technic:forcefield_emitter_on" then
			update_forcefield(pos, meta, false)
			technic.swap_node(pos, "technic:forcefield_emitter_off")
		end
	elseif eu_input >= power_requirement then
		if node.name == "technic:forcefield_emitter_off" then
			technic.swap_node(pos, "technic:forcefield_emitter_on")
			meta:set_string("infotext", S("%s Active"):format(machine_name))
		end
		update_forcefield(pos, meta, true)
	end
end

minetest.register_node("technic:forcefield_emitter_off", {
	description = S("%s Forcefield Emitter"):format("HV"),
	tiles = {
		"technic_forcefield_emitter_off.png",
		"technic_machine_bottom.png"..cable_entry,
		"technic_forcefield_emitter_off.png",
		"technic_forcefield_emitter_off.png",
		"technic_forcefield_emitter_off.png",
		"technic_forcefield_emitter_off.png"
	},
	groups = {cracky = 1, technic_machine = 1, technic_hv = 1},
	on_receive_fields = forcefield_receive_fields,
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_int("HV_EU_input", 0)
		meta:set_int("HV_EU_demand", 0)
		meta:set_int("range", 10)
		meta:set_int("enabled", 0)
		meta:set_int("mesecon_mode", 0)
		meta:set_int("mesecon_effect", 0)
		if digilines_path then
			meta:set_string("channel", "forcefield"..minetest.pos_to_string(pos))
		end
		meta:set_string("infotext", S("%s Forcefield Emitter"):format("HV"))
		set_forcefield_formspec(meta)
	end,
	mesecons = mesecons,
	digiline = digiline_def,
	technic_run = run,
})

minetest.register_node("technic:forcefield_emitter_on", {
	description = S("%s Forcefield Emitter"):format("HV"),
	tiles = {
		"technic_forcefield_emitter_on.png",
		"technic_machine_bottom.png"..cable_entry,
		"technic_forcefield_emitter_on.png",
		"technic_forcefield_emitter_on.png",
		"technic_forcefield_emitter_on.png",
		"technic_forcefield_emitter_on.png"
	},
	groups = {cracky = 1, technic_machine = 1, technic_hv = 1,
			not_in_creative_inventory=1},
	drop = "technic:forcefield_emitter_off",
	on_receive_fields = forcefield_receive_fields,
	on_destruct = function(pos)
		local meta = minetest.get_meta(pos)
		update_forcefield(pos, meta, false)
	end,
	mesecons = mesecons,
	digiline = digiline_def,
	technic_run = run,
	technic_on_disable = function (pos, node)
		local meta = minetest.get_meta(pos)
		update_forcefield(pos, meta, false)
		technic.swap_node(pos, "technic:forcefield_emitter_off")
	end,
	on_blast = function(pos, intensity)
		minetest.dig_node(pos)
		return {"technic:forcefield_emitter_off"}
	end,
})

minetest.register_node("technic:forcefield", {
	description = S("%s Forcefield"):format("HV"),
	sunlight_propagates = true,
	drawtype = "glasslike",
	groups = {not_in_creative_inventory=1},
	paramtype = "light",
	light_source = default.LIGHT_MAX,
	diggable = false,
	drop = '',
	tiles = {{
		name = "technic_forcefield_animated.png",
		animation = {
			type = "vertical_frames",
			aspect_w = 16,
			aspect_h = 16,
			length = 1.0,
		},
	}},
	on_blast = function(pos, intensity)
	end,
})

if minetest.get_modpath("mesecons_mvps") then
	mesecon.register_mvps_stopper("technic:forcefield")
end

technic.register_machine("HV", "technic:forcefield_emitter_on",  technic.receiver)
technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver)


code:
minetest.register_alias("hv_generator", "technic:hv_generator")

minetest.register_craft({
	output = 'technic:hv_generator',
	recipe = {
		{'technic:carbon_plate',          'technic:mv_generator',   'technic:composite_plate'},
		{'pipeworks:tube_1',              'technic:hv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:hv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_generator({tier="HV", tube=1, supply=5000})


code:
-- HV grinder

minetest.register_craft({
	output = 'technic:hv_grinder',
	recipe = {
		{'technic:carbon_plate',          'technic:mv_grinder',   'technic:composite_plate'},
		{'pipeworks:tube_1',              'technic:hv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:hv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_grinder({tier="HV", demand={1200, 900, 600}, speed=5, upgrade=1, tube=1})


code:
technic.register_tier("HV", "High Voltage")

local path = technic.modpath.."/machines/HV"

-- Wiring stuff
dofile(path.."/cables.lua")
dofile(path.."/battery_box.lua")

-- Generators
dofile(path.."/solar_array.lua")
dofile(path.."/nuclear_reactor.lua")
dofile(path.."/generator.lua")

-- Machines
dofile(path.."/quarry.lua")
dofile(path.."/forcefield.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/grinder.lua")
dofile(path.."/compressor.lua")


code:
--[[
 The enriched uranium rod driven EU generator.
A very large and advanced machine providing vast amounts of power.
Very efficient but also expensive to run as it needs uranium.
Provides 10000 HV EUs for one week (only counted when loaded).

The nuclear reactor core requires a casing of water and a protective
shield to work.  This is checked now and then and if the casing is not
intact the reactor will melt down!
--]]

local burn_ticks = 7 * 24 * 60 * 60  -- Seconds
local power_supply = 10000000  -- EUs
local fuel_type = "technic:uranium_fuel"  -- The reactor burns this
local digiline_meltdown = technic.config:get_bool("enable_nuclear_reactor_digiline_selfdestruct")
local has_digilines = minetest.get_modpath("digilines")

local S = technic.getter

local reactor_desc = S("@1 Nuclear Reactor Core", S("HV"))
local cable_entry = "^technic_cable_connection_overlay.png"

-- FIXME: Recipe should make more sense like a rod recepticle, steam chamber, HV generator?
minetest.register_craft({
	output = 'technic:hv_nuclear_reactor_core',
	recipe = {
		{'technic:carbon_plate',          'default:obsidian_glass', 'technic:carbon_plate'},
		{'technic:composite_plate',       'technic:machine_casing', 'technic:composite_plate'},
		{'technic:stainless_steel_ingot', 'technic:hv_cable',       'technic:stainless_steel_ingot'},
	}
})

local function make_reactor_formspec(meta)
	local f = "size[8,9]"..
	"label[0,0;"..S("Nuclear Reactor Rod Compartment").."]"..
	"list[current_name;src;2,1;3,2;]"..
	"list[current_player;main;0,5;8,4;]"..
	"listring[]"..
	"button[5.5,1.5;2,1;start;Start]"..
	"checkbox[5.5,2.5;autostart;automatic Start;"..meta:get_string("autostart").."]"
	if not has_digilines then
		return f
	end
	local digiline_enabled = meta:get_string("enable_digiline")
	f = f.."checkbox[0.5,2.8;enable_digiline;Enable Digiline;"..digiline_enabled.."]"
	if digiline_enabled ~= "true" then
		return f
	end
	return f..
		"button_exit[4.6,3.69;2,1;save;Save]"..
		"field[1,4;4,1;remote_channel;Digiline Remote Channel;${remote_channel}]"
end

local SS_OFF = 0
local SS_DANGER = 1
local SS_CLEAR = 2

local reactor_siren = {}
local function siren_set_state(pos, state)
	local hpos = minetest.hash_node_position(pos)
	local siren = reactor_siren[hpos]
	if not siren then
		if state == SS_OFF then return end
		siren = {state=SS_OFF}
		reactor_siren[hpos] = siren
	end
	if state == SS_DANGER and siren.state ~= SS_DANGER then
		if siren.handle then minetest.sound_stop(siren.handle) end
		siren.handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_danger_loop",
				{pos=pos, gain=1.5, loop=true, max_hear_distance=48})
		siren.state = SS_DANGER
	elseif state == SS_CLEAR then
		if siren.handle then minetest.sound_stop(siren.handle) end
		local clear_handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_clear",
				{pos=pos, gain=1.5, loop=false, max_hear_distance=48})
		siren.handle = clear_handle
		siren.state = SS_CLEAR
		minetest.after(10, function()
			if siren.handle ~= clear_handle then return end
			minetest.sound_stop(clear_handle)
			if reactor_siren[hpos] == siren then
				reactor_siren[hpos] = nil
			end
		end)
	elseif state == SS_OFF and siren.state ~= SS_OFF then
		if siren.handle then minetest.sound_stop(siren.handle) end
		reactor_siren[hpos] = nil
	end
end

local function siren_danger(pos, meta)
	meta:set_int("siren", 1)
	siren_set_state(pos, SS_DANGER)
end

local function siren_clear(pos, meta)
	if meta:get_int("siren") ~= 0 then
		siren_set_state(pos, SS_CLEAR)
		meta:set_int("siren", 0)
	end
end

--[[
The standard reactor structure consists of a 9x9x9 cube.  A cross
section through the middle:

	CCCC CCCC
	CBBB BBBC
	CBLL LLBC
	CBLWWWLBC
	CBLW#WLBC
	CBLW|WLBC
	CBLL|LLBC
	CBBB|BBBC
	CCCC|CCCC
	C = Concrete, B = Blast-resistant concrete, L = Lead,
	W = water node, # = reactor core, | = HV cable

The man-hole is optional (but necessary for refueling).

For the reactor to operate and not melt down, it insists on the inner
7x7x7 portion (from the core out to the blast-resistant concrete)
being intact.  Intactness only depends on the number of nodes of the
right type in each layer.  The water layer must have water in all but
at most one node; the steel and blast-resistant concrete layers must
have the right material in all but at most two nodes.  The permitted
gaps are meant for the cable and man-hole, but can actually be anywhere
and contain anything.  For the reactor to be useful, a cable must
connect to the core, but it can go in any direction.

The outer concrete layer of the standard structure is not required
for the reactor to operate.  It is noted here because it used to
be mandatory, and for historical reasons (that it predates the
implementation of radiation) it needs to continue being adequate
shielding of legacy reactors.  If it ever ceases to be adequate
shielding for new reactors, legacy ones should be grandfathered.

For legacy reasons, if the reactor has a stainless steel layer instead
of a lead layer it will be converted to a lead layer.
--]]
local function reactor_structure_badness(pos)
	local vm = VoxelManip()
	local pos1 = vector.subtract(pos, 3)
	local pos2 = vector.add(pos, 3)
	local MinEdge, MaxEdge = vm:read_from_map(pos1, pos2)
	local data = vm:get_data()
	local area = VoxelArea:new({MinEdge=MinEdge, MaxEdge=MaxEdge})

	local c_blast_concrete = minetest.get_content_id("technic:blast_resistant_concrete")
	local c_lead = minetest.get_content_id("technic:lead_block")
	local c_steel = minetest.get_content_id("technic:stainless_steel_block")
	local c_water_source = minetest.get_content_id("default:water_source")
	local c_water_flowing = minetest.get_content_id("default:water_flowing")

	local blast_layer, steel_layer, lead_layer, water_layer = 0, 0, 0, 0

	for z = pos1.z, pos2.z do
	for y = pos1.y, pos2.y do
	for x = pos1.x, pos2.x do
		local cid = data[area:index(x, y, z)]
		if x == pos1.x or x == pos2.x or
		   y == pos1.y or y == pos2.y or
		   z == pos1.z or z == pos2.z then
			if cid == c_blast_concrete then
				blast_layer = blast_layer + 1
			end
		elseif x == pos1.x+1 or x == pos2.x-1 or
		       y == pos1.y+1 or y == pos2.y-1 or
		       z == pos1.z+1 or z == pos2.z-1 then
			if cid == c_lead then
				lead_layer = lead_layer + 1
			elseif cid == c_steel then
				steel_layer = steel_layer + 1
			end
		elseif x == pos1.x+2 or x == pos2.x-2 or
		       y == pos1.y+2 or y == pos2.y-2 or
		       z == pos1.z+2 or z == pos2.z-2 then
			if cid == c_water_source or cid == c_water_flowing then
				water_layer = water_layer + 1
			end
		end
	end
	end
	end

	if steel_layer >= 96 then
		for z = pos1.z+1, pos2.z-1 do
		for y = pos1.y+1, pos2.y-1 do
		for x = pos1.x+1, pos2.x-1 do
			local vi = area:index(x, y, z)
			if x == pos1.x+1 or x == pos2.x-1 or
			   y == pos1.y+1 or y == pos2.y-1 or
			   z == pos1.z+1 or z == pos2.z-1 then
				if data[vi] == c_steel then
					data[vi] = c_lead
				end
			end
		end
		end
		end
		vm:set_data(data)
		vm:write_to_map()
		lead_layer = steel_layer
	end

	if water_layer > 25 then water_layer = 25 end
	if lead_layer > 96 then lead_layer = 96 end
	if blast_layer > 216 then blast_layer = 216 end
	return (25 - water_layer) + (96 - lead_layer) + (216 - blast_layer)
end

local function melt_down_reactor(pos)
	minetest.log("action", "A reactor melted down at "..minetest.pos_to_string(pos))
	minetest.set_node(pos, {name = "technic:corium_source"})
end

local function start_reactor(pos, meta)
	if minetest.get_node(pos).name ~= "technic:hv_nuclear_reactor_core" then
		return false
	end
	local inv = meta:get_inventory()
	if inv:is_empty("src") then
		return false
	end
	local src_list = inv:get_list("src")
	local correct_fuel_count = 0
	for _, src_stack in pairs(src_list) do
		if src_stack and src_stack:get_name() == fuel_type then
			correct_fuel_count = correct_fuel_count + 1
		end
	end
	-- Check that the reactor is complete and has the correct fuel
	if correct_fuel_count ~= 6 or reactor_structure_badness(pos) ~= 0 then
		return false
	end
	meta:set_int("burn_time", 1)
	technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active")
	meta:set_int("HV_EU_supply", power_supply)
	for idx, src_stack in pairs(src_list) do
		src_stack:take_item()
		inv:set_stack("src", idx, src_stack)
	end
	return true
end

minetest.register_abm({
	label = "Machines: reactor melt-down check",
	nodenames = {"technic:hv_nuclear_reactor_core_active"},
	interval = 4,
	chance = 1,
	action = function (pos, node)
		local meta = minetest.get_meta(pos)
		local badness = reactor_structure_badness(pos)
		local accum_badness = meta:get_int("structure_accumulated_badness")
		if badness == 0 then
			if accum_badness ~= 0 then
				meta:set_int("structure_accumulated_badness", math.max(accum_badness - 4, 0))
				siren_clear(pos, meta)
			end
		else
			siren_danger(pos, meta)
			accum_badness = accum_badness + badness
			if accum_badness >= 25 then
				melt_down_reactor(pos)
			else
				meta:set_int("structure_accumulated_badness", accum_badness)
			end
		end
	end,
})

local function run(pos, node)
	local meta = minetest.get_meta(pos)
	local burn_time = meta:get_int("burn_time") or 0
	if burn_time >= burn_ticks or burn_time == 0 then
		if has_digilines and meta:get_int("HV_EU_supply") == power_supply then
			digilines.receptor_send(pos, technic.digilines.rules, meta:get_string("remote_channel"), {
					command = "fuel_used",
					pos = pos
			})
		end
		if meta:get_string("autostart") == "true" then
			if start_reactor(pos, meta) then
				return
			end
		end
		meta:set_int("HV_EU_supply", 0)
		meta:set_int("burn_time", 0)
		meta:set_string("infotext", S("%s Idle"):format(reactor_desc))
		technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
		meta:set_int("structure_accumulated_badness", 0)
		siren_clear(pos, meta)
	elseif burn_time > 0 then
		burn_time = burn_time + 1
		meta:set_int("burn_time", burn_time)
		local percent = math.floor(burn_time / burn_ticks * 100)
		meta:set_string("infotext", reactor_desc.." ("..percent.."%)")
		meta:set_int("HV_EU_supply", power_supply)
	end
end

local nuclear_reactor_receive_fields = function(pos, formname, fields, sender)
	local player_name = sender:get_player_name()
	if minetest.is_protected(pos, player_name) then
		minetest.chat_send_player(player_name, "You are not allowed to edit this!")
		minetest.record_protection_violation(pos, player_name)
		return
	end
	local meta = minetest.get_meta(pos)
	local update_formspec = false
	if fields.remote_channel then
		meta:set_string("remote_channel", fields.remote_channel)
	end
	if fields.start then
		local b = start_reactor(pos, meta)
		if b then
			minetest.chat_send_player(player_name, "Start successful")
		else
			minetest.chat_send_player(player_name, "Error")
		end
	end
	if fields.autostart then
		meta:set_string("autostart", fields.autostart)
		update_formspec = true
	end
	if fields.enable_digiline then
		meta:set_string("enable_digiline", fields.enable_digiline)
		update_formspec = true
	end
	if update_formspec then
		meta:set_string("formspec", make_reactor_formspec(meta))
	end
end

local digiline_def = function(pos, _, channel, msg)
	local meta = minetest.get_meta(pos)
	if meta:get_string("enable_digiline") ~= "true" or
			channel ~= meta:get_string("remote_channel") then
		return
	end
	-- Convert string messages to tables:
	local msgt = type(msg)
	if msgt == "string" then
		local smsg = msg:lower()
		msg = {}
		if smsg == "get" then
			msg.command = "get"
		elseif smsg:sub(1, 13) == "self_destruct" then
			msg.command = "self_destruct"
			msg.timer = tonumber(smsg:sub(15)) or 0
		elseif smsg == "start" then
			msg.command = "start"
		end
	elseif msgt ~= "table" then
		return
	end

	if msg.command == "get" then
		local inv = meta:get_inventory()
		local invtable = {}
		for i = 1, 6 do
			local stack = inv:get_stack("src", i)
			if stack:is_empty() then
				invtable[i] = 0
			elseif stack:get_name() == fuel_type then
				invtable[i] = stack:get_count()
			else
				invtable[i] = -stack:get_count()
			end
		end
		digilines.receptor_send(pos, technic.digilines.rules, channel, {
			burn_time = meta:get_int("burn_time"),
			enabled   = meta:get_int("HV_EU_supply") == power_supply,
			siren     = meta:get_int("siren") == 1,
			structure_accumulated_badness = meta:get_int("structure_accumulated_badness"),
			rods = invtable
		})
	elseif digiline_meltdown and msg.command == "self_destruct" and
			minetest.get_node(pos).name == "technic:hv_nuclear_reactor_core_active" then
		if msg.timer ~= 0 and type(msg.timer) == "number" then
			siren_danger(pos, meta)
			minetest.after(msg.timer, melt_down_reactor, pos)
		else
			melt_down_reactor(pos)
		end
	elseif msg.command == "start" then
		local b = start_reactor(pos, meta)
		if b then
			digilines.receptor_send(pos, technic.digilines.rules, channel, {
				command = "start_success",
				pos = pos
			})
		else
			digilines.receptor_send(pos, technic.digilines.rules, channel, {
				command = "start_error",
				pos = pos
			})
		end
	end
end

minetest.register_node("technic:hv_nuclear_reactor_core", {
	description = reactor_desc,
	tiles = {
		"technic_hv_nuclear_reactor_core.png",
		"technic_hv_nuclear_reactor_core.png"..cable_entry
	},
	drawtype = "mesh",
	mesh = "technic_reactor.obj",
	groups = {cracky = 1, technic_machine = 1, technic_hv = 1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	paramtype = "light",
	paramtype2 = "facedir",
	stack_max = 1,
	on_receive_fields = nuclear_reactor_receive_fields,
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", reactor_desc)
		meta:set_string("formspec", make_reactor_formspec(meta))
		if has_digilines then
			meta:set_string("remote_channel",
					"nuclear_reactor"..minetest.pos_to_string(pos))
		end
		local inv = meta:get_inventory()
		inv:set_size("src", 6)
	end,

	-- digiline interface
	digiline = {
		receptor = {
			rules = technic.digilines.rules,
			action = function() end,
		},
		effector = {
			rules = technic.digilines.rules,
			action = digiline_def,
		},
	},

	can_dig = technic.machine_can_dig,
	on_destruct = function(pos) siren_set_state(pos, SS_OFF) end,
	allow_metadata_inventory_put = technic.machine_inventory_put,
	allow_metadata_inventory_take = technic.machine_inventory_take,
	allow_metadata_inventory_move = technic.machine_inventory_move,
	technic_run = run,
})

minetest.register_node("technic:hv_nuclear_reactor_core_active", {
	tiles = {
		"technic_hv_nuclear_reactor_core.png",
		"technic_hv_nuclear_reactor_core.png"..cable_entry
	},
	drawtype = "mesh",
	mesh = "technic_reactor.obj",
	groups = {cracky = 1, technic_machine = 1, technic_hv = 1, radioactive = 4,
		not_in_creative_inventory = 1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	drop = "technic:hv_nuclear_reactor_core",
	light_source = 14,
	paramtype = "light",
	paramtype2 = "facedir",
	on_receive_fields = nuclear_reactor_receive_fields,

	-- digiline interface
	digiline = {
		receptor = {
			rules = technic.digilines.rules,
			action = function() end,
		},
		effector = {
			rules = technic.digilines.rules,
			action = digiline_def,
		},
	},

	can_dig = technic.machine_can_dig,
	on_destruct = function(pos) siren_set_state(pos, SS_OFF) end,
	allow_metadata_inventory_put = technic.machine_inventory_put,
	allow_metadata_inventory_take = technic.machine_inventory_take,
	allow_metadata_inventory_move = technic.machine_inventory_move,
	technic_run = run,
	technic_on_disable = function(pos, node)
		local timer = minetest.get_node_timer(pos)
		timer:start(1)
        end,
	on_timer = function(pos, node)
		local meta = minetest.get_meta(pos)

		-- Connected back?
		if meta:get_int("HV_EU_timeout") > 0 then return false end

		local burn_time = meta:get_int("burn_time") or 0

		if burn_time >= burn_ticks or burn_time == 0 then
			meta:set_int("HV_EU_supply", 0)
			meta:set_int("burn_time", 0)
			technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
			meta:set_int("structure_accumulated_badness", 0)
			siren_clear(pos, meta)
			return false
		end

		meta:set_int("burn_time", burn_time + 1)
		return true
	end,
})

technic.register_machine("HV", "technic:hv_nuclear_reactor_core",        technic.producer)
technic.register_machine("HV", "technic:hv_nuclear_reactor_core_active", technic.producer)


code:
local S = technic.getter

local quarry_dig_above_nodes = tonumber(minetest.settings:get("technic.quarry.dig_above_nodes") or "3")
local quarry_max_depth = tonumber(minetest.settings:get("technic.quarry.maxdepth") or "100")
local quarry_time_limit = tonumber(minetest.settings:get("technic.quarry.time_limit") or "5000")

local quarry_demand = 10000
local quarry_eject_dir = vector.new(0, 1, 0)
local machine_name = S("%s Quarry"):format("HV")
local quarry_formspec =
	"size[8,9]"..
	"item_image[7,0;1,1;technic:quarry]"..
	"list[context;cache;1,1;4,3;]"..
	"listring[context;cache]"..
	"list[current_player;main;0,5;8,4;]"..
	"listring[current_player;main]"..
	"label[0,0;"..machine_name.."]"..
	"button[5,1.9;2,1;restart;"..S("Restart").."]"

-- hard-coded spiral dig pattern for up to 17x17 dig area
local quarry_dig_pattern = {
	0,1,2,2,3,3,0,0,0,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,1,1,1,1,1,2,2,
	2,2,2,2,3,3,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
	3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
	2,2,2,2,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
	1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,
	0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
	2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
	3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}

local function is_player_allowed(pos, name)
	local owner = minetest.get_meta(pos):get_string("owner")
	if owner == "" or owner == name then
		return true
	end
	if not minetest.is_protected(pos, name) then
		return true
	end
	return false
end

local function reset_quarry(pos)
	local meta = minetest.get_meta(pos)
	local node = technic.get_or_load_node(pos) or minetest.get_node(pos)
	meta:set_int("quarry_dir", node.param2)
	meta:set_string("quarry_pos", minetest.pos_to_string(pos))
	meta:set_string("dig_pos", "")
	meta:set_int("dig_level", pos.y + quarry_dig_above_nodes)
	local radius = meta:get_int("size")
	local diameter = (radius*2)+1
	meta:set_int("dig_steps", diameter*diameter)
	meta:set_int("dig_index", 0)
	meta:set_int("purge_on", 1)
	meta:set_int("finished", 0)
	meta:set_int("dug", 0)
end

local function set_quarry_status(pos)
	local meta = minetest.get_meta(pos)
	local formspec = quarry_formspec.."field[5.3,3.4;2,1;size;"..S("Radius:")..";"..meta:get_int("size").."]"
	local status = S("Digging not started")
	if meta:get_int("enabled") == 1 then
		formspec = formspec.."button[5,0.9;2,1;disable;"..S("Enabled").."]"
		if meta:get_int("purge_on") == 1 then
			status = S("Purging cache")
			meta:set_string("infotext", S("%s purging cache"):format(machine_name))
			meta:set_int("HV_EU_demand", 0)
		elseif meta:get_int("finished") == 1 then
			status = S("Digging finished")
			meta:set_string("infotext", S("%s Finished"):format(machine_name))
			meta:set_int("HV_EU_demand", 0)
		else
			local rel_y = meta:get_int("dig_level") - pos.y
			status = S("Digging %d m "..(rel_y > 0 and "above" or "below").." machine"):format(math.abs(rel_y))
			meta:set_string("infotext", S(meta:get_int("HV_EU_input") >= quarry_demand and "%s Active" or "%s Unpowered"):format(machine_name))
			meta:set_int("HV_EU_demand", quarry_demand)
		end
	else
		formspec = formspec.."button[5,0.9;2,1;enable;"..S("Disabled").."]"
		meta:set_string("infotext", S("%s Disabled"):format(machine_name))
		meta:set_int("HV_EU_demand", 0)
	end
	meta:set_string("formspec", formspec.."label[0,4.1;"..minetest.formspec_escape(status).."]")
end

local function quarry_receive_fields(pos, formname, fields, sender)
	local player_name = sender:get_player_name()
	if not is_player_allowed(pos, player_name) then
		minetest.chat_send_player(player_name, "You are not allowed to edit this!")
		minetest.record_protection_violation(pos, player_name)
		return
	end
	local meta = minetest.get_meta(pos)
	if fields.size and string.find(fields.size, "^[0-9]+$") then
		local size = tonumber(fields.size)
		if size >= 1 and size <= 8 and size ~= meta:get_int("size") then
			meta:set_int("size", size)
			reset_quarry(pos)
		end
	end
	if fields.enable then meta:set_int("enabled", 1) end
	if fields.disable then meta:set_int("enabled", 0) end
	if fields.restart then reset_quarry(pos) end
	set_quarry_status(pos)
end

local function quarry_handle_purge(pos)
	local meta = minetest.get_meta(pos)
	local inv = meta:get_inventory()
	local cache = inv:get_list("cache")
	if not cache then
		inv:set_size("cache", 12)
		return
	end
	local i = 0
	for _,stack in ipairs(cache) do
		i = i + 1
		if stack then
			local item = stack:to_table()
			if item then
				technic.tube_inject_item(pos, pos, quarry_eject_dir, item)
				stack:clear()
				inv:set_stack("cache", i, stack)
				break
			end
		end
	end
	if inv:is_empty("cache") then
		meta:set_int("purge_on", 0)
	end
end

local function can_dig_node(pos, node_name, owner, digger)
	if node_name == "air" or node_name == "vacuum:vacuum" then
		return false
	end
	local def = minetest.registered_nodes[node_name]
	if not def or not def.diggable or (def.can_dig and not def.can_dig(pos, digger)) then
		return false
	end
	if minetest.is_protected(pos, owner) then
		return false
	end
	return true
end

local function find_ground(quarry_pos, quarry_dir, meta)
	local dir = minetest.facedir_to_dir(quarry_dir % 4)
	local radius = meta:get_int("size")
	local dig_level = meta:get_int("dig_level")
	local middle_pos = vector.add(quarry_pos, vector.multiply(dir, radius + 1))
	local pos1 = vector.new(middle_pos.x - radius, dig_level, middle_pos.z - radius)
	local pos2 = vector.new(middle_pos.x + radius, dig_level, middle_pos.z + radius)
	local nodes = minetest.find_nodes_in_area(pos1, pos2, {"air", "vacuum:vacuum"})
	if #nodes < meta:get_int("dig_steps") then
		return vector.new(middle_pos.x, dig_level, middle_pos.z)
	end
	meta:set_int("dig_level", dig_level - 1)
	return nil
end

local function get_dig_pos(quarry_pos, quarry_dir, dig_pos, dig_index, dig_steps, meta)
	if dig_index > 0 and dig_index < dig_steps then
		local facedir = (quarry_dir + quarry_dig_pattern[dig_index]) % 4
		dig_pos = vector.add(dig_pos, minetest.facedir_to_dir(facedir))
	elseif dig_index >= dig_steps then
		local dig_level = meta:get_int("dig_level")
		if (quarry_pos.y - dig_level) >= quarry_max_depth then
			return nil, dig_index
		end
		local dir = minetest.facedir_to_dir(quarry_dir % 4)
		dig_pos = vector.add(quarry_pos, vector.multiply(dir, meta:get_int("size") + 1))
		dig_pos.y = dig_level - 1
		meta:set_int("dig_level", dig_pos.y)
		dig_index = 0
	end
	dig_index = dig_index + 1
	return dig_pos, dig_index
end

local function execute_dig(pos, node, meta)
	local dig_pos = minetest.string_to_pos(meta:get_string("dig_pos"))
	local quarry_dir = meta:get_int("quarry_dir")
	if not dig_pos then
		-- quarry has not hit ground yet
		dig_pos = find_ground(pos, quarry_dir, meta)
	else
		local owner = meta:get_string("owner")
		local digger = pipeworks.create_fake_player({name = owner})
		local dig_steps = meta:get_int("dig_steps")
		local dig_index = meta:get_int("dig_index")
		local t0 = minetest.get_us_time()
		local us_used = 0
		-- search for something to dig
		while us_used < quarry_time_limit do
			dig_pos, dig_index = get_dig_pos(pos, quarry_dir, dig_pos, dig_index, dig_steps, meta)
			if not dig_pos then
				-- finished digging
				meta:set_int("finished", 1)
				meta:set_int("purge_on", 1)
				break
			end
			local dig_node = technic.get_or_load_node(dig_pos) or minetest.get_node(dig_pos)
			if can_dig_node(dig_pos, dig_node.name, owner, digger) then
				-- found something to dig, dig it and stop searching
				minetest.remove_node(dig_pos)
				local inv = meta:get_inventory()
				local drops = minetest.get_node_drops(dig_node.name, "")
				for _, dropped_item in ipairs(drops) do
					local left = inv:add_item("cache", dropped_item)
					while not left:is_empty() do
						meta:set_int("purge_on", 1)
						quarry_handle_purge(pos)
						left = inv:add_item("cache", left)
					end
				end
				local dug_nodes = meta:get_int("dug") + 1
				meta:set_int("dug", dug_nodes)
				if dug_nodes % 100 == 0 then
					meta:set_int("purge_on", 1)
				end
				break
			end
			us_used = minetest.get_us_time() - t0
		end
		meta:set_int("dig_index", dig_index)
	end
	if dig_pos then
		meta:set_string("dig_pos", minetest.pos_to_string(dig_pos))
	end
end

local function quarry_run(pos, node)
	local meta = minetest.get_meta(pos)
	if minetest.pos_to_string(pos) ~= meta:get_string("quarry_pos") then
		-- quarry has been moved since last dig
		reset_quarry(pos)
	elseif meta:get_int("purge_on") == 1 then
		quarry_handle_purge(pos)
	elseif meta:get_int("enabled") and meta:get_int("HV_EU_input") >= quarry_demand and meta:get_int("finished") == 0 then
		execute_dig(pos, node, meta)
	elseif not meta:get_inventory():is_empty("cache") then
		meta:set_int("purge_on", 1)
	end
	set_quarry_status(pos)
end

minetest.register_node("technic:quarry", {
	description = S("%s Quarry"):format("HV"),
	tiles = {
		"technic_carbon_steel_block.png^pipeworks_tube_connection_metallic.png",
		"technic_carbon_steel_block.png^technic_cable_connection_overlay.png",
		"technic_carbon_steel_block.png^technic_cable_connection_overlay.png",
		"technic_carbon_steel_block.png^technic_cable_connection_overlay.png",
		"technic_carbon_steel_block.png^default_tool_mesepick.png",
		"technic_carbon_steel_block.png^technic_cable_connection_overlay.png"
	},
	paramtype2 = "facedir",
	groups = {cracky=2, tubedevice=1, technic_machine=1, technic_hv=1},
	connect_sides = {"bottom", "front", "left", "right"},
	tube = {
		connect_sides = {top = 1},
		-- lower priority than other tubes, so that quarries will prefer any
		-- other tube to another quarry, which could lead to server freezes
		-- in certain quarry placements (2x2 for example would never eject)
		priority = 10,
		can_go = function(pos, node, velocity, stack)
			-- always eject the same, even if items came in another way
			-- this further mitigates loops and generally avoids random sideway movement
			-- that can be expected in certain quarry placements
			return { quarry_eject_dir }
		end
	},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_int("size", 4)
		meta:get_inventory():set_size("cache", 12)
		reset_quarry(pos)
		set_quarry_status(pos)
	end,
	after_place_node = function(pos, placer, itemstack)
		minetest.get_meta(pos):set_string("owner", placer:get_player_name())
		pipeworks.scan_for_tube_objects(pos)
	end,
	can_dig = function(pos,player)
		return minetest.get_meta(pos):get_inventory():is_empty("cache")
	end,
	after_dig_node = pipeworks.scan_for_tube_objects,
	on_receive_fields = quarry_receive_fields,
	technic_run = quarry_run,
	allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
		return is_player_allowed(pos, player:get_player_name()) and count or 0
	end,
	allow_metadata_inventory_put = function(pos, listname, index, stack, player)
		return is_player_allowed(pos, player:get_player_name()) and stack:get_count() or 0
	end,
	allow_metadata_inventory_take = function(pos, listname, index, stack, player)
		return is_player_allowed(pos, player:get_player_name()) and stack:get_count() or 0
	end,
	mesecons = {
		effector = {
			action_on = function(pos)
				local meta = minetest.get_meta(pos)
				meta:set_int("enabled", 1)
				set_quarry_status(pos)
			end,
			action_off = function(pos)
				local meta = minetest.get_meta(pos)
				meta:set_int("enabled", 0)
				set_quarry_status(pos)
			end
		}
	}
})

minetest.register_craft({
	recipe = {
		{"technic:carbon_plate", "pipeworks:filter", "technic:composite_plate"},
		{"basic_materials:motor", "technic:machine_casing", "technic:diamond_drill_head"},
		{"technic:carbon_steel_block", "technic:hv_cable", "technic:carbon_steel_block"}},
	output = "technic:quarry"
})

technic.register_machine("HV", "technic:quarry", technic.receiver)


code:
-- The high voltage solar array is an assembly of medium voltage arrays.
-- Solar arrays are not able to store large amounts of energy.

minetest.register_craft({
	output = 'technic:solar_array_hv 1',
	recipe = {
		{'technic:solar_array_mv',     'technic:solar_array_mv', 'technic:solar_array_mv'},
		{'technic:carbon_plate',       'technic:hv_transformer', 'technic:composite_plate'},
		{'',                           'technic:hv_cable',       ''},
	}
})

technic.register_solar_array({tier="HV", power=100})


code:
-- LV Alloy furnace

-- FIXME: kpoppel: I'd like to introduce an induction heating element here...
minetest.register_craft({
	output = 'technic:lv_alloy_furnace',
	recipe = {
		{'default:brick', 'default:brick',          'default:brick'},
		{'default:brick', 'technic:machine_casing', 'default:brick'},
		{'default:brick', 'technic:lv_cable',       'default:brick'},
	}
})

technic.register_alloy_furnace({tier = "LV", speed = 1, demand = {300}})


code:
-- LV Battery box

minetest.register_craft({
	output = 'technic:lv_battery_box0',
	recipe = {
		{'group:wood',      'group:wood',             'group:wood'},
		{'technic:battery', 'technic:machine_casing', 'technic:battery'},
		{'technic:battery', 'technic:lv_cable',       'technic:battery'},
	}
})

technic.register_battery_box({
	tier           = "LV",
	max_charge     = 40000,
	charge_rate    = 1000,
	discharge_rate = 4000,
	charge_step    = 500,
	discharge_step = 800,
})


code:
minetest.register_alias("lv_cable", "technic:lv_cable")

minetest.register_craft({
	output = 'technic:lv_cable 6',
	recipe = {
		{'default:paper',        'default:paper',        'default:paper'},
		{'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'},
		{'default:paper',        'default:paper',        'default:paper'},
	}
})

technic.register_cable("LV", 2/16)


code:
minetest.register_alias("compressor", "technic:lv_compressor")

minetest.register_craft({
	output = 'technic:lv_compressor',
	recipe = {
		{'default:stone',            'basic_materials:motor',          'default:stone'},
		{'mesecons:piston',          'technic:machine_casing', 'mesecons:piston'},
		{'basic_materials:silver_wire', 'technic:lv_cable',       'basic_materials:silver_wire'},
	},
	replacements = {
		{"basic_materials:silver_wire", "basic_materials:empty_spool"},
		{"basic_materials:silver_wire", "basic_materials:empty_spool"}
	},
})

technic.register_compressor({tier = "LV", demand = {300}, speed = 1})


code:
-- 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', 'technic:machine_casing', 'default:cobble'},
		{'default:cobble', 'technic:lv_cable',       'default:cobble'},
	}
})

technic.register_electric_furnace({tier="LV", demand={300}, speed = 2})


code:
minetest.register_alias("extractor", "technic:lv_extractor")

minetest.register_craft({
	output = 'technic:lv_extractor',
	recipe = {
		{'technic:treetap', 'basic_materials:motor',          'technic:treetap'},
		{'technic:treetap', 'technic:machine_casing', 'technic:treetap'},
		{'',                'technic:lv_cable',       ''},
	}
})

technic.register_extractor({tier = "LV", demand = {300}, speed = 1})


code:
-- The electric generator.
-- A simple device to get started on the electric machines.
-- Inefficient and expensive in fuel (200EU per tick)
-- Also only allows for LV machinery to run.

minetest.register_alias("lv_generator", "technic:lv_generator")

minetest.register_craft({
	output = 'technic:lv_generator',
	recipe = {
		{'default:stone', 'default:furnace',        'default:stone'},
		{'default:stone', 'technic:machine_casing', 'default:stone'},
		{'default:stone', 'technic:lv_cable',       'default:stone'},
	}
})

technic.register_generator({tier="LV", supply=500})


code:
-- 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")

local S = technic.getter

minetest.register_craft({
	output = 'technic:geothermal',
	recipe = {
		{'technic:granite',          'default:diamond',        'technic:granite'},
		{'basic_materials:copper_wire', 'technic:machine_casing', 'basic_materials:copper_wire'},
		{'technic:granite',          'technic:lv_cable',       'technic:granite'},
	},
	replacements = {
		{"basic_materials:copper_wire", "basic_materials:empty_spool"},
		{"basic_materials:copper_wire", "basic_materials:empty_spool"}
	},
})

minetest.register_craftitem("technic:geothermal", {
	description = S("Geothermal %s Generator"):format("LV"),
})

local check_node_around = function(pos)
	local node = minetest.get_node(pos)
	if node.name == "default:water_source" or node.name == "default:water_flowing" then return 1 end
	if node.name == "default:lava_source"  or node.name == "default:lava_flowing"  then return 2 end
	return 0
end

local run = function(pos, node)
	local meta             = minetest.get_meta(pos)
	local water_nodes      = 0
	local lava_nodes       = 0
	local production_level = 0
	local eu_supply        = 0

	-- Correct positioning is water on one side and lava on the other.
	-- The two cannot be adjacent because the lava the turns into obsidian or rock.
	-- To get to 100% production stack the water and lava one extra block down as well:
	--    WGL (W=Water, L=Lava, G=the generator, |=an LV cable)
	--    W|L

	local positions = {
		{x=pos.x+1, y=pos.y,   z=pos.z},
		{x=pos.x+1, y=pos.y-1, z=pos.z},
		{x=pos.x-1, y=pos.y,   z=pos.z},
		{x=pos.x-1, y=pos.y-1, z=pos.z},
		{x=pos.x,   y=pos.y,   z=pos.z+1},
		{x=pos.x,   y=pos.y-1, z=pos.z+1},
		{x=pos.x,   y=pos.y,   z=pos.z-1},
		{x=pos.x,   y=pos.y-1, z=pos.z-1},
	}
	for _, p in pairs(positions) do
		local check = check_node_around(p)
		if check == 1 then water_nodes = water_nodes + 1 end
		if check == 2 then lava_nodes  = lava_nodes  + 1 end
	end

	if water_nodes == 1 and lava_nodes == 1 then production_level =  25; eu_supply = 50 end
	if water_nodes == 2 and lava_nodes == 1 then production_level =  50; eu_supply = 100 end
	if water_nodes == 1 and lava_nodes == 2 then production_level =  75; eu_supply = 200 end
	if water_nodes == 2 and lava_nodes == 2 then production_level = 100; eu_supply = 300 end

	if production_level > 0 then
		meta:set_int("LV_EU_supply", eu_supply)
	end

	meta:set_string("infotext",
		S("Geothermal %s Generator"):format("LV").." ("..production_level.."%)")

	if production_level > 0 and minetest.get_node(pos).name == "technic:geothermal" then
		technic.swap_node (pos, "technic:geothermal_active")
		return
	end
	if production_level == 0 then
		technic.swap_node(pos, "technic:geothermal")
		meta:set_int("LV_EU_supply", 0)
	end
end

minetest.register_node("technic:geothermal", {
	description = S("Geothermal %s Generator"):format("LV"),
	tiles = {"technic_geothermal_top.png", "technic_machine_bottom.png", "technic_geothermal_side.png",
	         "technic_geothermal_side.png", "technic_geothermal_side.png", "technic_geothermal_side.png"},
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
		technic_machine=1, technic_lv=1},
	paramtype2 = "facedir",
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", S("Geothermal %s Generator"):format("LV"))
		meta:set_int("LV_EU_supply", 0)
	end,
	technic_run = run,
})

minetest.register_node("technic:geothermal_active", {
	description = S("Geothermal %s Generator"):format("LV"),
	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,
		technic_machine=1, technic_lv=1, not_in_creative_inventory=1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	drop = "technic:geothermal",
	technic_run = run,
})

technic.register_machine("LV", "technic:geothermal",        technic.producer)
technic.register_machine("LV", "technic:geothermal_active", technic.producer)


code:
minetest.register_alias("grinder", "technic:lv_grinder")
minetest.register_craft({
	output = 'technic:lv_grinder',
	recipe = {
		{'default:desert_stone', 'default:diamond',        'default:desert_stone'},
		{'default:desert_stone', 'technic:machine_casing', 'default:desert_stone'},
		{'technic:granite',      'technic:lv_cable',       'technic:granite'},
	}
})

technic.register_grinder({tier="LV", demand={200}, speed=1})


code:
technic.register_tier("LV", "Low Voltage")

local path = technic.modpath.."/machines/LV"

-- Wiring stuff
dofile(path.."/cables.lua")
dofile(path.."/battery_box.lua")

-- Generators
dofile(path.."/solar_panel.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/geothermal.lua")
dofile(path.."/water_mill.lua")
dofile(path.."/generator.lua")

-- Machines
dofile(path.."/alloy_furnace.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/grinder.lua")
dofile(path.."/extractor.lua")
dofile(path.."/compressor.lua")

dofile(path.."/music_player.lua")

dofile(path.."/lamp.lua")


code:
-- LV LED and LV LED Lamp
-- LED - a weak light source, intended primarily as a core component for LED lamps
-- LED Lamp - a powerful light source, illuminating a 7x7x3(H) volume below itself
-- with light bright as the sun.

local S = technic.getter

local illuminate = function(pos, mode)
	for y=1,3,1 do
		for x=-3,3,1 do
			for z = -3,3,1 do
				local loc = {x = pos.x - x, y = pos.y - y, z = pos.z - z}
				if mode then
					if minetest.get_node(loc).name == "air" then
						minetest.swap_node(loc, {name = "technic:dummy_light_source"})
					end
				else
					if minetest.get_node(loc).name == "technic:dummy_light_source" then
						minetest.swap_node(loc, {name = "air"})
					end
				end
			end
		end
	end
end

local led_on = function(pos, node)
	local meta         = minetest.get_meta(pos)
	local eu_input     = meta:get_int("LV_EU_input")
	local machine_name = S("%s LED"):format("LV")
	local machine_node = "technic:lv_led"
	local demand       = 5

	if eu_input < demand then
		technic.swap_node(pos, machine_node)
		meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
	elseif eu_input >= demand then
		technic.swap_node(pos, machine_node.."_active")
		meta:set_string("infotext", S("%s Active"):format(machine_name))
	end
	meta:set_int("LV_EU_demand", demand)
end

local led_off = function(pos, node)
	local meta         = minetest.get_meta(pos)
	local machine_name = S("%s LED"):format("LV")
	local machine_node = "technic:lv_led"

	technic.swap_node(pos, machine_node)
	meta:set_string("infotext", S("%s Unpowered"):format(machine_name))

	meta:set_int("LV_EU_demand", 0)
end

local lamp_on = function(pos, node)
	local meta         = minetest.get_meta(pos)
	local eu_input     = meta:get_int("LV_EU_input")
	local machine_name = S("%s Lamp"):format("LV")
	local machine_node = "technic:lv_lamp"
	local demand       = 50

	if eu_input < demand then
		technic.swap_node(pos, machine_node)
		meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
		illuminate(pos, false)
	elseif eu_input >= demand then
		technic.swap_node(pos, machine_node.."_active")
		meta:set_string("infotext", S("%s Active"):format(machine_name))
		illuminate(pos, true)
	end
	meta:set_int("LV_EU_demand", demand)
end

local lamp_off = function(pos, node)
	local meta         = minetest.get_meta(pos)
	local machine_name = S("%s Lamp"):format("LV")
	local machine_node = "technic:lv_lamp"

	illuminate(pos, false)
	technic.swap_node(pos, machine_node)
	meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
	meta:set_int("LV_EU_demand", 0)
end

minetest.register_node("technic:dummy_light_source", {
	description = S("Dummy light source node"),
	node_box = {
		type = "fixed",
		fixed = {}
		},
	collision_box = {
		type = "fixed",
		fixed = {}
		},
	selection_box = {
		type = "fixed",
		fixed = {}
		},
	drawtype = "airlike",
	buildable_to = true,
	light_source = 14,
	sunlight_propagates = true,
	diggable = false,
	walkable = false,
	groups = { not_in_creative_inventory = 1 }
})

minetest.register_node("technic:lv_led", {
	description = S("LV LED"),
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {0.2,0.2,0.2,-0.2,-0.2,-0.2}
		},
	collision_box = {
		type = "fixed",
		fixed = {0.2,0.2,0.2,-0.2,-0.2,-0.2}
		},
	selection_box = {
		type = "fixed",
		fixed = {0.2,0.2,0.2,-0.2,-0.2,-0.2}
		},
	tiles = {"technic_lv_led.png"},
	inventory_image = "technic_lv_led_inv.png",
	sunlight_propagates = true,
	groups = {cracky=2, technic_machine=1, technic_lv=1},
	connect_sides = {"front", "back", "left", "right", "top", "bottom"},
	can_dig = technic.machine_can_dig,
	technic_run = led_on,
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", S("%s LED"):format("LV"))
	end,
	drop = "technic:lv_led"
})

minetest.register_node("technic:lv_led_active", {
	description = S("LV LED Active"),
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {0.2,0.2,0.2,-0.2,-0.2,-0.2}
		},
	collision_box = {
		type = "fixed",
		fixed = {0.2,0.2,0.2,-0.2,-0.2,-0.2}
		},
	selection_box = {
		type = "fixed",
		fixed = {0.2,0.2,0.2,-0.2,-0.2,-0.2}
		},
	tiles = {"technic_lv_led.png"},
	light_source = 9,
	sunlight_propagates = true,
	groups = {cracky=2, technic_machine=1, technic_lv=1, not_in_creative_inventory=1},
	connect_sides = {"front", "back", "left", "right", "top", "bottom"},
	can_dig = technic.machine_can_dig,
	technic_run = led_on,
	technic_on_disable = led_off,
	drop = "technic:lv_led"
})

minetest.register_node("technic:lv_lamp", {
	description = S("%s Lamp"):format("LV"),
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5}
		},
	collision_box = {
		type = "fixed",
		fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5}
		},
	selection_box = {
		type = "fixed",
		fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5}
		},
	tiles       = {"technic_lv_lamp_top.png", "technic_lv_lamp_bottom.png", "technic_lv_lamp_side.png",
	               "technic_lv_lamp_side.png", "technic_lv_lamp_side.png", "technic_lv_lamp_side.png"},
	groups = {cracky=2, technic_machine=1, technic_lv=1},
	connect_sides = {"front", "back", "left", "right", "top",},
	can_dig = technic.machine_can_dig,
	technic_run = lamp_on,
	on_destruct = lamp_off,
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", S("%s Lamp"):format("LV"))
	end,
})

minetest.register_node("technic:lv_lamp_active", {
	description = S("%s Lamp Active"):format("LV"),
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5}
		},
	collision_box = {
		type = "fixed",
		fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5}
		},
	selection_box = {
		type = "fixed",
		fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5}
		},
	tiles       = {"technic_lv_lamp_top.png", "technic_lv_lamp_bottom.png", "technic_lv_lamp_side.png",
	               "technic_lv_lamp_side.png", "technic_lv_lamp_side.png", "technic_lv_lamp_side.png"},
	groups = {cracky=2, technic_machine=1, technic_lv=1, not_in_creative_inventory=1},
	connect_sides = {"front", "back", "left", "right", "top"},
	light_source = 1,
	can_dig = technic.machine_can_dig,
	technic_run = lamp_on,
	on_destruct = lamp_off,
	technic_on_disable = lamp_off,
})

minetest.register_craft({
	output = 'technic:lv_led 2',
	recipe = {
		{'',                           'homedecor:plastic_sheeting',  ''},
		{'homedecor:plastic_sheeting', 'technic:doped_silicon_wafer', 'homedecor:plastic_sheeting'},
		{'',                           'technic:fine_silver_wire',    ''},
	},
})

minetest.register_craft({
	output = 'technic:lv_lamp',
	recipe = {
		{'default:glass',           'default:glass',    'default:glass'},
		{'technic:lv_led',          'technic:lv_led',   'technic:lv_led'},
		{'mesecons_materials:glue', 'technic:lv_cable', 'mesecons_materials:glue'},
	},
})

technic.register_machine("LV", "technic:lv_lamp", technic.receiver)
technic.register_machine("LV", "technic:lv_lamp_active", technic.receiver)

technic.register_machine("LV", "technic:lv_led", technic.receiver)
technic.register_machine("LV", "technic:lv_led_active", technic.receiver)


code:
-- LV Music player.
-- The player can play music. But it is high ampage!

local S = technic.getter

minetest.register_alias("music_player", "technic:music_player")
minetest.register_craft({
	output = 'technic:music_player',
	recipe = {
		{'technic:chromium_ingot', 'default:diamond',        'technic:chromium_ingot'},
		{'default:diamond',        'technic:machine_casing', 'default:diamond'},
		{'default:mossycobble',    'technic:lv_cable',       'default:mossycobble'},
	}
})

local music_handles = {}

local function play_track(pos, track)
	return minetest.sound_play("technic_track"..tostring(track),
			{pos = pos, gain = 1.0, loop = true, max_hear_distance = 72,})
end

local run = function(pos, node)
	local meta         = minetest.get_meta(pos)
	local eu_input     = meta:get_int("LV_EU_input")
	local machine_name = S("%s Music Player"):format("LV")
	local demand       = 150

	local current_track = meta:get_int("current_track")
	local pos_hash      = minetest.hash_node_position(pos)
	local music_handle  = music_handles[pos_hash]

	-- Setup meta data if it does not exist.
	if not eu_input then
		meta:set_int("LV_EU_demand", demand)
		meta:set_int("LV_EU_input", 0)
		return
	end

	if meta:get_int("active") == 0 then
		meta:set_string("infotext", S("%s Idle"):format(machine_name))
		meta:set_int("LV_EU_demand", 0)
		return
	end

	if eu_input < demand then
		meta:set_string("infotext", S("%s Unpowered"):format(machine_name))
		if music_handle then
			minetest.sound_stop(music_handle)
			music_handle = nil
		end
	elseif eu_input >= demand then
		meta:set_string("infotext", S("%s Active"):format(machine_name))
		if not music_handle then
			music_handle = play_track(pos, current_track)
		end
	end
	music_handles[pos_hash] = music_handle
	meta:set_int("LV_EU_demand", demand)
end

local function stop_player(pos, node)
	local pos_hash = minetest.hash_node_position(pos)
	local music_handle = music_handles[pos_hash]
	if music_handle then
		minetest.sound_stop(music_handle)
		music_handles[pos_hash] = nil
	end
end

local function set_display(meta)
	meta:set_string("formspec",
			"size[4,4.5]"..
			"item_image[0,0;1,1;technic:music_player]"..
			"label[1,0;"..S("%s Music Player"):format("LV").."]"..
			"button[0,1;1,1;track1;1]"..
			"button[1,1;1,1;track2;2]"..
			"button[2,1;1,1;track3;3]"..
			"button[0,2;1,1;track4;4]"..
			"button[1,2;1,1;track5;5]"..
			"button[2,2;1,1;track6;6]"..
			"button[0,3;1,1;track7;7]"..
			"button[1,3;1,1;track8;8]"..
			"button[2,3;1,1;track9;9]"..
			"button[3,1;1,1;stop;Stop]"..
			"label[0,4;"..minetest.formspec_escape(
				meta:get_int("active") == 0 and
					S("Stopped") or
					S("Current track %s"):format(meta:get_int("current_track"))).."]")
end

minetest.register_node("technic:music_player", {
	description = S("%s Music Player"):format("LV"),
	tiles = {"technic_music_player_top.png", "technic_machine_bottom.png", "technic_music_player_side.png",
	         "technic_music_player_side.png", "technic_music_player_side.png", "technic_music_player_side.png"},
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
		technic_machine=1, technic_lv=1},
	connect_sides = {"bottom"},
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", S("%s Music Player"):format("LV"))
		set_display(meta)
	end,
	on_receive_fields = function(pos, formanme, fields, sender)
		local new_track = nil
		if fields.stop then new_track = 0 end
		if fields.track1 then new_track = 1 end
		if fields.track2 then new_track = 2 end
		if fields.track3 then new_track = 3 end
		if fields.track4 then new_track = 4 end
		if fields.track5 then new_track = 5 end
		if fields.track6 then new_track = 6 end
		if fields.track7 then new_track = 7 end
		if fields.track8 then new_track = 8 end
		if fields.track9 then new_track = 9 end
		if new_track then
			stop_player(pos)
			local meta = minetest.get_meta(pos)
			meta:set_int("active", new_track == 0 and 0 or 1)
			meta:set_int("current_track", new_track)
			set_display(meta)
		end
	end,
	on_destruct = stop_player,
	technic_run = run,
	technic_on_disable = stop_player,
})

technic.register_machine("LV", "technic:music_player", technic.receiver)


code:
-- The solar array is an assembly of panels into a powerful array
-- The assembly can deliver more energy than the individual panel because
-- of the transformer unit which converts the panel output variations into
-- a stable supply.
-- Solar arrays are not able to store large amounts of energy.
-- The LV arrays are used to make medium voltage arrays.

minetest.register_craft({
	output = 'technic:solar_array_lv 1',
	recipe = {
		{'technic:solar_panel',        'technic:solar_panel',    'technic:solar_panel'},
		{'technic:carbon_steel_ingot', 'technic:lv_transformer', 'technic:carbon_steel_ingot'},
		{'',                           'technic:lv_cable',       ''},
	}
})

technic.register_solar_array({tier="LV", power=10})


code:
-- Solar panels are the building blocks of LV solar arrays
-- They can however also be used separately but with reduced efficiency due to the missing transformer.
-- Individual panels are less efficient than when the panels are combined into full arrays.

local S = technic.getter

minetest.register_craft({
	output = 'technic:solar_panel',
	recipe = {
		{'technic:doped_silicon_wafer', 'technic:doped_silicon_wafer', 'technic:doped_silicon_wafer'},
		{'basic_materials:silver_wire',    'technic:lv_cable',            'mesecons_materials:glue'},
	},
	replacements = { {"basic_materials:silver_wire", "basic_materials:empty_spool"}, },
})

local run = function(pos, node)
	-- The action here is to make the solar panel prodice power
	-- Power is dependent on the light level and the height above ground
	-- There are many ways to cheat by using other light sources like lamps.
	-- As there is no way to determine if light is sunlight that is just a shame.
	-- To take care of some of it solar panels do not work outside daylight hours or if
	-- built below 0m
	local pos1 = {x=pos.x, y=pos.y+1, z=pos.z}
	local machine_name = S("Small Solar %s Generator"):format("LV")

	local light = minetest.get_node_light(pos1, nil)
	local time_of_day = minetest.get_timeofday()
	local meta = minetest.get_meta(pos)
	if light == nil then light = 0 end
	-- turn on panel only during day time and if sufficient light
        -- I know this is counter intuitive when cheating by using other light sources underground.
	if light >= 12 and time_of_day >= 0.24 and time_of_day <= 0.76 and pos.y > -10 then
		local charge_to_give = math.floor((light + pos1.y) * 3)
		charge_to_give = math.max(charge_to_give, 0)
		charge_to_give = math.min(charge_to_give, 200)
		meta:set_string("infotext", S("@1 Active (@2)", machine_name,
			technic.EU_string(charge_to_give)))
		meta:set_int("LV_EU_supply", charge_to_give)
	else
		meta:set_string("infotext", S("%s Idle"):format(machine_name))
		meta:set_int("LV_EU_supply", 0)
	end
end

minetest.register_node("technic:solar_panel", {
	tiles = {"technic_solar_panel_top.png",  "technic_solar_panel_bottom.png", "technic_solar_panel_side.png",
	         "technic_solar_panel_side.png", "technic_solar_panel_side.png",   "technic_solar_panel_side.png"},
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
		technic_machine=1, technic_lv=1},
	connect_sides = {"bottom"},
	sounds = default.node_sound_wood_defaults(),
	description = S("Small Solar %s Generator"):format("LV"),
	active = false,
	drawtype = "nodebox",
	paramtype = "light",
	is_ground_content = true,
	node_box = {
		type = "fixed",
		fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
	},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_int("LV_EU_supply", 0)
		meta:set_string("infotext", S("Small Solar %s Generator"):format("LV"))
	end,
	technic_run = run,
})

technic.register_machine("LV", "technic:solar_panel", technic.producer)


code:
-- A water mill produces LV EUs by exploiting flowing water across it
-- It is a LV EU supplier and fairly low yield (max 180EUs)
-- It is a little over half as good as the thermal generator.

local S = technic.getter

local cable_entry = "^technic_cable_connection_overlay.png"

minetest.register_alias("water_mill", "technic:water_mill")

minetest.register_craft({
	output = 'technic:water_mill',
	recipe = {
		{'technic:marble', 'default:diamond',        'technic:marble'},
		{'group:wood',     'technic:machine_casing', 'group:wood'},
		{'technic:marble', 'technic:lv_cable',       'technic:marble'},
	}
})

local function check_node_around_mill(pos)
	local node = minetest.get_node(pos)
	if node.name == "default:water_flowing"
	  or node.name == "default:river_water_flowing" then
		return node.param2 -- returns approx. water flow, if any
	end
	return false
end

local run = function(pos, node)
	local meta             = minetest.get_meta(pos)
	local water_flow       = 0
	local production_level
	local eu_supply
	local max_output       = 4 * 45 -- keeping it around 180, little more than previous 150 :)

	local positions = {
		{x=pos.x+1, y=pos.y, z=pos.z},
		{x=pos.x-1, y=pos.y, z=pos.z},
		{x=pos.x,   y=pos.y, z=pos.z+1},
		{x=pos.x,   y=pos.y, z=pos.z-1},
	}

	for _, p in pairs(positions) do
		local check = check_node_around_mill(p)
		if check then
			water_flow = water_flow + check
		end
	end

	eu_supply = math.min(4 * water_flow, max_output)
	production_level = math.floor(100 * eu_supply / max_output)

	meta:set_int("LV_EU_supply", eu_supply)

	meta:set_string("infotext",
		S("Hydro %s Generator"):format("LV").." ("..production_level.."%)")

	if production_level > 0 and
	   minetest.get_node(pos).name == "technic:water_mill" then
		technic.swap_node (pos, "technic:water_mill_active")
		meta:set_int("LV_EU_supply", 0)
		return
	end
	if production_level == 0 then
		technic.swap_node(pos, "technic:water_mill")
	end
end

minetest.register_node("technic:water_mill", {
	description = S("Hydro %s Generator"):format("LV"),
	tiles = {
		"technic_water_mill_top.png",
		"technic_machine_bottom.png"..cable_entry,
		"technic_water_mill_side.png",
		"technic_water_mill_side.png",
		"technic_water_mill_side.png",
		"technic_water_mill_side.png"
	},
	paramtype2 = "facedir",
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
		technic_machine=1, technic_lv=1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", S("Hydro %s Generator"):format("LV"))
		meta:set_int("LV_EU_supply", 0)
	end,
	technic_run = run,
})

minetest.register_node("technic:water_mill_active", {
	description = S("Hydro %s Generator"):format("LV"),
	tiles = {"technic_water_mill_top_active.png", "technic_machine_bottom.png",
	         "technic_water_mill_side.png",       "technic_water_mill_side.png",
	         "technic_water_mill_side.png",       "technic_water_mill_side.png"},
	paramtype2 = "facedir",
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
		technic_machine=1, technic_lv=1, not_in_creative_inventory=1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	drop = "technic:water_mill",
	technic_run = run,
	technic_disabled_machine_name = "technic:water_mill",
})

technic.register_machine("LV", "technic:water_mill",        technic.producer)
technic.register_machine("LV", "technic:water_mill_active", technic.producer)


code:
-- MV alloy furnace

minetest.register_craft({
	output = 'technic:mv_alloy_furnace',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:lv_alloy_furnace', 'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:mv_transformer',   'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',         'technic:stainless_steel_ingot'},
	}
})

technic.register_alloy_furnace({tier = "MV", speed = 1.5, upgrade = 1, tube = 1, demand = {3000, 2000, 1000}})


code:
-- MV Battery box

minetest.register_craft({
	output = 'technic:mv_battery_box0',
	recipe = {
		{'technic:lv_battery_box0', 'technic:lv_battery_box0', 'technic:lv_battery_box0'},
		{'technic:lv_battery_box0', 'technic:mv_transformer',  'technic:lv_battery_box0'},
		{'',                        'technic:mv_cable',        ''},
	}
})

technic.register_battery_box({
	tier           = "MV",
	max_charge     = 200000,
	charge_rate    = 20000,
	discharge_rate = 80000,
	charge_step    = 2000,
	discharge_step = 8000,
	upgrade        = 1,
	tube           = 1,
})


code:
minetest.register_alias("mv_cable", "technic:mv_cable")

minetest.register_craft({
	output = 'technic:mv_cable 3',
	recipe ={
		{'technic:rubber',   'technic:rubber',   'technic:rubber'},
		{'technic:lv_cable', 'technic:lv_cable', 'technic:lv_cable'},
		{'technic:rubber',   'technic:rubber',   'technic:rubber'},
	}
})

technic.register_cable("MV", 2.5/16)


code:
minetest.register_craft({
	output = "technic:mv_centrifuge",
	recipe = {
		{"basic_materials:motor",          "technic:copper_plate",   "technic:diamond_drill_head"},
		{"technic:copper_plate",   "technic:machine_casing", "technic:copper_plate"      },
		{"pipeworks:one_way_tube", "technic:mv_cable",       "pipeworks:mese_filter"     },
	}
})

technic.register_centrifuge({
	tier = "MV",
	demand = { 8000, 7000, 6000 },
	speed = 2,
	upgrade = 1,
	tube = 1,
})


code:
-- MV compressor

minetest.register_craft({
	output = 'technic:mv_compressor',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:lv_compressor',  'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:mv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_compressor({tier = "MV", demand = {800, 600, 400}, speed = 2, upgrade = 1, tube = 1})


code:
-- MV Electric Furnace
-- This is a faster version of the stone furnace which runs on EUs
-- In addition to this it can be upgraded with microcontrollers and batteries
-- This new version uses the batteries to lower the power consumption of the machine
-- Also in addition this furnace can be attached to the pipe system from the pipeworks mod.

-- FIXME: kpoppel I'd like to introduce an induction heating element here also
minetest.register_craft({
	output = 'technic:mv_electric_furnace',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:lv_electric_furnace', 'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:mv_transformer',      'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',            'technic:stainless_steel_ingot'},
	}
})

technic.register_electric_furnace({tier="MV", upgrade=1, tube=1, demand={2000, 1000, 500}, speed=4})


code:
-- MV extractor

minetest.register_craft({
	output = 'technic:mv_extractor',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:lv_extractor',   'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:mv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_extractor({tier = "MV", demand = {800, 600, 400}, speed = 2, upgrade = 1, tube = 1})


code:
-- MV freezer

minetest.register_craft({
	output = 'technic:mv_freezer',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:motor',          'technic:stainless_steel_ingot'},
		{'pipeworks:pipe_1_empty',        'technic:mv_transformer', 'pipeworks:pipe_1_empty'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_freezer({tier = "MV", demand = {800, 600, 400}, speed = 0.5, upgrade = 1, tube = 1})


code:
minetest.register_alias("generator_mv", "technic:generator_mv")

minetest.register_craft({
	output = 'technic:mv_generator',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:lv_generator',   'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:mv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_generator({tier="MV", tube=1, supply=2400})


code:
-- MV grinder

minetest.register_craft({
	output = 'technic:mv_grinder',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:lv_grinder',     'technic:stainless_steel_ingot'},
		{'pipeworks:tube_1',              'technic:mv_transformer', 'pipeworks:tube_1'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable',       'technic:stainless_steel_ingot'},
	}
})

technic.register_grinder({tier="MV", demand={600, 450, 300}, speed=2, upgrade=1, tube=1})


code:
-- A Hydro Turbine produces MV EUs by exploiting flowing water across it
-- It is a MV EU supplier and fairly high yield (max 1800EUs)

local S = technic.getter

local cable_entry = "^technic_cable_connection_overlay.png"

minetest.register_alias("hydro_turbine", "technic:hydro_turbine")

minetest.register_craft({
	output = 'technic:hydro_turbine',
	recipe = {
		{'technic:stainless_steel_ingot', 'technic:water_mill', 'technic:stainless_steel_ingot'},
		{'technic:water_mill', 'technic:mv_transformer', 'technic:water_mill'},
		{'technic:stainless_steel_ingot', 'technic:mv_cable', 'technic:stainless_steel_ingot'},
	}
})

local function get_water_flow(pos)
	local node = minetest.get_node(pos)
	if minetest.get_item_group(node.name, "water") == 3 then
		return node.param2 -- returns approx. water flow, if any
	end
	return 0
end

---
-- 10 times better than LV hydro because of 2 extra water mills and 4 stainless steel, a transformer and whatnot ;P.
-- Man hydro turbines are tough and long lasting. So, give it some value :)
local run = function(pos, node)
	local meta             = minetest.get_meta(pos)
	local water_flow       = 0
	local production_level
	local eu_supply
	local max_output       = 40 * 45 -- Generates 1800EU/s

	local positions = {
		{x=pos.x+1, y=pos.y, z=pos.z},
		{x=pos.x-1, y=pos.y, z=pos.z},
		{x=pos.x,   y=pos.y, z=pos.z+1},
		{x=pos.x,   y=pos.y, z=pos.z-1},
	}

	for _, p in pairs(positions) do
		water_flow = water_flow + get_water_flow(p)
	end

	eu_supply = math.min(40 * water_flow, max_output)
	production_level = math.floor(100 * eu_supply / max_output)

	meta:set_int("MV_EU_supply", eu_supply)

	meta:set_string("infotext",
	S("Hydro %s Generator"):format("MV").." ("..production_level.."%)")
	if production_level > 0 and
		minetest.get_node(pos).name == "technic:hydro_turbine" then
		technic.swap_node(pos, "technic:hydro_turbine_active")
		meta:set_int("MV_EU_supply", 0)
		return
	end
	if production_level == 0 then
		technic.swap_node(pos, "technic:hydro_turbine")
	end
end

minetest.register_node("technic:hydro_turbine", {
	description = S("Hydro %s Generator"):format("MV"),
	tiles = {
		"technic_hydro_turbine_top.png",
		"technic_machine_bottom.png"..cable_entry,
		"technic_hydro_turbine_side.png",
		"technic_hydro_turbine_side.png",
		"technic_hydro_turbine_side.png",
		"technic_hydro_turbine_side.png"
	},
	paramtype2 = "facedir",
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
	technic_machine=1, technic_mv=1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", S("Hydro %s Generator"):format("MV"))
		meta:set_int("MV_EU_supply", 0)
	end,
	technic_run = run,
})

minetest.register_node("technic:hydro_turbine_active", {
	description = S("Hydro %s Generator"):format("MV"),
	tiles = {"technic_hydro_turbine_top_active.png", "technic_machine_bottom.png",
			"technic_hydro_turbine_side.png", "technic_hydro_turbine_side.png",
			"technic_hydro_turbine_side.png", "technic_hydro_turbine_side.png"},
	paramtype2 = "facedir",
	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2,
			technic_machine=1, technic_mv=1, not_in_creative_inventory=1},
	legacy_facedir_simple = true,
	sounds = default.node_sound_wood_defaults(),
	drop = "technic:hydro_turbine",
	technic_run = run,
	technic_disabled_machine_name = "technic:hydro_turbine",
})

technic.register_machine("MV", "technic:hydro_turbine",        technic.producer)
technic.register_machine("MV", "technic:hydro_turbine_active", technic.producer)


code:
technic.register_tier("MV", "Medium Voltage")

local path = technic.modpath.."/machines/MV"

-- Wiring stuff
dofile(path.."/cables.lua")
dofile(path.."/battery_box.lua")

-- Generators
if technic.config:get_bool("enable_wind_mill") then
	dofile(path.."/wind_mill.lua")
end
dofile(path.."/generator.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/hydro_turbine.lua")

-- Machines
dofile(path.."/alloy_furnace.lua")
dofile(path.."/electric_furnace.lua")
dofile(path.."/grinder.lua")
dofile(path.."/extractor.lua")
dofile(path.."/compressor.lua")
dofile(path.."/centrifuge.lua")

dofile(path.."/tool_workshop.lua")

dofile(path.."/freezer.lua")

-- The power radiator supplies appliances with inductive coupled power:
-- Lighting and associated textures is taken directly from VanessaE's homedecor and made electric.
-- This is currently useless, slow, and mostly copied
--dofile(path.."/power_radiator.lua")
--dofile(path.."/lighting.lua")