diff --git a/elepower_nuclear/crafting.lua b/elepower_nuclear/crafting.lua index 50534fc..653c7e6 100644 --- a/elepower_nuclear/crafting.lua +++ b/elepower_nuclear/crafting.lua @@ -36,7 +36,7 @@ elepm.register_craft({ elepm.register_craft({ type = "enrichment", output = { "elepower_nuclear:depleted_uranium_dust", "elepower_nuclear:nuclear_waste 3"}, - recipe = { "elepower_nuclear:nuclear_waste 4" }, + recipe = { "elepower_nuclear:nuclear_waste 5" }, time = 50, }) diff --git a/elepower_nuclear/craftitems.lua b/elepower_nuclear/craftitems.lua index b19e57b..b9e644f 100644 --- a/elepower_nuclear/craftitems.lua +++ b/elepower_nuclear/craftitems.lua @@ -31,17 +31,22 @@ minetest.register_craftitem("elepower_nuclear:nuclear_waste", { minetest.register_craftitem("elepower_nuclear:fuel_rod_empty", { description = "Empty Fuel Rod", - inventory_image = "elenuclear_fuel_rod_empty.png" + inventory_image = "elenuclear_fuel_rod_empty.png", + max_stack = 1, }) minetest.register_craftitem("elepower_nuclear:fuel_rod_fissile", { - description = "Fissile Fuel Rod", - inventory_image = "elenuclear_fuel_rod_fissile.png" + description = "Fissile Fuel Rod\nLasts 2 hours (7200 seconds)", + inventory_image = "elenuclear_fuel_rod_fissile.png", + groups = { fissile_fuel = 1 }, + fissile_count = 7200, + max_stack = 1, }) minetest.register_craftitem("elepower_nuclear:fuel_rod_depleted", { - description = "Depleted Fuel Rod", - inventory_image = "elenuclear_fuel_rod_depleted.png" + description = "Depleted Fuel Rod\nCan not be used in a reactor anymore", + inventory_image = "elenuclear_fuel_rod_depleted.png", + max_stack = 1, }) -------------------------- diff --git a/elepower_nuclear/fluids.lua b/elepower_nuclear/fluids.lua index dba797b..03c80a0 100644 --- a/elepower_nuclear/fluids.lua +++ b/elepower_nuclear/fluids.lua @@ -14,7 +14,7 @@ minetest.register_node("elepower_nuclear:coolant", { minetest.register_node("elepower_nuclear:coolant_hot", { description = "Coolant (hot)", - groups = {not_in_creative_inventory = 1, oddly_breakable_by_hand = 1, coolant = 1}, + groups = {not_in_creative_inventory = 1, oddly_breakable_by_hand = 1, coolant = 1, hot = 1}, tiles = {"elenuclear_hot_coolant.png"}, }) diff --git a/elepower_nuclear/init.lua b/elepower_nuclear/init.lua index 4584e55..a5e550b 100644 --- a/elepower_nuclear/init.lua +++ b/elepower_nuclear/init.lua @@ -10,3 +10,4 @@ dofile(modpath.."/craftitems.lua") dofile(modpath.."/nodes.lua") dofile(modpath.."/fluids.lua") dofile(modpath.."/crafting.lua") +dofile(modpath.."/worldgen.lua") diff --git a/elepower_nuclear/machines/enrichment_plant.lua b/elepower_nuclear/machines/enrichment_plant.lua index 45f63b9..cfd6d8f 100644 --- a/elepower_nuclear/machines/enrichment_plant.lua +++ b/elepower_nuclear/machines/enrichment_plant.lua @@ -31,7 +31,7 @@ elepm.register_crafter("elepower_nuclear:enrichment_plant", { description = "Enrichment Plant", craft_type = "enrichment", tiles = { - "elenuclear_machine_top.png", "elenuclear_machine_top.png", "elenuclear_machine_side.png", + "elenuclear_machine_top.png", "elepower_lead_block.png", "elenuclear_machine_side.png", "elenuclear_machine_side.png", "elenuclear_machine_side.png", "elenuclear_enrichment_plant.png", }, groups = {ele_user = 1, cracky = 3}, diff --git a/elepower_nuclear/machines/fission_reactor.lua b/elepower_nuclear/machines/fission_reactor.lua new file mode 100644 index 0000000..92e53da --- /dev/null +++ b/elepower_nuclear/machines/fission_reactor.lua @@ -0,0 +1,488 @@ + +--[[ + Reactor fitness check: + 8x8x8 area surrounding the core must either contain.. + Water source nodes + Neutron Absorber (with active medium) + Fluid Port (with COLD coolant available) + Also acceptable nodes: + Any fluid transfer conduit + Any reactor component + Unacceptable nodes (These raise heat INSTANTLY!): + Lava source + Hot coolant + ..in order to keep the heat below critical. Any other detected node will either be MOLTEN or ACTIVATED (TODO) (you don't want this!) + Reactor core will be replaced by a molten core when the heat reaches 100%. All components and fuel will be lost! + Do NOT run the reactor at 100% power 100% percent of the time! Keep some control rods partially inserted at all times. +]] + +local AREA_SIZE = 8 + +local function calculate_fitness(pos) + -- Calculate the heat sink percentage + -- Amount of nodes we shall count down from + local add = {x = (AREA_SIZE) / 2, y = (AREA_SIZE) / 2, z = (AREA_SIZE) / 2} + local minp = vector.subtract(pos, add) + local maxp = vector.add(pos, add) + + -- Get the vmanip mapgen object and the nodes and VoxelArea + local manip = minetest.get_voxel_manip() + local e1, e2 = manip:read_from_map(minp, maxp) + local area = VoxelArea:new{MinEdge=e1, MaxEdge=e2} + local data = manip:get_data() + + local ids = { + c_water = minetest.get_content_id("default:water_source"), + c_lava = minetest.get_content_id("default:lava"), + } + + local excession = 0 + local hu = 0 + local nodes = 0 + for i in area:iter( + minp.x, minp.y, minp.z, + maxp.x, maxp.y, maxp.z + ) do + nodes = nodes + 1 + if data[i] == ids["c_water"] then + hu = hu - 1 + elseif data[i] == ids["c_lava"] then + hu = hu + 1 + else + local dp = minetest.get_name_from_content_id(data[i]) + if excession <= 16 and (ele.helpers.get_item_group(dp, "ele_reactor_component") or + ele.helpers.get_item_group(dp, "ele_neutron_absorbant") or + ele.helpers.get_item_group(dp, "elefluid_transport_source") or + ele.helpers.get_item_group(dp, "elefluid_transport") or + ele.helpers.get_item_group(dp, "tube") or + ele.helpers.get_item_group(dp, "tubedevice")) then + hu = hu - 1 + excession = excession + 1 + elseif ele.helpers.get_item_group(dp, "hot") then + hu = hu + 1 + else + hu = hu + 1 + end + end + end + + hu = nodes + hu + + return 100 - math.floor(100 * hu / nodes), hu +end + +local function fuel_after_depletion(inv) + local fuel_count = 0 + local change = false + + local list = inv:get_list("fuel") + for i,stack in pairs(list) do + local sname = stack:get_name() + if ele.helpers.get_item_group(sname, "fissile_fuel") then + local stdef = minetest.registered_items[sname] + if stdef.fissile_count then + local meta = stack:get_meta() + local fscount = meta:get_int("fission_count") + if fscount < stdef.fissile_count then + fscount = fscount + 1 + fuel_count = fuel_count + 1 + + meta:set_int("fission_count", fscount) + meta:set_string("description", ("%s\nDepleted: %d "):format(stdef.description, + math.floor(100 * fscount / stdef.fissile_count)).." %") + else + stack = ItemStack("elepower_nuclear:fuel_rod_depleted") + end + list[i] = stack + change = true + end + end + end + + if change then + inv:set_list("fuel", list) + end + + return fuel_count +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:is_empty("fuel") +end + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + + if not ele.helpers.get_item_group(stack:get_name(), "fissile_fuel") then + return 0 + end + + return stack:get_count() +end + +local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack(from_list, from_index) + return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) +end + +local function get_core_formspec(heat, power) + local status = "Activate by extracting the control rods" + + if heat > 80 then + status = "!!! TEMPERATURE CRITICAL !!!" + elseif heat > 90 then + status = "!!! REACTOR CRITICAL !!!" + elseif heat > 95 then + status = "!!! REACTOR MELTDOWN IMMINENT !!!" + elseif power > 0 then + status = "Active reaction chain" + end + + return "size[8,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;fuel;2.5,0;3,3;]".. + "list[current_player;main;0,4.25;8,1;]".. + "list[current_player;main;0,5.5;8,3;8]".. + ele.formspec.create_bar(0, 0, power, "#ff0000", true).. + ele.formspec.create_bar(0.5, 0, heat, "#ffdd11", true).. + "label[0,3;Power: \t"..power.."%]".. + "label[0,3.25;Heat: \t"..heat.."%]".. + "label[0,3.75;".. status .."]".. + "listring[current_player;main]".. + "listring[context;fuel]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 4.25) +end + +local function get_controller_formspec(rod_pos, selected) + -- TODO: Reactor-dependent rod count + local rods = 4 + local ctrls = {} + + for num, depth in pairs(rod_pos) do + local xoffset = (num / rods) * 8 + local sel = "" + + if num == selected then + sel = " <- " + end + + local fspc = ("label[%d,0;%s]"):format(xoffset - 0.25, depth .. " %" .. sel) + + fspc = fspc .. ele.formspec.create_bar(xoffset - 1, 0.5, 100 - depth, "#252625", true) + + table.insert(ctrls, fspc) + end + + return "size[8,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + table.concat( ctrls, "" ).. + "button[0,3.5;1.5,0.5;next;Next]".. + "button[1.5,3.5;1.5,0.5;prev;Previous]".. + "button[3.25,3.5;1.5,0.5;stop;SCRAM]".. + "button[5,3.5;1.5,0.5;up;Raise]".. + "button[6.5,3.5;1.5,0.5;down;Lower]".. + "tooltip[next;Select the next control rod]".. + "tooltip[prev;Select the previous control rod]".. + "tooltip[stop;Drops all the rods into the reactor core, instantly stopping it]".. + "tooltip[up;Raise selected control rod]".. + "tooltip[down;Lower selected control rod]".. + "list[current_player;main;0,4.25;8,1;]".. + "list[current_player;main;0,5.5;8,3;8]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 4.25) +end + +local function get_port_formspec(cool, hot) + return "size[8,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + ele.formspec.fluid_bar(0, 0, cool).. + ele.formspec.fluid_bar(7, 0, hot).. + "list[current_player;main;0,4.25;8,1;]".. + "list[current_player;main;0,5.5;8,3;8]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 4.25) +end + +local function reactor_core_timer(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local headless = false + + -- SAFEGUARD: Expect a controller to be above the core + local controller_pos = {x = pos.x, y = pos.y + 1, z = pos.z} + local controller_node = minetest.get_node_or_nil(controller_pos) + if not controller_node or controller_node.name ~= "elepower_nuclear:fission_controller" then + -- Don't do anything without a head + headless = true + end + + local controller = minetest.get_meta(controller_pos) + + -- Only read area ever so often + -- Calculate the absorbance of heat around the core + local hp = meta:get_int("absorbance") + local absorb_tick = meta:get_int("absorb_tick") + if absorb_tick > 10 then + hp = calculate_fitness(pos) + absorb_tick = 0 + else + absorb_tick = absorb_tick + 1 + end + + meta:set_int("absorb_tick", absorb_tick) + meta:set_int("absorbance", hp) + + -- Get reactor power setting + local power_setting_target = controller:get_int("setting") + local power_setting = meta:get_int("setting") + + -- Do nothing + if headless then + power_setting = 0 + else + if not (power_setting_target == 0 and power_setting == 0) then + -- Decrease or increase power + if power_setting_target > power_setting then + power_setting = power_setting + 1 + elseif power_setting_target < power_setting then + power_setting = power_setting - 5 + end + + if power_setting < 0 then + power_setting = 0 + elseif power_setting > 100 then + power_setting = 100 + end + end + end + + if power_setting > 0 then + local fuel_reactor = fuel_after_depletion(inv) + if fuel_reactor == 0 then + -- Enforce zero power setting when no fuel present + power_setting = 0 + end + end + + -- Set power setting + meta:set_int("setting", power_setting) + + -- Get reactor heat + local heat = meta:get_int("heat") + + -- Calculate heat + if hp < 75 and power_setting > 0 then + heat = heat + (math.floor(((100-(hp/100))*power_setting)) + 1) + elseif power_setting > 5 then + local ceiling = math.floor(power_setting / 2) + if heat ~= ceiling then + if heat > ceiling then + heat = heat - 1 + else + heat = heat + 1 + end + end + elseif heat > 0 then + heat = heat - 1 + end + + if heat >= 100 then + -- TODO: Melt + print("It ded.") + minetest.set_node(pos, {name = "air"}) + return false + end + + -- Expect a fluid port below the core + local fluid_port_pos = {x = pos.x, y = pos.y - 1, z = pos.z} + local fluid_port_node = minetest.get_node_or_nil(fluid_port_pos) + if fluid_port_node ~= nil and fluid_port_node.name == "elepower_nuclear:reactor_fluid_port" then + -- TODO: Heat coolant + end + + meta:set_int("heat", heat) + meta:set_string("formspec", get_core_formspec(heat, power_setting)) + + return true +end + +local function reactor_controller_timer(pos) + local meta = minetest.get_meta(pos) + local settings = {} + local averg = 0 + + for i = 1, 4 do + table.insert(settings, meta:get_int("c" .. i)) + averg = averg + settings[i] + end + + meta:set_int("setting", 100 - (averg / 4)) + meta:set_string("formspec", get_controller_formspec(settings, meta:get_int("selected"))) + + return false +end + +local function reactor_controller_manage(pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + local selected = meta:get_int("selected") + local change = false + + if fields["next"] then + selected = selected + 1 + if selected > 4 then + selected = 1 + end + + meta:set_int("selected", selected) + change = true + elseif fields["prev"] then + selected = selected - 1 + if selected == 0 then + selected = 4 + end + + meta:set_int("selected", selected) + change = true + elseif fields["stop"] then + for i = 1, 4 do + meta:set_int("c" .. i, 100) + end + change = true + elseif fields["up"] then + local sl = meta:get_int("c"..selected) + sl = sl - 10 + + if sl <= 0 then + sl = 0 + end + + meta:set_int("c"..selected, sl) + change = true + elseif fields["down"] then + local sl = meta:get_int("c"..selected) + sl = sl + 10 + + if sl >= 100 then + sl = 100 + end + + meta:set_int("c"..selected, sl) + change = true + end + + if change then + minetest.get_node_timer(pos):start(1.0) + end +end + +local function reactor_port_timer(pos) + return false +end + +-- Reactor Core +ele.register_base_device("elepower_nuclear:fission_core", { + description = "Fission Reactor Core", + groups = { + cracky = 3, + ele_reactor_core = 1, + ele_reactor_component = 1, + }, + tiles = { + "elenuclear_fission_core_top.png", "elepower_lead_block.png", "elenuclear_fission_core_side.png", + "elenuclear_fission_core_side.png", "elenuclear_fission_core_side.png", "elenuclear_fission_core_side.png", + }, + on_timer = reactor_core_timer, + on_construct = function (pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + inv:set_size("fuel", 9) + meta:set_int("absorb_tick", 11) + + meta:set_string("formspec", get_core_formspec(0,0,false)) + end, + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = ele.default.allow_metadata_inventory_take, + + on_metadata_inventory_move = ele.default.metadata_inventory_changed, + on_metadata_inventory_put = ele.default.metadata_inventory_changed, + on_metadata_inventory_take = ele.default.metadata_inventory_changed, +}) + +-- Reactor Control +ele.register_base_device("elepower_nuclear:fission_controller", { + description = "Fission Control Module\nPlace me on top of a Fission Reactor Core", + groups = { + cracky = 3, + ele_reactor_component = 1, + }, + tiles = { + "elenuclear_fission_core_top.png", "elepower_lead_block.png", "elenuclear_fission_controller_side.png", + "elenuclear_fission_controller_side.png", "elenuclear_fission_controller_side.png", "elenuclear_fission_controller_side.png", + }, + on_timer = reactor_controller_timer, + on_receive_fields = reactor_controller_manage, + on_construct = function (pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + meta:set_int("c1", 100) + meta:set_int("c2", 100) + meta:set_int("c3", 100) + meta:set_int("c4", 100) + + meta:set_int("setting", 0) + meta:set_int("selected", 1) + + meta:set_string("formspec", get_controller_formspec({100, 100, 100, 100}, 1)) + end +}) + +-- Reactor Fluid Port +ele.register_base_device("elepower_nuclear:reactor_fluid_port", { + description = "Reactor Fluid Port\nPlace me on the bottom of a Fission Reactor Core", + groups = { + cracky = 3, + ele_reactor_component = 1, + ele_port = 1, + fluid_container = 1, + }, + tiles = { + "elenuclear_machine_top.png", "elepower_lead_block.png", "elenuclear_machine_side.png^elepower_power_port.png", + "elenuclear_machine_side.png^elepower_power_port.png", "elenuclear_machine_side.png^elepower_power_port.png", + "elenuclear_machine_side.png^elepower_power_port.png", + }, + on_timer = reactor_port_timer, + on_construct = function (pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + meta:set_string("formspec", get_port_formspec()) + end, + fluid_buffers = { + cool = { + capacity = 16000, + accepts = {"default:water_source", "elepower_nuclear:coolant"}, + drainable = false, + }, + hot = { + capacity = 16000, + accepts = {"elepower_nuclear:coolant_hot"}, + drainable = true, + } + }, +}) diff --git a/elepower_nuclear/machines/init.lua b/elepower_nuclear/machines/init.lua index 85685b2..25019a9 100644 --- a/elepower_nuclear/machines/init.lua +++ b/elepower_nuclear/machines/init.lua @@ -1,13 +1,6 @@ local mp = elenuclear.modpath .. "/machines/" -minetest.register_node("elepower_nuclear:machine_block", { - description = "Radiation-shielded Lead Machine Chassis", - tiles = { - "elenuclear_machine_top.png", "elepower_lead_block.png", "elenuclear_machine_block.png", - "elenuclear_machine_block.png", "elenuclear_machine_block.png", "elenuclear_machine_block.png", - }, - groups = {cracky = 3}, -}) - dofile(mp.."enrichment_plant.lua") +dofile(mp.."fission_reactor.lua") + diff --git a/elepower_nuclear/nodes.lua b/elepower_nuclear/nodes.lua index 7eff573..9c5f1be 100644 --- a/elepower_nuclear/nodes.lua +++ b/elepower_nuclear/nodes.lua @@ -1,2 +1,19 @@ dofile(elenuclear.modpath.."/machines/init.lua") + +minetest.register_node("elepower_nuclear:machine_block", { + description = "Radiation-shielded Lead Machine Chassis", + tiles = { + "elenuclear_machine_top.png", "elepower_lead_block.png", "elenuclear_machine_block.png", + "elenuclear_machine_block.png", "elenuclear_machine_block.png", "elenuclear_machine_block.png", + }, + groups = {cracky = 3}, +}) + +minetest.register_node("elepower_nuclear:stone_with_uranium", { + description = "Uranium Ore", + tiles = {"default_stone.png^elenuclear_mineral_uranium.png"}, + groups = {cracky = 2}, + drop = 'elepower_nuclear:uranium_lump', + sounds = default.node_sound_stone_defaults(), +}) diff --git a/elepower_nuclear/textures/elenuclear_fission_controller_side.png b/elepower_nuclear/textures/elenuclear_fission_controller_side.png new file mode 100644 index 0000000..3a5f939 Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_fission_controller_side.png differ diff --git a/elepower_nuclear/textures/elenuclear_fission_core_side.png b/elepower_nuclear/textures/elenuclear_fission_core_side.png new file mode 100644 index 0000000..4d5b7d4 Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_fission_core_side.png differ diff --git a/elepower_nuclear/textures/elenuclear_fission_core_top.png b/elepower_nuclear/textures/elenuclear_fission_core_top.png new file mode 100644 index 0000000..2845c2c Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_fission_core_top.png differ diff --git a/elepower_nuclear/textures/elenuclear_mineral_uranium.png b/elepower_nuclear/textures/elenuclear_mineral_uranium.png new file mode 100644 index 0000000..e62c8ab Binary files /dev/null and b/elepower_nuclear/textures/elenuclear_mineral_uranium.png differ diff --git a/elepower_nuclear/textures/elenuclear_uranium_lump.png b/elepower_nuclear/textures/elenuclear_uranium_lump.png index f0ce3c0..81f74b6 100644 Binary files a/elepower_nuclear/textures/elenuclear_uranium_lump.png and b/elepower_nuclear/textures/elenuclear_uranium_lump.png differ diff --git a/elepower_nuclear/textures/gui_sheen.png b/elepower_nuclear/textures/gui_sheen.png new file mode 100644 index 0000000..6f0b38d Binary files /dev/null and b/elepower_nuclear/textures/gui_sheen.png differ diff --git a/elepower_nuclear/worldgen.lua b/elepower_nuclear/worldgen.lua new file mode 100644 index 0000000..824ecb7 --- /dev/null +++ b/elepower_nuclear/worldgen.lua @@ -0,0 +1,39 @@ + +-------------- +-- Worldgen -- +-------------- + +-- Uranium + +minetest.register_ore({ + ore_type = "scatter", + ore = "elepower_nuclear:stone_with_uranium", + wherein = "default:stone", + clust_scarcity = 15 * 15 * 15, + clust_num_ores = 5, + clust_size = 3, + y_max = 846, + y_min = 248, +}) + +minetest.register_ore({ + ore_type = "scatter", + ore = "elepower_nuclear:stone_with_uranium", + wherein = "default:stone", + clust_scarcity = 14 * 14 * 14, + clust_num_ores = 5, + clust_size = 3, + y_max = -248, + y_min = -846, +}) + +minetest.register_ore({ + ore_type = "scatter", + ore = "elepower_nuclear:stone_with_uranium", + wherein = "default:stone", + clust_scarcity = 10 * 10 * 10, + clust_num_ores = 8, + clust_size = 3, + y_max = -1248, + y_min = -1846, +})