Partial rewrite

This commit is contained in:
ShadowNinja
2013-07-17 15:34:35 -04:00
parent 48ea6fb99d
commit ee0765804c
123 changed files with 5513 additions and 8341 deletions

View File

@ -0,0 +1,19 @@
-- HV battery box
minetest.register_craft({
output = 'technic:hv_battery_box0',
recipe = {
{'technic:mv_battery_box0', 'technic:mv_battery_box0', 'technic:mv_battery_box0'},
{'technic:mv_battery_box0', 'technic:hv_transformer', 'technic:mv_battery_box0'},
{'', 'technic:hv_cable0', ''},
}
})
technic.register_battery_box({
tier = "HV",
max_charge = 1500000,
charge_rate = 100000,
discharge_rate = 400000,
charge_step = 10000,
discharge_step = 40000,
})

View File

@ -0,0 +1,12 @@
minetest.register_craft({
output = 'technic:hv_cable0 3',
recipe = {
{'technic:rubber', 'technic:rubber', 'technic:rubber'},
{'technic:mv_cable0', 'technic:mv_cable0', 'technic:mv_cable0'},
{'technic:rubber', 'technic:rubber', 'technic:rubber'},
}
})
technic.register_cable("HV", 3/16)

View File

@ -0,0 +1,206 @@
-- Forcefield mod by ShadowNinja
-- Modified by kpoppel
--
-- Forcefields are powerful barriers but they consume huge amounts of power.
-- Forcefield Generator is a HV machine.
-- How expensive is the generator?
-- Leaves room for upgrades lowering the power drain?
local forcefield_power_drain = 10
local forcefield_step_interval = 1
minetest.register_craft({
output = 'technic:forcefield_emitter_off',
recipe = {
{'default:mese', 'technic:deployer_off', 'default:mese' },
{'technic:deployer_off', 'technic:motor', 'technic:deployer_off'},
{'default:mese', 'technic:deployer_off', 'default:mese' },
}
})
-- Idea: Let forcefields have different colors by upgrade slot.
-- Idea: Let forcefields add up by detecting if one hits another.
-- ___ __
-- / \/ \
-- | |
-- \___/\___/
local function update_forcefield(pos, range, active)
local vm = VoxelManip()
local p1 = {x = pos.x-range, y = pos.y-range, z = pos.z-range}
local p2 = {x = pos.x+range, y = pos.y+range, z = pos.z+range}
local MinEdge, MaxEdge = vm:read_from_map(p1, p2)
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local data = vm:get_data()
local c_air = minetest.get_content_id("air")
local c_field = minetest.get_content_id("technic:forcefield")
for z=-range, range do
for y=-range, range do
local vi = area:index(pos.x+(-range), pos.y+y, pos.z+z)
for x=-range, range do
if x*x+y*y+z*z <= range * range + range and
x*x+y*y+z*z >= (range-1) * (range-1) + (range-1) then
if active and data[vi] == c_air then
data[vi] = c_field
elseif not active and data[vi] == c_field then
data[vi] = c_air
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:update_liquids()
vm:write_to_map()
vm:update_map()
end
local get_forcefield_formspec = function(range)
return "size[3,1.5]"..
"field[1,0.5;2,1;range;Range;"..range.."]"..
"button[0,1;3,1;toggle;Enable/Disable]"
end
local forcefield_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
local range = fields.range
if fields.toggle then
if meta:get_int("enabled") == 1 then
meta:set_int("enabled", 0)
else
meta:set_int("enabled", 1)
end
end
-- Smallest field is 5. Anything less is asking for trouble.
-- Largest is 20. It is a matter of pratical node handling.
-- At the maximim range updating the forcefield takes about 0.2s
range = math.max(range, 5)
range = math.min(range, 20)
if meta:get_int("range") ~= range then
update_forcefield(pos, meta:get_int("range"), false)
meta:set_int("range", range)
meta:set_string("formspec", get_forcefield_formspec(range))
end
end
local mesecons = {
effector = {
action_on = function(pos, node)
minetest.get_meta(pos):set_int("enabled", 0)
end,
action_off = function(pos, node)
minetest.get_meta(pos):set_int("enabled", 1)
end
}
}
minetest.register_node("technic:forcefield_emitter_off", {
description = "Forcefield emitter",
tiles = {"technic_forcefield_emitter_off.png"},
groups = {cracky = 1},
on_receive_fields = forcefield_receive_fields,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("HV_EU_input", 0)
meta:set_int("HV_EU_demand", 0)
meta:set_int("range", 10)
meta:set_int("enabled", 0)
meta:set_string("formspec", get_forcefield_formspec(10))
meta:set_string("infotext", "Forcefield emitter");
end,
mesecons = mesecons
})
minetest.register_node("technic:forcefield_emitter_on", {
description = "Forcefield emitter on (you hacker you)",
tiles = {"technic_forcefield_emitter_on.png"},
groups = {cracky = 1, not_in_creative_inventory=1},
drop = "technic:forcefield_emitter_off",
on_receive_fields = forcefield_receive_fields,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local range = meta:get_int("range")
meta:set_string("formspec", get_forcefield_formspec(range))
end,
on_destruct = function(pos)
local meta = minetest.get_meta(pos)
update_forcefield(pos, meta:get_int("range"), false)
end,
mesecons = mesecons
})
minetest.register_node("technic:forcefield", {
description = "Forcefield (you hacker you)",
sunlight_propagates = true,
drawtype = "glasslike",
groups = {not_in_creative_inventory=1, unbreakable=1},
paramtype = "light",
light_source = 15,
drop = '',
tiles = {{
name = "technic_forcefield_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
}},
})
minetest.register_abm({
nodenames = {"technic:forcefield_emitter_on", "technic:forcefield_emitter_off"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.get_meta(pos)
local eu_input = meta:get_int("HV_EU_input")
local eu_demand = meta:get_int("HV_EU_demand")
local enabled = meta:get_int("enabled")
-- Power off automatically if no longer connected to a switching station
technic.switching_station_timeout_count(pos, "HV")
local power_requirement = math.floor(
4 * math.pi * math.pow(meta:get_int("range"), 2)
) * forcefield_power_drain
if meta:get_int("enabled") == 0 then
if node.name == "technic:forcefield_emitter_on" then
meta:set_int("HV_EU_demand", 0)
update_forcefield(pos, meta:get_int("range"), false)
hacky_swap_node(pos, "technic:forcefield_emitter_off")
meta:set_string("infotext", "Forcefield Generator Disabled")
return
end
elseif eu_input < power_requirement then
meta:set_string("infotext", "Forcefield Generator Unpowered")
if node.name == "technic:forcefield_emitter_on" then
update_forcefield(pos, meta:get_int("range"), false)
hacky_swap_node(pos, "technic:forcefield_emitter_off")
end
elseif eu_input >= power_requirement then
if node.name == "technic:forcefield_emitter_off" then
hacky_swap_node(pos, "technic:forcefield_emitter_on")
meta:set_string("infotext", "Forcefield Generator Active")
end
update_forcefield(pos, meta:get_int("range"), true)
end
meta:set_int("HV_EU_demand", power_requirement)
end
})
if minetest.get_modpath("mesecons_mvps") then
mesecon:register_mvps_stopper("technic:forcefield")
end
-- TODO: Register a stopper for frames
technic.register_machine("HV", "technic:forcefield_emitter_on", technic.receiver)
technic.register_machine("HV", "technic:forcefield_emitter_off", technic.receiver)

View File

@ -0,0 +1,12 @@
technic.register_tier("HV", "High Voltage")
local path = technic.modpath.."/machines/HV"
dofile(path.."/cables.lua")
dofile(path.."/quarry.lua")
dofile(path.."/forcefield.lua")
dofile(path.."/battery_box.lua")
dofile(path.."/solar_array.lua")
dofile(path.."/nuclear_reactor.lua")

View File

@ -0,0 +1,259 @@
-- The enriched uranium rod driven EU generator.
-- A very large and advanced machine providing vast amounts of power.
-- Very efficient but also expensive to run as it needs uranium. (10000EU 86400 ticks (24h))
-- Provides HV EUs that can be down converted as needed.
--
-- The nuclear reactor core needs water and a protective shield to work.
-- This is checked now and then and if the machine is tampered with... BOOM!
local burn_ticks = 7 * 24 * 60 * 60 -- (seconds).
local power_supply = 100000 -- EUs
local fuel_type = "technic:uranium_fuel" -- The reactor burns this stuff
-- FIXME: recipe must make more sense like a rod recepticle, steam chamber, HV generator?
minetest.register_craft({
output = 'technic:hv_nuclear_reactor_core',
recipe = {
{'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot', 'technic:stainless_steel_ingot'},
{'technic:stainless_steel_ingot', '', 'technic:stainless_steel_ingot'},
{'technic:stainless_steel_ingot', 'technic:hv_cable', 'technic:stainless_steel_ingot'},
}
})
local generator_formspec =
"invsize[8,9;]"..
"label[0,0;Nuclear Reactor Rod Compartment]"..
"list[current_name;src;2,1;3,2;]"..
"list[current_player;main;0,5;8,4;]"
-- "Boxy sphere"
local nodebox = {
{ -0.353, -0.353, -0.353, 0.353, 0.353, 0.353 }, -- Box
{ -0.495, -0.064, -0.064, 0.495, 0.064, 0.064 }, -- Circle +-x
{ -0.483, -0.128, -0.128, 0.483, 0.128, 0.128 },
{ -0.462, -0.191, -0.191, 0.462, 0.191, 0.191 },
{ -0.433, -0.249, -0.249, 0.433, 0.249, 0.249 },
{ -0.397, -0.303, -0.303, 0.397, 0.303, 0.303 },
{ -0.305, -0.396, -0.305, 0.305, 0.396, 0.305 }, -- Circle +-y
{ -0.250, -0.432, -0.250, 0.250, 0.432, 0.250 },
{ -0.191, -0.461, -0.191, 0.191, 0.461, 0.191 },
{ -0.130, -0.482, -0.130, 0.130, 0.482, 0.130 },
{ -0.066, -0.495, -0.066, 0.066, 0.495, 0.066 },
{ -0.064, -0.064, -0.495, 0.064, 0.064, 0.495 }, -- Circle +-z
{ -0.128, -0.128, -0.483, 0.128, 0.128, 0.483 },
{ -0.191, -0.191, -0.462, 0.191, 0.191, 0.462 },
{ -0.249, -0.249, -0.433, 0.249, 0.249, 0.433 },
{ -0.303, -0.303, -0.397, 0.303, 0.303, 0.397 },
}
minetest.register_node("technic:hv_nuclear_reactor_core", {
description = "Nuclear Reactor",
tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"},
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(),
drawtype="nodebox",
paramtype = "light",
stack_max = 1,
node_box = {
type = "fixed",
fixed = nodebox
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Nuclear Reactor Core")
meta:set_int("HV_EU_supply", 0)
-- Signal to the switching station that this device burns some
-- sort of fuel and needs special handling
meta:set_int("HV_EU_from_fuel", 1)
meta:set_int("burn_time", 0)
meta:set_string("formspec", generator_formspec)
local inv = meta:get_inventory()
inv:set_size("src", 6)
end,
can_dig = function(pos,player)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory()
if not inv:is_empty("src") then
minetest.chat_send_player(player:get_player_name(),
"Machine cannot be removed because it is not empty");
return false
else
return true
end
end,
})
minetest.register_node("technic:hv_nuclear_reactor_core_active", {
description = "HV Uranium Reactor",
tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png",
"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"},
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(),
drop="technic:hv_nuclear_reactor_core",
drawtype="nodebox",
light_source = 15,
paramtype = "light",
node_box = {
type = "fixed",
fixed = nodebox
},
can_dig = function(pos,player)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory()
if not inv:is_empty("src") then
minetest.chat_send_player(player:get_player_name(),
"Machine cannot be removed because it is not empty");
return false
else
return true
end
end,
})
local check_reactor_structure = function(pos)
-- The reactor consists of a 9x9x9 cube structure
-- A cross section through the middle:
-- CCCC CCCC
-- CBBB BBBC
-- CBSS SSBC
-- CBSWWWSBC
-- CBSW#WSBC
-- CBSW|WSBC
-- CBSS|SSBC
-- CBBB|BBBC
-- CCCC|CCCC
-- C = Concrete, B = Blast resistant concrete, S = Stainless Steel,
-- W = water node, # = reactor core, | = HV cable
-- The man-hole and the HV cable is only in the middle
-- The man-hole is optional
local vm = VoxelManip()
local pos1 = vector.subtract(pos, 4)
local pos2 = vector.add(pos, 4)
local MinEdge, MaxEdge = vm:read_from_map(pos1, pos2)
local data = vm:get_data()
local area = VoxelArea:new({MinEdge=MinEdge, MaxEdge=MaxEdge})
local c_concrete = minetest.get_content_id("technic:concrete")
local c_blast_concrete = minetest.get_content_id("technic:blast_resistant_concrete")
local c_stainless_steel = minetest.get_content_id("technic:stainless_steel_block")
local c_water_source = minetest.get_content_id("default:water_source")
local c_water_flowing = minetest.get_content_id("default:water_flowing")
local concretelayer, blastlayer, steellayer, waterlayer = 0, 0, 0, 0
for z = pos1.z, pos2.z do
for y = pos1.y, pos2.y do
for x = pos1.x, pos2.x do
-- If the position is in the outer layer
if x == pos1.x or x == pos2.x or
y == pos1.y or y == pos2.y or
z == pos1.z or z == pos2.z then
if data[area:index(x, y, z)] == c_concrete then
concretelayer = concretelayer + 1
end
elseif x == pos1.x+1 or x == pos2.x-1 or
y == pos1.y+1 or y == pos2.y-1 or
z == pos1.z+1 or z == pos2.z-1 then
if data[area:index(x, y, z)] == c_blast_concrete then
blastlayer = blastlayer + 1
end
elseif x == pos1.x+2 or x == pos2.x-2 or
y == pos1.y+2 or y == pos2.y-2 or
z == pos1.z+2 or z == pos2.z-2 then
if data[area:index(x, y, z)] == c_stainless_steel then
steellayer = steellayer + 1
end
elseif x == pos1.x+3 or x == pos2.x-3 or
y == pos1.y+3 or y == pos2.y-3 or
z == pos1.z+3 or z == pos2.z-3 then
local cid = data[area:index(x, y, z)]
if cid == c_water_source or cid == c_water_flowing then
waterlayer = waterlayer + 1
end
end
end
end
end
if waterlayer >= 25 and
steellayer >= 96 and
blastlayer >= 216 and
concretelayer >= 384 then
return true
end
end
local explode_reactor = function(pos)
print("A reactor exploded at "..minetest.pos_to_string(pos))
end
local function damage_nearby_players(pos)
local objs = minetest.get_objects_inside_radius(pos, 4)
for _, o in pairs(objs) do
if o:is_player() then
o:set_hp(math.max(o:get_hp() - 2, 0))
end
end
end
minetest.register_abm({
nodenames = {"technic:hv_nuclear_reactor_core", "technic:hv_nuclear_reactor_core_active"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.get_meta(pos)
local burn_time = meta:get_int("burn_time") or 0
if burn_time >= burn_ticks or burn_time == 0 then
local inv = meta:get_inventory()
if not inv:is_empty("src") then
local srclist = inv:get_list("src")
local correct_fuel_count = 0
for _, srcstack in pairs(srclist) do
if srcstack then
if srcstack:get_name() == fuel_type then
correct_fuel_count = correct_fuel_count + 1
end
end
end
-- Check that the reactor is complete as well
-- as the correct number of correct fuel
if correct_fuel_count == 6 and
check_reactor_structure(pos) then
meta:set_int("burn_time", 1)
hacky_swap_node(pos, "technic:hv_nuclear_reactor_core_active")
meta:set_int("HV_EU_supply", power_supply)
for idx, srcstack in pairs(srclist) do
srcstack:take_item()
inv:set_stack("src", idx, srcstack)
end
return
end
end
meta:set_int("HV_EU_supply", 0)
meta:set_int("burn_time", 0)
meta:set_string("infotext", "Nuclear Reactor Core (idle)")
hacky_swap_node(pos, "technic:hv_nuclear_reactor_core")
elseif burn_time > 0 then
damage_nearby_players(pos)
if not check_reactor_structure(pos) then
explode_reactor(pos)
end
burn_time = burn_time + 1
meta:set_int("burn_time", burn_time)
local percent = math.floor(burn_time / burn_ticks * 100)
meta:set_string("infotext", "Nuclear Reactor Core ("..percent.."%)")
meta:set_int("HV_EU_supply", power_supply)
end
end
})
technic.register_machine("HV", "technic:hv_nuclear_reactor_core", technic.producer)
technic.register_machine("HV", "technic:hv_nuclear_reactor_core_active", technic.producer)

View File

@ -0,0 +1,200 @@
minetest.register_craft({
recipe = {
{"default:steelblock", "pipeworks:filter", "default:steelblock"},
{"default:steelblock", "technic:motor", "default:steelblock"},
{"default:steelblock", "technic:diamond_drill_head", "default:steelblock"}},
output = "technic:quarry",
})
local quarry_dig_above_nodes = 3 -- How far above the quarry we will dig nodes
local quarry_max_depth = 100
local function get_quarry_formspec(size)
return "size[3,1.5]"..
"field[1,0.5;2,1;size;Radius;"..size.."]"..
"button[0,1;3,1;toggle;Enable/Disable]"
end
local function quarry_receive_fields(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
local size = tonumber(fields.size)
if fields.toggle then
if meta:get_int("enabled") == 0 then
meta:set_int("enabled", 1)
else
meta:set_int("enabled", 0)
end
end
-- Smallest size is 2. Anything less is asking for trouble.
-- Largest is 8. It is a matter of pratical node handling.
size = math.max(size, 2)
size = math.min(size, 8)
if meta:get_int("size") ~= size then
meta:set_int("size", size)
meta:set_string("formspec", get_quarry_formspec(size))
end
end
local function get_quarry_center(pos, size)
local node = minetest.get_node(pos)
local back_dir = minetest.facedir_to_dir(node.param2)
local relative_center = vector.multiply(back_dir, size + 1)
local center = vector.add(pos, relative_center)
return center
end
local function gen_next_digpos(center, digpos, size)
digpos.x = digpos.x + 1
if digpos.x > center.x + size then
digpos.x = center.x - size
digpos.z = digpos.z + 1
end
if digpos.z > center.z + size then
digpos.x = center.x - size
digpos.z = center.z - size
digpos.y = digpos.y - 1
end
end
local function find_next_digpos(data, area, center, dig_y, size)
local c_air = minetest.get_content_id("air")
for y = center.y + quarry_dig_above_nodes, dig_y - 1, -1 do
for z = center.z - size, center.z + size do
for x = center.x - size, center.x + size do
if data[area:index(x, y, z)] ~= c_air then
return vector.new(x, y, z)
end
end
end
end
end
local function quarry_dig(pos, center, size)
local meta = minetest.get_meta(pos)
local drops = {}
local dig_y = meta:get_int("dig_y")
local owner = meta:get_int("owner")
local vm = VoxelManip()
local p1 = vector.new(
center.x - size,
center.y + quarry_dig_above_nodes,
center.z - size)
local p2 = vector.new(
center.x + size,
dig_y - 1, -- One node lower in case we have finished the current layer
center.z + size)
local e1, e2 = vm:read_from_map(p1, p2)
local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
local data = vm:get_data()
local digpos = find_next_digpos(data, area, center, dig_y, size)
if digpos then
if digpos.y < pos.y - quarry_max_depth then
meta:set_int("dig_y", digpos.y)
return drops
end
if minetest.is_protected and minetest.is_protected(digpos, owner) then
meta:set_int("enabled", 0)
return
end
dig_y = digpos.y
local node = minetest.get_node(digpos)
drops = minetest.get_node_drops(node.name, "")
minetest.dig_node(digpos)
if minetest.get_node(digpos).name == node.name then
-- We tried to dig something undigable like a
-- filled chest. Notice that we check for a node
-- change, not for air. This is so that we get drops
-- from things like concrete posts with platforms,
-- which turn into regular concrete posts when dug.
drops = {}
end
elseif not (dig_y < pos.y - quarry_max_depth) then
dig_y = dig_y - 16
end
meta:set_int("dig_y", dig_y)
return drops
end
local function send_items(items, pos, node)
for _, item in pairs(items) do
local tube_item = tube_item(vector.new(pos), item)
tube_item:get_luaentity().start_pos = vector.new(pos)
tube_item:setvelocity(vector.new(0, 1, 0))
tube_item:setacceleration({x=0, y=0, z=0})
end
end
minetest.register_node("technic:quarry", {
description = "Quarry",
tiles = {"default_steel_block.png", "default_steel_block.png",
"default_steel_block.png", "default_steel_block.png",
"default_steel_block.png^default_tool_mesepick.png", "default_steel_block.png"},
paramtype2 = "facedir",
groups = {cracky=2, tubedevice=1},
tube = {
connect_sides = {top = 1},
},
on_construct = function(pos)
local size = 4
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Quarry")
meta:set_string("formspec", get_quarry_formspec(4))
meta:set_int("size", size)
meta:set_int("dig_y", pos.y)
end,
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
tube_scanforobjects(pos)
end,
after_dig_node = tube_scanforobjects,
on_receive_fields = quarry_receive_fields,
})
minetest.register_abm({
nodenames = {"technic:quarry"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.get_meta(pos)
local size = meta:get_int("size")
local eu_input = meta:get_int("HV_EU_input")
local demand = 10000
local center = get_quarry_center(pos, size)
local dig_y = meta:get_int("dig_y")
technic.switching_station_timeout_count(pos, "HV")
if meta:get_int("enabled") == 0 then
meta:set_string("infotext", "Quarry Disabled")
meta:set_int("HV_EU_demand", 0)
return
end
if eu_input < demand then
meta:set_string("infotext", "Quarry Unpowered")
elseif eu_input >= demand then
meta:set_string("infotext", "Quarry Active")
local items = quarry_dig(pos, center, size)
send_items(items, pos, node)
if dig_y < pos.y - quarry_max_depth then
meta:set_string("infotext", "Quarry Finished")
end
end
meta:set_int("HV_EU_demand", demand)
end
})
technic.register_machine("HV", "technic:quarry", technic.receiver)

View File

@ -0,0 +1,14 @@
-- The high voltage solar array is an assembly of medium voltage arrays.
-- Solar arrays are not able to store large amounts of energy.
minetest.register_craft({
output = 'technic:solar_array_hv 1',
recipe = {
{'technic:solar_array_mv', 'technic:solar_array_mv', 'technic:solar_array_mv'},
{'default:steel_ingot', 'technic:hv_transformer', 'default:steel_ingot'},
{'', 'technic:hv_cable0', ''},
}
})
technic.register_solar_array({tier="HV", power=100})