diff --git a/elepower_machines/machines/electrolyzer.lua b/elepower_machines/machines/electrolyzer.lua index dc4a08f..b79d115 100644 --- a/elepower_machines/machines/electrolyzer.lua +++ b/elepower_machines/machines/electrolyzer.lua @@ -9,7 +9,7 @@ elepm.electrolyzer_recipes = { time = 20 }, { - recipe = "elepower_nuclear:heavy_water 1000", + recipe = "elepower_nuclear:heavy_water_source 1000", output = { "elepower_nuclear:deuterium 600", "elepower_dynamics:oxygen 400", @@ -167,7 +167,7 @@ ele.register_machine("elepower_machines:electrolyzer", { on_timer = electrolyzer_timer, fluid_buffers = { input = { - accepts = {"default:water_source", "elepower_nuclear:heavy_water", + accepts = {"default:water_source", "elepower_nuclear:heavy_water_source", "group:biomass", "group:electrolysis_recipe"}, drainable = false, capacity = 8000, diff --git a/elepower_nuclear/fluids.lua b/elepower_nuclear/fluids.lua index 0335fcc..c4dc680 100644 --- a/elepower_nuclear/fluids.lua +++ b/elepower_nuclear/fluids.lua @@ -6,12 +6,6 @@ -- These nodes are used as "fluids" -- They do not actually exist as nodes that should be placed. -minetest.register_node("elepower_nuclear:heavy_water", { - description = "Heavy Water", - groups = {not_in_creative_inventory = 1, oddly_breakable_by_hand = 1, water = 1}, - tiles = {"elenuclear_heavy_water.png"}, -}) - minetest.register_node("elepower_nuclear:tritium", { description = "Tritium Gas", groups = {not_in_creative_inventory = 1, oddly_breakable_by_hand = 1, gas = 1}, @@ -30,13 +24,112 @@ minetest.register_node("elepower_nuclear:helium", { tiles = {"elenuclear_helium.png"}, }) +minetest.register_node("elepower_nuclear:helium_plasma", { + description = "Helium Plasma\nSuperheated", + groups = {not_in_creative_inventory = 1, oddly_breakable_by_hand = 1, gas = 1}, + tiles = {"elenuclear_helium_plasma.png"}, +}) + ele.register_gas(nil, "Tritium", "elepower_nuclear:tritium") ele.register_gas(nil, "Deuterium", "elepower_nuclear:deuterium") ele.register_gas(nil, "Helium", "elepower_nuclear:helium") +ele.register_gas(nil, "Helium Plasma", "elepower_nuclear:helium_plasma") + +------------- +-- Liquids -- +------------- + +-- Heavy Water +minetest.register_node("elepower_nuclear:heavy_water_source", { + description = "Heavy Water Source", + drawtype = "liquid", + tiles = { + { + name = "elenuclear_heavy_water_source_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 2.0, + }, + }, + }, + special_tiles = { + { + name = "elenuclear_heavy_water_source_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 2.0, + }, + backface_culling = false, + }, + }, + alpha = 160, + paramtype = "light", + walkable = false, + pointable = false, + diggable = false, + buildable_to = true, + is_ground_content = false, + drop = "", + drowning = 1, + liquidtype = "source", + liquid_alternative_flowing = "elepower_nuclear:heavy_water_flowing", + liquid_alternative_source = "elepower_nuclear:heavy_water_source", + liquid_viscosity = 4, + post_effect_color = {a = 103, r = 13, g = 69, b = 121}, + groups = {heavy_water = 3, liquid = 3, puts_out_fire = 1, cools_lava = 1}, + sounds = default.node_sound_water_defaults(), +}) + +minetest.register_node("elepower_nuclear:heavy_water_flowing", { + description = "Flowing Heavy Water", + drawtype = "flowingliquid", + tiles = {"elenuclear_heavy_water.png"}, + special_tiles = { + { + name = "elenuclear_heavy_water_flowing_animated.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 0.8, + }, + }, + { + name = "elenuclear_heavy_water_flowing_animated.png", + backface_culling = true, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 0.8, + }, + }, + }, + alpha = 160, + paramtype = "light", + paramtype2 = "flowingliquid", + walkable = false, + pointable = false, + diggable = false, + buildable_to = true, + is_ground_content = false, + drop = "", + drowning = 1, + liquidtype = "flowing", + liquid_alternative_flowing = "elepower_nuclear:heavy_water_flowing", + liquid_alternative_source = "elepower_nuclear:heavy_water_source", + liquid_viscosity = 4, + post_effect_color = {a = 103, r = 13, g = 69, b = 121}, + groups = {heavy_water = 3, liquid = 3, puts_out_fire = 1, + not_in_creative_inventory = 1, cools_lava = 1}, + sounds = default.node_sound_water_defaults(), +}) ------------- --- Fluids -- ------------- -- Cold coolant @@ -136,8 +229,13 @@ minetest.register_node("elepower_nuclear:hot_coolant_flowing", { sounds = default.node_sound_water_defaults(), }) -bucket.register_liquid("elepower_nuclear:coolant_source", "elepower_nuclear:hot_coolant_flowing", - "elepower_nuclear:bucket_coolant", "#2497ff", "Coolant (Cold)") +if minetest.get_modpath("bucket") ~= nil then + bucket.register_liquid("elepower_nuclear:coolant_source", "elepower_nuclear:hot_coolant_flowing", + "elepower_nuclear:bucket_coolant", "#2497ff", "Coolant (Cold)") -bucket.register_liquid("elepower_nuclear:hot_coolant_source", "elepower_nuclear:hot_coolant_flowing", - "elepower_nuclear:bucket_hot_coolant", "#88649e", "Coolant (Hot)") + bucket.register_liquid("elepower_nuclear:hot_coolant_source", "elepower_nuclear:hot_coolant_flowing", + "elepower_nuclear:bucket_hot_coolant", "#88649e", "Coolant (Hot)") + + bucket.register_liquid("elepower_nuclear:heavy_water_source", "elepower_nuclear:heavy_water_flowing", + "elepower_nuclear:bucket_heavy_water", "#0d4579", "Heavy Water Bucket") +end diff --git a/elepower_nuclear/machines/fusion_reactor.lua b/elepower_nuclear/machines/fusion_reactor.lua index 26d9598..54846f1 100644 --- a/elepower_nuclear/machines/fusion_reactor.lua +++ b/elepower_nuclear/machines/fusion_reactor.lua @@ -1,4 +1,6 @@ +local struct_cache = {} + local iC = 1 -- Casing local iR = 2 -- Controller local iI = 3 -- Inputs @@ -55,9 +57,11 @@ local function determine_structure(pos, player) local scan_pos = vector.add(pos, {x = relX, y = y, z = relZ}) local index = area:indexp(scan_pos) if data[index] ~= ntype then - minetest.chat_send_player(player, ('Incorrect node at %d,%d,%d; expected %s, found %s'):format( - scan_pos.x,scan_pos.y,scan_pos.z,minetest.get_name_from_content_id(ntype), - minetest.get_name_from_content_id(data[index]))) + if player then + minetest.chat_send_player(player, ('Incorrect node at %d,%d,%d; expected %s, found %s'):format( + scan_pos.x,scan_pos.y,scan_pos.z,minetest.get_name_from_content_id(ntype), + minetest.get_name_from_content_id(data[index]))) + end success = false break end @@ -73,13 +77,180 @@ local function determine_structure(pos, player) end end - if success then + if success and player then minetest.chat_send_player(player, "Multi-node structure complete!") end return success, inputs, outputs, power end +local function notify_controller_presence(posi, posj) + for _, pos in pairs(posi) do + local meta = minetest.get_meta(pos) + meta:set_string("ctrl", posj) + + local t = minetest.get_node_timer(pos) + if not t:is_started() then + t:start(1.0) + end + end +end + +local function controller_formspec(in1, in2, out, power, time, state) + local bar = "image[3.5,1;1,1;gui_furnace_arrow_bg.png^[transformR270]" + + if time ~= nil then + bar = "image[3.5,1;1,1;gui_furnace_arrow_bg.png^[lowpart:".. + (time)..":gui_furnace_arrow_fg.png^[transformR270]" + end + + return "size[8,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + ele.formspec.power_meter(power).. + ele.formspec.fluid_bar(1, 0, in1).. + ele.formspec.fluid_bar(2, 0, in2).. + bar.. + ele.formspec.fluid_bar(7, 0, out).. + ele.formspec.state_switcher(7, 2.5, state) +end + +local function controller_timer(pos) + local refresh = false + local meta = minetest.get_meta(pos) + + -- Cache all reactor components + local cpos = minetest.pos_to_string(pos) + if not struct_cache[cpos] then + local st, i, o, p = determine_structure(pos) + if st then + struct_cache[cpos] = { + inputs = i, + outputs = o, + power = p, + } + + notify_controller_presence(i, cpos) + notify_controller_presence(o, cpos) + notify_controller_presence(p, cpos) + else + return false + end + end + + local in1_buffer = fluid_lib.get_buffer_data(pos, "in1") + local in2_buffer = fluid_lib.get_buffer_data(pos, "in2") + local out_buffer = fluid_lib.get_buffer_data(pos, "out") + + local capacity = ele.helpers.get_node_property(meta, pos, "capacity") + local storage = ele.helpers.get_node_property(meta, pos, "storage") + local pow_buffer = {capacity = capacity, storage = storage, usage = 0} + + meta:set_string("formspec", controller_formspec(in1_buffer, in2_buffer, out_buffer, pow_buffer, 0, 0)) + + -- Factors: + -- 1. Power. Power keeps these stats up: + -- 1. Field Strength + -- 2. Internal Temperature + -- 2. Fuel + + -- Deuterium + Tritium -> Helium Plasma + -- Ignition temperature: 2000K (70% scale) + -- Field strength: >90% + -- 1000 + 1000 mB of fuel : 2600 sec, 675 neutrons/s + -- Helium plasma will be used to create electricity via heat exchange. + + return refresh +end + +local function get_port_controller(pos) + local meta = minetest.get_meta(pos) + local ctrl = minetest.string_to_pos(meta:get_string("ctrl")) + local ctrl_node = minetest.get_node_or_nil(ctrl) + + if not ctrl_node or ctrl_node.name ~= "elepower_nuclear:reactor_controller" then + return nil + end + + return ctrl, minetest.get_meta(ctrl) +end + +local function port_destruct(pos) + local meta = minetest.get_meta(pos) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return nil end + + -- Remove controller's cache entry, forcing it to redetect its structure + local ctrl_name = minetest.pos_to_string(ctrl) + if struct_cache[ctrl_name] then + struct_cache[ctrl_name] = nil + end + + local t = minetest.get_node_timer(ctrl) + if not t:is_started() then + t:start(1.0) + end +end + +-- Transfer power from the power port to the controller +local function power_timer(pos) + local refresh = false + local meta = minetest.get_meta(pos) + local ctrl, ctrl_meta = get_port_controller(pos) + + if not ctrl then + meta:set_string("No controller found.") + return false + end + + local localc = ele.helpers.get_node_property(meta, pos, "capacity") + local locals = ele.helpers.get_node_property(meta, pos, "storage") + + local remotec = ele.helpers.get_node_property(ctrl_meta, ctrl, "capacity") + local remotes = ele.helpers.get_node_property(ctrl_meta, ctrl, "storage") + + if remotes ~= remotec then + if remotes + locals > remotec then + local add = remotec - remotes + locals = locals - add + remotes = remotes + add + else + remotes = remotes + locals + locals = 0 + end + refresh = true + end + + if refresh then + meta:set_int("storage", locals) + ctrl_meta:set_int("storage", remotes) + + local t = minetest.get_node_timer(ctrl) + if not t:is_started() then + t:start(1.0) + end + end + + meta:set_string("infotext", ("Feeding controller at %s\nLocal %s"):format( + minetest.pos_to_string(ctrl), ele.capacity_text(localc, locals))) + + return refresh +end + +local function port_timer(pos) + local meta = minetest.get_meta(pos) + local ctrl = get_port_controller(pos) + + if not ctrl then + meta:set_string("No controller found.") + return false + end + + meta:set_string("infotext", "Feeding controller at " .. minetest.pos_to_string(ctrl)) + return false +end + ----------- -- Nodes -- ----------- @@ -90,9 +261,30 @@ minetest.register_node("elepower_nuclear:reactor_controller", { "elepower_advblock_combined.png", "elepower_advblock_combined.png", "elepower_advblock_combined.png", "elepower_advblock_combined.png", "elepower_advblock_combined.png", "elepower_advblock_combined.png^elenuclear_fusion_controller.png", }, - groups = {cracky = 2}, + groups = { + cracky = 2, + }, + fluid_buffers = { + in1 = { + capacity = 16000, + accepts = {"elepower_nuclear:deuterium"}, + drainable = false, + }, + in2 = { + capacity = 16000, + accepts = {"elepower_nuclear:tritium", "elepower_nuclear:helium"}, + drainable = false, + }, + out = { + capacity = 16000, + accepts = nil, + drainable = true, + }, + }, + ele_capacity = 64000, + on_timer = controller_timer, on_punch = function (pos, node, puncher, pointed_thing) - print(determine_structure(pos, puncher:get_player_name())) + determine_structure(pos, puncher:get_player_name()) minetest.node_punch(pos, node, puncher, pointed_thing) end, }) @@ -104,7 +296,16 @@ minetest.register_node("elepower_nuclear:reactor_power", { "elepower_advblock_combined.png", "elepower_advblock_combined.png", "elepower_advblock_combined.png^elenuclear_power_port.png^elepower_power_port.png", }, paramtype2 = "facedir", - groups = {cracky = 2}, + groups = { + cracky = 2, + ele_machine = 1, + ele_user = 1, + }, + ele_capacity = 8000, + ele_usage = 0, + ele_inrush = 64, + on_timer = power_timer, + on_destruct = port_destruct, }) minetest.register_node("elepower_nuclear:reactor_fluid", { @@ -115,7 +316,66 @@ minetest.register_node("elepower_nuclear:reactor_fluid", { "elepower_advblock_combined.png^elenuclear_fluid_port.png^elepower_power_port.png", }, paramtype2 = "facedir", - groups = {cracky = 2}, + groups = { + cracky = 2, + fluid_container = 1, + tube = 1, + }, + fluid_buffers = {}, + on_timer = port_timer, + on_destruct = port_destruct, + node_io_can_put_liquid = function (pos, node, side) + return true + end, + node_io_can_take_liquid = function (pos, node, side) + return false + end, + node_io_get_liquid_size = function (pos, node, side) + return 2 + end, + node_io_get_liquid_name = function(pos, node, side, index) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return nil end + + return ctrl_meta:get_string("in" .. index .. "_fluid") + end, + node_io_get_liquid_stack = function(pos, node, side, index) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return ItemStack(nil) end + + return ItemStack(ctrl_meta:get_string("in" .. index .. "_fluid") .. " " .. + ctrl_meta:get_int("in" .. index .. "_fluid_storage")) + end, + node_io_accepts_millibuckets = function(pos, node, side) return true end, + node_io_put_liquid = function(pos, node, side, putter, liquid, millibuckets) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return nil end + + local buffers = fluid_lib.get_node_buffers(ctrl) + local leftovers = 0 + for buffer,data in pairs(buffers) do + if millibuckets == 0 then break end + local didnt_fit = fluid_lib.insert_into_buffer(ctrl, buffer, liquid, millibuckets) + millibuckets = millibuckets - (millibuckets - didnt_fit) + leftovers = leftovers + didnt_fit + end + return leftovers + end, + node_io_room_for_liquid = function(pos, node, side, liquid, millibuckets) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return nil end + + local buffers = fluid_lib.get_node_buffers(ctrl) + local insertable = 0 + for buffer,data in pairs(buffers) do + local insert = fluid_lib.can_insert_into_buffer(ctrl, buffer, liquid, millibuckets) + if insert > 0 then + insertable = insert + break + end + end + return insertable + end, }) minetest.register_node("elepower_nuclear:reactor_output", { @@ -126,7 +386,67 @@ minetest.register_node("elepower_nuclear:reactor_output", { "elepower_advblock_combined.png^elenuclear_fluid_port_out.png^elepower_power_port.png", }, paramtype2 = "facedir", - groups = {cracky = 2}, + groups = { + cracky = 2, + fluid_container = 1, + tube = 1, + }, + fluid_buffers = {}, + on_timer = port_timer, + on_destruct = port_destruct, + node_io_can_put_liquid = function (pos, node, side) + return false + end, + node_io_can_take_liquid = function (pos, node, side) + return true + end, + node_io_accepts_millibuckets = function(pos, node, side) return true end, + node_io_take_liquid = function(pos, node, side, taker, want_liquid, want_millibuckets) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return nil end + + local buffers = fluid_lib.get_node_buffers(ctrl) + local buffer = "out" + local took = 0 + local name = "" + + local bfdata = fluid_lib.get_buffer_data(ctrl, buffer) + local storage = bfdata.amount + local fluid = bfdata.fluid + if (fluid == want_liquid or want_liquid == "") and storage >= want_millibuckets then + name, took = fluid_lib.take_from_buffer(ctrl, buffer, want_millibuckets) + end + + return {name = name, millibuckets = took} + end, + node_io_get_liquid_size = function (pos, node, side) + return 1 + end, + node_io_get_liquid_name = function(pos, node, side, index) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return "" end + return ctrl_meta:get_string("out_fluid") + end, + node_io_get_liquid_stack = function(pos, node, side, index) + local ctrl, ctrl_meta = get_port_controller(pos) + if not ctrl then return ItemStack(nil) end + + return ItemStack(ctrl_meta:get_string("out_fluid") .. " " .. + ctrl_meta:get_int("out_fluid_storage")) + end, +}) + +minetest.register_lbm({ + label = "Enable Fusion Reactors on load", + name = "elepower_nuclear:fusion_reactors", + nodenames = {"elepower_nuclear:reactor_controller"}, + run_at_every_load = true, + action = function (pos) + local t = minetest.get_node_timer(pos) + if not t:is_started() then + t:start(1.0) + end + end, }) -- Define reactor structure with Content IDs diff --git a/elepower_nuclear/machines/heat_exchanger.lua b/elepower_nuclear/machines/heat_exchanger.lua index ad265a0..0ffbff4 100644 --- a/elepower_nuclear/machines/heat_exchanger.lua +++ b/elepower_nuclear/machines/heat_exchanger.lua @@ -15,6 +15,17 @@ local function get_formspec(heat, cold, water, steam) default.get_hotbar_bg(0, 4.25) end +local heat_recipes = { + ["elepower_nuclear:hot_coolant_source"] = { + out = "elepower_nuclear:coolant_source", + factor = 1, + }, + ["elepower_nuclear:helium_plasma"] = { + out = "elepower_nuclear:helium", + factor = 8, + }, +} + local function heat_exchanger_timer(pos) local meta = minetest.get_meta(pos) local change = false @@ -24,15 +35,25 @@ local function heat_exchanger_timer(pos) local water = fluid_lib.get_buffer_data(pos, "water") local steam = fluid_lib.get_buffer_data(pos, "steam") - -- See if we have enough hot coolant - if heat.amount >= 1000 then - local water_convert = math.min(water.amount, 1000) - if steam.amount + water_convert > steam.capacity then - water_convert = steam.capacity - steam.amount + while true do + if heat.amount < 1000 or heat.fluid == "" or not heat_recipes[heat.fluid] then + break end - if water_convert > 0 then - if cold.amount + 1000 < cold.capacity then + -- See if we have enough hot coolant + if heat.amount >= 1000 and heat.fluid ~= "" then + local damnt = heat_recipes[heat.fluid] + local water_convert = math.min(water.amount, 1000 * damnt.factor) + + if cold.fluid ~= damnt.fluid and cold.fluid ~= "" then + break + end + + if steam.amount + water_convert > steam.capacity then + water_convert = steam.capacity - steam.amount + end + + if water_convert > 0 and cold.amount + 1000 < cold.capacity then -- Conversion heat.amount = heat.amount - 1000 cold.amount = cold.amount + 1000 @@ -40,13 +61,16 @@ local function heat_exchanger_timer(pos) water.amount = water.amount - water_convert steam.amount = steam.amount + water_convert + cold.fluid = damnt.out change = true end end + + break end if change then - meta:set_string("cold_fluid", "elepower_nuclear:coolant_source") + meta:set_string("cold_fluid", cold.fluid) meta:set_string("steam_fluid", "elepower_dynamics:steam") meta:set_int("heat_fluid_storage", heat.amount) @@ -58,7 +82,7 @@ local function heat_exchanger_timer(pos) meta:set_string("formspec", get_formspec(heat, cold, water, steam)) - return false + return change end ele.register_machine("elepower_nuclear:heat_exchanger", { @@ -71,12 +95,12 @@ ele.register_machine("elepower_nuclear:heat_exchanger", { fluid_buffers = { heat = { capacity = 8000, - accepts = {"elepower_nuclear:hot_coolant_source"}, + accepts = {"elepower_nuclear:hot_coolant_source", "elepower_nuclear:helium_plasma"}, drainable = false, }, cold = { capacity = 8000, - accepts = {"elepower_nuclear:coolant_source"}, + accepts = {"elepower_nuclear:coolant_source", "elepower_nuclear:helium"}, drainable = true, }, water = { diff --git a/elepower_nuclear/textures/elenuclear_heavy_water.png b/elepower_nuclear/textures/elenuclear_heavy_water.png index 6929134..717879e 100644 Binary files a/elepower_nuclear/textures/elenuclear_heavy_water.png and b/elepower_nuclear/textures/elenuclear_heavy_water.png differ diff --git a/elepower_nuclear/textures/elenuclear_heavy_water_flowing_animated.png b/elepower_nuclear/textures/elenuclear_heavy_water_flowing_animated.png new file mode 100644 index 0000000..96a8077 Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_heavy_water_flowing_animated.png differ diff --git a/elepower_nuclear/textures/elenuclear_heavy_water_source_animated.png b/elepower_nuclear/textures/elenuclear_heavy_water_source_animated.png new file mode 100644 index 0000000..0a93b6b Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_heavy_water_source_animated.png differ diff --git a/elepower_nuclear/textures/elenuclear_helium_plasma.png b/elepower_nuclear/textures/elenuclear_helium_plasma.png new file mode 100644 index 0000000..7103ef1 Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_helium_plasma.png differ