From 888b0ebfec8c2eff9015163549a7e47443cb8665 Mon Sep 17 00:00:00 2001 From: Vanessa Ezekowitz Date: Fri, 1 Apr 2016 21:00:20 -0400 Subject: "explode" all modpacks into their individual components (you can't have a modpack buried inside a modpack) --- technic/machines/HV/battery_box.lua | 21 + technic/machines/HV/cables.lua | 12 + technic/machines/HV/forcefield.lua | 261 +++++++ technic/machines/HV/generator.lua | 13 + technic/machines/HV/init.lua | 18 + technic/machines/HV/nuclear_reactor.lua | 723 ++++++++++++++++++ technic/machines/HV/quarry.lua | 251 ++++++ technic/machines/HV/solar_array.lua | 14 + technic/machines/LV/alloy_furnace.lua | 14 + technic/machines/LV/battery_box.lua | 19 + technic/machines/LV/cables.lua | 14 + technic/machines/LV/cnc.lua | 237 ++++++ technic/machines/LV/cnc_api.lua | 369 +++++++++ technic/machines/LV/cnc_nodes.lua | 91 +++ technic/machines/LV/compressor.lua | 13 + technic/machines/LV/electric_furnace.lua | 16 + technic/machines/LV/extractor.lua | 13 + technic/machines/LV/generator.lua | 18 + technic/machines/LV/geothermal.lua | 111 +++ technic/machines/LV/grinder.lua | 13 + technic/machines/LV/init.lua | 29 + technic/machines/LV/music_player.lua | 130 ++++ technic/machines/LV/solar_array.lua | 18 + technic/machines/LV/solar_panel.lua | 67 ++ technic/machines/LV/water_mill.lua | 102 +++ technic/machines/MV/alloy_furnace.lua | 14 + technic/machines/MV/battery_box.lua | 22 + technic/machines/MV/cables.lua | 14 + technic/machines/MV/centrifuge.lua | 16 + technic/machines/MV/compressor.lua | 12 + technic/machines/MV/electric_furnace.lua | 18 + technic/machines/MV/extractor.lua | 12 + technic/machines/MV/generator.lua | 13 + technic/machines/MV/grinder.lua | 13 + technic/machines/MV/init.lua | 32 + technic/machines/MV/lighting.lua | 590 ++++++++++++++ technic/machines/MV/power_radiator.lua | 220 ++++++ technic/machines/MV/solar_array.lua | 14 + technic/machines/MV/tool_workshop.lua | 117 +++ technic/machines/MV/wind_mill.lua | 87 +++ technic/machines/init.lua | 14 + technic/machines/other/anchor.lua | 109 +++ technic/machines/other/coal_alloy_furnace.lua | 177 +++++ technic/machines/other/coal_furnace.lua | 5 + technic/machines/other/constructor.lua | 189 +++++ technic/machines/other/frames.lua | 928 +++++++++++++++++++++++ technic/machines/other/init.lua | 15 + technic/machines/other/injector.lua | 118 +++ technic/machines/register/alloy_furnace.lua | 10 + technic/machines/register/alloy_recipes.lua | 35 + technic/machines/register/battery_box.lua | 291 +++++++ technic/machines/register/cables.lua | 177 +++++ technic/machines/register/centrifuge.lua | 8 + technic/machines/register/centrifuge_recipes.lua | 38 + technic/machines/register/common.lua | 214 ++++++ technic/machines/register/compressor.lua | 9 + technic/machines/register/compressor_recipes.lua | 34 + technic/machines/register/electric_furnace.lua | 9 + technic/machines/register/extractor.lua | 9 + technic/machines/register/extractor_recipes.lua | 59 ++ technic/machines/register/generator.lua | 173 +++++ technic/machines/register/grinder.lua | 9 + technic/machines/register/grinder_recipes.lua | 161 ++++ technic/machines/register/grindings.lua | 62 ++ technic/machines/register/init.lua | 33 + technic/machines/register/machine_base.lua | 197 +++++ technic/machines/register/recipes.lua | 107 +++ technic/machines/register/solar_array.lua | 65 ++ technic/machines/supply_converter.lua | 80 ++ technic/machines/switching_station.lua | 404 ++++++++++ 70 files changed, 7520 insertions(+) create mode 100644 technic/machines/HV/battery_box.lua create mode 100644 technic/machines/HV/cables.lua create mode 100644 technic/machines/HV/forcefield.lua create mode 100644 technic/machines/HV/generator.lua create mode 100644 technic/machines/HV/init.lua create mode 100644 technic/machines/HV/nuclear_reactor.lua create mode 100644 technic/machines/HV/quarry.lua create mode 100644 technic/machines/HV/solar_array.lua create mode 100644 technic/machines/LV/alloy_furnace.lua create mode 100644 technic/machines/LV/battery_box.lua create mode 100644 technic/machines/LV/cables.lua create mode 100644 technic/machines/LV/cnc.lua create mode 100644 technic/machines/LV/cnc_api.lua create mode 100644 technic/machines/LV/cnc_nodes.lua create mode 100644 technic/machines/LV/compressor.lua create mode 100644 technic/machines/LV/electric_furnace.lua create mode 100644 technic/machines/LV/extractor.lua create mode 100644 technic/machines/LV/generator.lua create mode 100644 technic/machines/LV/geothermal.lua create mode 100644 technic/machines/LV/grinder.lua create mode 100644 technic/machines/LV/init.lua create mode 100644 technic/machines/LV/music_player.lua create mode 100644 technic/machines/LV/solar_array.lua create mode 100644 technic/machines/LV/solar_panel.lua create mode 100644 technic/machines/LV/water_mill.lua create mode 100644 technic/machines/MV/alloy_furnace.lua create mode 100644 technic/machines/MV/battery_box.lua create mode 100644 technic/machines/MV/cables.lua create mode 100644 technic/machines/MV/centrifuge.lua create mode 100644 technic/machines/MV/compressor.lua create mode 100644 technic/machines/MV/electric_furnace.lua create mode 100644 technic/machines/MV/extractor.lua create mode 100644 technic/machines/MV/generator.lua create mode 100644 technic/machines/MV/grinder.lua create mode 100644 technic/machines/MV/init.lua create mode 100644 technic/machines/MV/lighting.lua create mode 100644 technic/machines/MV/power_radiator.lua create mode 100644 technic/machines/MV/solar_array.lua create mode 100644 technic/machines/MV/tool_workshop.lua create mode 100644 technic/machines/MV/wind_mill.lua create mode 100644 technic/machines/init.lua create mode 100644 technic/machines/other/anchor.lua create mode 100644 technic/machines/other/coal_alloy_furnace.lua create mode 100644 technic/machines/other/coal_furnace.lua create mode 100644 technic/machines/other/constructor.lua create mode 100644 technic/machines/other/frames.lua create mode 100644 technic/machines/other/init.lua create mode 100644 technic/machines/other/injector.lua create mode 100644 technic/machines/register/alloy_furnace.lua create mode 100644 technic/machines/register/alloy_recipes.lua create mode 100644 technic/machines/register/battery_box.lua create mode 100644 technic/machines/register/cables.lua create mode 100644 technic/machines/register/centrifuge.lua create mode 100644 technic/machines/register/centrifuge_recipes.lua create mode 100644 technic/machines/register/common.lua create mode 100644 technic/machines/register/compressor.lua create mode 100644 technic/machines/register/compressor_recipes.lua create mode 100644 technic/machines/register/electric_furnace.lua create mode 100644 technic/machines/register/extractor.lua create mode 100644 technic/machines/register/extractor_recipes.lua create mode 100644 technic/machines/register/generator.lua create mode 100644 technic/machines/register/grinder.lua create mode 100644 technic/machines/register/grinder_recipes.lua create mode 100644 technic/machines/register/grindings.lua create mode 100644 technic/machines/register/init.lua create mode 100644 technic/machines/register/machine_base.lua create mode 100644 technic/machines/register/recipes.lua create mode 100644 technic/machines/register/solar_array.lua create mode 100644 technic/machines/supply_converter.lua create mode 100644 technic/machines/switching_station.lua (limited to 'technic/machines') diff --git a/technic/machines/HV/battery_box.lua b/technic/machines/HV/battery_box.lua new file mode 100644 index 0000000..1e054ec --- /dev/null +++ b/technic/machines/HV/battery_box.lua @@ -0,0 +1,21 @@ +-- 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 = 1000000, + charge_rate = 100000, + discharge_rate = 400000, + charge_step = 10000, + discharge_step = 40000, + upgrade = 1, + tube = 1, +}) + diff --git a/technic/machines/HV/cables.lua b/technic/machines/HV/cables.lua new file mode 100644 index 0000000..25297c8 --- /dev/null +++ b/technic/machines/HV/cables.lua @@ -0,0 +1,12 @@ + +minetest.register_craft({ + output = 'technic:hv_cable0 3', + recipe = { + {'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting'}, + {'technic:mv_cable0', 'technic:mv_cable0', 'technic:mv_cable0'}, + {'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting', 'homedecor:plastic_sheeting'}, + } +}) + +technic.register_cable("HV", 3/16) + diff --git a/technic/machines/HV/forcefield.lua b/technic/machines/HV/forcefield.lua new file mode 100644 index 0000000..0f0836d --- /dev/null +++ b/technic/machines/HV/forcefield.lua @@ -0,0 +1,261 @@ +--- 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 forcefield_power_drain = 10 + +local S = technic.getter + +minetest.register_craft({ + output = "technic:forcefield_emitter_off", + recipe = { + {"default:mese", "technic:motor", "default:mese" }, + {"technic:deployer_off", "technic:machine_casing", "technic:deployer_off"}, + {"default:mese", "technic:hv_cable0", "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, first) + 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() + -- update_map is very slow, but if we don't call it we'll + -- get phantom blocks on the client. + if not active or first then + vm:update_map() + end +end + +local function set_forcefield_formspec(meta) + local formspec = "size[5,2.25]".. + "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 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.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 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 + local first = false + if node.name == "technic:forcefield_emitter_off" then + first = true + technic.swap_node(pos, "technic:forcefield_emitter_on") + meta:set_string("infotext", S("%s Active"):format(machine_name)) + end + update_forcefield(pos, meta, true, first) + end +end + +minetest.register_node("technic:forcefield_emitter_off", { + description = S("%s Forcefield Emitter"):format("HV"), + tiles = {"technic_forcefield_emitter_off.png"}, + groups = {cracky = 1, technic_machine = 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) + meta:set_string("infotext", S("%s Forcefield Emitter"):format("HV")) + set_forcefield_formspec(meta) + end, + mesecons = mesecons, + technic_run = run, +}) + +minetest.register_node("technic:forcefield_emitter_on", { + description = S("%s Forcefield Emitter"):format("HV"), + tiles = {"technic_forcefield_emitter_on.png"}, + groups = {cracky = 1, technic_machine = 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, + 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, +}) + +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 = 15, + diggable = false, + drop = '', + tiles = {{ + name = "technic_forcefield_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 1.0, + }, + }}, +}) + + +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) + diff --git a/technic/machines/HV/generator.lua b/technic/machines/HV/generator.lua new file mode 100644 index 0000000..aa83590 --- /dev/null +++ b/technic/machines/HV/generator.lua @@ -0,0 +1,13 @@ +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_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +technic.register_generator({tier="HV", tube=1, supply=1200}) + diff --git a/technic/machines/HV/init.lua b/technic/machines/HV/init.lua new file mode 100644 index 0000000..d7136b4 --- /dev/null +++ b/technic/machines/HV/init.lua @@ -0,0 +1,18 @@ + +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") + diff --git a/technic/machines/HV/nuclear_reactor.lua b/technic/machines/HV/nuclear_reactor.lua new file mode 100644 index 0000000..3aa1ba8 --- /dev/null +++ b/technic/machines/HV/nuclear_reactor.lua @@ -0,0 +1,723 @@ +-- 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 (one week)) +-- 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 + +local S = technic.getter + +if not vector.length_square then + vector.length_square = function (v) + return v.x*v.x + v.y*v.y + v.z*v.z + end +end + +-- 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:carbon_plate', 'default:obsidian_glass', 'technic:carbon_plate'}, + {'technic:composite_plate', 'technic:machine_casing', 'technic:composite_plate'}, + {'technic:stainless_steel_ingot', 'technic:hv_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +local generator_formspec = + "invsize[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[]" + +-- "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 }, +} + +local reactor_siren = {} +local function siren_set_state(pos, newstate) + local hpos = minetest.hash_node_position(pos) + local siren = reactor_siren[hpos] + if not siren then + if newstate == "off" then return end + siren = {state="off"} + reactor_siren[hpos] = siren + end + if newstate == "danger" and siren.state ~= "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 = "danger" + elseif newstate == "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 = "clear" + minetest.after(10, function () + if siren.handle == clear_handle then + minetest.sound_stop(clear_handle) + if reactor_siren[hpos] == siren then + reactor_siren[hpos] = nil + end + end + end) + elseif newstate == "off" and siren.state ~= "off" then + if siren.handle then minetest.sound_stop(siren.handle) end + siren.handle = nil + reactor_siren[hpos] = nil + end +end +local function siren_danger(pos, meta) + meta:set_int("siren", 1) + siren_set_state(pos, "danger") +end +local function siren_clear(pos, meta) + if meta:get_int("siren") ~= 0 then + siren_set_state(pos, "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 +-- 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 are only in the middle, and the man-hole +-- is optional. +-- +-- 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. +local reactor_structure_badness = function(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_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 blastlayer, steellayer, waterlayer = 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 + blastlayer = blastlayer + 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_stainless_steel then + steellayer = steellayer + 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 + waterlayer = waterlayer + 1 + end + end + end + end + end + if waterlayer > 25 then waterlayer = 25 end + if steellayer > 96 then steellayer = 96 end + if blastlayer > 216 then blastlayer = 216 end + return (25 - waterlayer) + (96 - steellayer) + (216 - blastlayer) +end + +local function meltdown_reactor(pos) + print("A reactor melted down at "..minetest.pos_to_string(pos)) + minetest.set_node(pos, {name="technic:corium_source"}) +end + +minetest.register_abm({ + nodenames = {"technic:hv_nuclear_reactor_core_active"}, + interval = 1, + 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", accum_badness - 1) + siren_clear(pos, meta) + end + else + siren_danger(pos, meta) + accum_badness = accum_badness + badness + if accum_badness >= 100 then + meltdown_reactor(pos) + else + meta:set_int("structure_accumulated_badness", accum_badness) + end + end + end, +}) + +local run = function(pos, node) + local meta = minetest.get_meta(pos) + local machine_name = S("Nuclear %s Generator Core"):format("HV") + local burn_time = meta:get_int("burn_time") or 0 + + if burn_time >= burn_ticks or burn_time == 0 then + local inv = meta:get_inventory() + if not inv:is_empty("src") then + local srclist = inv:get_list("src") + local correct_fuel_count = 0 + for _, srcstack in pairs(srclist) do + if srcstack then + if srcstack:get_name() == fuel_type then + correct_fuel_count = correct_fuel_count + 1 + end + end + end + -- Check that the reactor is complete as well + -- as the correct number of correct fuel + if correct_fuel_count == 6 and + reactor_structure_badness(pos) == 0 then + meta:set_int("burn_time", 1) + technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active") + meta:set_int("HV_EU_supply", power_supply) + for idx, srcstack in pairs(srclist) do + srcstack:take_item() + inv:set_stack("src", idx, srcstack) + end + return + end + end + meta:set_int("HV_EU_supply", 0) + meta:set_int("burn_time", 0) + meta:set_string("infotext", S("%s Idle"):format(machine_name)) + technic.swap_node(pos, "technic:hv_nuclear_reactor_core") + 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", machine_name.." ("..percent.."%)") + meta:set_int("HV_EU_supply", power_supply) + end +end + +minetest.register_node("technic:hv_nuclear_reactor_core", { + description = S("Nuclear %s Generator Core"):format("HV"), + tiles = {"technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png", + "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png", + "technic_hv_nuclear_reactor_core.png", "technic_hv_nuclear_reactor_core.png"}, + groups = {cracky=1, technic_machine=1}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + drawtype="nodebox", + paramtype = "light", + stack_max = 1, + node_box = { + type = "fixed", + fixed = nodebox + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("Nuclear %s Generator Core"):format("HV")) + meta:set_int("HV_EU_supply", 0) + -- Signal to the switching station that this device burns some + -- sort of fuel and needs special handling + meta:set_int("HV_EU_from_fuel", 1) + meta:set_int("burn_time", 0) + meta:set_string("formspec", generator_formspec) + local inv = meta:get_inventory() + inv:set_size("src", 6) + end, + can_dig = technic.machine_can_dig, + on_destruct = function(pos) siren_set_state(pos, "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", + "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 = {cracky=1, technic_machine=1, radioactive=11000, not_in_creative_inventory=1}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + drop="technic:hv_nuclear_reactor_core", + drawtype="nodebox", + light_source = 15, + paramtype = "light", + node_box = { + type = "fixed", + fixed = nodebox + }, + can_dig = technic.machine_can_dig, + after_dig_node = meltdown_reactor, + on_destruct = function(pos) siren_set_state(pos, "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) + +-- radioactivity + +-- Radiation resistance represents the extent to which a material +-- attenuates radiation passing through it; i.e., how good a radiation +-- shield it is. This is identified per node type. For materials that +-- exist in real life, the radiation resistance value that this system +-- uses for a node type consisting of a solid cube of that material is the +-- (approximate) number of halvings of ionising radiation that is achieved +-- by a metre of the material in real life. This is approximately +-- proportional to density, which provides a good way to estimate it. +-- Homogeneous mixtures of materials have radiation resistance computed +-- by a simple weighted mean. Note that the amount of attenuation that +-- a material achieves in-game is not required to be (and is not) the +-- same as the attenuation achieved in real life. +-- +-- Radiation resistance for a node type may be specified in the node +-- definition, under the key "radiation_resistance". As an interim +-- measure, until node definitions widely include this, this code +-- knows a bunch of values for particular node types in several mods, +-- and values for groups of node types. The node definition takes +-- precedence if it specifies a value. Nodes for which no value at +-- all is known are taken to provide no radiation resistance at all; +-- this is appropriate for the majority of node types. Only node types +-- consisting of a fairly homogeneous mass of material should report +-- non-zero radiation resistance; anything with non-uniform geometry +-- or complex internal structure should show no radiation resistance. +-- Fractional resistance values are permitted; two significant figures +-- is the recommended precision. +local default_radiation_resistance_per_node = { + ["default:brick"] = 13, + ["default:bronzeblock"] = 45, + ["default:clay"] = 15, + ["default:coalblock"] = 9.6, + ["default:cobble"] = 15, + ["default:copperblock"] = 46, + ["default:desert_cobble"] = 15, + ["default:desert_sand"] = 10, + ["default:desert_stone"] = 17, + ["default:desert_stonebrick"] = 17, + ["default:diamondblock"] = 24, + ["default:dirt"] = 8.2, + ["default:dirt_with_grass"] = 8.2, + ["default:dirt_with_grass_footsteps"] = 8.2, + ["default:dirt_with_snow"] = 8.2, + ["default:glass"] = 17, + ["default:goldblock"] = 170, + ["default:gravel"] = 10, + ["default:ice"] = 5.6, + ["default:lava_flowing"] = 8.5, + ["default:lava_source"] = 17, + ["default:mese"] = 21, + ["default:mossycobble"] = 15, + ["default:nyancat"] = 1000, + ["default:nyancat_rainbow"] = 1000, + ["default:obsidian"] = 18, + ["default:obsidian_glass"] = 18, + ["default:sand"] = 10, + ["default:sandstone"] = 15, + ["default:sandstonebrick"] = 15, + ["default:snowblock"] = 1.7, + ["default:steelblock"] = 40, + ["default:stone"] = 17, + ["default:stone_with_coal"] = 16, + ["default:stone_with_copper"] = 20, + ["default:stone_with_diamond"] = 18, + ["default:stone_with_gold"] = 34, + ["default:stone_with_iron"] = 20, + ["default:stone_with_mese"] = 17, + ["default:stonebrick"] = 17, + ["default:water_flowing"] = 2.8, + ["default:water_source"] = 5.6, + ["farming:desert_sand_soil"] = 10, + ["farming:desert_sand_soil_wet"] = 10, + ["farming:soil"] = 8.2, + ["farming:soil_wet"] = 8.2, + ["glooptest:akalin_crystal_glass"] = 21, + ["glooptest:akalinblock"] = 40, + ["glooptest:alatro_crystal_glass"] = 21, + ["glooptest:alatroblock"] = 40, + ["glooptest:amethystblock"] = 18, + ["glooptest:arol_crystal_glass"] = 21, + ["glooptest:crystal_glass"] = 21, + ["glooptest:emeraldblock"] = 19, + ["glooptest:heavy_crystal_glass"] = 21, + ["glooptest:mineral_akalin"] = 20, + ["glooptest:mineral_alatro"] = 20, + ["glooptest:mineral_amethyst"] = 17, + ["glooptest:mineral_arol"] = 20, + ["glooptest:mineral_desert_coal"] = 16, + ["glooptest:mineral_desert_iron"] = 20, + ["glooptest:mineral_emerald"] = 17, + ["glooptest:mineral_kalite"] = 20, + ["glooptest:mineral_ruby"] = 18, + ["glooptest:mineral_sapphire"] = 18, + ["glooptest:mineral_talinite"] = 20, + ["glooptest:mineral_topaz"] = 18, + ["glooptest:reinforced_crystal_glass"] = 21, + ["glooptest:rubyblock"] = 27, + ["glooptest:sapphireblock"] = 27, + ["glooptest:talinite_crystal_glass"] = 21, + ["glooptest:taliniteblock"] = 40, + ["glooptest:topazblock"] = 24, + ["mesecons_extrawires:mese_powered"] = 21, + ["moreblocks:cactus_brick"] = 13, + ["moreblocks:cactus_checker"] = 8.5, + ["moreblocks:circle_stone_bricks"] = 17, + ["moreblocks:clean_glass"] = 17, + ["moreblocks:coal_checker"] = 9.0, + ["moreblocks:coal_glass"] = 17, + ["moreblocks:coal_stone"] = 17, + ["moreblocks:coal_stone_bricks"] = 17, + ["moreblocks:glow_glass"] = 17, + ["moreblocks:grey_bricks"] = 15, + ["moreblocks:iron_checker"] = 11, + ["moreblocks:iron_glass"] = 17, + ["moreblocks:iron_stone"] = 17, + ["moreblocks:iron_stone_bricks"] = 17, + ["moreblocks:plankstone"] = 9.3, + ["moreblocks:split_stone_tile"] = 15, + ["moreblocks:split_stone_tile_alt"] = 15, + ["moreblocks:stone_tile"] = 15, + ["moreblocks:super_glow_glass"] = 17, + ["moreblocks:tar"] = 7.0, + ["moreblocks:wood_tile"] = 1.7, + ["moreblocks:wood_tile_center"] = 1.7, + ["moreblocks:wood_tile_down"] = 1.7, + ["moreblocks:wood_tile_flipped"] = 1.7, + ["moreblocks:wood_tile_full"] = 1.7, + ["moreblocks:wood_tile_left"] = 1.7, + ["moreblocks:wood_tile_right"] = 1.7, + ["moreblocks:wood_tile_up"] = 1.7, + ["moreores:mineral_mithril"] = 18, + ["moreores:mineral_silver"] = 21, + ["moreores:mineral_tin"] = 19, + ["moreores:mithril_block"] = 26, + ["moreores:silver_block"] = 53, + ["moreores:tin_block"] = 37, + ["snow:snow_brick"] = 2.8, + ["technic:brass_block"] = 43, + ["technic:carbon_steel_block"] = 40, + ["technic:cast_iron_block"] = 40, + ["technic:chernobylite_block"] = 40, + ["technic:chromium_block"] = 37, + ["technic:corium_flowing"] = 40, + ["technic:corium_source"] = 80, + ["technic:granite"] = 18, + ["technic:lead_block"] = 80, + ["technic:marble"] = 18, + ["technic:marble_bricks"] = 18, + ["technic:mineral_chromium"] = 19, + ["technic:mineral_uranium"] = 71, + ["technic:mineral_zinc"] = 19, + ["technic:stainless_steel_block"] = 40, + ["technic:zinc_block"] = 36, + ["tnt:tnt"] = 11, + ["tnt:tnt_burning"] = 11, +} +local default_radiation_resistance_per_group = { + concrete = 16, + tree = 3.4, + uranium_block = 500, + wood = 1.7, +} +local cache_radiation_resistance = {} +local function node_radiation_resistance(nodename) + local eff = cache_radiation_resistance[nodename] + if eff then return eff end + local def = minetest.registered_nodes[nodename] or {groups={}} + eff = def.radiation_resistance or default_radiation_resistance_per_node[nodename] + if not eff then + for g, v in pairs(def.groups) do + if v > 0 and default_radiation_resistance_per_group[g] then + eff = default_radiation_resistance_per_group[g] + break + end + end + end + if not eff then eff = 0 end + cache_radiation_resistance[nodename] = eff + return eff +end + +-- Radioactive nodes cause damage to nearby players. The damage +-- effect depends on the intrinsic strength of the radiation source, +-- the distance between the source and the player, and the shielding +-- effect of the intervening material. These determine a rate of damage; +-- total damage caused is the integral of this over time. +-- +-- In the absence of effective shielding, for a specific source the +-- damage rate varies realistically in inverse proportion to the square +-- of the distance. (Distance is measured to the player's abdomen, +-- not to the nominal player position which corresponds to the foot.) +-- However, if the player is inside a non-walkable (liquid or gaseous) +-- radioactive node, the nominal distance could go to zero, yielding +-- infinite damage. In that case, the player's body is displacing the +-- radioactive material, so the effective distance should remain non-zero. +-- We therefore apply a lower distance bound of sqrt(0.75) m, which is +-- the maximum distance one can get from the node centre within the node. +-- +-- A radioactive node is identified by being in the "radioactive" group, +-- and the group value signifies the strength of the radiation source. +-- The group value is the distance in millimetres from a node at which +-- an unshielded player will be damaged by 0.25 HP/s. Or, equivalently, +-- it is 2000 times the square root of the damage rate in HP/s that an +-- unshielded player 1 m away will take. +-- +-- Shielding is assessed by sampling every 0.25 m along the path +-- from the source to the player, ignoring the source node itself. +-- The summed shielding values from the sampled nodes yield a measure +-- of the total amount of shielding on the path. As in reality, +-- shielding causes exponential attenuation of radiation. However, the +-- effect is scaled down relative to real life. A metre of a node with +-- radiation resistance value R yields attenuation of sqrt(R)*0.1 nepers. +-- (In real life it would be about R*0.69 nepers, by the definition +-- of the radiation resistance values.) The sqrt part of this formula +-- scales down the differences between shielding types, reflecting the +-- game's simplification of making expensive materials such as gold +-- readily available in cubic metres. The multiplicative factor in the +-- formula scales down the difference between shielded and unshielded +-- safe distances, avoiding the latter becoming impractically large. +-- +-- Damage is processed at rates down to 0.25 HP/s, which in the absence of +-- shielding is attained at the distance specified by the "radioactive" +-- group value. Computed damage rates below 0.25 HP/s result in no +-- damage at all to the player. This gives the player an opportunity +-- to be safe, and limits the range at which source/player interactions +-- need to be considered. +local assumed_abdomen_offset = vector.new(0, 1, 0) +local assumed_abdomen_offset_length = vector.length(assumed_abdomen_offset) +local cache_scaled_shielding = {} + +local damage_enabled = minetest.setting_getbool("enable_damage") + +if damage_enabled then + minetest.register_abm({ + nodenames = {"group:radioactive"}, + interval = 1, + chance = 1, + action = function (pos, node) + local strength = minetest.registered_nodes[node.name].groups.radioactive + for _, o in ipairs(minetest.get_objects_inside_radius(pos, strength*0.001 + assumed_abdomen_offset_length)) do + if o:is_player() then + local rel = vector.subtract(vector.add(o:getpos(), assumed_abdomen_offset), pos) + local dist_sq = vector.length_square(rel) + local dist = math.sqrt(dist_sq) + local dirstep = dist == 0 and vector.new(0,0,0) or vector.divide(rel, dist*4) + local intpos = pos + local shielding = 0 + for intdist = 0.25, dist, 0.25 do + intpos = vector.add(intpos, dirstep) + local intnodepos = vector.round(intpos) + if not vector.equals(intnodepos, pos) then + local sname = minetest.get_node(intnodepos).name + local sval = cache_scaled_shielding[sname] + if not sval then + sval = math.sqrt(node_radiation_resistance(sname)) * -0.025 + cache_scaled_shielding[sname] = sval + end + shielding = shielding + sval + end + end + local dmg_rate = 0.25e-6 * strength*strength * math.exp(shielding) / math.max(0.75, dist_sq) + if dmg_rate >= 0.25 then + local dmg_int = math.floor(dmg_rate) + if math.random() < dmg_rate-dmg_int then + dmg_int = dmg_int + 1 + end + if dmg_int > 0 then + o:set_hp(math.max(o:get_hp() - dmg_int, 0)) + end + end + end + end + end, + }) +end + +-- radioactive materials that can result from destroying a reactor +local corium_griefing = 1 +if (not technic.config:get_bool("enable_corium_griefing")) then + corium_griefing = 0 +end + +for _, state in ipairs({ "flowing", "source" }) do + minetest.register_node("technic:corium_"..state, { + description = S(state == "source" and "Corium Source" or "Flowing Corium"), + drawtype = (state == "source" and "liquid" or "flowingliquid"), + [state == "source" and "tiles" or "special_tiles"] = {{ + name = "technic_corium_"..state.."_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0, + }, + }}, + paramtype = "light", + paramtype2 = (state == "flowing" and "flowingliquid" or nil), + light_source = (state == "source" and 8 or 5), + walkable = false, + pointable = false, + diggable = false, + buildable_to = true, + drop = "", + drowning = 1, + liquidtype = state, + liquid_alternative_flowing = "technic:corium_flowing", + liquid_alternative_source = "technic:corium_source", + liquid_viscosity = LAVA_VISC, + liquid_renewable = false, + damage_per_second = 6, + post_effect_color = { a=192, r=80, g=160, b=80 }, + groups = { + liquid = 2, + hot = 3, + igniter = corium_griefing, + radioactive = (state == "source" and 32000 or 16000), + not_in_creative_inventory = (state == "flowing" and 1 or nil), + }, + }) +end + +if bucket and bucket.register_liquid then + bucket.register_liquid( + "technic:corium_source", + "technic:corium_flowing", + "technic:bucket_corium", + "technic_bucket_corium.png", + "Corium Bucket" + ) +end + +minetest.register_node("technic:chernobylite_block", { + description = S("Chernobylite Block"), + tiles = { "technic_chernobylite_block.png" }, + is_ground_content = true, + groups = { cracky=1, radioactive=5000, level=2 }, + sounds = default.node_sound_stone_defaults(), + light_source = 2, + +}) + +minetest.register_abm({ + nodenames = {"group:water"}, + neighbors = {"technic:corium_source"}, + interval = 1, + chance = 1, + action = function (pos, node) + minetest.remove_node(pos) + end, +}) + +if (corium_griefing == 1) then + minetest.register_abm({ + nodenames = {"technic:corium_flowing"}, + interval = 5, + chance = 10, + action = function (pos, node) + minetest.set_node(pos, {name="technic:chernobylite_block"}) + end, + }) + minetest.register_abm({ + nodenames = { "technic:corium_source", "technic:corium_flowing" }, + interval = 4, + chance = 4, + action = function (pos, node) + for _, offset in ipairs({ + vector.new(1,0,0), + vector.new(-1,0,0), + vector.new(0,0,1), + vector.new(0,0,-1), + vector.new(0,-1,0), + }) do + if math.random(8) == 1 then + minetest.dig_node(vector.add(pos, offset)) + end + end + end, + }) +end diff --git a/technic/machines/HV/quarry.lua b/technic/machines/HV/quarry.lua new file mode 100644 index 0000000..60805cc --- /dev/null +++ b/technic/machines/HV/quarry.lua @@ -0,0 +1,251 @@ + +local S = technic.getter + +minetest.register_craft({ + recipe = { + {"technic:carbon_plate", "pipeworks:filter", "technic:composite_plate"}, + {"technic:motor", "technic:machine_casing", "technic:diamond_drill_head"}, + {"technic:carbon_steel_block", "technic:hv_cable0", "technic:carbon_steel_block"}}, + output = "technic:quarry", +}) + +local quarry_dig_above_nodes = 3 -- How far above the quarry we will dig nodes +local quarry_max_depth = 100 +local quarry_demand = 10000 + +local function set_quarry_formspec(meta) + local radius = meta:get_int("size") + local formspec = "size[6,4.3]".. + "list[context;cache;0,1;4,3;]".. + "item_image[4.8,0;1,1;technic:quarry]".. + "label[0,0.2;"..S("%s Quarry"):format("HV").."]".. + "field[4.3,3.5;2,1;size;"..S("Radius:")..";"..radius.."]" + if meta:get_int("enabled") == 0 then + formspec = formspec.."button[4,1;2,1;enable;"..S("Disabled").."]" + else + formspec = formspec.."button[4,1;2,1;disable;"..S("Enabled").."]" + end + local diameter = radius*2 + 1 + local nd = meta:get_int("dug") + local rel_y = quarry_dig_above_nodes - math.floor(nd / (diameter*diameter)) + formspec = formspec.."label[0,4;"..minetest.formspec_escape( + nd == 0 and S("Digging not started") or + (rel_y < -quarry_max_depth and S("Digging finished") or + (meta:get_int("purge_on") == 1 and S("Purging cache") or + S("Digging %d m "..(rel_y > 0 and "above" or "below").." machine") + :format(math.abs(rel_y)))) + ).."]" + formspec = formspec.."button[4,2;2,1;restart;"..S("Restart").."]" + meta:set_string("formspec", formspec) +end + +local function set_quarry_demand(meta) + local radius = meta:get_int("size") + local diameter = radius*2 + 1 + local machine_name = S("%s Quarry"):format("HV") + if meta:get_int("enabled") == 0 or meta:get_int("purge_on") == 1 then + meta:set_string("infotext", S(meta:get_int("purge_on") == 1 and "%s purging cache" or "%s Disabled"):format(machine_name)) + meta:set_int("HV_EU_demand", 0) + elseif meta:get_int("dug") == diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) then + meta:set_string("infotext", S("%s Finished"):format(machine_name)) + meta:set_int("HV_EU_demand", 0) + else + 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 +end + +local function quarry_receive_fields(pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + if fields.size and string.find(fields.size, "^[0-9]+$") then + local size = tonumber(fields.size) + if size >= 2 and size <= 8 and size ~= meta:get_int("size") then + meta:set_int("size", size) + meta:set_int("dug", 0) + 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 + meta:set_int("dug", 0) + meta:set_int("purge_on", 1) + end + set_quarry_formspec(meta) + set_quarry_demand(meta) +end + +local function quarry_handle_purge(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local i = 0 + for _,stack in ipairs(inv:get_list("cache")) do + i = i + 1 + if stack then + local item = stack:to_table() + if item then + technic.tube_inject_item(pos, pos, vector.new(0, 1, 0), 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 quarry_run(pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + -- initialize cache for the case we load an older world + inv:set_size("cache", 12) + -- toss a coin whether we do an automatic purge. Chance 1:200 + local purge_rand = math.random() + if purge_rand <= 0.005 then + meta:set_int("purge_on", 1) + end + + if meta:get_int("enabled") and meta:get_int("HV_EU_input") >= quarry_demand and meta:get_int("purge_on") == 0 then + local pdir = minetest.facedir_to_dir(node.param2) + local qdir = pdir.x == 1 and vector.new(0,0,-1) or + (pdir.z == -1 and vector.new(-1,0,0) or + (pdir.x == -1 and vector.new(0,0,1) or + vector.new(1,0,0))) + local radius = meta:get_int("size") + local diameter = radius*2 + 1 + local startpos = vector.add(vector.add(vector.add(pos, + vector.new(0, quarry_dig_above_nodes, 0)), + pdir), + vector.multiply(qdir, -radius)) + local endpos = vector.add(vector.add(vector.add(startpos, + vector.new(0, -quarry_dig_above_nodes-quarry_max_depth, 0)), + vector.multiply(pdir, diameter-1)), + vector.multiply(qdir, diameter-1)) + local vm = VoxelManip() + local minpos, maxpos = vm:read_from_map(startpos, endpos) + local area = VoxelArea:new({MinEdge=minpos, MaxEdge=maxpos}) + local data = vm:get_data() + local c_air = minetest.get_content_id("air") + local owner = meta:get_string("owner") + local nd = meta:get_int("dug") + while nd ~= diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) do + local ry = math.floor(nd / (diameter*diameter)) + local ndl = nd % (diameter*diameter) + if ry % 2 == 1 then + ndl = diameter*diameter - 1 - ndl + end + local rq = math.floor(ndl / diameter) + local rp = ndl % diameter + if rq % 2 == 1 then rp = diameter - 1 - rp end + local digpos = vector.add(vector.add(vector.add(startpos, + vector.new(0, -ry, 0)), + vector.multiply(pdir, rp)), + vector.multiply(qdir, rq)) + local can_dig = true + if can_dig and minetest.is_protected and minetest.is_protected(digpos, owner) then + can_dig = false + end + local dignode + if can_dig then + dignode = technic.get_or_load_node(digpos) or minetest.get_node(digpos) + local dignodedef = minetest.registered_nodes[dignode.name] or {diggable=false} + if not dignodedef.diggable or (dignodedef.can_dig and not dignodedef.can_dig(digpos, nil)) then + can_dig = false + end + end + + if can_dig then + for ay = startpos.y, digpos.y+1, -1 do + local checkpos = {x=digpos.x, y=ay, z=digpos.z} + local checknode = technic.get_or_load_node(checkpos) or minetest.get_node(checkpos) + if checknode.name ~= "air" then + can_dig = false + break + end + end + end + nd = nd + 1 + if can_dig then + minetest.remove_node(digpos) + local drops = minetest.get_node_drops(dignode.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 + break + end + end + if nd == diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) then + -- if a quarry is finished, we enable purge mode + meta:set_int("purge_on", 1) + end + meta:set_int("dug", nd) + else + -- if a quarry is disabled or has no power, we enable purge mode + meta:set_int("purge_on", 1) + end + -- if something triggered a purge, we handle it + if meta:get_int("purge_on") == 1 then + quarry_handle_purge(pos) + end + set_quarry_formspec(meta) + set_quarry_demand(meta) +end + +local function send_move_error(player) + minetest.chat_send_player(player:get_player_name(), + S("Manually taking/removing from cache by hand is not possible. ".. + "If you can't wait, restart or disable the quarry to start automatic purge.")) + return 0 +end + +minetest.register_node("technic:quarry", { + description = S("%s Quarry"):format("HV"), + tiles = {"technic_carbon_steel_block.png", "technic_carbon_steel_block.png", + "technic_carbon_steel_block.png", "technic_carbon_steel_block.png", + "technic_carbon_steel_block.png^default_tool_mesepick.png", "technic_carbon_steel_block.png"}, + inventory_image = minetest.inventorycube("technic_carbon_steel_block.png", + "technic_carbon_steel_block.png^default_tool_mesepick.png", + "technic_carbon_steel_block.png"), + paramtype2 = "facedir", + groups = {cracky=2, tubedevice=1, technic_machine = 1}, + tube = { + connect_sides = {top = 1}, + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("%s Quarry"):format("HV")) + meta:set_int("size", 4) + set_quarry_formspec(meta) + set_quarry_demand(meta) + end, + after_place_node = function(pos, placer, itemstack) + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + pipeworks.scan_for_tube_objects(pos) + end, + can_dig = function(pos,player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv: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 send_move_error(player) + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + return send_move_error(player) + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + return send_move_error(player) + end +}) + +technic.register_machine("HV", "technic:quarry", technic.receiver) diff --git a/technic/machines/HV/solar_array.lua b/technic/machines/HV/solar_array.lua new file mode 100644 index 0000000..414291a --- /dev/null +++ b/technic/machines/HV/solar_array.lua @@ -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'}, + {'technic:carbon_plate', 'technic:hv_transformer', 'technic:composite_plate'}, + {'', 'technic:hv_cable0', ''}, + } +}) + +technic.register_solar_array({tier="HV", power=100}) + diff --git a/technic/machines/LV/alloy_furnace.lua b/technic/machines/LV/alloy_furnace.lua new file mode 100644 index 0000000..bdf2f31 --- /dev/null +++ b/technic/machines/LV/alloy_furnace.lua @@ -0,0 +1,14 @@ +-- LV Alloy furnace + +-- FIXME: kpoppel: I'd like to introduce an induction heating element here... +minetest.register_craft({ + output = 'technic:lv_alloy_furnace', + recipe = { + {'default:brick', 'default:brick', 'default:brick'}, + {'default:brick', 'technic:machine_casing', 'default:brick'}, + {'default:brick', 'technic:lv_cable0', 'default:brick'}, + } +}) + +technic.register_alloy_furnace({tier = "LV", speed = 1, demand = {300}}) + diff --git a/technic/machines/LV/battery_box.lua b/technic/machines/LV/battery_box.lua new file mode 100644 index 0000000..429bcd6 --- /dev/null +++ b/technic/machines/LV/battery_box.lua @@ -0,0 +1,19 @@ + +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_cable0', 'technic:battery'}, + } +}) + +technic.register_battery_box({ + tier = "LV", + max_charge = 40000, + charge_rate = 1000, + discharge_rate = 4000, + charge_step = 500, + discharge_step = 800, +}) + diff --git a/technic/machines/LV/cables.lua b/technic/machines/LV/cables.lua new file mode 100644 index 0000000..e18eae1 --- /dev/null +++ b/technic/machines/LV/cables.lua @@ -0,0 +1,14 @@ + +minetest.register_alias("lv_cable", "technic:lv_cable0") + +minetest.register_craft({ + output = 'technic:lv_cable0 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) + diff --git a/technic/machines/LV/cnc.lua b/technic/machines/LV/cnc.lua new file mode 100644 index 0000000..dd67e9b --- /dev/null +++ b/technic/machines/LV/cnc.lua @@ -0,0 +1,237 @@ +-- Technic CNC v1.0 by kpoppel +-- Based on the NonCubic Blocks MOD v1.4 by yves_de_beck + +-- Idea: +-- Somehow have a tabbed/paged panel if the number of shapes should expand +-- beyond what is available in the panel today. +-- I could imagine some form of API allowing modders to come with their own node +-- box definitions and easily stuff it in the this machine for production. + +local S = technic.getter + +local shape = {} +local onesize_products = { + slope = 2, + slope_edge = 1, + slope_inner_edge = 1, + pyramid = 2, + spike = 1, + cylinder = 2, + oblate_spheroid = 1, + sphere = 1, + stick = 8, + slope_upsdown = 2, + slope_edge_upsdown = 1, + slope_inner_edge_upsdown = 1, + cylinder_horizontal = 2, + slope_lying = 2, + onecurvededge = 1, + twocurvededge = 1, +} +local twosize_products = { + element_straight = 4, + element_end = 2, + element_cross = 1, + element_t = 1, + element_edge = 2, +} + +local cnc_formspec = + "invsize[9,11;]".. + "label[1,0;"..S("Choose Milling Program:").."]".. + "image_button[1,0.5;1,1;technic_cnc_slope.png;slope; ]".. + "image_button[2,0.5;1,1;technic_cnc_slope_edge.png;slope_edge; ]".. + "image_button[3,0.5;1,1;technic_cnc_slope_inner_edge.png;slope_inner_edge; ]".. + "image_button[4,0.5;1,1;technic_cnc_pyramid.png;pyramid; ]".. + "image_button[5,0.5;1,1;technic_cnc_spike.png;spike; ]".. + "image_button[6,0.5;1,1;technic_cnc_cylinder.png;cylinder; ]".. + "image_button[7,0.5;1,1;technic_cnc_oblate_spheroid.png;oblate_spheroid; ]".. + "image_button[8,0.5;1,1;technic_cnc_stick.png;stick; ]".. + + "image_button[1,1.5;1,1;technic_cnc_slope_upsdwn.png;slope_upsdown; ]".. + "image_button[2,1.5;1,1;technic_cnc_slope_edge_upsdwn.png;slope_edge_upsdown; ]".. + "image_button[3,1.5;1,1;technic_cnc_slope_inner_edge_upsdwn.png;slope_inner_edge_upsdown; ]".. + "image_button[4,1.5;1,1;technic_cnc_cylinder_horizontal.png;cylinder_horizontal; ]".. + "image_button[5,1.5;1,1;technic_cnc_sphere.png;sphere; ]".. + + "image_button[1,2.5;1,1;technic_cnc_slope_lying.png;slope_lying; ]".. + "image_button[2,2.5;1,1;technic_cnc_onecurvededge.png;onecurvededge; ]".. + "image_button[3,2.5;1,1;technic_cnc_twocurvededge.png;twocurvededge; ]".. + + "label[1,3.5;"..S("Slim Elements half / normal height:").."]".. + + "image_button[1,4;1,0.5;technic_cnc_full.png;full; ]".. + "image_button[1,4.5;1,0.5;technic_cnc_half.png;half; ]".. + "image_button[2,4;1,1;technic_cnc_element_straight.png;element_straight; ]".. + "image_button[3,4;1,1;technic_cnc_element_end.png;element_end; ]".. + "image_button[4,4;1,1;technic_cnc_element_cross.png;element_cross; ]".. + "image_button[5,4;1,1;technic_cnc_element_t.png;element_t; ]".. + "image_button[6,4;1,1;technic_cnc_element_edge.png;element_edge; ]".. + + "label[0, 5.5;"..S("In:").."]".. + "list[current_name;src;0.5,5.5;1,1;]".. + "label[4, 5.5;"..S("Out:").."]".. + "list[current_name;dst;5,5.5;4,1;]".. + + "list[current_player;main;0,7;8,4;]".. + "listring[current_name;dst]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]" + +local size = 1; + +-- The form handler is declared here because we need it in both the inactive and active modes +-- in order to be able to change programs wile it is running. +local function form_handler(pos, formname, fields, sender) + -- REGISTER MILLING PROGRAMS AND OUTPUTS: + ------------------------------------------ + -- Program for half/full size + if fields["full"] then + size = 1 + return + end + + if fields["half"] then + size = 2 + return + end + + -- Resolve the node name and the number of items to make + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local inputstack = inv:get_stack("src", 1) + local inputname = inputstack:get_name() + local multiplier = 0 + for k, _ in pairs(fields) do + -- Set a multipier for the half/full size capable blocks + if twosize_products[k] ~= nil then + multiplier = size * twosize_products[k] + else + multiplier = onesize_products[k] + end + + if onesize_products[k] ~= nil or twosize_products[k] ~= nil then + meta:set_float( "cnc_multiplier", multiplier) + meta:set_string("cnc_user", sender:get_player_name()) + end + + if onesize_products[k] ~= nil or (twosize_products[k] ~= nil and size==2) then + meta:set_string("cnc_product", inputname .. "_technic_cnc_" .. k) + --print(inputname .. "_technic_cnc_" .. k) + break + end + + if twosize_products[k] ~= nil and size==1 then + meta:set_string("cnc_product", inputname .. "_technic_cnc_" .. k .. "_double") + --print(inputname .. "_technic_cnc_" .. k .. "_double") + break + end + end + return +end + +-- Action code performing the transformation +local run = function(pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local eu_input = meta:get_int("LV_EU_input") + local machine_name = S("%s CNC Machine"):format("LV") + local machine_node = "technic:cnc" + local demand = 450 + + local result = meta:get_string("cnc_product") + if inv:is_empty("src") or + (not minetest.registered_nodes[result]) or + (not inv:room_for_item("dst", result)) then + technic.swap_node(pos, machine_node) + meta:set_string("infotext", S("%s Idle"):format(machine_name)) + meta:set_string("cnc_product", "") + meta:set_int("LV_EU_demand", 0) + return + end + + if eu_input < demand then + technic.swap_node(pos, machine_node) + meta:set_string("infotext", S("%s Unpowered"):format(machine_name)) + elseif eu_input >= demand then + technic.swap_node(pos, machine_node.."_active") + meta:set_string("infotext", S("%s Active"):format(machine_name)) + meta:set_int("src_time", meta:get_int("src_time") + 1) + if meta:get_int("src_time") >= 3 then -- 3 ticks per output + meta:set_int("src_time", 0) + srcstack = inv:get_stack("src", 1) + srcstack:take_item() + inv:set_stack("src", 1, srcstack) + inv:add_item("dst", result.." "..meta:get_int("cnc_multiplier")) + end + end + meta:set_int("LV_EU_demand", demand) +end + +-- The actual block inactive state +minetest.register_node("technic:cnc", { + description = S("%s CNC Machine"):format("LV"), + tiles = {"technic_cnc_top.png", "technic_cnc_bottom.png", "technic_cnc_side.png", + "technic_cnc_side.png", "technic_cnc_side.png", "technic_cnc_front.png"}, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + }, + }, + groups = {cracky=2, technic_machine=1}, + legacy_facedir_simple = true, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("%s CNC Machine"):format("LV")) + meta:set_float("technic_power_machine", 1) + meta:set_string("formspec", cnc_formspec) + local inv = meta:get_inventory() + inv:set_size("src", 1) + inv:set_size("dst", 4) + end, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + on_receive_fields = form_handler, + technic_run = run, +}) + +-- Active state block +minetest.register_node("technic:cnc_active", { + description = S("%s CNC Machine"):format("LV"), + tiles = {"technic_cnc_top_active.png", "technic_cnc_bottom.png", "technic_cnc_side.png", + "technic_cnc_side.png", "technic_cnc_side.png", "technic_cnc_front_active.png"}, + paramtype2 = "facedir", + drop = "technic:cnc", + groups = {cracky=2, technic_machine=1, not_in_creative_inventory=1}, + legacy_facedir_simple = true, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + on_receive_fields = form_handler, + technic_run = run, + technic_disabled_machine_name = "technic:cnc", +}) + +technic.register_machine("LV", "technic:cnc", technic.receiver) +technic.register_machine("LV", "technic:cnc_active", technic.receiver) + +------------------------- +-- CNC Machine Recipe +------------------------- +minetest.register_craft({ + output = 'technic:cnc', + recipe = { + {'default:glass', 'technic:diamond_drill_head', 'default:glass'}, + {'technic:control_logic_unit', 'technic:machine_casing', 'technic:motor'}, + {'technic:carbon_steel_ingot', 'technic:lv_cable0', 'technic:carbon_steel_ingot'}, + }, +}) + diff --git a/technic/machines/LV/cnc_api.lua b/technic/machines/LV/cnc_api.lua new file mode 100644 index 0000000..f5aae5c --- /dev/null +++ b/technic/machines/LV/cnc_api.lua @@ -0,0 +1,369 @@ +-- API for the technic CNC machine +-- Again code is adapted from the NonCubic Blocks MOD v1.4 by yves_de_beck + +local S = technic.getter + +technic.cnc = {} + +-- REGISTER NONCUBIC FORMS, CREATE MODELS AND RECIPES: +------------------------------------------------------ + +-- Define slope boxes for the various nodes +------------------------------------------- +technic.cnc.programs = { + { suffix = "technic_cnc_stick", + model = {-0.15, -0.5, -0.15, 0.15, 0.5, 0.15}, + desc = S("Stick") + }, + + { suffix = "technic_cnc_element_end_double", + model = {-0.3, -0.5, -0.3, 0.3, 0.5, 0.5}, + desc = S("Element End Double") + }, + + { suffix = "technic_cnc_element_cross_double", + model = { + {0.3, -0.5, -0.3, 0.5, 0.5, 0.3}, + {-0.3, -0.5, -0.5, 0.3, 0.5, 0.5}, + {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}}, + desc = S("Element Cross Double") + }, + + { suffix = "technic_cnc_element_t_double", + model = { + {-0.3, -0.5, -0.5, 0.3, 0.5, 0.3}, + {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}, + {0.3, -0.5, -0.3, 0.5, 0.5, 0.3}}, + desc = S("Element T Double") + }, + + { suffix = "technic_cnc_element_edge_double", + model = { + {-0.3, -0.5, -0.5, 0.3, 0.5, 0.3}, + {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}}, + desc = S("Element Edge Double") + }, + + { suffix = "technic_cnc_element_straight_double", + model = {-0.3, -0.5, -0.5, 0.3, 0.5, 0.5}, + desc = S("Element Straight Double") + }, + + { suffix = "technic_cnc_element_end", + model = {-0.3, -0.5, -0.3, 0.3, 0, 0.5}, + desc = S("Element End") + }, + + { suffix = "technic_cnc_element_cross", + model = { + {0.3, -0.5, -0.3, 0.5, 0, 0.3}, + {-0.3, -0.5, -0.5, 0.3, 0, 0.5}, + {-0.5, -0.5, -0.3, -0.3, 0, 0.3}}, + desc = S("Element Cross") + }, + + { suffix = "technic_cnc_element_t", + model = { + {-0.3, -0.5, -0.5, 0.3, 0, 0.3}, + {-0.5, -0.5, -0.3, -0.3, 0, 0.3}, + {0.3, -0.5, -0.3, 0.5, 0, 0.3}}, + desc = S("Element T") + }, + + { suffix = "technic_cnc_element_edge", + model = { + {-0.3, -0.5, -0.5, 0.3, 0, 0.3}, + {-0.5, -0.5, -0.3, -0.3, 0, 0.3}}, + desc = S("Element Edge") + }, + + { suffix = "technic_cnc_element_straight", + model = {-0.3, -0.5, -0.5, 0.3, 0, 0.5}, + desc = S("Element Straight") + }, + + { suffix = "technic_cnc_oblate_spheroid", + model = "technic_oblate_spheroid.obj", + desc = S("Oblate spheroid"), + cbox = { + type = "fixed", + fixed = { + { -6/16, 4/16, -6/16, 6/16, 8/16, 6/16 }, + { -8/16, -4/16, -8/16, 8/16, 4/16, 8/16 }, + { -6/16, -8/16, -6/16, 6/16, -4/16, 6/16 } + } + } + }, + + { suffix = "technic_cnc_sphere", + model = "technic_sphere.obj", + desc = S("Sphere") + }, + + { suffix = "technic_cnc_cylinder_horizontal", + model = "technic_cylinder_horizontal.obj", + desc = S("Horizontal Cylinder") + }, + + { suffix = "technic_cnc_cylinder", + model = "technic_cylinder.obj", + desc = S("Cylinder") + }, + + { suffix = "technic_cnc_twocurvededge", + model = "technic_two_curved_edge.obj", + desc = S("Two Curved Edge/Corner Block") + }, + + { suffix = "technic_cnc_onecurvededge", + model = "technic_one_curved_edge.obj", + desc = S("One Curved Edge Block") + }, + + { suffix = "technic_cnc_spike", + model = "technic_pyramid_spike.obj", + desc = S("Spike"), + cbox = { + type = "fixed", + fixed = { + { -2/16, 4/16, -2/16, 2/16, 8/16, 2/16 }, + { -4/16, 0, -4/16, 4/16, 4/16, 4/16 }, + { -6/16, -4/16, -6/16, 6/16, 0, 6/16 }, + { -8/16, -8/16, -8/16, 8/16, -4/16, 8/16 } + } + } + }, + + { suffix = "technic_cnc_pyramid", + model = "technic_pyramid.obj", + desc = S("Pyramid"), + cbox = { + type = "fixed", + fixed = { + { -2/16, -2/16, -2/16, 2/16, 0, 2/16 }, + { -4/16, -4/16, -4/16, 4/16, -2/16, 4/16 }, + { -6/16, -6/16, -6/16, 6/16, -4/16, 6/16 }, + { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 } + } + } + }, + + { suffix = "technic_cnc_slope_inner_edge_upsdown", + model = "technic_innercorner_upsdown.obj", + desc = S("Slope Upside Down Inner Edge/Corner"), + sbox = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } + }, + cbox = { + type = "fixed", + fixed = { + { 0.25, -0.25, -0.5, 0.5, -0.5, 0.5 }, + { -0.5, -0.25, 0.25, 0.5, -0.5, 0.5 }, + { 0, 0, -0.5, 0.5, -0.25, 0.5 }, + { -0.5, 0, 0, 0.5, -0.25, 0.5 }, + { -0.25, 0.25, -0.5, 0.5, 0, -0.25 }, + { -0.5, 0.25, -0.25, 0.5, 0, 0.5 }, + { -0.5, 0.5, -0.5, 0.5, 0.25, 0.5 } + } + } + }, + + { suffix = "technic_cnc_slope_edge_upsdown", + model = "technic_outercorner_upsdown.obj", + desc = S("Slope Upside Down Outer Edge/Corner"), + cbox = { + type = "fixed", + fixed = { + { -8/16, 8/16, -8/16, 8/16, 4/16, 8/16 }, + { -4/16, 4/16, -4/16, 8/16, 0, 8/16 }, + { 0, 0, 0, 8/16, -4/16, 8/16 }, + { 4/16, -4/16, 4/16, 8/16, -8/16, 8/16 } + } + } + }, + + { suffix = "technic_cnc_slope_inner_edge", + model = "technic_innercorner.obj", + desc = S("Slope Inner Edge/Corner"), + sbox = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } + }, + cbox = { + type = "fixed", + fixed = { + { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 }, + { -0.5, -0.25, -0.25, 0.5, 0, 0.5 }, + { -0.25, -0.25, -0.5, 0.5, 0, -0.25 }, + { -0.5, 0, 0, 0.5, 0.25, 0.5 }, + { 0, 0, -0.5, 0.5, 0.25, 0.5 }, + { -0.5, 0.25, 0.25, 0.5, 0.5, 0.5 }, + { 0.25, 0.25, -0.5, 0.5, 0.5, 0.5 } + } + } + }, + + { suffix = "technic_cnc_slope_edge", + model = "technic_outercorner.obj", + desc = S("Slope Outer Edge/Corner"), + cbox = { + type = "fixed", + fixed = { + { 4/16, 4/16, 4/16, 8/16, 8/16, 8/16 }, + { 0, 0, 0, 8/16, 4/16, 8/16 }, + { -4/16, -4/16, -4/16, 8/16, 0, 8/16 }, + { -8/16, -8/16, -8/16, 8/16, -4/16, 8/16 } + } + } + }, + + { suffix = "technic_cnc_slope_upsdown", + model = "technic_slope_upsdown.obj", + desc = S("Slope Upside Down"), + cbox = { + type = "fixed", + fixed = { + { -8/16, 8/16, -8/16, 8/16, 4/16, 8/16 }, + { -8/16, 4/16, -4/16, 8/16, 0, 8/16 }, + { -8/16, 0, 0, 8/16, -4/16, 8/16 }, + { -8/16, -4/16, 4/16, 8/16, -8/16, 8/16 } + } + } + }, + + { suffix = "technic_cnc_slope_lying", + model = "technic_slope_horizontal.obj", + desc = S("Slope Lying"), + cbox = { + type = "fixed", + fixed = { + { 4/16, -8/16, 4/16, 8/16, 8/16, 8/16 }, + { 0, -8/16, 0, 4/16, 8/16, 8/16 }, + { -4/16, -8/16, -4/16, 0, 8/16, 8/16 }, + { -8/16, -8/16, -8/16, -4/16, 8/16, 8/16 } + } + } + }, + + { suffix = "technic_cnc_slope", + model = "technic_slope.obj", + desc = S("Slope"), + cbox = { + type = "fixed", + fixed = { + { -8/16, 4/16, 4/16, 8/16, 8/16, 8/16 }, + { -8/16, 0, 0, 8/16, 4/16, 8/16 }, + { -8/16, -4/16, -4/16, 8/16, 0, 8/16 }, + { -8/16, -8/16, -8/16, 8/16, -4/16, 8/16 } + } + } + }, + +} + +-- Allow disabling certain programs for some node. Default is allowing all types for all nodes +technic.cnc.programs_disable = { + -- ["default:brick"] = {"technic_cnc_stick"}, -- Example: Disallow the stick for brick + -- ... + ["default:dirt"] = {"technic_cnc_oblate_spheroid", "technic_cnc_slope_upsdown", "technic_cnc_edge", + "technic_cnc_inner_edge", "technic_cnc_slope_edge_upsdown", + "technic_cnc_slope_inner_edge_upsdown", "technic_cnc_stick", + "technic_cnc_cylinder_horizontal"} +} + +-- Generic function for registering all the different node types +function technic.cnc.register_program(recipeitem, suffix, model, groups, images, description, cbox, sbox) + + local dtype + local nodeboxdef + local meshdef + + if type(model) ~= "string" then -- assume a nodebox if it's a table or function call + dtype = "nodebox" + nodeboxdef = { + type = "fixed", + fixed = model + } + else + dtype = "mesh" + meshdef = model + end + + if cbox and not sbox then sbox = cbox end + + minetest.register_node(":"..recipeitem.."_"..suffix, { + description = description, + drawtype = dtype, + node_box = nodeboxdef, + mesh = meshdef, + tiles = images, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + groups = groups, + selection_box = sbox, + collision_box = cbox + }) +end + +-- function to iterate over all the programs the CNC machine knows +function technic.cnc.register_all(recipeitem, groups, images, description) + for _, data in ipairs(technic.cnc.programs) do + -- Disable node creation for disabled node types for some material + local do_register = true + if technic.cnc.programs_disable[recipeitem] ~= nil then + for __, disable in ipairs(technic.cnc.programs_disable[recipeitem]) do + if disable == data.suffix then + do_register = false + end + end + end + -- Create the node if it passes the test + if do_register then + technic.cnc.register_program(recipeitem, data.suffix, data.model, + groups, images, description.." "..data.desc, data.cbox, data.sbox) + end + end +end + + +-- REGISTER NEW TECHNIC_CNC_API's PART 2: technic.cnc..register_element_end(subname, recipeitem, groups, images, desc_element_xyz) +----------------------------------------------------------------------------------------------------------------------- +function technic.cnc.register_slope_edge_etc(recipeitem, groups, images, desc_slope, desc_slope_lying, desc_slope_upsdown, desc_slope_edge, desc_slope_inner_edge, desc_slope_upsdwn_edge, desc_slope_upsdwn_inner_edge, desc_pyramid, desc_spike, desc_onecurvededge, desc_twocurvededge, desc_cylinder, desc_cylinder_horizontal, desc_spheroid, desc_element_straight, desc_element_edge, desc_element_t, desc_element_cross, desc_element_end) + + technic.cnc.register_slope(recipeitem, groups, images, desc_slope) + technic.cnc.register_slope_lying(recipeitem, groups, images, desc_slope_lying) + technic.cnc.register_slope_upsdown(recipeitem, groups, images, desc_slope_upsdown) + technic.cnc.register_slope_edge(recipeitem, groups, images, desc_slope_edge) + technic.cnc.register_slope_inner_edge(recipeitem, groups, images, desc_slope_inner_edge) + technic.cnc.register_slope_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_edge) + technic.cnc.register_slope_inner_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_inner_edge) + technic.cnc.register_pyramid(recipeitem, groups, images, desc_pyramid) + technic.cnc.register_spike(recipeitem, groups, images, desc_spike) + technic.cnc.register_onecurvededge(recipeitem, groups, images, desc_onecurvededge) + technic.cnc.register_twocurvededge(recipeitem, groups, images, desc_twocurvededge) + technic.cnc.register_cylinder(recipeitem, groups, images, desc_cylinder) + technic.cnc.register_cylinder_horizontal(recipeitem, groups, images, desc_cylinder_horizontal) + technic.cnc.register_spheroid(recipeitem, groups, images, desc_spheroid) + technic.cnc.register_element_straight(recipeitem, groups, images, desc_element_straight) + technic.cnc.register_element_edge(recipeitem, groups, images, desc_element_edge) + technic.cnc.register_element_t(recipeitem, groups, images, desc_element_t) + technic.cnc.register_element_cross(recipeitem, groups, images, desc_element_cross) + technic.cnc.register_element_end(recipeitem, groups, images, desc_element_end) +end + +-- REGISTER STICKS: noncubic.register_xyz(recipeitem, groups, images, desc_element_xyz) +------------------------------------------------------------------------------------------------------------ +function technic.cnc.register_stick_etc(recipeitem, groups, images, desc_stick) + technic.cnc.register_stick(recipeitem, groups, images, desc_stick) +end + +function technic.cnc.register_elements(recipeitem, groups, images, desc_element_straight_double, desc_element_edge_double, desc_element_t_double, desc_element_cross_double, desc_element_end_double) + technic.cnc.register_element_straight_double(recipeitem, groups, images, desc_element_straight_double) + technic.cnc.register_element_edge_double(recipeitem, groups, images, desc_element_edge_double) + technic.cnc.register_element_t_double(recipeitem, groups, images, desc_element_t_double) + technic.cnc.register_element_cross_double(recipeitem, groups, images, desc_element_cross_double) + technic.cnc.register_element_end_double(recipeitem, groups, images, desc_element_end_double) +end + diff --git a/technic/machines/LV/cnc_nodes.lua b/technic/machines/LV/cnc_nodes.lua new file mode 100644 index 0000000..05be9af --- /dev/null +++ b/technic/machines/LV/cnc_nodes.lua @@ -0,0 +1,91 @@ +-- REGISTER MATERIALS AND PROPERTIES FOR NONCUBIC ELEMENTS: +----------------------------------------------------------- + +local S = technic.getter + +-- DIRT +------- +technic.cnc.register_all("default:dirt", + {snappy=2,choppy=2,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + {"default_grass.png", "default_dirt.png", "default_grass.png"}, + S("Dirt")) +-- WOOD +------- +technic.cnc.register_all("default:wood", + {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1}, + {"default_wood.png"}, + S("Wooden")) +-- STONE +-------- +technic.cnc.register_all("default:stone", + {cracky=3, not_in_creative_inventory=1}, + {"default_stone.png"}, + S("Stone")) +-- COBBLE +--------- +technic.cnc.register_all("default:cobble", + {cracky=3, not_in_creative_inventory=1}, + {"default_cobble.png"}, + S("Cobble")) +-- BRICK +-------- +technic.cnc.register_all("default:brick", + {cracky=3, not_in_creative_inventory=1}, + {"default_brick.png"}, + S("Brick")) + +-- SANDSTONE +------------ +technic.cnc.register_all("default:sandstone", + {crumbly=2, cracky=3, not_in_creative_inventory=1}, + {"default_sandstone.png"}, + S("Sandstone")) + +-- LEAVES +--------- +technic.cnc.register_all("default:leaves", + {snappy=2, choppy=2, oddly_breakable_by_hand=3, not_in_creative_inventory=1}, + {"default_leaves.png"}, + S("Leaves")) +-- TREE +------- +technic.cnc.register_all("default:tree", + {snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=3, wood=1, not_in_creative_inventory=1}, + {"default_tree.png"}, + S("Tree")) + +-- WROUGHT IRON +--------------- +technic.cnc.register_all("default:steelblock", + {cracky=1, level=2, not_in_creative_inventory=1}, + {"technic_wrought_iron_block.png"}, + S("Wrought Iron")) + +-- Bronze +-------- +technic.cnc.register_all("default:bronzeblock", + {cracky=1, level=2, not_in_creative_inventory=1}, + {"default_bronze_block.png"}, + S("Bronze")) + +-- Stainless Steel +-------- +technic.cnc.register_all("technic:stainless_steel_block", + {cracky=1, level=2, not_in_creative_inventory=1}, + {"technic_stainless_steel_block.png"}, + S("Stainless Steel")) + +-- Marble +------------ +technic.cnc.register_all("technic:marble", + {cracky=3, not_in_creative_inventory=1}, + {"technic_marble.png"}, + S("Marble")) + +-- Granite +------------ +technic.cnc.register_all("technic:granite", + {cracky=1, not_in_creative_inventory=1}, + {"technic_granite.png"}, + S("Granite")) + diff --git a/technic/machines/LV/compressor.lua b/technic/machines/LV/compressor.lua new file mode 100644 index 0000000..e2bde40 --- /dev/null +++ b/technic/machines/LV/compressor.lua @@ -0,0 +1,13 @@ + +minetest.register_alias("compressor", "technic:lv_compressor") + +minetest.register_craft({ + output = 'technic:lv_compressor', + recipe = { + {'default:stone', 'technic:motor', 'default:stone'}, + {'mesecons:piston', 'technic:machine_casing', 'mesecons:piston'}, + {'technic:fine_silver_wire', 'technic:lv_cable0', 'technic:fine_silver_wire'}, + } +}) + +technic.register_compressor({tier = "LV", demand = {300}, speed = 1}) diff --git a/technic/machines/LV/electric_furnace.lua b/technic/machines/LV/electric_furnace.lua new file mode 100644 index 0000000..cc4daff --- /dev/null +++ b/technic/machines/LV/electric_furnace.lua @@ -0,0 +1,16 @@ +-- LV Electric Furnace +-- This is a faster version of the stone furnace which runs on EUs + +-- FIXME: kpoppel I'd like to introduce an induction heating element here also +minetest.register_craft({ + output = 'technic:electric_furnace', + recipe = { + {'default:cobble', 'default:cobble', 'default:cobble'}, + {'default:cobble', 'technic:machine_casing', 'default:cobble'}, + {'default:cobble', 'technic:lv_cable0', 'default:cobble'}, + } +}) + +technic.register_electric_furnace({tier="LV", demand={300}, speed = 2}) + + diff --git a/technic/machines/LV/extractor.lua b/technic/machines/LV/extractor.lua new file mode 100644 index 0000000..363d2e3 --- /dev/null +++ b/technic/machines/LV/extractor.lua @@ -0,0 +1,13 @@ + +minetest.register_alias("extractor", "technic:lv_extractor") + +minetest.register_craft({ + output = 'technic:lv_extractor', + recipe = { + {'technic:treetap', 'technic:motor', 'technic:treetap'}, + {'technic:treetap', 'technic:machine_casing', 'technic:treetap'}, + {'', 'technic:lv_cable0', ''}, + } +}) + +technic.register_extractor({tier = "LV", demand = {300}, speed = 1}) diff --git a/technic/machines/LV/generator.lua b/technic/machines/LV/generator.lua new file mode 100644 index 0000000..999dbc5 --- /dev/null +++ b/technic/machines/LV/generator.lua @@ -0,0 +1,18 @@ +-- 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_cable0', 'default:stone'}, + } +}) + +technic.register_generator({tier="LV", supply=200}) + diff --git a/technic/machines/LV/geothermal.lua b/technic/machines/LV/geothermal.lua new file mode 100644 index 0000000..e88d3c9 --- /dev/null +++ b/technic/machines/LV/geothermal.lua @@ -0,0 +1,111 @@ +-- 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'}, + {'technic:fine_copper_wire', 'technic:machine_casing', 'technic:fine_copper_wire'}, + {'technic:granite', 'technic:lv_cable0', 'technic:granite'}, + } +}) + +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"}, + paramtype2 = "facedir", + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("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, 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) + diff --git a/technic/machines/LV/grinder.lua b/technic/machines/LV/grinder.lua new file mode 100644 index 0000000..da9ea29 --- /dev/null +++ b/technic/machines/LV/grinder.lua @@ -0,0 +1,13 @@ + +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_cable0', 'technic:granite'}, + } +}) + +technic.register_grinder({tier="LV", demand={200}, speed=1}) + diff --git a/technic/machines/LV/init.lua b/technic/machines/LV/init.lua new file mode 100644 index 0000000..30523c9 --- /dev/null +++ b/technic/machines/LV/init.lua @@ -0,0 +1,29 @@ + +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.."/cnc.lua") +dofile(path.."/cnc_api.lua") +dofile(path.."/cnc_nodes.lua") + diff --git a/technic/machines/LV/music_player.lua b/technic/machines/LV/music_player.lua new file mode 100644 index 0000000..dc7e2d0 --- /dev/null +++ b/technic/machines/LV/music_player.lua @@ -0,0 +1,130 @@ +-- 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_cable0', '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 machine_node = "technic:music_player" + local demand = 150 + + local current_track = meta:get_int("current_track") + local pos_hash = minetest.hash_node_position(pos) + local music_handle = music_handles[pos_hash] + + -- Setup meta data if it does not exist. + if not eu_input then + meta:set_int("LV_EU_demand", demand) + meta:set_int("LV_EU_input", 0) + return + end + + if meta:get_int("active") == 0 then + meta:set_string("infotext", S("%s Idle"):format(machine_name)) + meta:set_int("LV_EU_demand", 0) + return + end + + if eu_input < demand then + meta:set_string("infotext", S("%s Unpowered"):format(machine_name)) + if music_handle then + minetest.sound_stop(music_handle) + music_handle = nil + end + elseif eu_input >= demand then + meta:set_string("infotext", S("%s Active"):format(machine_name)) + if not music_handle then + music_handle = play_track(pos, current_track) + end + end + music_handles[pos_hash] = music_handle + meta:set_int("LV_EU_demand", demand) +end + +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}, + 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) + diff --git a/technic/machines/LV/solar_array.lua b/technic/machines/LV/solar_array.lua new file mode 100644 index 0000000..4d2c3b3 --- /dev/null +++ b/technic/machines/LV/solar_array.lua @@ -0,0 +1,18 @@ +-- The solar array is an assembly of panels into a powerful array +-- The assembly can deliver more energy than the individual panel because +-- of the transformer unit which converts the panel output variations into +-- a stable supply. +-- Solar arrays are not able to store large amounts of energy. +-- The LV arrays are used to make medium voltage arrays. + +minetest.register_craft({ + output = 'technic:solar_array_lv 1', + recipe = { + {'technic:solar_panel', 'technic:solar_panel', 'technic:solar_panel'}, + {'technic:carbon_steel_ingot', 'technic:lv_transformer', 'technic:carbon_steel_ingot'}, + {'', 'technic:lv_cable0', ''}, + } +}) + +technic.register_solar_array({tier="LV", power=10}) + diff --git a/technic/machines/LV/solar_panel.lua b/technic/machines/LV/solar_panel.lua new file mode 100644 index 0000000..41dff95 --- /dev/null +++ b/technic/machines/LV/solar_panel.lua @@ -0,0 +1,67 @@ +-- 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 + +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 EU)", machine_name, technic.prettynum(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}, + 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, +}) + +minetest.register_craft({ + output = 'technic:solar_panel', + recipe = { + {'technic:doped_silicon_wafer', 'technic:doped_silicon_wafer', 'technic:doped_silicon_wafer'}, + {'technic:fine_silver_wire', 'technic:lv_cable0', 'mesecons_materials:glue'}, + + } +}) + +technic.register_machine("LV", "technic:solar_panel", technic.producer) + diff --git a/technic/machines/LV/water_mill.lua b/technic/machines/LV/water_mill.lua new file mode 100644 index 0000000..9088d1d --- /dev/null +++ b/technic/machines/LV/water_mill.lua @@ -0,0 +1,102 @@ +-- A water mill produces LV EUs by exploiting flowing water across it +-- It is a LV EU supplyer and fairly low yield (max 120EUs) +-- It is a little under half as good as the thermal generator. + +local S = technic.getter + +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_cable0', '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:water_source" then + return true + end + return false +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 + + local positions = { + {x=pos.x+1, y=pos.y, z=pos.z}, + {x=pos.x-1, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z+1}, + {x=pos.x, y=pos.y, z=pos.z-1}, + } + + for _, p in pairs(positions) do + local check = check_node_around_mill(p) + if check then + water_nodes = water_nodes + 1 + end + end + + production_level = 25 * water_nodes + eu_supply = 30 * water_nodes + + if production_level > 0 then + meta:set_int("LV_EU_supply", eu_supply) + end + + meta:set_string("infotext", + S("Hydro %s Generator"):format("LV").." ("..production_level.."%)") + + if production_level > 0 and + minetest.get_node(pos).name == "technic:water_mill" then + technic.swap_node (pos, "technic:water_mill_active") + meta:set_int("LV_EU_supply", 0) + return + end + if production_level == 0 then + technic.swap_node(pos, "technic:water_mill") + end +end + +minetest.register_node("technic:water_mill", { + description = S("Hydro %s Generator"):format("LV"), + tiles = {"technic_water_mill_top.png", "technic_machine_bottom.png", + "technic_water_mill_side.png", "technic_water_mill_side.png", + "technic_water_mill_side.png", "technic_water_mill_side.png"}, + paramtype2 = "facedir", + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("Hydro %s Generator"):format("LV")) + meta:set_int("LV_EU_supply", 0) + end, + technic_run = run, +}) + +minetest.register_node("technic:water_mill_active", { + description = S("Hydro %s Generator"):format("LV"), + tiles = {"technic_water_mill_top_active.png", "technic_machine_bottom.png", + "technic_water_mill_side.png", "technic_water_mill_side.png", + "technic_water_mill_side.png", "technic_water_mill_side.png"}, + paramtype2 = "facedir", + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, not_in_creative_inventory=1}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + drop = "technic:water_mill", + technic_run = 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) + diff --git a/technic/machines/MV/alloy_furnace.lua b/technic/machines/MV/alloy_furnace.lua new file mode 100644 index 0000000..a1918fd --- /dev/null +++ b/technic/machines/MV/alloy_furnace.lua @@ -0,0 +1,14 @@ +-- MV alloy furnace + +minetest.register_craft({ + output = 'technic:mv_alloy_furnace', + recipe = { + {'technic:stainless_steel_ingot', 'technic:lv_alloy_furnace', 'technic:stainless_steel_ingot'}, + {'pipeworks:tube_1', 'technic:mv_transformer', 'pipeworks:tube_1'}, + {'technic:stainless_steel_ingot', 'technic:mv_cable0', 'technic:stainless_steel_ingot'}, + } +}) + + +technic.register_alloy_furnace({tier = "MV", speed = 1.5, upgrade = 1, tube = 1, demand = {3000, 2000, 1000}}) + diff --git a/technic/machines/MV/battery_box.lua b/technic/machines/MV/battery_box.lua new file mode 100644 index 0000000..45437c1 --- /dev/null +++ b/technic/machines/MV/battery_box.lua @@ -0,0 +1,22 @@ +-- MV Battery box + +minetest.register_craft({ + output = 'technic:mv_battery_box0', + recipe = { + {'technic:lv_battery_box0', 'technic:lv_battery_box0', 'technic:lv_battery_box0'}, + {'technic:lv_battery_box0', 'technic:mv_transformer', 'technic:lv_battery_box0'}, + {'', 'technic:mv_cable0', ''}, + } +}) + +technic.register_battery_box({ + tier = "MV", + max_charge = 200000, + charge_rate = 20000, + discharge_rate = 80000, + charge_step = 2000, + discharge_step = 8000, + upgrade = 1, + tube = 1, +}) + diff --git a/technic/machines/MV/cables.lua b/technic/machines/MV/cables.lua new file mode 100644 index 0000000..b1a34c8 --- /dev/null +++ b/technic/machines/MV/cables.lua @@ -0,0 +1,14 @@ + +minetest.register_alias("mv_cable", "technic:mv_cable0") + +minetest.register_craft({ + output = 'technic:mv_cable0 3', + recipe ={ + {'technic:rubber', 'technic:rubber', 'technic:rubber'}, + {'technic:lv_cable0', 'technic:lv_cable0', 'technic:lv_cable0'}, + {'technic:rubber', 'technic:rubber', 'technic:rubber'}, + } +}) + +technic.register_cable("MV", 2.5/16) + diff --git a/technic/machines/MV/centrifuge.lua b/technic/machines/MV/centrifuge.lua new file mode 100644 index 0000000..5bf24bf --- /dev/null +++ b/technic/machines/MV/centrifuge.lua @@ -0,0 +1,16 @@ +minetest.register_craft({ + output = "technic:mv_centrifuge", + recipe = { + { "technic:motor", "technic:copper_plate", "technic:diamond_drill_head" }, + { "technic:copper_plate", "technic:machine_casing", "technic:copper_plate" }, + { "pipeworks:one_way_tube", "technic:mv_cable0", "pipeworks:mese_filter" }, + } +}) + +technic.register_centrifuge({ + tier = "MV", + demand = { 8000, 7000, 6000 }, + speed = 2, + upgrade = 1, + tube = 1, +}) diff --git a/technic/machines/MV/compressor.lua b/technic/machines/MV/compressor.lua new file mode 100644 index 0000000..5b36cc5 --- /dev/null +++ b/technic/machines/MV/compressor.lua @@ -0,0 +1,12 @@ +-- 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_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +technic.register_compressor({tier = "MV", demand = {800, 600, 400}, speed = 2, upgrade = 1, tube = 1}) diff --git a/technic/machines/MV/electric_furnace.lua b/technic/machines/MV/electric_furnace.lua new file mode 100644 index 0000000..1f6b1c2 --- /dev/null +++ b/technic/machines/MV/electric_furnace.lua @@ -0,0 +1,18 @@ +-- MV Electric Furnace +-- This is a faster version of the stone furnace which runs on EUs +-- In addition to this it can be upgraded with microcontrollers and batteries +-- This new version uses the batteries to lower the power consumption of the machine +-- Also in addition this furnace can be attached to the pipe system from the pipeworks mod. + +-- FIXME: kpoppel I'd like to introduce an induction heating element here also +minetest.register_craft({ + output = 'technic:mv_electric_furnace', + recipe = { + {'technic:stainless_steel_ingot', 'technic:lv_electric_furnace', 'technic:stainless_steel_ingot'}, + {'pipeworks:tube_1', 'technic:mv_transformer', 'pipeworks:tube_1'}, + {'technic:stainless_steel_ingot', 'technic:mv_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +technic.register_electric_furnace({tier="MV", upgrade=1, tube=1, demand={2000, 1000, 500}, speed=4}) + diff --git a/technic/machines/MV/extractor.lua b/technic/machines/MV/extractor.lua new file mode 100644 index 0000000..fdef5b2 --- /dev/null +++ b/technic/machines/MV/extractor.lua @@ -0,0 +1,12 @@ +-- 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_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +technic.register_extractor({tier = "MV", demand = {800, 600, 400}, speed = 2, upgrade = 1, tube = 1}) diff --git a/technic/machines/MV/generator.lua b/technic/machines/MV/generator.lua new file mode 100644 index 0000000..4ae24b8 --- /dev/null +++ b/technic/machines/MV/generator.lua @@ -0,0 +1,13 @@ +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_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +technic.register_generator({tier="MV", tube=1, supply=600}) + diff --git a/technic/machines/MV/grinder.lua b/technic/machines/MV/grinder.lua new file mode 100644 index 0000000..dac536c --- /dev/null +++ b/technic/machines/MV/grinder.lua @@ -0,0 +1,13 @@ +-- MV grinder + +minetest.register_craft({ + output = 'technic:mv_grinder', + recipe = { + {'technic:stainless_steel_ingot', 'technic:lv_grinder', 'technic:stainless_steel_ingot'}, + {'pipeworks:tube_1', 'technic:mv_transformer', 'pipeworks:tube_1'}, + {'technic:stainless_steel_ingot', 'technic:mv_cable0', 'technic:stainless_steel_ingot'}, + } +}) + +technic.register_grinder({tier="MV", demand={600, 450, 300}, speed=2, upgrade=1, tube=1}) + diff --git a/technic/machines/MV/init.lua b/technic/machines/MV/init.lua new file mode 100644 index 0000000..72a98b6 --- /dev/null +++ b/technic/machines/MV/init.lua @@ -0,0 +1,32 @@ + +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") + +-- 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") + +-- 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") + diff --git a/technic/machines/MV/lighting.lua b/technic/machines/MV/lighting.lua new file mode 100644 index 0000000..76fcb20 --- /dev/null +++ b/technic/machines/MV/lighting.lua @@ -0,0 +1,590 @@ +-- NOTE: The code is takes directly from VanessaE's homedecor mod. +-- I just made it the lights into indictive appliances for this mod. + +-- This file supplies electric powered glowlights + +-- Boilerplate to support localized strings if intllib mod is installed. +local S +if (minetest.get_modpath("intllib")) then + dofile(minetest.get_modpath("intllib").."/intllib.lua") + S = intllib.Getter(minetest.get_current_modname()) +else + S = function (s) return s end +end + +function technic_homedecor_node_is_owned(pos, placer) + local ownername = false + if type(IsPlayerNodeOwner) == "function" then -- node_ownership mod + if HasOwner(pos, placer) then + if not IsPlayerNodeOwner(pos, placer:get_player_name()) then + if type(getLastOwner) == "function" then -- ...is an old version + ownername = getLastOwner(pos) + elseif type(GetNodeOwnerName) == "function" then -- ...is a recent version + ownername = GetNodeOwnerName(pos) + else + ownername = S("someone") + end + end + end + + elseif type(isprotect) == "function" then -- glomie's protection mod + if not isprotect(5, pos, placer) then + ownername = S("someone") + end + elseif type(protector) == "table" and type(protector.can_dig) == "function" then -- Zeg9's protection mod + if not protector.can_dig(5, pos, placer) then + ownername = S("someone") + end + end + + if ownername ~= false then + minetest.chat_send_player(placer:get_player_name(), S("Sorry, %s owns that spot."):format(ownername) ) + return true + else + return false + end +end + +local dirs1 = {20, 23, 22, 21} +local dirs2 = {9, 18, 7, 12} + +local technic_homedecor_rotate_and_place = function(itemstack, placer, pointed_thing) + if not technic_homedecor_node_is_owned(pointed_thing.under, placer) + and not technic_homedecor_node_is_owned(pointed_thing.above, placer) then + local node = minetest.get_node(pointed_thing.under) + if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].on_rightclick then + + local above = pointed_thing.above + local under = pointed_thing.under + local pitch = placer:get_look_pitch() + local pname = minetest.get_node(under).name + local node = minetest.get_node(above) + local fdir = minetest.dir_to_facedir(placer:get_look_dir()) + local wield_name = itemstack:get_name() + + if not minetest.registered_nodes[pname] + or not minetest.registered_nodes[pname].on_rightclick then + + local iswall = (above.x ~= under.x) or (above.z ~= under.z) + local isceiling = (above.x == under.x) and (above.z == under.z) and (pitch > 0) + local pos1 = above + + if minetest.registered_nodes[pname]["buildable_to"] then + pos1 = under + iswall = false + end + + if not minetest.registered_nodes[minetest.get_node(pos1).name]["buildable_to"] then return end + + if iswall then + minetest.add_node(pos1, {name = wield_name, param2 = dirs2[fdir+1] }) -- place wall variant + elseif isceiling then + minetest.add_node(pos1, {name = wield_name, param2 = 20 }) -- place upside down variant + else + minetest.add_node(pos1, {name = wield_name, param2 = 0 }) -- place right side up + end + + if not homedecor_expect_infinite_stacks then + itemstack:take_item() + return itemstack + end + end + else + minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) + end + end +end + +-- Yellow -- Half node +minetest.register_node('technic:homedecor_glowlight_half_yellow', { + description = S("Yellow Glowlight (thick)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3 }, + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thick)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_half_yellow_active") + end +}) + +minetest.register_node('technic:homedecor_glowlight_half_yellow_active', { + description = S("Yellow Glowlight (thick)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png', + 'technic_homedecor_glowlight_thick_yellow_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + light_source = LIGHT_MAX, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3, not_in_creative_inventory=1}, + drop="technic:homedecor_glowlight_half_yellow", + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thick)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_half_yellow") + end +}) + +-- Yellow -- Quarter node +minetest.register_node('technic:homedecor_glowlight_quarter_yellow', { + description = S("Yellow Glowlight (thin)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3 }, + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thin)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_quarter_yellow_active") + end +}) + +minetest.register_node('technic:homedecor_glowlight_quarter_yellow_active', { + description = S("Yellow Glowlight (thin)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_yellow_tb.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png', + 'technic_homedecor_glowlight_thin_yellow_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + light_source = LIGHT_MAX-1, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3, not_in_creative_inventory=1}, + drop="technic:homedecor_glowlight_quarter_yellow", + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "Yellow Glowlight (thin)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_quarter_yellow") + end +}) + + +-- White -- half node +minetest.register_node('technic:homedecor_glowlight_half_white', { + description = S("White Glowlight (thick)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_thick_white_sides.png', + 'technic_homedecor_glowlight_thick_white_sides.png', + 'technic_homedecor_glowlight_thick_white_sides.png', + 'technic_homedecor_glowlight_thick_white_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3 }, + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "White Glowlight (thick)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_half_white_active") + end +}) + +minetest.register_node('technic:homedecor_glowlight_half_white_active', { + description = S("White Glowlight (thick)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_thick_white_sides.png', + 'technic_homedecor_glowlight_thick_white_sides.png', + 'technic_homedecor_glowlight_thick_white_sides.png', + 'technic_homedecor_glowlight_thick_white_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + light_source = LIGHT_MAX, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3, not_in_creative_inventory=1}, + drop="technic:homedecor_glowlight_half_white", + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "White Glowlight (thick)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_half_white") + end +}) + +-- White -- Quarter node +minetest.register_node('technic:homedecor_glowlight_quarter_white', { + description = S("White Glowlight (thin)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_thin_white_sides.png', + 'technic_homedecor_glowlight_thin_white_sides.png', + 'technic_homedecor_glowlight_thin_white_sides.png', + 'technic_homedecor_glowlight_thin_white_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3 }, + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "White Glowlight (thin)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_off(pos, 100, "technic:homedecor_glowlight_quarter_white_active") + end +}) + +minetest.register_node('technic:homedecor_glowlight_quarter_white_active', { + description = S("White Glowlight (thin)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_white_tb.png', + 'technic_homedecor_glowlight_thin_white_sides.png', + 'technic_homedecor_glowlight_thin_white_sides.png', + 'technic_homedecor_glowlight_thin_white_sides.png', + 'technic_homedecor_glowlight_thin_white_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + node_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + light_source = LIGHT_MAX-1, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3, not_in_creative_inventory=1}, + drop="technic:homedecor_glowlight_quarter_white", + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 100, "White Glowlight (thin)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_quarter_white") + end +}) + +-- Glowlight "cubes" - yellow +minetest.register_node('technic:homedecor_glowlight_small_cube_yellow', { + description = S("Yellow Glowlight (small cube)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_cube_yellow_tb.png', + 'technic_homedecor_glowlight_cube_yellow_tb.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + node_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3 }, + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 50, "Yellow Glowlight (small cube)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_off(pos, 50, "technic:homedecor_glowlight_small_cube_yellow_active") + end +}) + +minetest.register_node('technic:homedecor_glowlight_small_cube_yellow_active', { + description = S("Yellow Glowlight (small cube)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_cube_yellow_tb.png', + 'technic_homedecor_glowlight_cube_yellow_tb.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png', + 'technic_homedecor_glowlight_cube_yellow_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + node_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + light_source = LIGHT_MAX-1, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3, not_in_creative_inventory=1}, + drop="technic:homedecor_glowlight_small_cube_yellow", + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 50, "Yellow Glowlight (small cube)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_small_cube_yellow") + end +}) + +-- Glowlight "cubes" - white +minetest.register_node('technic:homedecor_glowlight_small_cube_white', { + description = S("White Glowlight (small cube)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_cube_white_tb.png', + 'technic_homedecor_glowlight_cube_white_tb.png', + 'technic_homedecor_glowlight_cube_white_sides.png', + 'technic_homedecor_glowlight_cube_white_sides.png', + 'technic_homedecor_glowlight_cube_white_sides.png', + 'technic_homedecor_glowlight_cube_white_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + node_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3 }, + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 50, "White Glowlight (small cube)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_off(pos, 50, "technic:homedecor_glowlight_small_cube_white_active") + end +}) + +minetest.register_node('technic:homedecor_glowlight_small_cube_white_active', { + description = S("White Glowlight (small cube)"), + drawtype = "nodebox", + tiles = { + 'technic_homedecor_glowlight_cube_white_tb.png', + 'technic_homedecor_glowlight_cube_white_tb.png', + 'technic_homedecor_glowlight_cube_white_sides.png', + 'technic_homedecor_glowlight_cube_white_sides.png', + 'technic_homedecor_glowlight_cube_white_sides.png', + 'technic_homedecor_glowlight_cube_white_sides.png' + }, + selection_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + node_box = { + type = "fixed", + fixed = { -0.25, -0.5, -0.25, 0.25, 0, 0.25 } + }, + + sunlight_propagates = false, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + light_source = LIGHT_MAX-1, + sounds = default.node_sound_wood_defaults(), + + groups = { snappy = 3, not_in_creative_inventory=1}, + drop="technic:homedecor_glowlight_small_cube_white", + on_place = function(itemstack, placer, pointed_thing) + technic_homedecor_rotate_and_place(itemstack, placer, pointed_thing) + return itemstack + end, + on_construct = function(pos) + technic.inductive_on_construct(pos, 50, "White Glowlight (small cube)") + end, + on_punch = function(pos, node, puncher) + technic.inductive_on_punch_on(pos, 0, "technic:homedecor_glowlight_small_cube_white") + end +}) + +technic.register_inductive_machine("technic:homedecor_glowlight_half_yellow") +technic.register_inductive_machine("technic:homedecor_glowlight_half_white") +technic.register_inductive_machine("technic:homedecor_glowlight_quarter_yellow") +technic.register_inductive_machine("technic:homedecor_glowlight_quarter_white") +technic.register_inductive_machine("technic:homedecor_glowlight_small_cube_yellow") +technic.register_inductive_machine("technic:homedecor_glowlight_small_cube_white") diff --git a/technic/machines/MV/power_radiator.lua b/technic/machines/MV/power_radiator.lua new file mode 100644 index 0000000..560f8a9 --- /dev/null +++ b/technic/machines/MV/power_radiator.lua @@ -0,0 +1,220 @@ +-- The power radiator fuctions like an inductive charger +-- only better in the game setting. +-- The purpose is to allow small appliances to receive power +-- without the overhead of the wiring needed for larger machines. +-- +-- The power radiator will consume power corresponding to the +-- sum(power rating of the attached appliances)/0.06 +-- Using inductive power transfer is very inefficient so this is +-- set to the factor 0.06. +-- +-- Punching the radiator will toggle the power state of all attached appliances. + +local power_radius = 12 + +------------------------------------------------------------------ +-- API for inductive powered nodes: +-- Use the functions below to set the corresponding callbacks +-- Also two nodes are needed: The inactive and the active one. The active must be called _active . +------------------------------------------------------------------ +-- Register a new appliance using this function + +technic.inductive_nodes = {} +technic.register_inductive_machine = function(name) + table.insert(technic.inductive_nodes, name) + table.insert(technic.inductive_nodes, name.."_active") +end + +-- Appliances: +-- has_supply: pos of supply node if the appliance has a power radiator near with sufficient power for the demand else "" +-- EU_demand: The power demand of the device. +-- EU_charge: Actual use. set to EU_demand if active==1 +-- active: set to 1 if the device is on +technic.inductive_on_construct = function(pos, eu_demand, infotext) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", infotext) + meta:set_int("technic_inductive_power_machine", 1) + meta:set_int("EU_demand", eu_demand) -- The power demand of this appliance + meta:set_int("EU_charge", 0) -- The actual power draw of this appliance + meta:set_string("has_supply", "") -- Register whether we are powered or not. For use with several radiators. + meta:set_int("active", 0) -- If the appliance can be turned on and off by using it use this. +end + +technic.inductive_on_punch_off = function(pos, eu_charge, swapnode) + local meta = minetest.get_meta(pos) + if meta:get_string("has_supply") ~= "" then + technic.swap_node(pos, swapnode) + meta:set_int("active", 1) + meta:set_int("EU_charge",eu_charge) + --print("-----------") + --print("Turn on:") + --print("EU_charge: "..meta:get_int("EU_charge")) + --print("has_supply: "..meta:get_string("has_supply")) + --print("<----------->") + end +end + +technic.inductive_on_punch_on = function(pos, eu_charge, swapnode) + local meta = minetest.get_meta(pos) + technic.swap_node(pos, swapnode) + meta:set_int("active", 0) + meta:set_int("EU_charge",eu_charge) + --print("-----------") + --print("Turn off:") + --print("EU_charge: "..meta:get_int("EU_charge")) + --print("has_supply: "..meta:get_string("has_supply")) + --print("<---------->") +end + +local shutdown_inductive_appliances = function(pos) + -- The supply radius + local rad = power_radius + -- If the radiator is removed. turn off all appliances in region + -- If another radiator is near it will turn on the appliances again + local positions = minetest.find_nodes_in_area( + {x=pos.x-rad, y=pos.y-rad, z=pos.z-rad}, + {x=pos.x+rad, y=pos.y+rad, z=pos.z+rad}, + technic.inductive_nodes) + for _, pos1 in pairs(positions) do + local meta1 = minetest.get_meta(pos1) + -- If the appliance is belonging to this node + if meta1:get_string("has_supply") == pos.x..pos.y..pos.z then + local nodename = minetest.get_node(pos1).name + -- Swap the node and make sure it is off and unpowered + if string.sub(nodename, -7) == "_active" then + technic.swap_node(pos1, string.sub(nodename, 1, -8)) + meta1:set_int("active", 0) + meta1:set_int("EU_charge", 0) + end + meta1:set_string("has_supply", "") + end + end +end + +local toggle_on_off_inductive_appliances = function(pos, node, puncher) + if pos == nil then return end + -- The supply radius + local rad = power_radius + local positions = minetest.find_nodes_in_area( + {x=pos.x-rad, y=pos.y-rad, z=pos.z-rad}, + {x=pos.x+rad, y=pos.y+rad, z=pos.z+rad}, + technic.inductive_nodes) + for _, pos1 in pairs(positions) do + local meta1 = minetest.get_meta(pos1) + if meta1:get_string("has_supply") == pos.x..pos.y..pos.z then + minetest.punch_node(pos1) + end + end +end + +minetest.register_node("technic:power_radiator", { + description = "MV Power Radiator", + tiles = {"technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png", + "technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}, + sounds = default.node_sound_wood_defaults(), + drawtype = "nodebox", + paramtype = "light", + is_ground_content = true, + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_int("MV_EU_demand",1) -- Demand on the primary side when idle + meta:set_int("connected_EU_demand",0) -- Potential demand of connected appliances + meta:set_string("infotext", "MV Power Radiator") + end, + on_dig = function(pos, node, digger) + shutdown_inductive_appliances(pos) + return minetest.node_dig(pos, node, digger) + end, + on_punch = function(pos, node, puncher) + toggle_on_off_inductive_appliances(pos, node, puncher) + end +}) + +minetest.register_craft({ + output = 'technic:power_radiator 1', + recipe = { + {'technic:stainless_steel_ingot', 'technic:mv_transformer', 'technic:stainless_steel_ingot'}, + {'technic:copper_coil', 'technic:machine_casing', 'technic:copper_coil'}, + {'technic:rubber', 'technic:mv_cable0', 'technic:rubber'}, + } +}) + +minetest.register_abm({ + nodenames = {"technic:power_radiator"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local meta = minetest.get_meta(pos) + local eu_input = meta:get_int("MV_EU_input") + local eu_demand = meta:get_int("MV_EU_demand") + + -- Power off automatically if no longer connected to a switching station + technic.switching_station_timeout_count(pos, "MV") + + if eu_input == 0 then + -- No power + meta:set_string("infotext", "MV Power Radiator is unpowered"); + -- meta:set_int("active", 1) -- used for setting textures someday maybe + shutdown_inductive_appliances(pos) + meta:set_int("connected_EU_demand", 0) + meta:set_int("MV_EU_demand",1) + elseif eu_input == eu_demand then + -- Powered and ready + + -- The maximum EU sourcing a single radiator can provide. + local max_charge = 30000 -- == the max EU demand of the radiator + local connected_EU_demand = meta:get_int("connected_EU_demand") + + -- Efficiency factor + local eff_factor = 0.06 + -- The supply radius + local rad = power_radius + + local meta1 = nil + local pos1 = {} + local used_charge = 0 + + -- Index all nodes within supply range + local positions = minetest.find_nodes_in_area( + {x=pos.x-rad, y=pos.y-rad, z=pos.z-rad}, + {x=pos.x+rad, y=pos.y+rad, z=pos.z+rad}, + technic.inductive_nodes) + for _, pos1 in pairs(positions) do + local meta1 = minetest.get_meta(pos1) + -- If not supplied see if this node can handle it. + if meta1:get_string("has_supply") == "" then + -- if demand surpasses the capacity of this node, don't bother adding it. + local app_eu_demand = math.floor(meta1:get_int("EU_demand") / eff_factor) + if connected_EU_demand + app_eu_demand <= max_charge then + -- We can power the appliance. Register, and spend power if it is on. + connected_EU_demand = connected_EU_demand + app_eu_demand + + meta1:set_string("has_supply", pos.x..pos.y..pos.z) + --Always 0: used_charge = math.floor(used_charge + meta1:get_int("EU_charge") / eff_factor) + end + elseif meta1:get_string("has_supply") == pos.x..pos.y..pos.z then + -- The appliance has power from this node. Spend power if it is on. + used_charge = used_charge + math.floor(meta1:get_int("EU_charge") / eff_factor) + end + meta:set_string("infotext", "MV Power Radiator is powered (" + ..math.floor(used_charge / max_charge * 100) + .."% of maximum power)"); + if used_charge == 0 then + meta:set_int("MV_EU_demand", 1) -- Still idle + else + meta:set_int("MV_EU_demand", used_charge) + end + end + -- Save state + meta:set_int("connected_EU_demand", connected_EU_demand) + end + end, +}) + +technic.register_machine("MV", "technic:power_radiator", technic.receiver) + diff --git a/technic/machines/MV/solar_array.lua b/technic/machines/MV/solar_array.lua new file mode 100644 index 0000000..227d8ee --- /dev/null +++ b/technic/machines/MV/solar_array.lua @@ -0,0 +1,14 @@ + +minetest.register_craft({ + output = 'technic:solar_array_mv 1', + recipe = { + {'technic:solar_array_lv', 'technic:solar_array_lv', 'technic:solar_array_lv'}, + {'technic:carbon_steel_ingot', 'technic:mv_transformer', 'technic:carbon_steel_ingot'}, + {'', 'technic:mv_cable0', ''}, + } +}) + +technic.register_solar_array({tier="MV", power=30}) + +-- compatibility alias for upgrading from old versions of technic +minetest.register_alias("technic:solar_panel_mv", "technic:solar_array_mv") diff --git a/technic/machines/MV/tool_workshop.lua b/technic/machines/MV/tool_workshop.lua new file mode 100644 index 0000000..318b1ec --- /dev/null +++ b/technic/machines/MV/tool_workshop.lua @@ -0,0 +1,117 @@ +-- Tool workshop +-- This machine repairs tools. + +minetest.register_alias("tool_workshop", "technic:tool_workshop") + +local S = technic.getter + +minetest.register_craft({ + output = 'technic:tool_workshop', + recipe = { + {'group:wood', 'default:diamond', 'group:wood'}, + {'mesecons_pistons:piston_sticky_off', 'technic:machine_casing', 'technic:carbon_cloth'}, + {'default:obsidian', 'technic:mv_cable0', 'default:obsidian'}, + } +}) + +local workshop_demand = {5000, 3500, 2000} + +local workshop_formspec = + "invsize[8,9;]".. + "list[current_name;src;3,1;1,1;]".. + "label[0,0;"..S("%s Tool Workshop"):format("MV").."]".. + "list[current_name;upgrade1;1,3;1,1;]".. + "list[current_name;upgrade2;2,3;1,1;]".. + "label[1,4;"..S("Upgrade Slots").."]".. + "list[current_player;main;0,5;8,4;]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]".. + "listring[current_name;upgrade1]".. + "listring[current_player;main]".. + "listring[current_name;upgrade2]".. + "listring[current_player;main]" + +local run = function(pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local eu_input = meta:get_int("MV_EU_input") + local machine_name = S("%s Tool Workshop"):format("MV") + local machine_node = "technic:tool_workshop" + + -- Setup meta data if it does not exist. + if not eu_input then + meta:set_int("MV_EU_demand", workshop_demand[1]) + meta:set_int("MV_EU_input", 0) + return + end + + local EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta) + + local repairable = false + local srcstack = inv:get_stack("src", 1) + if not srcstack:is_empty() then + local itemdef = minetest.registered_items[srcstack:get_name()] + if itemdef and + (not itemdef.wear_represents or + itemdef.wear_represents == "mechanical_wear") and + srcstack:get_wear() ~= 0 then + repairable = true + end + end + technic.handle_machine_pipeworks(pos, tube_upgrade, function (pos, x_velocity, z_velocity) + if not repairable then + technic.send_items(pos, x_velocity, z_velocity, "src") + end + end) + if not repairable then + meta:set_string("infotext", S("%s Idle"):format(machine_name)) + meta:set_int("MV_EU_demand", 0) + return + end + + if eu_input < workshop_demand[EU_upgrade+1] then + meta:set_string("infotext", S("%s Unpowered"):format(machine_name)) + elseif eu_input >= workshop_demand[EU_upgrade+1] then + meta:set_string("infotext", S("%s Active"):format(machine_name)) + srcstack:add_wear(-1000) + inv:set_stack("src", 1, srcstack) + end + meta:set_int("MV_EU_demand", workshop_demand[EU_upgrade+1]) +end + +minetest.register_node("technic:tool_workshop", { + description = S("%s Tool Workshop"):format("MV"), + paramtype2 = "facedir", + tiles = {"technic_workshop_top.png", "technic_machine_bottom.png", "technic_workshop_side.png", + "technic_workshop_side.png", "technic_workshop_side.png", "technic_workshop_side.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, tubedevice=1, tubedevice_receiver=1}, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("%s Tool Workshop"):format("MV")) + meta:set_string("formspec", workshop_formspec) + local inv = meta:get_inventory() + inv:set_size("src", 1) + inv:set_size("upgrade1", 1) + inv:set_size("upgrade2", 1) + end, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + tube = { + can_insert = function (pos, node, stack, direction) + return minetest.get_meta(pos):get_inventory():room_for_item("src", stack) + end, + insert_object = function (pos, node, stack, direction) + return minetest.get_meta(pos):get_inventory():add_item("src", stack) + end, + connect_sides = {left = 1, right = 1, back = 1, top = 1, bottom = 1}, + }, + technic_run = run, + after_place_node = pipeworks.after_place, + after_dig_node = technic.machine_after_dig_node +}) + +technic.register_machine("MV", "technic:tool_workshop", technic.receiver) + diff --git a/technic/machines/MV/wind_mill.lua b/technic/machines/MV/wind_mill.lua new file mode 100644 index 0000000..c553051 --- /dev/null +++ b/technic/machines/MV/wind_mill.lua @@ -0,0 +1,87 @@ + +local S = technic.getter + +minetest.register_craft({ + output = 'technic:wind_mill_frame 5', + recipe = { + {'technic:carbon_steel_ingot', '', 'technic:carbon_steel_ingot'}, + {'', 'technic:carbon_steel_ingot', ''}, + {'technic:carbon_steel_ingot', '', 'technic:carbon_steel_ingot'}, + } +}) + +minetest.register_craft({ + output = 'technic:wind_mill', + recipe = { + {'', 'technic:motor', ''}, + {'technic:carbon_steel_ingot', 'technic:carbon_steel_block', 'technic:carbon_steel_ingot'}, + {'', 'technic:mv_cable0', ''}, + } +}) + +minetest.register_node("technic:wind_mill_frame", { + description = S("Wind Mill Frame"), + drawtype = "glasslike_framed", + tiles = {"technic_carbon_steel_block.png", "default_glass.png"}, + sunlight_propagates = true, + groups = {cracky=3}, + sounds = default.node_sound_stone_defaults(), + paramtype = "light", +}) + +local function check_wind_mill(pos) + if pos.y < 30 then + return false + end + for i = 1, 20 do + local node = minetest.get_node({x=pos.x, y=pos.y-i, z=pos.z}) + if node.name ~= "technic:wind_mill_frame" then + return false + end + end + return true +end + +local run = function(pos, node) + local meta = minetest.get_meta(pos) + local machine_name = S("Wind %s Generator"):format("MV") + local power = math.min(pos.y * 100, 5000) + + if not check_wind_mill(pos) then + meta:set_int("MV_EU_supply", 0) + meta:set_string("infotext", S("%s Improperly Placed"):format(machine_name)) + return + else + meta:set_int("MV_EU_supply", power) + end + + meta:set_string("infotext", S("@1 (@2 EU)", machine_name, technic.prettynum(power))) +end + +minetest.register_node("technic:wind_mill", { + description = S("Wind %s Generator"):format("MV"), + tiles = {"technic_carbon_steel_block.png"}, + paramtype2 = "facedir", + groups = {cracky=1, technic_machine=1}, + sounds = default.node_sound_stone_defaults(), + drawtype = "nodebox", + paramtype = "light", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, -- Main box + {-0.1, -0.1, -0.5, 0.1, 0.1, -0.6}, -- Shaft + {-0.1, -1, -0.6, 0.1, 1, -0.7}, -- Vertical blades + {-1, -0.1, -0.6, 1, 0.1, -0.7}, -- Horizontal blades + } + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("Wind %s Generator"):format("MV")) + meta:set_int("MV_EU_supply", 0) + end, + technic_run = run, +}) + +technic.register_machine("MV", "technic:wind_mill", technic.producer) + diff --git a/technic/machines/init.lua b/technic/machines/init.lua new file mode 100644 index 0000000..ad79eab --- /dev/null +++ b/technic/machines/init.lua @@ -0,0 +1,14 @@ +local path = technic.modpath.."/machines" + +dofile(path.."/register/init.lua") + +-- Tiers +dofile(path.."/LV/init.lua") +dofile(path.."/MV/init.lua") +dofile(path.."/HV/init.lua") + +dofile(path.."/switching_station.lua") +dofile(path.."/supply_converter.lua") + +dofile(path.."/other/init.lua") + diff --git a/technic/machines/other/anchor.lua b/technic/machines/other/anchor.lua new file mode 100644 index 0000000..1c15bd2 --- /dev/null +++ b/technic/machines/other/anchor.lua @@ -0,0 +1,109 @@ +local S = technic.getter + +local desc = S("Administrative World Anchor") + +local function compute_forceload_positions(pos, meta) + local radius = meta:get_int("radius") + local minpos = vector.subtract(pos, vector.new(radius, radius, radius)) + local maxpos = vector.add(pos, vector.new(radius, radius, radius)) + local minbpos = {} + local maxbpos = {} + for _, coord in ipairs({"x","y","z"}) do + minbpos[coord] = math.floor(minpos[coord] / 16) * 16 + maxbpos[coord] = math.floor(maxpos[coord] / 16) * 16 + end + local flposes = {} + for x = minbpos.x, maxbpos.x, 16 do + for y = minbpos.y, maxbpos.y, 16 do + for z = minbpos.z, maxbpos.z, 16 do + table.insert(flposes, vector.new(x, y, z)) + end + end + end + return flposes +end + +local function currently_forceloaded_positions(meta) + local ser = meta:get_string("forceloaded") + return ser == "" and {} or minetest.deserialize(ser) +end + +local function forceload_off(meta) + local flposes = currently_forceloaded_positions(meta) + meta:set_string("forceloaded", "") + for _, p in ipairs(flposes) do + minetest.forceload_free_block(p) + end +end + +local function forceload_on(pos, meta) + local want_flposes = compute_forceload_positions(pos, meta) + local have_flposes = {} + for _, p in ipairs(want_flposes) do + if minetest.forceload_block(p) then + table.insert(have_flposes, p) + end + end + meta:set_string("forceloaded", #have_flposes == 0 and "" or minetest.serialize(have_flposes)) +end + +local function set_display(pos, meta) + meta:set_string("infotext", S(meta:get_int("enabled") ~= 0 and "%s Enabled" or "%s Disabled"):format(desc)) + meta:set_string("formspec", + "size[5,3.5]".. + "item_image[0,0;1,1;technic:admin_anchor]".. + "label[1,0;"..minetest.formspec_escape(desc).."]".. + "label[0,1;"..minetest.formspec_escape(S("Owner:").." "..meta:get_string("owner")).."]".. + (meta:get_int("locked") == 0 and + "button[3,1;2,1;lock;"..minetest.formspec_escape(S("Unlocked")).."]" or + "button[3,1;2,1;unlock;"..minetest.formspec_escape(S("Locked")).."]").. + "field[0.25,2.3;1,1;radius;"..minetest.formspec_escape(S("Radius:"))..";"..meta:get_int("radius").."]".. + (meta:get_int("enabled") == 0 and + "button[3,2;2,1;enable;"..minetest.formspec_escape(S("Disabled")).."]" or + "button[3,2;2,1;disable;"..minetest.formspec_escape(S("Enabled")).."]").. + "label[0,3;"..minetest.formspec_escape(S("Keeping %d/%d map blocks loaded"):format(#currently_forceloaded_positions(meta), #compute_forceload_positions(pos, meta))).."]") +end + +minetest.register_node("technic:admin_anchor", { + description = desc, + drawtype = "normal", + tiles = {"technic_admin_anchor.png"}, + is_ground_content = true, + groups = {cracky=3, not_in_creative_inventory=1}, + sounds = default.node_sound_stone_defaults(), + after_place_node = function (pos, placer) + local meta = minetest.get_meta(pos) + if placer and placer:is_player() then + meta:set_string("owner", placer:get_player_name()) + end + set_display(pos, meta) + end, + can_dig = function (pos, player) + local meta = minetest.get_meta(pos) + return meta:get_int("locked") == 0 or (player and player:is_player() and player:get_player_name() == meta:get_string("owner")) + end, + on_destruct = function (pos) + local meta = minetest.get_meta(pos) + forceload_off(meta) + end, + on_receive_fields = function (pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + if (meta:get_int("locked") ~= 0 or fields.lock) and + not (sender and sender:is_player() and + sender:get_player_name() == meta:get_string("owner")) then + return + end + if fields.unlock then meta:set_int("locked", 0) end + if fields.lock then meta:set_int("locked", 1) end + if fields.disable or fields.enable or fields.radius then + forceload_off(meta) + if fields.disable then meta:set_int("enabled", 0) end + if fields.enable then meta:set_int("enabled", 1) end + if fields.radius and string.find(fields.radius, "^[0-9]+$") and tonumber(fields.radius) < 256 then meta:set_int("radius", fields.radius) end + if meta:get_int("enabled") ~= 0 then + forceload_on(pos, meta) + end + end + set_display(pos, meta) + end, +}) diff --git a/technic/machines/other/coal_alloy_furnace.lua b/technic/machines/other/coal_alloy_furnace.lua new file mode 100644 index 0000000..58af679 --- /dev/null +++ b/technic/machines/other/coal_alloy_furnace.lua @@ -0,0 +1,177 @@ + +-- Fuel driven alloy furnace. This uses no EUs: + +local S = technic.getter + +minetest.register_craft({ + output = 'technic:coal_alloy_furnace', + recipe = { + {'default:brick', 'default:brick', 'default:brick'}, + {'default:brick', '', 'default:brick'}, + {'default:brick', 'default:brick', 'default:brick'}, + } +}) + +local machine_name = S("Fuel-Fired Alloy Furnace") +local formspec = + "size[8,9]".. + "label[0,0;"..machine_name.."]".. + "image[2,2;1,1;default_furnace_fire_bg.png]".. + "list[current_name;fuel;2,3;1,1;]".. + "list[current_name;src;2,1;2,1;]".. + "list[current_name;dst;5,1;2,2;]".. + "list[current_player;main;0,5;8,4;]".. + "listring[current_name;dst]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]".. + "listring[current_name;fuel]".. + "listring[current_player;main]" + +minetest.register_node("technic:coal_alloy_furnace", { + description = machine_name, + tiles = {"technic_coal_alloy_furnace_top.png", "technic_coal_alloy_furnace_bottom.png", + "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_side.png", + "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_front.png"}, + paramtype2 = "facedir", + groups = {cracky=2}, + legacy_facedir_simple = true, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec) + meta:set_string("infotext", machine_name) + local inv = meta:get_inventory() + inv:set_size("fuel", 1) + inv:set_size("src", 2) + inv:set_size("dst", 4) + end, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, +}) + +minetest.register_node("technic:coal_alloy_furnace_active", { + description = machine_name, + tiles = {"technic_coal_alloy_furnace_top.png", "technic_coal_alloy_furnace_bottom.png", + "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_side.png", + "technic_coal_alloy_furnace_side.png", "technic_coal_alloy_furnace_front_active.png"}, + paramtype2 = "facedir", + light_source = 8, + drop = "technic:coal_alloy_furnace", + groups = {cracky=2, not_in_creative_inventory=1}, + legacy_facedir_simple = true, + sounds = default.node_sound_stone_defaults(), + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, +}) + +minetest.register_abm({ + nodenames = {"technic:coal_alloy_furnace", "technic:coal_alloy_furnace_active"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + if inv:get_size("src") == 1 then -- Old furnace -> convert it + inv:set_size("src", 2) + inv:set_stack("src", 2, inv:get_stack("src2", 1)) + inv:set_size("src2", 0) + end + + local recipe = nil + + for i, name in pairs({ + "fuel_totaltime", + "fuel_time", + "src_totaltime", + "src_time"}) do + if not meta:get_float(name) then + meta:set_float(name, 0.0) + end + end + + -- Get what to cook if anything + local result = technic.get_recipe("alloy", inv:get_list("src")) + + local was_active = false + + if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then + was_active = true + meta:set_int("fuel_time", meta:get_int("fuel_time") + 1) + if result then + meta:set_int("src_time", meta:get_int("src_time") + 1) + if meta:get_int("src_time") >= result.time then + meta:set_int("src_time", 0) + local result_stack = ItemStack(result.output) + if inv:room_for_item("dst", result_stack) then + inv:set_list("src", result.new_input) + inv:add_item("dst", result_stack) + end + end + else + meta:set_int("src_time", 0) + end + end + + if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then + local percent = math.floor(meta:get_float("fuel_time") / + meta:get_float("fuel_totaltime") * 100) + meta:set_string("infotext", S("%s Active"):format(machine_name).." ("..percent.."%)") + technic.swap_node(pos, "technic:coal_alloy_furnace_active") + meta:set_string("formspec", + "size[8,9]".. + "label[0,0;"..machine_name.."]".. + "image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:".. + (100 - percent)..":default_furnace_fire_fg.png]".. + "list[current_name;fuel;2,3;1,1;]".. + "list[current_name;src;2,1;2,1;]".. + "list[current_name;dst;5,1;2,2;]".. + "list[current_player;main;0,5;8,4;]".. + "listring[current_name;dst]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]".. + "listring[current_name;fuel]".. + "listring[current_player;main]") + return + end + + local recipe = technic.get_recipe("alloy", inv:get_list("src")) + + if not recipe then + if was_active then + meta:set_string("infotext", S("%s is empty"):format(machine_name)) + technic.swap_node(pos, "technic:coal_alloy_furnace") + meta:set_string("formspec", formspec) + end + return + end + + -- Next take a hard look at the fuel situation + local fuel = nil + local afterfuel + local fuellist = inv:get_list("fuel") + + if fuellist then + fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist}) + end + + if fuel.time <= 0 then + meta:set_string("infotext", S("%s Out Of Fuel"):format(machine_name)) + technic.swap_node(pos, "technic:coal_alloy_furnace") + meta:set_string("formspec", formspec) + return + end + + meta:set_string("fuel_totaltime", fuel.time) + meta:set_string("fuel_time", 0) + + inv:set_stack("fuel", 1, afterfuel.items[1]) + end, +}) + diff --git a/technic/machines/other/coal_furnace.lua b/technic/machines/other/coal_furnace.lua new file mode 100644 index 0000000..53a0f8b --- /dev/null +++ b/technic/machines/other/coal_furnace.lua @@ -0,0 +1,5 @@ +local S = technic.getter + +if minetest.registered_nodes["default:furnace"].description == "Furnace" then + minetest.override_item("default:furnace", { description = S("Fuel-Fired Furnace") }) +end diff --git a/technic/machines/other/constructor.lua b/technic/machines/other/constructor.lua new file mode 100644 index 0000000..3396ac7 --- /dev/null +++ b/technic/machines/other/constructor.lua @@ -0,0 +1,189 @@ + +local S = technic.getter + +local function deploy_node(inv, slot_name, pos, node, machine_node) + if node.name ~= "air" then + if node.name == "ignore" or + node.name == "default:lava_source" or + node.name == "default:lava_flowing" or + node.name == "default:water_source" or + node.name == "default:water_flowing" then + return + end + local drops = minetest.get_node_drops(node.name, "") + local remove_to = false + for i, item in ipairs(drops) do + if not inv:room_for_item(slot_name, item) then + remove_to = i - 1 + break + end + inv:add_item(slot_name, item) + end + if remove_to then + for i = 1, remove_to do + inv:remove_item(drops[i]) + end + else + minetest.remove_node(pos) + end + return + end + if not inv:is_empty(slot_name) then + local stack = inv:get_list(slot_name)[1] + local def = stack:get_definition() + if def.type == "node" then + minetest.set_node(pos, { + name = stack:get_name(), + param2 = machine_node.param2 + }) + stack:take_item() + inv:set_stack(slot_name, 1, stack) + elseif def.type == "craft" then + if def.on_place then + -- Use pcall to avoid nil placer errors. + -- TODO: Do without pcall. + local ok, stk = pcall(def.on_place, stack, nil, { + -- Fake pointed_thing + type = "node", + above = pos, + under = {x=pos.x, y=pos.y-1, z=pos.z}, + }) + if ok then + inv:set_stack(slot_name, 1, stk or stack) + return + end + end + minetest.item_place_object(stack, nil, { + -- Fake pointed_thing + type = "node", + above = pos, + under = pos, + }) + inv:set_stack(slot_name, 1, nil) + end + end +end + +minetest.register_craft({ + type = "shapeless", + output = 'technic:constructor_mk1_off 1', + recipe = {'technic:nodebreaker_off', 'technic:deployer_off'}, + +}) +minetest.register_craft({ + type = "shapeless", + output = 'technic:constructor_mk2_off 1', + recipe = {'technic:constructor_mk1_off', 'technic:constructor_mk1_off'}, + +}) + +minetest.register_craft({ + type = "shapeless", + output = 'technic:constructor_mk3_off 1', + recipe = {'technic:constructor_mk2_off', 'technic:constructor_mk2_off'}, + +}) + +local function make_on(mark, length) + return function(pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local dir = vector.new() + if node.param2 == 3 then dir.x = 1 end + if node.param2 == 2 then dir.z = 1 end + if node.param2 == 1 then dir.x = -1 end + if node.param2 == 0 then dir.z = -1 end + + local place_pos = vector.new(pos) + + if node.name == "technic:constructor_mk"..mark.."_off" then + technic.swap_node(pos, "technic:constructor_mk"..mark.."_on") + nodeupdate(pos) + for i = 1, length do + place_pos = vector.add(place_pos, dir) + local place_node = minetest.get_node(place_pos) + deploy_node(inv, "slot"..i, place_pos, place_node, node) + end + end + end +end + +local function make_off(mark) + return function(pos, node) + if node.name == "technic:constructor_mk"..mark.."_on" then + technic.swap_node(pos,"technic:constructor_mk"..mark.."_off") + nodeupdate(pos) + end + end +end + + +local function make_constructor(mark, length) + minetest.register_node("technic:constructor_mk"..mark.."_off", { + description = S("Constructor Mk%d"):format(mark), + tiles = {"technic_constructor_mk"..mark.."_top_off.png", + "technic_constructor_mk"..mark.."_bottom_off.png", + "technic_constructor_mk"..mark.."_side2_off.png", + "technic_constructor_mk"..mark.."_side1_off.png", + "technic_constructor_back.png", + "technic_constructor_front_off.png"}, + paramtype2 = "facedir", + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, mesecon = 2}, + mesecons = {effector = {action_on = make_on(mark, length)}}, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local formspec = "size[8,9;]".. + "label[0,0;"..S("Constructor Mk%d"):format(mark).."]".. + "list[current_player;main;0,5;8,4;]" + for i = 1, length do + formspec = formspec + .."label[5,"..(i - 1)..";"..S("Slot %d"):format(i).."]" + .."list[current_name;slot"..i + ..";6,"..(i - 1)..";1,1;]" + end + meta:set_string("formspec", formspec) + meta:set_string("infotext", S("Constructor Mk%d"):format(mark)) + local inv = meta:get_inventory() + for i = 1, length do + inv:set_size("slot"..i, 1) + end + end, + can_dig = function(pos, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + for i = 1, length do + if not inv:is_empty("slot"..i) then + return false + end + end + return true + 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, + }) + + minetest.register_node("technic:constructor_mk"..mark.."_on", { + tiles = {"technic_constructor_mk"..mark.."_top_on.png", + "technic_constructor_mk"..mark.."_bottom_on.png", + "technic_constructor_mk"..mark.."_side2_on.png", + "technic_constructor_mk"..mark.."_side1_on.png", + "technic_constructor_back.png", + "technic_constructor_front_on.png"}, + paramtype2 = "facedir", + drop = "technic:constructor_mk"..mark.."_off", + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, + mesecon=2, not_in_creative_inventory=1}, + mesecons= {effector = {action_off = make_off(mark)}}, + sounds = default.node_sound_stone_defaults(), + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + }) +end + +make_constructor(1, 1) +make_constructor(2, 2) +make_constructor(3, 4) + diff --git a/technic/machines/other/frames.lua b/technic/machines/other/frames.lua new file mode 100644 index 0000000..b3f39b9 --- /dev/null +++ b/technic/machines/other/frames.lua @@ -0,0 +1,928 @@ + +local S = technic.getter + +frames = {} + +local infinite_stacks = minetest.setting_getbool("creative_mode") and minetest.get_modpath("unified_inventory") == nil + +local frames_pos = {} + +-- Helpers + +local function get_face(pos,ppos,pvect) + -- Raytracer to get which face has been clicked + ppos={x=ppos.x-pos.x,y=ppos.y-pos.y+1.5,z=ppos.z-pos.z} + if pvect.x>0 then + local t=(-0.5-ppos.x)/pvect.x + local y_int=ppos.y+t*pvect.y + local z_int=ppos.z+t*pvect.z + if y_int>-0.45 and y_int<0.45 and z_int>-0.45 and z_int<0.45 then return 1 end + elseif pvect.x<0 then + local t=(0.5-ppos.x)/pvect.x + local y_int=ppos.y+t*pvect.y + local z_int=ppos.z+t*pvect.z + if y_int>-0.45 and y_int<0.45 and z_int>-0.45 and z_int<0.45 then return 2 end + end + if pvect.y>0 then + local t=(-0.5-ppos.y)/pvect.y + local x_int=ppos.x+t*pvect.x + local z_int=ppos.z+t*pvect.z + if x_int>-0.45 and x_int<0.45 and z_int>-0.45 and z_int<0.45 then return 3 end + elseif pvect.y<0 then + local t=(0.5-ppos.y)/pvect.y + local x_int=ppos.x+t*pvect.x + local z_int=ppos.z+t*pvect.z + if x_int>-0.45 and x_int<0.45 and z_int>-0.45 and z_int<0.45 then return 4 end + end + if pvect.z>0 then + local t=(-0.5-ppos.z)/pvect.z + local x_int=ppos.x+t*pvect.x + local y_int=ppos.y+t*pvect.y + if x_int>-0.45 and x_int<0.45 and y_int>-0.45 and y_int<0.45 then return 5 end + elseif pvect.z<0 then + local t=(0.5-ppos.z)/pvect.z + local x_int=ppos.x+t*pvect.x + local y_int=ppos.y+t*pvect.y + if x_int>-0.45 and x_int<0.45 and y_int>-0.45 and y_int<0.45 then return 6 end + end +end + +local function lines(str) + local t = {} + local function helper(line) table.insert(t, line) return "" end + helper((str:gsub("(.-)\r?\n", helper))) + return t +end + +local function pos_to_string(pos) + if pos.x == 0 then pos.x = 0 end -- Fix for signed 0 + if pos.y == 0 then pos.y = 0 end -- Fix for signed 0 + if pos.z == 0 then pos.z = 0 end -- Fix for signed 0 + return tostring(pos.x).."\n"..tostring(pos.y).."\n"..tostring(pos.z) +end + +local function pos_from_string(str) + local l = lines(str) + return {x = tonumber(l[1]), y = tonumber(l[2]), z = tonumber(l[3])} +end + +local function pos_in_list(l,pos) + for _,p in ipairs(l) do + if p.x==pos.x and p.y==pos.y and p.z==pos.z then return true end + end + return false +end + +local function table_empty(table) + for _, __ in pairs(table) do + return false + end + return true +end + +local function add_table(table,toadd) + local i = 1 + while true do + o = table[i] + if o == toadd then return end + if o == nil then break end + i = i+1 + end + table[i] = toadd +end + +local function move_nodes_vect(poslist,vect,must_not_move,owner) + if minetest.is_protected then + for _,pos in ipairs(poslist) do + local npos=vector.add(pos,vect) + if minetest.is_protected(pos, owner) or minetest.is_protected(npos, owner) then + return + end + end + end + for _,pos in ipairs(poslist) do + local npos=vector.add(pos,vect) + local name = minetest.get_node(npos).name + if ((name~="air" and minetest.registered_nodes[name].liquidtype=="none") or frames_pos[pos_to_string(npos)]) and not(pos_in_list(poslist,npos)) then + return + end + --[[if pos.x==must_not_move.x and pos.y==must_not_move.y and pos.z==must_not_move.z then + return + end]] + end + local nodelist = {} + for _, pos in ipairs(poslist) do + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos):to_table() + nodelist[#(nodelist)+1] = {oldpos = pos, pos = vector.add(pos, vect), node = node, meta = meta} + end + local objects = {} + for _, pos in ipairs(poslist) do + for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do + local entity = object:get_luaentity() + if not entity or not mesecon.is_mvps_unmov(entity.name) then + add_table(objects, object) + end + end + end + for _, obj in ipairs(objects) do + obj:setpos(vector.add(obj:getpos(), vect)) + end + for _,n in ipairs(nodelist) do + local npos = n.pos + minetest.set_node(npos, n.node) + local meta = minetest.get_meta(npos) + meta:from_table(n.meta) + for __,pos in ipairs(poslist) do + if npos.x == pos.x and npos.y == pos.y and npos.z == pos.z then + table.remove(poslist, __) + break + end + end + end + for __, pos in ipairs(poslist) do + minetest.remove_node(pos) + end + for _, callback in ipairs(mesecon.on_mvps_move) do + callback(nodelist) + end +end + +local function is_supported_node(name) + return ((string.find(name, "tube") ~= nil) and (string.find(name, "pipeworks") ~= nil)) +end + + +-- Frames +for xm=0,1 do +for xp=0,1 do +for ym=0,1 do +for yp=0,1 do +for zm=0,1 do +for zp=0,1 do + +local a=8/16 +local b=7/16 +local nodeboxes= { + { -a, -a, -a, -b, a, -b }, + { -a, -a, b, -b, a, a }, + { b, -a, b, a, a, a }, + { b, -a, -a, a, a, -b }, + + { -b, b, -a, b, a, -b }, + { -b, -a, -a, b, -b, -b }, + + { -b, b, b, b, a, a }, + { -b, -a, b, b, -b, a }, + + { b, b, -b, a, a, b }, + { b, -a, -b, a, -b, b }, + + { -a, b, -b, -b, a, b }, + { -a, -a, -b, -b, -b, b }, + } + + if yp==0 then + table.insert(nodeboxes, {-b,b,-b, b,a,b}) + end + if ym==0 then + table.insert(nodeboxes, {-b,-a,-b, b,-b,b}) + end + if xp==0 then + table.insert(nodeboxes, {b,b,b,a,-b,-b}) + end + if xm==0 then + table.insert(nodeboxes, {-a,-b,-b,-b,b,b}) + end + if zp==0 then + table.insert(nodeboxes, {-b,-b,b, b,b,a}) + end + if zm==0 then + table.insert(nodeboxes, {-b,-b,-a, b,b,-b}) + end + + local nameext=tostring(xm)..tostring(xp)..tostring(ym)..tostring(yp)..tostring(zm)..tostring(zp) + local groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2} + if nameext~="111111" then groups.not_in_creative_inventory=1 end + + + minetest.register_node("technic:frame_"..nameext,{ + description = S("Frame"), + tiles = {"technic_frame.png"}, + groups=groups, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed=nodeboxes, + }, + selection_box = { + type="fixed", + fixed={-0.5,-0.5,-0.5,0.5,0.5,0.5} + }, + paramtype = "light", + frame=1, + drop="technic:frame_111111", + sunlight_propagates = true, + frame_connect_all=function(nodename) + l2={} + l1={{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}} + for i,dir in ipairs(l1) do + if string.sub(nodename,-7+i,-7+i)=="1" then + l2[#(l2)+1]=dir + end + end + return l2 + end, + on_punch=function(pos,node,puncher) + local ppos=puncher:getpos() + local pvect=puncher:get_look_dir() + local pface=get_face(pos,ppos,pvect) + if pface==nil then return end + local nodename=node.name + local newstate=tostring(1-tonumber(string.sub(nodename,-7+pface,-7+pface))) + if pface<=5 then + nodename=string.sub(nodename,1,-7+pface-1)..newstate..string.sub(nodename,-7+pface+1) + else + nodename=string.sub(nodename,1,-2)..newstate + end + node.name=nodename + minetest.set_node(pos,node) + end, + on_place = function(itemstack, placer, pointed_thing) + local pos = pointed_thing.above + if minetest.is_protected(pos, placer:get_player_name()) then + minetest.log("action", placer:get_player_name() + .. " tried to place " .. itemstack:get_name() + .. " at protected position " + .. minetest.pos_to_string(pos)) + minetest.record_protection_violation(pos, placer:get_player_name()) + return itemstack + end + if pos == nil then return end + local node = minetest.get_node(pos) + if node.name ~= "air" then + if is_supported_node(node.name) then + obj = minetest.add_entity(pos, "technic:frame_entity") + obj:get_luaentity():set_node({name=itemstack:get_name()}) + end + else + minetest.set_node(pos, {name = itemstack:get_name()}) + end + if not infinite_stacks then + itemstack:take_item() + end + return itemstack + end, + on_rightclick = function(pos, node, placer, itemstack, pointed_thing) + if is_supported_node(itemstack:get_name()) then + if minetest.is_protected(pos, placer:get_player_name()) then + minetest.log("action", placer:get_player_name() + .. " tried to place " .. itemstack:get_name() + .. " at protected position " + .. minetest.pos_to_string(pos)) + minetest.record_protection_violation(pos, placer:get_player_name()) + return itemstack + end + + minetest.set_node(pos, {name = itemstack:get_name()}) + + local take_item = true + local def = minetest.registered_items[itemstack:get_name()] + -- Run callback + if def.after_place_node then + -- Copy place_to because callback can modify it + local pos_copy = {x=pos.x, y=pos.y, z=pos.z} + if def.after_place_node(pos_copy, placer, itemstack) then + take_item = false + end + end + + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_placenodes) do + -- Copy pos and node because callback can modify them + local pos_copy = {x=pos.x, y=pos.y, z=pos.z} + local newnode_copy = {name=def.name, param1=0, param2=0} + local oldnode_copy = {name="air", param1=0, param2=0} + if callback(pos_copy, newnode_copy, placer, oldnode_copy, itemstack) then + take_item = false + end + end + + if take_item then + itemstack:take_item() + end + + obj = minetest.add_entity(pos, "technic:frame_entity") + obj:get_luaentity():set_node({name=node.name}) + + return itemstack + else + --local pointed_thing = {type = "node", under = pos} + if pointed_thing then + minetest.item_place_node(itemstack, placer, pointed_thing) + end + end + end, + }) + +end +end +end +end +end +end + +minetest.register_entity("technic:frame_entity", { + initial_properties = { + physical = true, + collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, + visual = "wielditem", + textures = {}, + visual_size = {x=0.667, y=0.667}, + }, + + node = {}, + + set_node = function(self, node) + self.node = node + local pos = self.object:getpos() + pos = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)} + frames_pos[pos_to_string(pos)] = node.name + local stack = ItemStack(node.name) + local itemtable = stack:to_table() + local itemname = nil + if itemtable then + itemname = stack:to_table().name + end + local item_texture = nil + local item_type = "" + if minetest.registered_items[itemname] then + item_texture = minetest.registered_items[itemname].inventory_image + item_type = minetest.registered_items[itemname].type + end + prop = { + is_visible = true, + textures = {node.name}, + } + self.object:set_properties(prop) + end, + + get_staticdata = function(self) + return self.node.name + end, + + on_activate = function(self, staticdata) + self.object:set_armor_groups({immortal=1}) + self:set_node({name=staticdata}) + end, + + dig = function(self) + minetest.handle_node_drops(self.object:getpos(), {ItemStack("technic:frame_111111")}, self.last_puncher) + local pos = self.object:getpos() + pos = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)} + frames_pos[pos_to_string(pos)] = nil + self.object:remove() + end, + + on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) + local pos = self.object:getpos() + if self.damage_object == nil then + self.damage_object = minetest.add_entity(pos, "technic:damage_entity") + self.damage_object:get_luaentity().remaining_time = 0.25 + self.damage_object:get_luaentity().frame_object = self + self.damage_object:get_luaentity().texture_index = 0 + self.damage_object:get_luaentity().texture_change_time = 0.15 + else + self.damage_object:get_luaentity().remaining_time = 0.25 + end + self.last_puncher = puncher + local ppos = puncher:getpos() + local pvect = puncher:get_look_dir() + local pface = get_face(pos,ppos,pvect) + if pface == nil then return end + local nodename = self.node.name + local newstate = tostring(1-tonumber(string.sub(nodename, -7+pface, -7+pface))) + if pface <= 5 then + nodename = string.sub(nodename, 1, -7+pface-1)..newstate..string.sub(nodename, -7+pface+1) + else + nodename = string.sub(nodename, 1, -2)..newstate + end + self.node.name = nodename + self:set_node(self.node) + end, + + on_rightclick = function(self, clicker) + local pos = self.object:getpos() + local ppos = clicker:getpos() + local pvect = clicker:get_look_dir() + local pface = get_face(pos, ppos, pvect) + if pface == nil then return end + local pos_under = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)} + local pos_above = {x = pos_under.x, y = pos_under.y, z = pos_under.z} + local index = ({"x", "y", "z"})[math.floor((pface+1)/2)] + pos_above[index] = pos_above[index] + 2*((pface+1)%2) - 1 + local pointed_thing = {type = "node", under = pos_under, above = pos_above} + local itemstack = clicker:get_wielded_item() + local itemdef = minetest.registered_items[itemstack:get_name()] + if itemdef ~= nil then + itemdef.on_place(itemstack, clicker, pointed_thing) + end + end, +}) + +local crack = "crack_anylength.png^[verticalframe:5:0" +minetest.register_entity("technic:damage_entity", { + initial_properties = { + visual = "cube", + visual_size = {x=1.01, y=1.01}, + textures = {crack, crack, crack, crack, crack, crack}, + collisionbox = {0, 0, 0, 0, 0, 0}, + physical = false, + }, + on_step = function(self, dtime) + if self.remaining_time == nil then + self.object:remove() + self.frame_object.damage_object = nil + end + self.remaining_time = self.remaining_time - dtime + if self.remaining_time < 0 then + self.object:remove() + self.frame_object.damage_object = nil + end + self.texture_change_time = self.texture_change_time - dtime + if self.texture_change_time < 0 then + self.texture_change_time = self.texture_change_time + 0.15 + self.texture_index = self.texture_index + 1 + if self.texture_index == 5 then + self.object:remove() + self.frame_object.damage_object = nil + self.frame_object:dig() + end + local ct = "crack_anylength.png^[verticalframe:5:"..self.texture_index + self.object:set_properties({textures = {ct, ct, ct, ct, ct, ct}}) + end + end, +}) + +mesecon.register_mvps_unmov("technic:frame_entity") +mesecon.register_mvps_unmov("technic:damage_entity") +mesecon.register_on_mvps_move(function(moved_nodes) + local to_move = {} + for _, n in ipairs(moved_nodes) do + if frames_pos[pos_to_string(n.oldpos)] ~= nil then + to_move[#to_move+1] = {pos = n.pos, oldpos = n.oldpos, name = frames_pos[pos_to_string(n.oldpos)]} + frames_pos[pos_to_string(n.oldpos)] = nil + end + end + if #to_move > 0 then + for _, t in ipairs(to_move) do + frames_pos[pos_to_string(t.pos)] = t.name + local objects = minetest.get_objects_inside_radius(t.oldpos, 0.1) + for _, obj in ipairs(objects) do + local entity = obj:get_luaentity() + if entity and (entity.name == "technic:frame_entity" or entity.name == "technic:damage_entity") then + obj:setpos(t.pos) + end + end + end + end +end) + +minetest.register_on_dignode(function(pos, node) + if frames_pos[pos_to_string(pos)] ~= nil then + minetest.set_node(pos, {name = frames_pos[pos_to_string(pos)]}) + frames_pos[pos_to_string(pos)] = nil + local objects = minetest.get_objects_inside_radius(pos, 0.1) + for _, obj in ipairs(objects) do + local entity = obj:get_luaentity() + if entity and (entity.name == "technic:frame_entity" or entity.name == "technic:damage_entity") then + obj:remove() + end + end + end +end) + +-- Frame motor +local function connected(pos,c,adj) + for _,vect in ipairs(adj) do + local pos1=vector.add(pos,vect) + local nodename=minetest.get_node(pos1).name + if frames_pos[pos_to_string(pos1)] then + nodename = frames_pos[pos_to_string(pos1)] + end + if not(pos_in_list(c,pos1)) and nodename~="air" and + (minetest.registered_nodes[nodename].frames_can_connect==nil or + minetest.registered_nodes[nodename].frames_can_connect(pos1,vect)) then + c[#(c)+1]=pos1 + if minetest.registered_nodes[nodename].frame==1 then + local adj=minetest.registered_nodes[nodename].frame_connect_all(nodename) + connected(pos1,c,adj) + end + end + end +end + +local function get_connected_nodes(pos) + c={pos} + local nodename=minetest.get_node(pos).name + if frames_pos[pos_to_string(pos)] then + nodename = frames_pos[pos_to_string(pos)] + end + connected(pos,c,minetest.registered_nodes[nodename].frame_connect_all(nodename)) + return c +end + +local function frame_motor_on(pos, node) + local dirs = {{x=0,y=1,z=0},{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=-1,z=0}} + local nnodepos = vector.add(pos, dirs[math.floor(node.param2/4)+1]) + local dir = minetest.facedir_to_dir(node.param2) + local nnode=minetest.get_node(nnodepos) + if frames_pos[pos_to_string(nnodepos)] then + nnode.name = frames_pos[pos_to_string(nnodepos)] + end + local meta = minetest.get_meta(pos) + if meta:get_int("last_moved") == minetest.get_gametime() then + return + end + local owner = meta:get_string("owner") + if minetest.registered_nodes[nnode.name].frame==1 then + local connected_nodes=get_connected_nodes(nnodepos) + move_nodes_vect(connected_nodes,dir,pos,owner) + end + minetest.get_meta(vector.add(pos, dir)):set_int("last_moved", minetest.get_gametime()) +end + +minetest.register_node("technic:frame_motor",{ + description = S("Frame Motor"), + tiles = {"pipeworks_filter_top.png^[transformR90", "technic_lv_cable.png", "technic_lv_cable.png", + "technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"}, + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,mesecon=2}, + paramtype2 = "facedir", + mesecons={effector={action_on=frame_motor_on}}, + after_place_node = function(pos, placer, itemstack) + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + end, + frames_can_connect=function(pos,dir) + local node = minetest.get_node(pos) + local dir2 = ({{x=0,y=1,z=0},{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=-1,z=0}})[math.floor(node.param2/4)+1] + return dir2.x~=-dir.x or dir2.y~=-dir.y or dir2.z~=-dir.z + end +}) + + + +-- Templates +local function template_connected(pos,c,connectors) + for _,vect in ipairs({{x=0,y=1,z=0},{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=-1,z=0}}) do + local pos1=vector.add(pos,vect) + local nodename=minetest.get_node(pos1).name + if not(pos_in_list(c,pos1)) and (nodename=="technic:template" or nodename == "technic:template_connector")then + local meta = minetest.get_meta(pos1) + if meta:get_string("connected") == "" then + c[#(c)+1]=pos1 + template_connected(pos1,c,connectors) + if nodename == "technic:template_connector" then + connectors[#connectors+1] = pos1 + end + end + end + end +end + +local function get_templates(pos) + local c = {pos} + local connectors + if minetest.get_node(pos).name == "technic:template_connector" then + connectors = {pos} + else + connectors = {} + end + template_connected(pos,c,connectors) + return c, connectors +end + +local function swap_template(pos, new) + local meta = minetest.get_meta(pos) + local saved_node = meta:get_string("saved_node") + meta:set_string("saved_node", "") + technic.swap_node(pos, new) + local meta = minetest.get_meta(pos) + meta:set_string("saved_node", saved_node) +end + +local function save_node(pos) + local node = minetest.get_node(pos) + if node.name == "air" then + minetest.set_node(pos, {name="technic:template"}) + return + end + if node.name == "technic:template" then + swap_template(pos, "technic:template_connector") + local meta = minetest.get_meta(pos) + meta:set_string("connected", "") + return + end + local meta = minetest.get_meta(pos) + local meta0 = meta:to_table() + for _, list in pairs(meta0.inventory) do + for key, stack in pairs(list) do + list[key] = stack:to_string() + end + end + node.meta = meta0 + minetest.set_node(pos, {name="technic:template"}) + return node +end + +local function restore_node(pos, node) + minetest.set_node(pos, node) + local meta = minetest.get_meta(pos) + for _, list in pairs(node.meta.inventory) do + for key, stack in pairs(list) do + list[key] = ItemStack(stack) + end + end + meta:from_table(node.meta) +end + +local function expand_template(pos) + local meta = minetest.get_meta(pos) + local c = meta:get_string("connected") + if c == "" then return end + c = minetest.deserialize(c) + for _, vect in ipairs(c) do + local pos1 = vector.add(pos, vect) + local saved_node = save_node(pos1) + local meta1 = minetest.get_meta(pos1) + if saved_node ~= nil then + meta1:set_string("saved_node", minetest.serialize(saved_node)) + else + --meta1:set_string("saved_node", "") + end + end +end + +local function compress_templates(pos) + local templates, connectors = get_templates(pos) + if #connectors == 0 then + connectors = {pos} + end + for _, cn in ipairs(connectors) do + local meta = minetest.get_meta(cn) + local c = {} + for _,p in ipairs(templates) do + local np = vector.subtract(p, cn) + if not pos_in_list(c,np) then + c[#c+1] = np + end + end + local cc = {} + for _,p in ipairs(connectors) do + local np = vector.subtract(p, cn) + if (np.x ~= 0 or np.y ~= 0 or np.z ~= 0) then + cc[pos_to_string(np)] = true + end + end + swap_template(cn, "technic:template") + meta:set_string("connected", minetest.serialize(c)) + meta:set_string("connectors_connected", minetest.serialize(cc)) + end + + for _,p in ipairs(templates) do + if not pos_in_list(connectors, p) then + minetest.set_node(p, {name = "air"}) + end + end +end + +local function template_drops(pos, node, oldmeta, digger) + local c = oldmeta.fields.connected + local cc = oldmeta.fields.connectors_connected + local drops + if c == "" or c == nil then + drops = {"technic:template 1"} + else + if cc == "" or cc == nil then + drops = {"technic:template 1"} + else + local dcc = minetest.deserialize(cc) + if not table_empty(dcc) then + drops = {} + for sp, _ in pairs(dcc) do + local ssp = pos_from_string(sp) + local p = vector.add(ssp, pos) + local meta = minetest.get_meta(p) + local d = minetest.deserialize(meta:get_string("connectors_connected")) + if d ~= nil then + d[pos_to_string({x=-ssp.x, y=-ssp.y, z=-ssp.z})] = nil + meta:set_string("connectors_connected", minetest.serialize(d)) + end + end + else + local stack_max = 99 + local num = #(minetest.deserialize(c)) + drops = {} + while num > stack_max do + drops[#drops+1] = "technic:template "..stack_max + num = num - stack_max + end + drops[#drops+1] = "technic:template "..num + end + end + end + minetest.handle_node_drops(pos, drops, digger) +end + +local function template_on_destruct(pos, node) + local meta = minetest.get_meta(pos) + local saved_node = meta:get_string("saved_node") + if saved_node ~= "" then + local nnode = minetest.deserialize(saved_node) + minetest.after(0, restore_node, pos, nnode) + end +end + +minetest.register_node("technic:template",{ + description = S("Template"), + tiles = {"technic_mv_cable.png"}, + drop = "", + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}, + on_destruct = template_on_destruct, + after_dig_node = template_drops, + on_punch = function(pos,node,puncher) + swap_template(pos, "technic:template_disabled") + end +}) + +minetest.register_node("technic:template_disabled",{ + description = S("Template"), + tiles = {"technic_hv_cable.png"}, + drop = "", + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1}, + on_destruct = template_on_destruct, + after_dig_node = template_drops, + on_punch = function(pos,node,puncher) + local meta = minetest.get_meta(pos) + swap_template(pos, "technic:template_connector") + end +}) + +minetest.register_node("technic:template_connector",{ + description = S("Template"), + tiles = {"technic_lv_cable.png"}, + drop = "", + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1}, + on_destruct = template_on_destruct, + after_dig_node = template_drops, + on_punch = function(pos,node,puncher) + swap_template(pos, "technic:template") + end +}) + +minetest.register_craftitem("technic:template_replacer",{ + description = S("Template (replacing)"), + inventory_image = "technic_template_replacer.png", + on_place = function(itemstack, placer, pointed_thing) + local p = pointed_thing.under + if minetest.is_protected and minetest.is_protected(p, placer:get_player_name()) then + return nil + end + local node = minetest.get_node(p) + if node.name == "technic:template" then return end + local saved_node = save_node(p) + itemstack:take_item() + if saved_node ~= nil then + local meta = minetest.get_meta(p) + meta:set_string("saved_node", minetest.serialize(saved_node)) + end + return itemstack + end +}) + +minetest.register_tool("technic:template_tool",{ + description = S("Template Tool"), + inventory_image = "technic_template_tool.png", + on_use = function(itemstack, puncher, pointed_thing) + local pos = pointed_thing.under + if pos == nil or (minetest.is_protected and minetest.is_protected(pos, puncher:get_player_name())) then + return nil + end + local node = minetest.get_node(pos) + if node.name ~= "technic:template" and node.name ~= "technic:template_connector" then return end + local meta = minetest.get_meta(pos) + local c2 = meta:get_string("connected") + if c2 ~= "" then + expand_template(pos) + else + compress_templates(pos) + end + + end +}) + + + +-- Template motor +local function get_template_nodes(pos) + local meta = minetest.get_meta(pos) + local connected = meta:get_string("connected") + if connected == "" then return {} end + local adj = minetest.deserialize(connected) + local c = {} + for _,vect in ipairs(adj) do + local pos1=vector.add(pos,vect) + local nodename=minetest.get_node(pos1).name + if not(pos_in_list(c,pos1)) and nodename~="air" then + c[#(c)+1]=pos1 + end + end + return c +end + +local function template_motor_on(pos, node) + local dirs = {{x=0,y=1,z=0},{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=-1,z=0}} + local nnodepos = vector.add(pos, dirs[math.floor(node.param2/4)+1]) + local dir = minetest.facedir_to_dir(node.param2) + local nnode=minetest.get_node(nnodepos) + local meta = minetest.get_meta(pos) + if meta:get_int("last_moved") == minetest.get_gametime() then + return + end + local owner = meta:get_string("owner") + if nnode.name == "technic:template" then + local connected_nodes=get_template_nodes(nnodepos) + move_nodes_vect(connected_nodes,dir,pos,owner) + end + minetest.get_meta(vector.add(pos, dir)):set_int("last_moved", minetest.get_gametime()) +end + +minetest.register_node("technic:template_motor",{ + description = S("Template Motor"), + tiles = {"pipeworks_filter_top.png^[transformR90", "technic_lv_cable.png", "technic_lv_cable.png", + "technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"}, + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,mesecon=2}, + paramtype2 = "facedir", + mesecons={effector={action_on=template_motor_on}}, + after_place_node = function(pos, placer, itemstack) + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + end, +}) + +-- Crafts +minetest.register_craft({ + output = 'technic:frame_111111', + recipe = { + {'', 'default:stick', ''}, + {'default:stick', 'technic:brass_ingot', 'default:stick'}, + {'', 'default:stick', ''}, + } +}) + +minetest.register_craft({ + output = 'technic:frame_motor', + recipe = { + {'', 'technic:frame_111111', ''}, + {'group:mesecon_conductor_craftable', 'technic:motor', 'group:mesecon_conductor_craftable'}, + {'', 'technic:frame_111111', ''}, + } +}) + +minetest.register_craft({ + output = 'technic:template 10', + recipe = { + {'', 'technic:brass_ingot', ''}, + {'technic:brass_ingot', 'default:mese_crystal', 'technic:brass_ingot'}, + {'', 'technic:brass_ingot', ''}, + } +}) + +minetest.register_craft({ + output = 'technic:template_replacer', + recipe = {{'technic:template'}} +}) + +minetest.register_craft({ + output = 'technic:template', + recipe = {{'technic:template_replacer'}} +}) + +minetest.register_craft({ + output = 'technic:template_motor', + recipe = { + {'', 'technic:template', ''}, + {'group:mesecon_conductor_craftable', 'technic:motor', 'group:mesecon_conductor_craftable'}, + {'', 'technic:template', ''}, + } +}) + +minetest.register_craft({ + output = 'technic:template_tool', + recipe = { + {'', 'technic:template', ''}, + {'default:mese_crystal', 'default:stick', 'default:mese_crystal'}, + {'', 'default:stick', ''}, + } +}) diff --git a/technic/machines/other/init.lua b/technic/machines/other/init.lua new file mode 100644 index 0000000..f4a82f0 --- /dev/null +++ b/technic/machines/other/init.lua @@ -0,0 +1,15 @@ +local path = technic.modpath.."/machines/other" + +-- mesecons and tubes related +dofile(path.."/injector.lua") +dofile(path.."/constructor.lua") + +if technic.config:get_bool("enable_frames") and minetest.get_modpath("mesecons_mvps") ~= nil then + dofile(path.."/frames.lua") +end + +-- Coal-powered machines +dofile(path.."/coal_alloy_furnace.lua") +dofile(path.."/coal_furnace.lua") + +dofile(path.."/anchor.lua") diff --git a/technic/machines/other/injector.lua b/technic/machines/other/injector.lua new file mode 100644 index 0000000..ec8966c --- /dev/null +++ b/technic/machines/other/injector.lua @@ -0,0 +1,118 @@ + +local S = technic.getter + +local function inject_items (pos) + local meta=minetest.get_meta(pos) + local inv = meta:get_inventory() + local mode=meta:get_string("mode") + if mode=="single items" then + local i=0 + for _,stack in ipairs(inv:get_list("main")) do + i=i+1 + if stack then + local item0=stack:to_table() + if item0 then + item0["count"] = "1" + technic.tube_inject_item(pos, pos, vector.new(0, -1, 0), item0) + stack:take_item(1) + inv:set_stack("main", i, stack) + return + end + end + end + end + if mode=="whole stacks" then + local i=0 + for _,stack in ipairs(inv:get_list("main")) do + i=i+1 + if stack then + local item0=stack:to_table() + if item0 then + technic.tube_inject_item(pos, pos, vector.new(0, -1, 0), item0) + stack:clear() + inv:set_stack("main", i, stack) + return + end + end + end + end + +end + +minetest.register_craft({ + output = 'technic:injector 1', + recipe = { + {'', 'technic:control_logic_unit',''}, + {'', 'default:chest',''}, + {'', 'pipeworks:tube_1',''}, + } +}) + +local function set_injector_formspec(meta) + local is_stack = meta:get_string("mode") == "whole stacks" + meta:set_string("formspec", + "invsize[8,9;]".. + "item_image[0,0;1,1;technic:injector]".. + "label[1,0;"..S("Self-Contained Injector").."]".. + (is_stack and + "button[0,1;2,1;mode_item;"..S("Stackwise").."]" or + "button[0,1;2,1;mode_stack;"..S("Itemwise").."]").. + "list[current_name;main;0,2;8,2;]".. + "list[current_player;main;0,5;8,4;]".. + "listring[]") +end + +minetest.register_node("technic:injector", { + description = S("Self-Contained Injector"), + tiles = {"technic_injector_top.png", "technic_injector_bottom.png", "technic_injector_side.png", + "technic_injector_side.png", "technic_injector_side.png", "technic_injector_side.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, tubedevice=1, tubedevice_receiver=1}, + tube = { + can_insert = function(pos, node, stack, direction) + return minetest.get_meta(pos):get_inventory():room_for_item("main",stack) + end, + insert_object = function(pos, node, stack, direction) + return minetest.get_meta(pos):get_inventory():add_item("main",stack) + end, + connect_sides = {left=1, right=1, front=1, back=1, top=1, bottom=1}, + }, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("Self-Contained Injector")) + local inv = meta:get_inventory() + inv:set_size("main", 8*4) + meta:set_string("mode","single items") + set_injector_formspec(meta) + end, + can_dig = function(pos,player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("main") + end, + on_receive_fields = function(pos, formanme, fields, sender) + local meta = minetest.get_meta(pos) + if fields.mode_item then meta:set_string("mode", "single items") end + if fields.mode_stack then meta:set_string("mode", "whole stacks") end + set_injector_formspec(meta) + 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, + after_place_node = pipeworks.after_place, + after_dig_node = pipeworks.after_dig +}) + +minetest.register_abm({ + nodenames = {"technic:injector"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local pos1 = vector.add(pos, vector.new(0, -1, 0)) + local node1 = minetest.get_node(pos1) + if minetest.get_item_group(node1.name, "tubedevice") > 0 then + inject_items(pos) + end + end, +}) + diff --git a/technic/machines/register/alloy_furnace.lua b/technic/machines/register/alloy_furnace.lua new file mode 100644 index 0000000..879e528 --- /dev/null +++ b/technic/machines/register/alloy_furnace.lua @@ -0,0 +1,10 @@ + +local S = technic.getter + +function technic.register_alloy_furnace(data) + data.typename = "alloy" + data.machine_name = "alloy_furnace" + data.machine_desc = S("%s Alloy Furnace") + technic.register_base_machine(data) +end + diff --git a/technic/machines/register/alloy_recipes.lua b/technic/machines/register/alloy_recipes.lua new file mode 100644 index 0000000..bd09bd6 --- /dev/null +++ b/technic/machines/register/alloy_recipes.lua @@ -0,0 +1,35 @@ + +local S = technic.getter + +technic.register_recipe_type("alloy", { + description = S("Alloying"), + input_size = 2, +}) + +function technic.register_alloy_recipe(data) + data.time = data.time or 6 + technic.register_recipe("alloy", data) +end + +local recipes = { + {"technic:copper_dust 3", "technic:tin_dust", "technic:bronze_dust 4"}, + {"default:copper_ingot 3", "moreores:tin_ingot", "default:bronze_ingot 4"}, + {"technic:wrought_iron_dust", "technic:coal_dust", "technic:carbon_steel_dust", 3}, + {"technic:wrought_iron_ingot", "technic:coal_dust", "technic:carbon_steel_ingot", 3}, + {"technic:carbon_steel_dust", "technic:coal_dust", "technic:cast_iron_dust", 3}, + {"technic:carbon_steel_ingot", "technic:coal_dust", "technic:cast_iron_ingot", 3}, + {"technic:carbon_steel_dust 3", "technic:chromium_dust", "technic:stainless_steel_dust 4"}, + {"technic:carbon_steel_ingot 3", "technic:chromium_ingot", "technic:stainless_steel_ingot 4"}, + {"technic:copper_dust 2", "technic:zinc_dust", "technic:brass_dust 3"}, + {"default:copper_ingot 2", "technic:zinc_ingot", "technic:brass_ingot 3"}, + {"default:sand 2", "technic:coal_dust 2", "technic:silicon_wafer"}, + {"technic:silicon_wafer", "technic:gold_dust", "technic:doped_silicon_wafer"}, + -- from https://en.wikipedia.org/wiki/Carbon_black + -- The highest volume use of carbon black is as a reinforcing filler in rubber products, especially tires. + -- "[Compounding a] pure gum vulcanizate … with 50% of its weight of carbon black improves its tensile strength and wear resistance …" + {"technic:raw_latex 4", "technic:coal_dust 2", "technic:rubber 6", 2}, +} + +for _, data in pairs(recipes) do + technic.register_alloy_recipe({input = {data[1], data[2]}, output = data[3], time = data[4]}) +end diff --git a/technic/machines/register/battery_box.lua b/technic/machines/register/battery_box.lua new file mode 100644 index 0000000..82edca0 --- /dev/null +++ b/technic/machines/register/battery_box.lua @@ -0,0 +1,291 @@ + +local S = technic.getter + +technic.register_power_tool("technic:battery", 10000) +technic.register_power_tool("technic:red_energy_crystal", 50000) +technic.register_power_tool("technic:green_energy_crystal", 150000) +technic.register_power_tool("technic:blue_energy_crystal", 450000) + +minetest.register_craft({ + output = 'technic:battery', + recipe = { + {'group:wood', 'default:copper_ingot', 'group:wood'}, + {'group:wood', 'moreores:tin_ingot', 'group:wood'}, + {'group:wood', 'default:copper_ingot', 'group:wood'}, + } +}) + +minetest.register_tool("technic:battery", { + description = S("RE Battery"), + inventory_image = "technic_battery.png", + wear_represents = "technic_RE_charge", + on_refill = technic.refill_RE_charge, + tool_capabilities = { + charge = 0, + max_drop_level = 0, + groupcaps = { + fleshy = {times={}, uses=10000, maxlevel=0} + } + } +}) + +local tube = { + insert_object = function(pos, node, stack, direction) + if direction.y == 0 then + return stack + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if direction.y > 0 then + return inv:add_item("src", stack) + else + return inv:add_item("dst", stack) + end + end, + can_insert = function(pos, node, stack, direction) + if direction.y == 0 then + return false + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if direction.y > 0 then + return inv:room_for_item("src", stack) + else + return inv:room_for_item("dst", stack) + end + end, + connect_sides = {left=1, right=1, back=1, top=1, bottom=1}, +} + +function technic.register_battery_box(data) + local tier = data.tier + local ltier = string.lower(tier) + + local formspec = + "invsize[8,9;]".. + "image[1,1;1,2;technic_power_meter_bg.png]".. + "list[current_name;src;3,1;1,1;]".. + "image[4,1;1,1;technic_battery_reload.png]".. + "list[current_name;dst;5,1;1,1;]".. + "label[0,0;"..S("%s Battery Box"):format(tier).."]".. + "label[3,0;"..S("Charge").."]".. + "label[5,0;"..S("Discharge").."]".. + "label[1,3;"..S("Power level").."]".. + "list[current_player;main;0,5;8,4;]".. + "listring[current_name;dst]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]" + + if data.upgrade then + formspec = formspec.. + "list[current_name;upgrade1;3.5,3;1,1;]".. + "list[current_name;upgrade2;4.5,3;1,1;]".. + "label[3.5,4;"..S("Upgrade Slots").."]".. + "listring[current_name;upgrade1]".. + "listring[current_player;main]".. + "listring[current_name;upgrade2]".. + "listring[current_player;main]" + end + + local run = function(pos, node) + local meta = minetest.get_meta(pos) + local eu_input = meta:get_int(tier.."_EU_input") + local current_charge = meta:get_int("internal_EU_charge") + + local EU_upgrade, tube_upgrade = 0, 0 + if data.upgrade then + EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta) + end + local max_charge = data.max_charge * (1 + EU_upgrade / 10) + + -- Charge/discharge the battery with the input EUs + if eu_input >= 0 then + current_charge = math.min(current_charge + eu_input, max_charge) + else + current_charge = math.max(current_charge + eu_input, 0) + end + + -- Charging/discharging tools here + local tool_full, tool_empty + current_charge, tool_full = technic.charge_tools(meta, + current_charge, data.charge_step) + current_charge, tool_empty = technic.discharge_tools(meta, + current_charge, data.discharge_step, + max_charge) + + if data.tube then + local inv = meta:get_inventory() + technic.handle_machine_pipeworks(pos, tube_upgrade, + function(pos, x_velocity, z_velocity) + if tool_full and not inv:is_empty("src") then + technic.send_items(pos, x_velocity, z_velocity, "src") + elseif tool_empty and not inv:is_empty("dst") then + technic.send_items(pos, x_velocity, z_velocity, "dst") + end + end) + end + + -- We allow batteries to charge on less than the demand + meta:set_int(tier.."_EU_demand", + math.min(data.charge_rate, max_charge - current_charge)) + meta:set_int(tier.."_EU_supply", + math.min(data.discharge_rate, current_charge)) + meta:set_int("internal_EU_charge", current_charge) + + -- Select node textures + local charge_count = math.ceil((current_charge / max_charge) * 8) + charge_count = math.min(charge_count, 8) + charge_count = math.max(charge_count, 0) + local last_count = meta:get_float("last_side_shown") + if charge_count ~= last_count then + technic.swap_node(pos,"technic:"..ltier.."_battery_box"..charge_count) + meta:set_float("last_side_shown", charge_count) + end + + local charge_percent = math.floor(current_charge / max_charge * 100) + meta:set_string("formspec", + formspec.. + "image[1,1;1,2;technic_power_meter_bg.png" + .."^[lowpart:"..charge_percent + ..":technic_power_meter_fg.png]") + + local infotext = S("@1 Battery Box: @2/@3", tier, + technic.prettynum(current_charge), technic.prettynum(max_charge)) + if eu_input == 0 then + infotext = S("%s Idle"):format(infotext) + end + meta:set_string("infotext", infotext) + end + + for i = 0, 8 do + local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1} + if i ~= 0 then + groups.not_in_creative_inventory = 1 + end + + if data.tube then + groups.tubedevice = 1 + groups.tubedevice_receiver = 1 + end + + minetest.register_node("technic:"..ltier.."_battery_box"..i, { + description = S("%s Battery Box"):format(tier), + tiles = {"technic_"..ltier.."_battery_box_top.png", + "technic_"..ltier.."_battery_box_bottom.png", + "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png", + "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png", + "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png", + "technic_"..ltier.."_battery_box_side.png^technic_power_meter"..i..".png"}, + groups = groups, + tube = data.tube and tube or nil, + paramtype2 = "facedir", + sounds = default.node_sound_wood_defaults(), + drop = "technic:"..ltier.."_battery_box0", + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local node = minetest.get_node(pos) + + meta:set_string("infotext", S("%s Battery Box"):format(tier)) + meta:set_string("formspec", formspec) + meta:set_int(tier.."_EU_demand", 0) + meta:set_int(tier.."_EU_supply", 0) + meta:set_int(tier.."_EU_input", 0) + meta:set_float("internal_EU_charge", 0) + inv:set_size("src", 1) + inv:set_size("dst", 1) + inv:set_size("upgrade1", 1) + inv:set_size("upgrade2", 1) + end, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + technic_run = run, + after_place_node = data.tube and pipeworks.after_place, + after_dig_node = technic.machine_after_dig_node + }) + end + + -- Register as a battery type + -- Battery type machines function as power reservoirs and can both receive and give back power + for i = 0, 8 do + technic.register_machine(tier, "technic:"..ltier.."_battery_box"..i, technic.battery) + end + +end -- End registration + + +function technic.charge_tools(meta, batt_charge, charge_step) + local inv = meta:get_inventory() + if inv:is_empty("src") then + return batt_charge, false + end + local src_stack = inv:get_stack("src", 1) + + local tool_name = src_stack:get_name() + if not technic.power_tools[tool_name] then + return batt_charge, false + end + -- Set meta data for the tool if it didn't do it itself + local src_meta = minetest.deserialize(src_stack:get_metadata()) or {} + if not src_meta.charge then + src_meta.charge = 0 + end + -- Do the charging + local item_max_charge = technic.power_tools[tool_name] + local tool_charge = src_meta.charge + if tool_charge >= item_max_charge then + return batt_charge, true + elseif batt_charge <= 0 then + return batt_charge, false + end + charge_step = math.min(charge_step, batt_charge) + charge_step = math.min(charge_step, item_max_charge - tool_charge) + tool_charge = tool_charge + charge_step + batt_charge = batt_charge - charge_step + technic.set_RE_wear(src_stack, tool_charge, item_max_charge) + src_meta.charge = tool_charge + src_stack:set_metadata(minetest.serialize(src_meta)) + inv:set_stack("src", 1, src_stack) + return batt_charge, (tool_charge == item_max_charge) +end + + +function technic.discharge_tools(meta, batt_charge, charge_step, max_charge) + local inv = meta:get_inventory() + if inv:is_empty("dst") then + return batt_charge, false + end + srcstack = inv:get_stack("dst", 1) + local toolname = srcstack:get_name() + if technic.power_tools[toolname] == nil then + return batt_charge, false + end + -- Set meta data for the tool if it didn't do it itself :-( + local src_meta = minetest.deserialize(srcstack:get_metadata()) + src_meta = src_meta or {} + if not src_meta.charge then + src_meta.charge = 0 + end + + -- Do the discharging + local item_max_charge = technic.power_tools[toolname] + local tool_charge = src_meta.charge + if tool_charge <= 0 then + return batt_charge, true + elseif batt_charge >= max_charge then + return batt_charge, false + end + charge_step = math.min(charge_step, max_charge - batt_charge) + charge_step = math.min(charge_step, tool_charge) + tool_charge = tool_charge - charge_step + batt_charge = batt_charge + charge_step + technic.set_RE_wear(srcstack, tool_charge, item_max_charge) + src_meta.charge = tool_charge + srcstack:set_metadata(minetest.serialize(src_meta)) + inv:set_stack("dst", 1, srcstack) + return batt_charge, (tool_charge == 0) +end + diff --git a/technic/machines/register/cables.lua b/technic/machines/register/cables.lua new file mode 100644 index 0000000..a1e7bc8 --- /dev/null +++ b/technic/machines/register/cables.lua @@ -0,0 +1,177 @@ + +local S = technic.getter + +local cable_itstr_to_tier = {} + +function technic.register_cable(tier, size) + local ltier = string.lower(tier) + + for x1 = 0, 1 do + for x2 = 0, 1 do + for y1 = 0, 1 do + for y2 = 0, 1 do + for z1 = 0, 1 do + for z2 = 0, 1 do + local id = technic.get_cable_id({x1, x2, y1, y2, z1, z2}) + + cable_itstr_to_tier["technic:"..ltier.."_cable"..id] = tier + + local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2} + if id ~= 0 then + groups.not_in_creative_inventory = 1 + end + + minetest.register_node("technic:"..ltier.."_cable"..id, { + description = S("%s Cable"):format(tier), + tiles = {"technic_"..ltier.."_cable.png"}, + inventory_image = "technic_"..ltier.."_cable_wield.png", + wield_image = "technic_"..ltier.."_cable_wield.png", + groups = groups, + sounds = default.node_sound_wood_defaults(), + drop = "technic:"..ltier.."_cable0", + paramtype = "light", + sunlight_propagates = true, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = technic.gen_cable_nodebox(x1, y1, z1, x2, y2, z2, size) + }, + on_construct = function() + technic.networks = {} + end, + on_destruct = function() + technic.networks = {} + end, + after_place_node = function(pos) + local node = minetest.get_node(pos) + technic.update_cables(pos, technic.get_cable_tier(node.name)) + end, + after_dig_node = function(pos, oldnode) + local tier = technic.get_cable_tier(oldnode.name) + technic.update_cables(pos, tier, true) + end + }) + end + end + end + end + end + end +end + +minetest.register_on_placenode(function(pos, node) + for tier, machine_list in pairs(technic.machines) do + if machine_list[node.name] ~= nil then + technic.update_cables(pos, tier, true) + technic.networks = {} + end + end +end) + + +minetest.register_on_dignode(function(pos, node) + for tier, machine_list in pairs(technic.machines) do + if machine_list[node.name] ~= nil then + technic.update_cables(pos, tier, true) + technic.networks = {} + end + end +end) + +function technic.get_cable_id(links) + return (links[6] * 1) + (links[5] * 2) + + (links[4] * 4) + (links[3] * 8) + + (links[2] * 16) + (links[1] * 32) +end + +function technic.update_cables(pos, tier, no_set, secondrun) + local link_positions = { + {x=pos.x+1, y=pos.y, z=pos.z}, + {x=pos.x-1, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y+1, z=pos.z}, + {x=pos.x, y=pos.y-1, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z+1}, + {x=pos.x, y=pos.y, z=pos.z-1}} + + local links = {0, 0, 0, 0, 0, 0} + + for i, link_pos in pairs(link_positions) do + local connect_type = technic.cables_should_connect(pos, link_pos, tier) + if connect_type then + links[i] = 1 + -- Have cables next to us update theirselves, + -- but only once. (We don't want to update the entire + -- network or start an infinite loop of updates) + if not secondrun and connect_type == "cable" then + technic.update_cables(link_pos, tier, false, true) + end + end + end + -- We don't want to set ourselves if we have been removed or we are + -- updating a machine + if not no_set then + minetest.set_node(pos, {name="technic:"..string.lower(tier) + .."_cable"..technic.get_cable_id(links)}) + + end +end + + +function technic.is_tier_cable(name, tier) + return cable_itstr_to_tier[name] and cable_itstr_to_tier[name] == tier +end + + +function technic.get_cable_tier(name) + return cable_itstr_to_tier[name] +end + + +function technic.cables_should_connect(pos1, pos2, tier) + local name = minetest.get_node(pos2).name + + if name == "technic:switching_station" then + return pos2.y == pos1.y + 1 and "machine" or false + elseif name == "technic:supply_converter" then + return math.abs(pos2.y - pos1.y) == 1 and "machine" or false + elseif technic.is_tier_cable(name, tier) then + return "cable" + elseif technic.machines[tier][name] then + return "machine" + end + return false +end + + +function technic.gen_cable_nodebox(x1, y1, z1, x2, y2, z2, size) + -- Nodeboxes + local box_center = {-size, -size, -size, size, size, size} + local box_y1 = {-size, -size, -size, size, 0.5, size} -- y+ + local box_x1 = {-size, -size, -size, 0.5, size, size} -- x+ + local box_z1 = {-size, -size, size, size, size, 0.5} -- z+ + local box_z2 = {-size, -size, -0.5, size, size, size} -- z- + local box_y2 = {-size, -0.5, -size, size, size, size} -- y- + local box_x2 = {-0.5, -size, -size, size, size, size} -- x- + + local box = {box_center} + if x1 == 1 then + table.insert(box, box_x1) + end + if y1 == 1 then + table.insert(box, box_y1) + end + if z1 == 1 then + table.insert(box, box_z1) + end + if x2 == 1 then + table.insert(box, box_x2) + end + if y2 == 1 then + table.insert(box, box_y2) + end + if z2 == 1 then + table.insert(box, box_z2) + end + return box +end + diff --git a/technic/machines/register/centrifuge.lua b/technic/machines/register/centrifuge.lua new file mode 100644 index 0000000..dd05977 --- /dev/null +++ b/technic/machines/register/centrifuge.lua @@ -0,0 +1,8 @@ +local S = technic.getter + +function technic.register_centrifuge(data) + data.typename = "separating" + data.machine_name = "centrifuge" + data.machine_desc = S("%s Centrifuge") + technic.register_base_machine(data) +end diff --git a/technic/machines/register/centrifuge_recipes.lua b/technic/machines/register/centrifuge_recipes.lua new file mode 100644 index 0000000..05642f5 --- /dev/null +++ b/technic/machines/register/centrifuge_recipes.lua @@ -0,0 +1,38 @@ +local S = technic.getter + +technic.register_recipe_type("separating", { + description = S("Separating"), + output_size = 2, +}) + +function technic.register_separating_recipe(data) + data.time = data.time or 10 + technic.register_recipe("separating", data) +end + +local recipes = { + { "technic:bronze_dust 4", "technic:copper_dust 3", "technic:tin_dust" }, + { "technic:stainless_steel_dust 4", "technic:wrought_iron_dust 3", "technic:chromium_dust" }, + { "technic:brass_dust 3", "technic:copper_dust 2", "technic:zinc_dust" }, +} + +local function uranium_dust(p) + return "technic:uranium"..(p == 7 and "" or p).."_dust" +end +for p = 1, 34 do + table.insert(recipes, { uranium_dust(p).." 2", uranium_dust(p-1), uranium_dust(p+1) }) +end + +if minetest.get_modpath("bushes_classic") then + for _, berry in ipairs({ "blackberry", "blueberry", "gooseberry", "raspberry", "strawberry" }) do + table.insert(recipes, { "bushes:"..berry.."_bush", "default:stick 20", "bushes:"..berry.." 4" }) + end +end + +if minetest.get_modpath("farming") then + table.insert(recipes, { "farming:wheat 4", "farming:seed_wheat 3", "default:dry_shrub 1" }) +end + +for _, data in pairs(recipes) do + technic.register_separating_recipe({ input = { data[1] }, output = { data[2], data[3] } }) +end diff --git a/technic/machines/register/common.lua b/technic/machines/register/common.lua new file mode 100644 index 0000000..ce0eee6 --- /dev/null +++ b/technic/machines/register/common.lua @@ -0,0 +1,214 @@ + +local S = technic.getter + +-- handles the machine upgrades every tick +function technic.handle_machine_upgrades(meta) + -- Get the names of the upgrades + local inv = meta:get_inventory() + + local srcstack = inv:get_stack("upgrade1", 1) + local upg_item1 = srcstack and srcstack:get_name() + + srcstack = inv:get_stack("upgrade2", 1) + local upg_item2 = srcstack and srcstack:get_name() + + -- Save some power by installing battery upgrades. + -- Tube loading speed can be upgraded using control logic units. + local EU_upgrade = 0 + local tube_upgrade = 0 + + if upg_item1 == "technic:control_logic_unit" then + tube_upgrade = tube_upgrade + 1 + elseif upg_item1 == "technic:battery" then + EU_upgrade = EU_upgrade + 1 + end + + if upg_item2 == "technic:control_logic_unit" then + tube_upgrade = tube_upgrade + 1 + elseif upg_item2 == "technic:battery" then + EU_upgrade = EU_upgrade + 1 + end + + return EU_upgrade, tube_upgrade +end + +-- handles the machine upgrades when set or removed +local function on_machine_upgrade(meta, stack) + local stack_name = stack:get_name() + if stack_name == "default:chest" then + meta:set_int("public", 1) + return 1 + elseif stack_name ~= "technic:control_logic_unit" + and stack_name ~= "technic:battery" then + return 0 + end + return 1 +end + +-- something is about to be removed +local function on_machine_downgrade(meta, stack, list) + if stack:get_name() == "default:chest" then + local inv = meta:get_inventory() + local upg1, upg2 = inv:get_stack("upgrade1", 1), inv:get_stack("upgrade2", 1) + + -- only set 0 if theres not a nother chest in the other list too + if (not upg1 or not upg2 or upg1:get_name() ~= upg2:get_name()) then + meta:set_int("public", 0) + end + end + return 1 +end + + +function technic.send_items(pos, x_velocity, z_velocity, output_name) + -- Send items on their way in the pipe system. + if output_name == nil then + output_name = "dst" + end + + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local i = 0 + for _, stack in ipairs(inv:get_list(output_name)) do + i = i + 1 + if stack then + local item0 = stack:to_table() + if item0 then + item0["count"] = "1" + technic.tube_inject_item(pos, pos, vector.new(x_velocity, 0, z_velocity), item0) + stack:take_item(1) + inv:set_stack(output_name, i, stack) + return + end + end + end +end + + +function technic.smelt_item(meta, result, speed) + local inv = meta:get_inventory() + meta:set_int("cook_time", meta:get_int("cook_time") + 1) + if meta:get_int("cook_time") < result.time / speed then + return + end + local result + local afterfuel + result, afterfuel = minetest.get_craft_result({method = "cooking", width = 1, items = inv:get_list("src")}) + + if result and result.item then + meta:set_int("cook_time", 0) + -- check if there's room for output in "dst" list + if inv:room_for_item("dst", result.item) then + inv:set_stack("src", 1, afterfuel.items[1]) + inv:add_item("dst", result.item) + end + end +end + +function technic.handle_machine_pipeworks(pos, tube_upgrade, send_function) + if send_function == nil then + send_function = technic.send_items + end + + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local pos1 = vector.new(pos) + local x_velocity = 0 + local z_velocity = 0 + + -- Output is on the left side of the furnace + if node.param2 == 3 then pos1.z = pos1.z - 1 z_velocity = -1 end + if node.param2 == 2 then pos1.x = pos1.x - 1 x_velocity = -1 end + if node.param2 == 1 then pos1.z = pos1.z + 1 z_velocity = 1 end + if node.param2 == 0 then pos1.x = pos1.x + 1 x_velocity = 1 end + + local output_tube_connected = false + local node1 = minetest.get_node(pos1) + if minetest.get_item_group(node1.name, "tubedevice") > 0 then + output_tube_connected = true + end + local tube_time = meta:get_int("tube_time") + tube_upgrade + if tube_time >= 2 then + tube_time = 0 + if output_tube_connected then + send_function(pos, x_velocity, z_velocity) + end + end + meta:set_int("tube_time", tube_time) +end + +function technic.machine_can_dig(pos, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if not inv:is_empty("src") or not inv:is_empty("dst") then + if player then + minetest.chat_send_player(player:get_player_name(), + S("Machine cannot be removed because it is not empty")) + end + return false + end + + return true +end + +function technic.machine_after_dig_node(pos, oldnode, oldmetadata, player) + if oldmetadata.inventory then + if oldmetadata.inventory.upgrade1 and oldmetadata.inventory.upgrade1[1] then + local stack = ItemStack(oldmetadata.inventory.upgrade1[1]) + if not stack:is_empty() then + minetest.item_drop(stack, "", pos) + end + end + if oldmetadata.inventory.upgrade2 and oldmetadata.inventory.upgrade2[1] then + local stack = ItemStack(oldmetadata.inventory.upgrade2[1]) + if not stack:is_empty() then + minetest.item_drop(stack, "", pos) + end + end + end + + if minetest.registered_nodes[oldnode.name].tube then + pipeworks.after_dig(pos, oldnode, oldmetadata, player) + end +end + +local function inv_change(pos, player, count, from_list, to_list, stack) + local playername = player:get_player_name() + local meta = minetest.get_meta(pos); + local public = (meta:get_int("public") == 1) + local to_upgrade = to_list == "upgrade1" or to_list == "upgrade2" + local from_upgrade = from_list == "upgrade1" or from_list == "upgrade2" + + if (not public or to_upgrade or from_upgrade) and minetest.is_protected(pos, playername) then + minetest.chat_send_player(playername, S("Inventory move disallowed due to protection")) + return 0 + end + if to_upgrade then + -- only place a single item into it, if it's empty + local empty = meta:get_inventory():is_empty(to_list) + if empty then + return on_machine_upgrade(meta, stack) + end + return 0 + elseif from_upgrade then + -- only called on take (not move) + on_machine_downgrade(meta, stack, from_list) + end + return count +end + +function technic.machine_inventory_put(pos, listname, index, stack, player) + return inv_change(pos, player, stack:get_count(), nil, listname, stack) +end + +function technic.machine_inventory_take(pos, listname, index, stack, player) + return inv_change(pos, player, stack:get_count(), listname, nil, stack) +end + +function technic.machine_inventory_move(pos, from_list, from_index, + to_list, to_index, count, player) + local stack = minetest.get_meta(pos):get_inventory():get_stack(from_list, from_index) + return inv_change(pos, player, count, from_list, to_list, stack) +end + diff --git a/technic/machines/register/compressor.lua b/technic/machines/register/compressor.lua new file mode 100644 index 0000000..49830d7 --- /dev/null +++ b/technic/machines/register/compressor.lua @@ -0,0 +1,9 @@ + +local S = technic.getter + +function technic.register_compressor(data) + data.typename = "compressing" + data.machine_name = "compressor" + data.machine_desc = S("%s Compressor") + technic.register_base_machine(data) +end diff --git a/technic/machines/register/compressor_recipes.lua b/technic/machines/register/compressor_recipes.lua new file mode 100644 index 0000000..872be04 --- /dev/null +++ b/technic/machines/register/compressor_recipes.lua @@ -0,0 +1,34 @@ + +local S = technic.getter + +technic.register_recipe_type("compressing", { description = S("Compressing") }) + +function technic.register_compressor_recipe(data) + data.time = data.time or 4 + technic.register_recipe("compressing", data) +end + +local recipes = { + {"default:snowblock", "default:ice"}, + {"default:sand 2", "default:sandstone"}, + {"default:desert_sand", "default:desert_stone"}, + {"technic:mixed_metal_ingot", "technic:composite_plate"}, + {"default:copper_ingot 5", "technic:copper_plate"}, + {"technic:coal_dust 4", "technic:graphite"}, + {"technic:carbon_cloth", "technic:carbon_plate"}, + {"technic:uranium35_ingot 5", "technic:uranium_fuel"}, +} + +-- defuse the default sandstone recipe, since we have the compressor to take over in a more realistic manner +minetest.register_craft({ + output = "default:sand 0", + recipe = { + {'group:sand', 'group:sand'}, + {'group:sand', 'group:sand'} + }, +}) + +for _, data in pairs(recipes) do + technic.register_compressor_recipe({input = {data[1]}, output = data[2]}) +end + diff --git a/technic/machines/register/electric_furnace.lua b/technic/machines/register/electric_furnace.lua new file mode 100644 index 0000000..44de16c --- /dev/null +++ b/technic/machines/register/electric_furnace.lua @@ -0,0 +1,9 @@ + +local S = technic.getter + +function technic.register_electric_furnace(data) + data.typename = "cooking" + data.machine_name = "electric_furnace" + data.machine_desc = S("%s Furnace") + technic.register_base_machine(data) +end diff --git a/technic/machines/register/extractor.lua b/technic/machines/register/extractor.lua new file mode 100644 index 0000000..eeef9ff --- /dev/null +++ b/technic/machines/register/extractor.lua @@ -0,0 +1,9 @@ + +local S = technic.getter + +function technic.register_extractor(data) + data.typename = "extracting" + data.machine_name = "extractor" + data.machine_desc = S("%s Extractor") + technic.register_base_machine(data) +end diff --git a/technic/machines/register/extractor_recipes.lua b/technic/machines/register/extractor_recipes.lua new file mode 100644 index 0000000..1de0ba0 --- /dev/null +++ b/technic/machines/register/extractor_recipes.lua @@ -0,0 +1,59 @@ + +local S = technic.getter + +technic.register_recipe_type("extracting", { description = S("Extracting") }) + +function technic.register_extractor_recipe(data) + data.time = data.time or 4 + technic.register_recipe("extracting", data) +end + +if minetest.get_modpath("dye") then + -- check if we are using dye or unifieddyes + local unifieddyes = minetest.get_modpath("unifieddyes") + + -- register recipes with the same crafting ratios as `dye` provides + local dye_recipes = { + {"technic:coal_dust", "dye:black 2"}, + {"default:grass_1", "dye:green 1"}, + {"default:dry_shrub", "dye:brown 1"}, + {"default:junglegrass", "dye:green 2"}, + {"default:cactus", "dye:green 4"}, + {"flowers:geranium", "dye:blue 4"}, + {"flowers:dandelion_white", "dye:white 4"}, + {"flowers:dandelion_yellow", "dye:yellow 4"}, + {"flowers:tulip", "dye:orange 4"}, + {"flowers:rose", "dye:red 4"}, + {"flowers:viola", "dye:violet 4"}, + {"bushes:blackberry", unifieddyes and "unifieddyes:magenta_s50 4" or "dye:violet 4"}, + {"bushes:blueberry", unifieddyes and "unifieddyes:magenta_s50 4" or "dye:magenta 4"}, + } + + for _, data in ipairs(dye_recipes) do + technic.register_extractor_recipe({input = {data[1]}, output = data[2]}) + end + + -- overwrite the existing crafting recipes + local dyes = {"white", "red", "yellow", "blue", "violet", "orange"} + for _, color in ipairs(dyes) do + minetest.register_craft({ + type = "shapeless", + output = "dye:"..color.." 1", + recipe = {"group:flower,color_"..color}, + }) + + end + minetest.register_craft({ + type = "shapeless", + output = "dye:black 1", + recipe = {"group:coal"}, + }) + + if unifieddyes then + minetest.register_craft({ + type = "shapeless", + output = "dye:green 1", + recipe = {"default:cactus"}, + }) + end +end diff --git a/technic/machines/register/generator.lua b/technic/machines/register/generator.lua new file mode 100644 index 0000000..31c1cef --- /dev/null +++ b/technic/machines/register/generator.lua @@ -0,0 +1,173 @@ +local S = technic.getter + +local tube = { + insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item("src", stack) + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:room_for_item("src", stack) + end, + connect_sides = {left=1, right=1, back=1, top=1, bottom=1}, +} + +function technic.register_generator(data) + local tier = data.tier + local ltier = string.lower(tier) + + local groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1} + local active_groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, not_in_creative_inventory=1} + if data.tube then + groups.tubedevice = 1 + groups.tubedevice_receiver = 1 + active_groups.tubedevice = 1 + active_groups.tubedevice_receiver = 1 + end + + local generator_formspec = + "invsize[8,9;]".. + "label[0,0;"..S("Fuel-Fired %s Generator"):format(tier).."]".. + "list[current_name;src;3,1;1,1;]".. + "image[4,1;1,1;default_furnace_fire_bg.png]".. + "list[current_player;main;0,5;8,4;]".. + "listring[]" + + local desc = S("Fuel-Fired %s Generator"):format(tier) + + local run = function(pos, node) + local meta = minetest.get_meta(pos) + local burn_time = meta:get_int("burn_time") + local burn_totaltime = meta:get_int("burn_totaltime") + -- If more to burn and the energy produced was used: produce some more + if burn_time > 0 then + meta:set_int(tier.."_EU_supply", data.supply) + burn_time = burn_time - 1 + meta:set_int("burn_time", burn_time) + end + -- Burn another piece of fuel + if burn_time == 0 then + local inv = meta:get_inventory() + if not inv:is_empty("src") then + local fuellist = inv:get_list("src") + local fuel + local afterfuel + fuel, afterfuel = minetest.get_craft_result( + {method = "fuel", width = 1, + items = fuellist}) + if not fuel or fuel.time == 0 then + meta:set_string("infotext", S("%s Out Of Fuel"):format(desc)) + technic.swap_node(pos, "technic:"..ltier.."_generator") + meta:set_int(tier.."_EU_supply", 0) + return + end + meta:set_int("burn_time", fuel.time) + meta:set_int("burn_totaltime", fuel.time) + inv:set_stack("src", 1, afterfuel.items[1]) + technic.swap_node(pos, "technic:"..ltier.."_generator_active") + meta:set_int(tier.."_EU_supply", data.supply) + else + technic.swap_node(pos, "technic:"..ltier.."_generator") + meta:set_int(tier.."_EU_supply", 0) + end + end + if burn_totaltime == 0 then burn_totaltime = 1 end + local percent = math.floor((burn_time / burn_totaltime) * 100) + meta:set_string("infotext", desc.." ("..percent.."%)") + meta:set_string("formspec", + "size[8, 9]".. + "label[0, 0;"..minetest.formspec_escape(desc).."]".. + "list[current_name;src;3, 1;1, 1;]".. + "image[4, 1;1, 1;default_furnace_fire_bg.png^[lowpart:".. + (percent)..":default_furnace_fire_fg.png]".. + "list[current_player;main;0, 5;8, 4;]".. + "listring[]") + end + + minetest.register_node("technic:"..ltier.."_generator", { + description = desc, + tiles = {"technic_"..ltier.."_generator_top.png", "technic_machine_bottom.png", + "technic_"..ltier.."_generator_side.png", "technic_"..ltier.."_generator_side.png", + "technic_"..ltier.."_generator_side.png", "technic_"..ltier.."_generator_front.png"}, + paramtype2 = "facedir", + groups = groups, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + tube = data.tube and tube or nil, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", desc) + meta:set_int(data.tier.."_EU_supply", 0) + meta:set_int("burn_time", 0) + meta:set_int("tube_time", 0) + meta:set_string("formspec", generator_formspec) + local inv = meta:get_inventory() + inv:set_size("src", 1) + end, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + technic_run = run, + after_place_node = data.tube and pipeworks.after_place, + after_dig_node = technic.machine_after_dig_node + }) + + minetest.register_node("technic:"..ltier.."_generator_active", { + description = desc, + tiles = {"technic_"..ltier.."_generator_top.png", "technic_machine_bottom.png", + "technic_"..ltier.."_generator_side.png", "technic_"..ltier.."_generator_side.png", + "technic_"..ltier.."_generator_side.png", "technic_"..ltier.."_generator_front_active.png"}, + paramtype2 = "facedir", + groups = active_groups, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + tube = data.tube and tube or nil, + drop = "technic:"..ltier.."_generator", + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + technic_run = run, + technic_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(tier.."_EU_timeout") > 0 then return false end + + local burn_time = meta:get_int("burn_time") or 0 + + if burn_time <= 0 then + meta:set_int(tier.."_EU_supply", 0) + meta:set_int("burn_time", 0) + technic.swap_node(pos, "technic:"..ltier.."_generator") + return false + end + + local burn_totaltime = meta:get_int("burn_totaltime") or 0 + if burn_totaltime == 0 then burn_totaltime = 1 end + burn_time = burn_time - 1 + meta:set_int("burn_time", burn_time) + local percent = math.floor(burn_time / burn_totaltime * 100) + meta:set_string("formspec", + "size[8, 9]".. + "label[0, 0;"..minetest.formspec_escape(desc).."]".. + "list[current_name;src;3, 1;1, 1;]".. + "image[4, 1;1, 1;default_furnace_fire_bg.png^[lowpart:".. + (percent)..":default_furnace_fire_fg.png]".. + "list[current_player;main;0, 5;8, 4;]".. + "listring[]") + return true + end, + }) + + technic.register_machine(tier, "technic:"..ltier.."_generator", technic.producer) + technic.register_machine(tier, "technic:"..ltier.."_generator_active", technic.producer) +end + diff --git a/technic/machines/register/grinder.lua b/technic/machines/register/grinder.lua new file mode 100644 index 0000000..19ea094 --- /dev/null +++ b/technic/machines/register/grinder.lua @@ -0,0 +1,9 @@ + +local S = technic.getter + +function technic.register_grinder(data) + data.typename = "grinding" + data.machine_name = "grinder" + data.machine_desc = S("%s Grinder") + technic.register_base_machine(data) +end diff --git a/technic/machines/register/grinder_recipes.lua b/technic/machines/register/grinder_recipes.lua new file mode 100644 index 0000000..87c6ade --- /dev/null +++ b/technic/machines/register/grinder_recipes.lua @@ -0,0 +1,161 @@ + +local S = technic.getter + +technic.register_recipe_type("grinding", { description = S("Grinding") }) + +function technic.register_grinder_recipe(data) + data.time = data.time or 3 + technic.register_recipe("grinding", data) +end + +local recipes = { + -- Dusts + {"default:coal_lump", "technic:coal_dust 2"}, + {"default:copper_lump", "technic:copper_dust 2"}, + {"default:desert_stone", "default:desert_sand"}, + {"default:gold_lump", "technic:gold_dust 2"}, + {"default:iron_lump", "technic:wrought_iron_dust 2"}, + {"technic:chromium_lump", "technic:chromium_dust 2"}, + {"technic:uranium_lump", "technic:uranium_dust 2"}, + {"technic:zinc_lump", "technic:zinc_dust 2"}, + {"technic:lead_lump", "technic:lead_dust 2"}, + {"technic:sulfur_lump", "technic:sulfur_dust 2"}, + + -- Other + {"default:cobble", "default:gravel"}, + {"default:gravel", "default:dirt"}, + {"default:stone", "default:sand"}, + {"default:sandstone", "default:sand 2"}, -- reverse recipe can be found in the compressor +} + +-- defuse the sandstone -> 4 sand recipe to avoid infinite sand bugs (also consult the inverse compressor recipe) +minetest.register_craft({ + output = "default:sandstone 0", + recipe = { + {'default:sandstone'} + }, +}) + +if minetest.get_modpath("farming") then + table.insert(recipes, {"farming:seed_wheat", "farming:flour 1"}) +end + +if minetest.get_modpath("moreores") then + table.insert(recipes, {"moreores:mithril_lump", "technic:mithril_dust 2"}) + table.insert(recipes, {"moreores:silver_lump", "technic:silver_dust 2"}) + table.insert(recipes, {"moreores:tin_lump", "technic:tin_dust 2"}) +end + +if minetest.get_modpath("gloopores") or minetest.get_modpath("glooptest") then + table.insert(recipes, {"gloopores:alatro_lump", "technic:alatro_dust 2"}) + table.insert(recipes, {"gloopores:kalite_lump", "technic:kalite_dust 2"}) + table.insert(recipes, {"gloopores:arol_lump", "technic:arol_dust 2"}) + table.insert(recipes, {"gloopores:talinite_lump", "technic:talinite_dust 2"}) + table.insert(recipes, {"gloopores:akalin_lump", "technic:akalin_dust 2"}) +end + +if minetest.get_modpath("homedecor") then + table.insert(recipes, {"home_decor:brass_ingot", "technic:brass_dust 1"}) +end + +for _, data in pairs(recipes) do + technic.register_grinder_recipe({input = {data[1]}, output = data[2]}) +end + +-- defuse common grinder unfriendly recipes +if minetest.get_modpath("fake_fire") then -- from homedecor_modpack + minetest.register_craft({ output='default:cobble 0', recipe={{'default:cobble'}}}) + minetest.register_craft({ output='default:gravel 0', recipe={{'default:gravel'}}}) +end + +-- dusts +local function register_dust(name, ingot) + local lname = string.lower(name) + lname = string.gsub(lname, ' ', '_') + minetest.register_craftitem("technic:"..lname.."_dust", { + description = S("%s Dust"):format(S(name)), + inventory_image = "technic_"..lname.."_dust.png", + }) + if ingot then + minetest.register_craft({ + type = "cooking", + recipe = "technic:"..lname.."_dust", + output = ingot, + }) + technic.register_grinder_recipe({ input = {ingot}, output = "technic:"..lname.."_dust 1" }) + end +end + +-- Sorted alphibeticaly +register_dust("Brass", "technic:brass_ingot") +register_dust("Bronze", "default:bronze_ingot") +register_dust("Carbon Steel", "technic:carbon_steel_ingot") +register_dust("Cast Iron", "technic:cast_iron_ingot") +register_dust("Chromium", "technic:chromium_ingot") +register_dust("Coal", nil) +register_dust("Copper", "default:copper_ingot") +register_dust("Lead", "technic:lead_ingot") +register_dust("Gold", "default:gold_ingot") +register_dust("Mithril", "moreores:mithril_ingot") +register_dust("Silver", "moreores:silver_ingot") +register_dust("Stainless Steel", "technic:stainless_steel_ingot") +register_dust("Sulfur", nil) +register_dust("Tin", "moreores:tin_ingot") +register_dust("Wrought Iron", "technic:wrought_iron_ingot") +register_dust("Zinc", "technic:zinc_ingot") +if minetest.get_modpath("gloopores") or minetest.get_modpath("glooptest") then + register_dust("Akalin", "glooptest:akalin_ingot") + register_dust("Alatro", "glooptest:alatro_ingot") + register_dust("Arol", "glooptest:arol_ingot") + register_dust("Kalite", nil) + register_dust("Talinite", "glooptest:talinite_ingot") +end + +for p = 0, 35 do + local nici = (p ~= 0 and p ~= 7 and p ~= 35) and 1 or nil + local psuffix = p == 7 and "" or p + local ingot = "technic:uranium"..psuffix.."_ingot" + local dust = "technic:uranium"..psuffix.."_dust" + minetest.register_craftitem(dust, { + description = S("%s Dust"):format(string.format(S("%.1f%%-Fissile Uranium"), p/10)), + inventory_image = "technic_uranium_dust.png", + on_place_on_ground = minetest.craftitem_place_item, + groups = {uranium_dust=1, not_in_creative_inventory=nici}, + }) + minetest.register_craft({ + type = "cooking", + recipe = dust, + output = ingot, + }) + technic.register_grinder_recipe({ input = {ingot}, output = dust }) +end + +local function uranium_dust(p) + return "technic:uranium"..(p == 7 and "" or p).."_dust" +end +for pa = 0, 34 do + for pb = pa+1, 35 do + local pc = (pa+pb)/2 + if pc == math.floor(pc) then + minetest.register_craft({ + type = "shapeless", + recipe = { uranium_dust(pa), uranium_dust(pb) }, + output = uranium_dust(pc).." 2", + }) + end + end +end + +minetest.register_craft({ + type = "fuel", + recipe = "technic:coal_dust", + burntime = 50, +}) + +if minetest.get_modpath("gloopores") or minetest.get_modpath("glooptest") then + minetest.register_craft({ + type = "fuel", + recipe = "technic:kalite_dust", + burntime = 37.5, + }) +end diff --git a/technic/machines/register/grindings.lua b/technic/machines/register/grindings.lua new file mode 100644 index 0000000..9231166 --- /dev/null +++ b/technic/machines/register/grindings.lua @@ -0,0 +1,62 @@ +local S = technic.getter +local moretrees = minetest.get_modpath("moretrees") +local mesecons_materials = minetest.get_modpath("mesecons_materials") +local dye = minetest.get_modpath("dye") + +-- sawdust, the finest wood/tree grinding +local sawdust = "technic:sawdust" +minetest.register_craftitem(sawdust, { + description = S("Sawdust"), + inventory_image = "technic_sawdust.png", +}) +minetest.register_craft({ type = "fuel", recipe = sawdust, burntime = 6 }) +technic.register_compressor_recipe({ input = {sawdust .. " 4"}, output = "default:wood" }) + +-- tree/wood grindings +local function register_tree_grinding(name, tree, wood, extract, grinding_color) + local lname = string.lower(name) + lname = string.gsub(lname, ' ', '_') + local grindings_name = "technic:"..lname.."_grindings" + local inventory_image = "technic_"..lname.."_grindings.png" + if grinding_color then + inventory_image = inventory_image .. "^[colorize:" .. grinding_color + end + minetest.register_craftitem(grindings_name, { + description = S("%s Grinding"):format(S(name)), + inventory_image = inventory_image, + }) + minetest.register_craft({ + type = "fuel", + recipe = grindings_name, + burntime = 8, + }) + technic.register_grinder_recipe({ input = { tree }, output = grindings_name .. " 4" }) + technic.register_grinder_recipe({ input = { grindings_name }, output = sawdust .. " 4" }) + if wood then + technic.register_grinder_recipe({ input = { wood }, output = grindings_name }) + end + if extract then + technic.register_extractor_recipe({ input = { grindings_name .. " 4" }, output = extract}) + technic.register_separating_recipe({ + input = { grindings_name .. " 4" }, + output = { sawdust .. " 4", extract } + }) + end +end + +local rubber_tree_planks = moretrees and "moretrees:rubber_tree_planks" +local default_extract = dye and "dye:brown 2" + +local grinding_recipes = { + {"Common Tree", "group:tree", "group:wood", default_extract }, + {"Rubber Tree", "moretrees:rubber_tree_trunk", rubber_tree_planks, "technic:raw_latex"} +} + +for _, data in pairs(grinding_recipes) do + register_tree_grinding(unpack(data)) +end + +if moretrees and dye then + -- https://en.wikipedia.org/wiki/Catechu ancient brown dye from the wood of acacia trees + register_tree_grinding("Acacia", "moretrees:acacia_trunk", "moretrees:acacia_planks", "dye:brown 8") +end diff --git a/technic/machines/register/init.lua b/technic/machines/register/init.lua new file mode 100644 index 0000000..1667d75 --- /dev/null +++ b/technic/machines/register/init.lua @@ -0,0 +1,33 @@ +local path = technic.modpath.."/machines/register" + +dofile(path.."/common.lua") + +-- Wiring stuff +dofile(path.."/cables.lua") +dofile(path.."/battery_box.lua") + +-- Generators +dofile(path.."/solar_array.lua") +dofile(path.."/generator.lua") + +-- API for machines +dofile(path.."/recipes.lua") +dofile(path.."/machine_base.lua") + +-- Recipes +dofile(path.."/alloy_recipes.lua") +dofile(path.."/grinder_recipes.lua") +dofile(path.."/extractor_recipes.lua") +dofile(path.."/compressor_recipes.lua") +dofile(path.."/centrifuge_recipes.lua") + +-- Multi-Machine Recipes +dofile(path.."/grindings.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") diff --git a/technic/machines/register/machine_base.lua b/technic/machines/register/machine_base.lua new file mode 100644 index 0000000..0c46261 --- /dev/null +++ b/technic/machines/register/machine_base.lua @@ -0,0 +1,197 @@ + +local S = technic.getter + +local tube = { + insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item("src", stack) + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:room_for_item("src", stack) + end, + connect_sides = {left = 1, right = 1, back = 1, top = 1, bottom = 1}, +} + +local function round(v) + return math.floor(v + 0.5) +end + +function technic.register_base_machine(data) + local typename = data.typename + local input_size = technic.recipes[typename].input_size + local machine_name = data.machine_name + local machine_desc = data.machine_desc + local tier = data.tier + local ltier = string.lower(tier) + + local groups = {cracky = 2, technic_machine = 1} + local active_groups = {cracky = 2, technic_machine = 1, not_in_creative_inventory = 1} + if data.tube then + groups.tubedevice = 1 + groups.tubedevice_receiver = 1 + active_groups.tubedevice = 1 + active_groups.tubedevice_receiver = 1 + end + + + local formspec = + "invsize[8,9;]".. + "list[current_name;src;"..(4-input_size)..",1;"..input_size..",1;]".. + "list[current_name;dst;5,1;2,2;]".. + "list[current_player;main;0,5;8,4;]".. + "label[0,0;"..machine_desc:format(tier).."]".. + "listring[current_name;dst]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]" + if data.upgrade then + formspec = formspec.. + "list[current_name;upgrade1;1,3;1,1;]".. + "list[current_name;upgrade2;2,3;1,1;]".. + "label[1,4;"..S("Upgrade Slots").."]".. + "listring[current_name;upgrade1]".. + "listring[current_player;main]".. + "listring[current_name;upgrade2]".. + "listring[current_player;main]" + end + + local run = function(pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local eu_input = meta:get_int(tier.."_EU_input") + + local machine_desc_tier = machine_desc:format(tier) + local machine_node = "technic:"..ltier.."_"..machine_name + local machine_demand = data.demand + + -- Setup meta data if it does not exist. + if not eu_input then + meta:set_int(tier.."_EU_demand", machine_demand[1]) + meta:set_int(tier.."_EU_input", 0) + return + end + + local EU_upgrade, tube_upgrade = 0, 0 + if data.upgrade then + EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta) + end + if data.tube then + technic.handle_machine_pipeworks(pos, tube_upgrade) + end + + local powered = eu_input >= machine_demand[EU_upgrade+1] + if powered then + meta:set_int("src_time", meta:get_int("src_time") + round(data.speed*10)) + end + while true do + local result = technic.get_recipe(typename, inv:get_list("src")) + if not result then + technic.swap_node(pos, machine_node) + meta:set_string("infotext", S("%s Idle"):format(machine_desc_tier)) + meta:set_int(tier.."_EU_demand", 0) + meta:set_int("src_time", 0) + return + end + meta:set_int(tier.."_EU_demand", machine_demand[EU_upgrade+1]) + technic.swap_node(pos, machine_node.."_active") + meta:set_string("infotext", S("%s Active"):format(machine_desc_tier)) + if meta:get_int("src_time") < round(result.time*10) then + if not powered then + technic.swap_node(pos, machine_node) + meta:set_string("infotext", S("%s Unpowered"):format(machine_desc_tier)) + end + return + end + local output = result.output + if type(output) ~= "table" then output = { output } end + local output_stacks = {} + for _, o in ipairs(output) do + table.insert(output_stacks, ItemStack(o)) + end + local room_for_output = true + inv:set_size("dst_tmp", inv:get_size("dst")) + inv:set_list("dst_tmp", inv:get_list("dst")) + for _, o in ipairs(output_stacks) do + if not inv:room_for_item("dst_tmp", o) then + room_for_output = false + break + end + inv:add_item("dst_tmp", o) + end + if not room_for_output then + technic.swap_node(pos, machine_node) + meta:set_string("infotext", S("%s Idle"):format(machine_desc_tier)) + meta:set_int(tier.."_EU_demand", 0) + meta:set_int("src_time", round(result.time*10)) + return + end + meta:set_int("src_time", meta:get_int("src_time") - round(result.time*10)) + inv:set_list("src", result.new_input) + inv:set_list("dst", inv:get_list("dst_tmp")) + end + end + + minetest.register_node("technic:"..ltier.."_"..machine_name, { + description = machine_desc:format(tier), + tiles = {"technic_"..ltier.."_"..machine_name.."_top.png", + "technic_"..ltier.."_"..machine_name.."_bottom.png", + "technic_"..ltier.."_"..machine_name.."_side.png", + "technic_"..ltier.."_"..machine_name.."_side.png", + "technic_"..ltier.."_"..machine_name.."_side.png", + "technic_"..ltier.."_"..machine_name.."_front.png"}, + paramtype2 = "facedir", + groups = groups, + tube = data.tube and tube or nil, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", machine_desc:format(tier)) + meta:set_int("tube_time", 0) + meta:set_string("formspec", formspec) + local inv = meta:get_inventory() + inv:set_size("src", input_size) + inv:set_size("dst", 4) + inv:set_size("upgrade1", 1) + inv:set_size("upgrade2", 1) + end, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + technic_run = run, + after_place_node = data.tube and pipeworks.after_place, + after_dig_node = technic.machine_after_dig_node + }) + + minetest.register_node("technic:"..ltier.."_"..machine_name.."_active",{ + description = machine_desc:format(tier), + tiles = {"technic_"..ltier.."_"..machine_name.."_top.png", + "technic_"..ltier.."_"..machine_name.."_bottom.png", + "technic_"..ltier.."_"..machine_name.."_side.png", + "technic_"..ltier.."_"..machine_name.."_side.png", + "technic_"..ltier.."_"..machine_name.."_side.png", + "technic_"..ltier.."_"..machine_name.."_front_active.png"}, + paramtype2 = "facedir", + drop = "technic:"..ltier.."_"..machine_name, + groups = active_groups, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + tube = data.tube and tube or nil, + can_dig = technic.machine_can_dig, + allow_metadata_inventory_put = technic.machine_inventory_put, + allow_metadata_inventory_take = technic.machine_inventory_take, + allow_metadata_inventory_move = technic.machine_inventory_move, + technic_run = run, + technic_disabled_machine_name = "technic:"..ltier.."_"..machine_name, + }) + + technic.register_machine(tier, "technic:"..ltier.."_"..machine_name, technic.receiver) + technic.register_machine(tier, "technic:"..ltier.."_"..machine_name.."_active", technic.receiver) + +end -- End registration + diff --git a/technic/machines/register/recipes.lua b/technic/machines/register/recipes.lua new file mode 100644 index 0000000..d30fd4f --- /dev/null +++ b/technic/machines/register/recipes.lua @@ -0,0 +1,107 @@ +local have_ui = minetest.get_modpath("unified_inventory") + +technic.recipes = { cooking = { input_size = 1, output_size = 1 } } +function technic.register_recipe_type(typename, origdata) + local data = {} + for k, v in pairs(origdata) do data[k] = v end + data.input_size = data.input_size or 1 + data.output_size = data.output_size or 1 + if have_ui and unified_inventory.register_craft_type and data.output_size == 1 then + unified_inventory.register_craft_type(typename, { + description = data.description, + width = data.input_size, + height = 1, + }) + end + data.recipes = {} + technic.recipes[typename] = data +end + +local function get_recipe_index(items) + if not items or type(items) ~= "table" then return false end + local l = {} + for i, stack in ipairs(items) do + l[i] = ItemStack(stack):get_name() + end + table.sort(l) + return table.concat(l, "/") +end + +local function register_recipe(typename, data) + -- Handle aliases + for i, stack in ipairs(data.input) do + data.input[i] = ItemStack(stack):to_string() + end + if type(data.output) == "table" then + for i, v in ipairs(data.output) do + data.output[i] = ItemStack(data.output[i]):to_string() + end + else + data.output = ItemStack(data.output):to_string() + end + + local recipe = {time = data.time, input = {}, output = data.output} + local index = get_recipe_index(data.input) + if not index then + print("[Technic] ignored registration of garbage recipe!") + return + end + for _, stack in ipairs(data.input) do + recipe.input[ItemStack(stack):get_name()] = ItemStack(stack):get_count() + end + + technic.recipes[typename].recipes[index] = recipe + if unified_inventory and technic.recipes[typename].output_size == 1 then + unified_inventory.register_craft({ + type = typename, + output = data.output, + items = data.input, + width = 0, + }) + end +end + +function technic.register_recipe(typename, data) + minetest.after(0.01, register_recipe, typename, data) -- Handle aliases +end + +function technic.get_recipe(typename, items) + if typename == "cooking" then -- Already builtin in Minetest, so use that + local result, new_input = minetest.get_craft_result({ + method = "cooking", + width = 1, + items = items}) + -- Compatibility layer + if not result or result.time == 0 then + return nil + else + return {time = result.time, + new_input = new_input.items, + output = result.item} + end + end + local index = get_recipe_index(items) + if not index then + print("[Technic] ignored registration of garbage recipe!") + return + end + local recipe = technic.recipes[typename].recipes[index] + if recipe then + local new_input = {} + for i, stack in ipairs(items) do + if stack:get_count() < recipe.input[stack:get_name()] then + return nil + else + new_input[i] = ItemStack(stack) + new_input[i]:take_item(recipe.input[stack:get_name()]) + end + end + return {time = recipe.time, + new_input = new_input, + output = recipe.output} + else + return nil + end +end + + diff --git a/technic/machines/register/solar_array.lua b/technic/machines/register/solar_array.lua new file mode 100644 index 0000000..39f50d2 --- /dev/null +++ b/technic/machines/register/solar_array.lua @@ -0,0 +1,65 @@ + +local S = technic.getter + +function technic.register_solar_array(data) + local tier = data.tier + local ltier = string.lower(tier) + + local run = function(pos, node) + -- The action here is to make the solar array produce power + -- Power is dependent on the light level and the height above ground + -- There are many ways to cheat by using other light sources like lamps. + -- As there is no way to determine if light is sunlight that is just a shame. + -- To take care of some of it solar panels do not work outside daylight hours or if + -- built below 0m + local pos1 = {} + local machine_name = S("Arrayed Solar %s Generator"):format(tier) + pos1.y = pos.y + 1 + pos1.x = pos.x + pos1.z = pos.z + + technic.get_or_load_node(pos1) + local light = minetest.get_node_light(pos1, nil) + local time_of_day = minetest.get_timeofday() + local meta = minetest.get_meta(pos) + light = light or 0 + + -- turn on array only during day time and if sufficient light + -- I know this is counter intuitive when cheating by using other light sources. + if light >= 12 and time_of_day >= 0.24 and time_of_day <= 0.76 and pos.y > 0 then + local charge_to_give = math.floor((light + pos.y) * data.power) + charge_to_give = math.max(charge_to_give, 0) + charge_to_give = math.min(charge_to_give, data.power * 50) + meta:set_string("infotext", S("@1 Active (@2 EU)", machine_name, technic.prettynum(charge_to_give))) + meta:set_int(tier.."_EU_supply", charge_to_give) + else + meta:set_string("infotext", S("%s Idle"):format(machine_name)) + meta:set_int(tier.."_EU_supply", 0) + end + end + + minetest.register_node("technic:solar_array_"..ltier, { + tiles = {"technic_"..ltier.."_solar_array_top.png", "technic_"..ltier.."_solar_array_bottom.png", + "technic_"..ltier.."_solar_array_side.png", "technic_"..ltier.."_solar_array_side.png", + "technic_"..ltier.."_solar_array_side.png", "technic_"..ltier.."_solar_array_side.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1}, + sounds = default.node_sound_wood_defaults(), + description = S("Arrayed Solar %s Generator"):format(tier), + active = false, + drawtype = "nodebox", + paramtype = "light", + 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) + local name = minetest.get_node(pos).name + meta:set_int(tier.."_EU_supply", 0) + end, + technic_run = run, + }) + + technic.register_machine(tier, "technic:solar_array_"..ltier, technic.producer) +end + diff --git a/technic/machines/supply_converter.lua b/technic/machines/supply_converter.lua new file mode 100644 index 0000000..ffcd40d --- /dev/null +++ b/technic/machines/supply_converter.lua @@ -0,0 +1,80 @@ +-- The supply converter is a generic device which can convert from +-- LV to MV and back, and HV to MV and back. +-- The machine is configured by the wiring below and above it. +-- +-- It works like this: +-- The top side is setup as the receiver side, the bottom as the producer side. +-- Once the receiver side is powered it will deliver power to the other side. +-- Unused power is wasted just like any other producer! + +local S = technic.getter + +local run = function(pos, node) + local demand = 10000 + local remain = 0.9 + -- Machine information + local machine_name = S("Supply Converter") + local meta = minetest.get_meta(pos) + + local pos_up = {x=pos.x, y=pos.y+1, z=pos.z} + local pos_down = {x=pos.x, y=pos.y-1, z=pos.z} + local name_up = minetest.get_node(pos_up).name + local name_down = minetest.get_node(pos_down).name + + local from = technic.get_cable_tier(name_up) + local to = technic.get_cable_tier(name_down) + + if from and to then + local input = meta:get_int(from.."_EU_input") + meta:set_int(from.."_EU_demand", demand) + meta:set_int(from.."_EU_supply", 0) + meta:set_int(to.."_EU_demand", 0) + meta:set_int(to.."_EU_supply", input * remain) + meta:set_string("infotext", S("@1 (@2 @3 -> @4 @5)", machine_name, technic.prettynum(input), from, technic.prettynum(input * remain), to)) + else + meta:set_string("infotext", S("%s Has Bad Cabling"):format(machine_name)) + if to then + meta:set_int(to.."_EU_supply", 0) + end + if from then + meta:set_int(from.."_EU_demand", 0) + end + return + end + +end + +minetest.register_node("technic:supply_converter", { + description = S("Supply Converter"), + tiles = {"technic_supply_converter_top.png", "technic_supply_converter_bottom.png", + "technic_supply_converter_side.png", "technic_supply_converter_side.png", + "technic_supply_converter_side.png", "technic_supply_converter_side.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1}, + sounds = default.node_sound_wood_defaults(), + drawtype = "nodebox", + paramtype = "light", + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("Supply Converter")) + meta:set_float("active", false) + end, + technic_run = run, +}) + +minetest.register_craft({ + output = 'technic:supply_converter 1', + recipe = { + {'technic:fine_gold_wire', 'technic:rubber', 'technic:doped_silicon_wafer'}, + {'technic:mv_transformer', 'technic:machine_casing', 'technic:lv_transformer'}, + {'technic:mv_cable0', 'technic:rubber', 'technic:lv_cable0'}, + } +}) + +for tier, machines in pairs(technic.machines) do + technic.register_machine(tier, "technic:supply_converter", technic.producer_receiver) +end + diff --git a/technic/machines/switching_station.lua b/technic/machines/switching_station.lua new file mode 100644 index 0000000..d6f23a3 --- /dev/null +++ b/technic/machines/switching_station.lua @@ -0,0 +1,404 @@ +-- SWITCHING STATION +-- The switching station is the center of all power distribution on an electric network. +-- +-- The station collects power from sources (PR), distributes it to sinks (RE), +-- and uses the excess/shortfall to charge and discharge batteries (BA). +-- +-- For now, all supply and demand values are expressed in kW. +-- +-- It works like this: +-- All PR,BA,RE nodes are indexed and tagged with the switching station. +-- The tagging is to allow more stations to be built without allowing a cheat +-- with duplicating power. +-- All the RE nodes are queried for their current EU demand. Those which are off +-- would require no or a small standby EU demand, while those which are on would +-- require more. +-- If the total demand is less than the available power they are all updated with the +-- demand number. +-- If any surplus exists from the PR nodes the batteries will be charged evenly with this. +-- If the total demand requires draw on the batteries they will be discharged evenly. +-- +-- If the total demand is more than the available power all RE nodes will be shut down. +-- We have a brown-out situation. +-- +-- Hence all the power distribution logic resides in this single node. +-- +-- Nodes connected to the network will have one or more of these parameters as meta data: +-- _EU_supply : Exists for PR and BA node types. This is the EU value supplied by the node. Output +-- _EU_demand : Exists for RE and BA node types. This is the EU value the node requires to run. Output +-- _EU_input : Exists for RE and BA node types. This is the actual EU value the network can give the node. Input +-- +-- The reason the LV|MV|HV type is prepended toe meta data is because some machine could require several supplies to work. +-- This way the supplies are separated per network. + +technic.networks = {} + +local S = technic.getter + +minetest.register_craft({ + output = "technic:switching_station", + recipe = { + {"", "technic:lv_transformer", ""}, + {"default:copper_ingot", "technic:machine_casing", "default:copper_ingot"}, + {"technic:lv_cable0", "technic:lv_cable0", "technic:lv_cable0"} + } +}) + +minetest.register_node("technic:switching_station",{ + description = S("Switching Station"), + tiles = {"technic_water_mill_top_active.png", "technic_water_mill_top_active.png", + "technic_water_mill_top_active.png", "technic_water_mill_top_active.png", + "technic_water_mill_top_active.png", "technic_water_mill_top_active.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}, + sounds = default.node_sound_wood_defaults(), + drawtype = "nodebox", + paramtype = "light", + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("Switching Station")) + meta:set_string("active", 1) + end, +}) + +-------------------------------------------------- +-- Functions to traverse the electrical network +-------------------------------------------------- + +-- Add a wire node to the LV/MV/HV network +local add_new_cable_node = function(nodes, pos) + -- Ignore if the node has already been added + for i = 1, #nodes do + if pos.x == nodes[i].x and + pos.y == nodes[i].y and + pos.z == nodes[i].z then + return false + end + end + table.insert(nodes, {x=pos.x, y=pos.y, z=pos.z, visited=1}) + return true +end + +-- Generic function to add found connected nodes to the right classification array +local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, from_below) + technic.get_or_load_node(pos) + local meta = minetest.get_meta(pos) + local name = minetest.get_node(pos).name + + if technic.is_tier_cable(name, tier) then + add_new_cable_node(all_nodes, pos) + elseif machines[name] then + --dprint(name.." is a "..machines[name]) + if machines[name] == technic.producer then + add_new_cable_node(PR_nodes, pos) + elseif machines[name] == technic.receiver then + add_new_cable_node(RE_nodes, pos) + elseif machines[name] == technic.producer_receiver then + add_new_cable_node(PR_nodes, pos) + add_new_cable_node(RE_nodes, pos) + elseif machines[name] == "SPECIAL" and + (pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) and + from_below then + -- Another switching station -> disable it + add_new_cable_node(SP_nodes, pos) + meta:set_int("active", 0) + meta:set_string("active_pos", minetest.serialize(sw_pos)) + elseif machines[name] == technic.battery then + add_new_cable_node(BA_nodes, pos) + end + + meta:set_int(tier.."_EU_timeout", 2) -- Touch node + end +end + +-- Traverse a network given a list of machines and a cable type name +local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, i, machines, tier, sw_pos) + local pos = all_nodes[i] + local positions = { + {x=pos.x+1, y=pos.y, z=pos.z}, + {x=pos.x-1, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y+1, z=pos.z}, + {x=pos.x, y=pos.y-1, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z+1}, + {x=pos.x, y=pos.y, z=pos.z-1}} + --print("ON") + for i, cur_pos in pairs(positions) do + check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, cur_pos, machines, tier, sw_pos, i == 3) + end +end + +local touch_nodes = function(list, tier) + for _, pos in ipairs(list) do + local meta = minetest.get_meta(pos) + meta:set_int(tier.."_EU_timeout", 2) -- Touch node + end +end + +local get_network = function(sw_pos, pos1, tier) + local cached = technic.networks[minetest.hash_node_position(pos1)] + if cached and cached.tier == tier then + touch_nodes(cached.PR_nodes, tier) + touch_nodes(cached.BA_nodes, tier) + touch_nodes(cached.RE_nodes, tier) + for _, pos in ipairs(cached.SP_nodes) do + local meta = minetest.get_meta(pos) + meta:set_int("active", 0) + meta:set_string("active_pos", minetest.serialize(sw_pos)) + end + return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes + end + local i = 1 + local PR_nodes = {} + local BA_nodes = {} + local RE_nodes = {} + local SP_nodes = {} + local all_nodes = {pos1} + repeat + traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, + i, technic.machines[tier], tier, sw_pos) + i = i + 1 + until all_nodes[i] == nil + technic.networks[minetest.hash_node_position(pos1)] = {tier = tier, PR_nodes = PR_nodes, + RE_nodes = RE_nodes, BA_nodes = BA_nodes, SP_nodes = SP_nodes} + return PR_nodes, BA_nodes, RE_nodes +end + +----------------------------------------------- +-- The action code for the switching station -- +----------------------------------------------- +minetest.register_abm({ + nodenames = {"technic:switching_station"}, + label = "Switching Station", -- allows the mtt profiler to profile this abm individually + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local meta = minetest.get_meta(pos) + local meta1 = nil + local pos1 = {} + local PR_EU = 0 -- EUs from PR nodes + local BA_PR_EU = 0 -- EUs from BA nodes (discharching) + local BA_RE_EU = 0 -- EUs to BA nodes (charging) + local RE_EU = 0 -- EUs to RE nodes + + local tier = "" + local PR_nodes + local BA_nodes + local RE_nodes + local machine_name = S("Switching Station") + + if meta:get_int("active") ~= 1 then + meta:set_int("active", 1) + local active_pos = minetest.deserialize(meta:get_string("active_pos")) + if active_pos then + local meta1 = minetest.get_meta(active_pos) + meta:set_string("infotext", S("%s (Slave)"):format(meta1:get_string("infotext"))) + end + return + end + + -- Which kind of network are we on: + pos1 = {x=pos.x, y=pos.y-1, z=pos.z} + + local name = minetest.get_node(pos1).name + local tier = technic.get_cable_tier(name) + if tier then + PR_nodes, BA_nodes, RE_nodes = get_network(pos, pos1, tier) + else + --dprint("Not connected to a network") + meta:set_string("infotext", S("%s Has No Network"):format(machine_name)) + return + end + + -- Run all the nodes + local function run_nodes(list) + for _, pos2 in ipairs(list) do + technic.get_or_load_node(pos2) + local node2 = minetest.get_node(pos2) + local nodedef + if node2 and node2.name then + nodedef = minetest.registered_nodes[node2.name] + end + if nodedef and nodedef.technic_run then + nodedef.technic_run(pos2, node2) + end + end + end + + run_nodes(PR_nodes) + run_nodes(RE_nodes) + run_nodes(BA_nodes) + + -- Strings for the meta data + local eu_demand_str = tier.."_EU_demand" + local eu_input_str = tier.."_EU_input" + local eu_supply_str = tier.."_EU_supply" + + -- Distribute charge equally across multiple batteries. + local charge_total = 0 + local battery_count = 0 + + for n, pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + local charge = meta1:get_int("internal_EU_charge") + + if (meta1:get_int(eu_demand_str) ~= 0) then + charge_total = charge_total + charge + battery_count = battery_count + 1 + end + end + + local charge_distributed = math.floor(charge_total / battery_count) + + for n, pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + + if (meta1:get_int(eu_demand_str) ~= 0) then + meta1:set_int("internal_EU_charge", charge_distributed) + end + end + + -- Get all the power from the PR nodes + local PR_eu_supply = 0 -- Total power + for _, pos1 in pairs(PR_nodes) do + meta1 = minetest.get_meta(pos1) + PR_eu_supply = PR_eu_supply + meta1:get_int(eu_supply_str) + end + --dprint("Total PR supply:"..PR_eu_supply) + + -- Get all the demand from the RE nodes + local RE_eu_demand = 0 + for _, pos1 in pairs(RE_nodes) do + meta1 = minetest.get_meta(pos1) + RE_eu_demand = RE_eu_demand + meta1:get_int(eu_demand_str) + end + --dprint("Total RE demand:"..RE_eu_demand) + + -- Get all the power from the BA nodes + local BA_eu_supply = 0 + for _, pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + BA_eu_supply = BA_eu_supply + meta1:get_int(eu_supply_str) + end + --dprint("Total BA supply:"..BA_eu_supply) + + -- Get all the demand from the BA nodes + local BA_eu_demand = 0 + for _, pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + BA_eu_demand = BA_eu_demand + meta1:get_int(eu_demand_str) + end + --dprint("Total BA demand:"..BA_eu_demand) + + meta:set_string("infotext", + S("@1. Supply: @2 Demand: @3", + machine_name, technic.prettynum(PR_eu_supply), technic.prettynum(RE_eu_demand))) + + -- If the PR supply is enough for the RE demand supply them all + if PR_eu_supply >= RE_eu_demand then + --dprint("PR_eu_supply"..PR_eu_supply.." >= RE_eu_demand"..RE_eu_demand) + for _, pos1 in pairs(RE_nodes) do + meta1 = minetest.get_meta(pos1) + local eu_demand = meta1:get_int(eu_demand_str) + meta1:set_int(eu_input_str, eu_demand) + end + -- We have a surplus, so distribute the rest equally to the BA nodes + -- Let's calculate the factor of the demand + PR_eu_supply = PR_eu_supply - RE_eu_demand + local charge_factor = 0 -- Assume all batteries fully charged + if BA_eu_demand > 0 then + charge_factor = PR_eu_supply / BA_eu_demand + end + for n, pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + local eu_demand = meta1:get_int(eu_demand_str) + meta1:set_int(eu_input_str, math.floor(eu_demand * charge_factor)) + --dprint("Charging battery:"..math.floor(eu_demand*charge_factor)) + end + return + end + + -- If the PR supply is not enough for the RE demand we will discharge the batteries too + if PR_eu_supply + BA_eu_supply >= RE_eu_demand then + --dprint("PR_eu_supply "..PR_eu_supply.."+BA_eu_supply "..BA_eu_supply.." >= RE_eu_demand"..RE_eu_demand) + for _, pos1 in pairs(RE_nodes) do + meta1 = minetest.get_meta(pos1) + local eu_demand = meta1:get_int(eu_demand_str) + meta1:set_int(eu_input_str, eu_demand) + end + -- We have a deficit, so distribute to the BA nodes + -- Let's calculate the factor of the supply + local charge_factor = 0 -- Assume all batteries depleted + if BA_eu_supply > 0 then + charge_factor = (PR_eu_supply - RE_eu_demand) / BA_eu_supply + end + for n,pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + local eu_supply = meta1:get_int(eu_supply_str) + meta1:set_int(eu_input_str, math.floor(eu_supply * charge_factor)) + --dprint("Discharging battery:"..math.floor(eu_supply*charge_factor)) + end + return + end + + -- If the PR+BA supply is not enough for the RE demand: Power only the batteries + local charge_factor = 0 -- Assume all batteries fully charged + if BA_eu_demand > 0 then + charge_factor = PR_eu_supply / BA_eu_demand + end + for n, pos1 in pairs(BA_nodes) do + meta1 = minetest.get_meta(pos1) + local eu_demand = meta1:get_int(eu_demand_str) + meta1:set_int(eu_input_str, math.floor(eu_demand * charge_factor)) + end + for n, pos1 in pairs(RE_nodes) do + meta1 = minetest.get_meta(pos1) + meta1:set_int(eu_input_str, 0) + end + end, +}) + +-- Timeout ABM +-- Timeout for a node in case it was disconnected from the network +-- A node must be touched by the station continuously in order to function +local function switching_station_timeout_count(pos, tier) + local meta = minetest.get_meta(pos) + local timeout = meta:get_int(tier.."_EU_timeout") + if timeout <= 0 then + meta:set_int(tier.."_EU_input", 0) -- Not needed anymore <-- actually, it is for supply converter + return true + else + meta:set_int(tier.."_EU_timeout", timeout - 1) + return false + end +end +minetest.register_abm({ + nodenames = {"group:technic_machine"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + for tier, machines in pairs(technic.machines) do + if machines[node.name] and switching_station_timeout_count(pos, tier) then + local nodedef = minetest.registered_nodes[node.name] + if nodedef and nodedef.technic_disabled_machine_name then + node.name = nodedef.technic_disabled_machine_name + minetest.swap_node(pos, node) + elseif nodedef and nodedef.technic_on_disable then + nodedef.technic_on_disable(pos, node) + end + if nodedef then + local meta = minetest.get_meta(pos) + meta:set_string("infotext", S("%s Has No Network"):format(nodedef.description)) + end + end + end + end, +}) + +for tier, machines in pairs(technic.machines) do + -- SPECIAL will not be traversed + technic.register_machine(tier, "technic:switching_station", "SPECIAL") +end + -- cgit v1.2.3