BobFred7
2020-05-13 df7f2e464afa034fa5667f0ba7c0e391a8e793fe
technic/machines/HV/nuclear_reactor.lua
@@ -1,206 +1,428 @@
-- 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!
--[[
 The enriched uranium rod driven EU generator.
A very large and advanced machine providing vast amounts of power.
Very efficient but also expensive to run as it needs uranium.
Provides 10000 HV EUs for one week (only counted when loaded).
local burn_ticks   = 7 * 24 * 60 * 60       -- (seconds).
local power_supply = 100000                 -- EUs
local fuel_type    = "technic:uranium_fuel" -- The reactor burns this stuff
The nuclear reactor core requires a casing of water and a protective
shield to work.  This is checked now and then and if the casing is not
intact the reactor will melt down!
--]]
local burn_ticks = 7 * 24 * 60 * 60  -- Seconds
local power_supply = 100000  -- EUs
local fuel_type = "technic:uranium_fuel"  -- The reactor burns this
local digiline_meltdown = technic.config:get_bool("enable_nuclear_reactor_digiline_selfdestruct")
local digiline_remote_path = minetest.get_modpath("digiline_remote")
local S = technic.getter
-- FIXME: recipe must make more sense like a rod recepticle, steam chamber, HV generator?
local reactor_desc = S("@1 Nuclear Reactor Core", S("HV"))
local cable_entry = "^technic_cable_connection_overlay.png"
-- FIXME: Recipe should make more sense like a rod recepticle, steam chamber, HV generator?
minetest.register_craft({
   output = 'technic:hv_nuclear_reactor_core',
   recipe = {
      {'technic:carbon_plate',          'default:obsidian_glass', 'technic:carbon_plate'},
      {'technic:composite_plate',       'technic:machine_casing', 'technic:composite_plate'},
      {'technic:stainless_steel_ingot',      'technic:hv_cable0', 'technic:stainless_steel_ingot'},
      {'technic:stainless_steel_ingot', 'technic:hv_cable',       'technic:stainless_steel_ingot'},
   }
})
local generator_formspec =
   "invsize[8,9;]"..
local function make_reactor_formspec(meta)
   local f = "size[8,9]"..
   "label[0,0;"..S("Nuclear Reactor Rod Compartment").."]"..
   "list[current_name;src;2,1;3,2;]"..
   "list[current_player;main;0,5;8,4;]"
   "list[current_player;main;0,5;8,4;]"..
   "listring[]"..
   "button[5.5,1.5;2,1;start;Start]"..
   "checkbox[5.5,2.5;autostart;automatic Start;"..meta:get_string("autostart").."]"
   if not digiline_remote_path then
      return f
   end
   local digiline_enabled = meta:get_string("enable_digiline")
   f = f.."checkbox[0.5,2.8;enable_digiline;Enable Digiline;"..digiline_enabled.."]"
   if digiline_enabled ~= "true" then
      return f
   end
   return f..
      "button_exit[4.6,3.69;2,1;save;Save]"..
      "field[1,4;4,1;remote_channel;Digiline Remote Channel;${remote_channel}]"
end
-- "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 SS_OFF = 0
local SS_DANGER = 1
local SS_CLEAR = 2
local check_reactor_structure = function(pos)
   -- The reactor consists of a 9x9x9 cube structure
   -- A cross section through the middle:
   --  CCCC CCCC
   --  CBBB BBBC
   --  CBSS SSBC
   --  CBSWWWSBC
   --  CBSW#WSBC
   --  CBSW|WSBC
   --  CBSS|SSBC
   --  CBBB|BBBC
   --  CCCC|CCCC
   --  C = Concrete, B = Blast resistant concrete, S = Stainless Steel,
   --  W = water node, # = reactor core, | = HV cable
   --  The man-hole and the HV cable is only in the middle
   --  The man-hole is optional
local reactor_siren = {}
local function siren_set_state(pos, state)
   local hpos = minetest.hash_node_position(pos)
   local siren = reactor_siren[hpos]
   if not siren then
      if state == SS_OFF then return end
      siren = {state=SS_OFF}
      reactor_siren[hpos] = siren
   end
   if state == SS_DANGER and siren.state ~= SS_DANGER then
      if siren.handle then minetest.sound_stop(siren.handle) end
      siren.handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_danger_loop",
            {pos=pos, gain=1.5, loop=true, max_hear_distance=48})
      siren.state = SS_DANGER
   elseif state == SS_CLEAR then
      if siren.handle then minetest.sound_stop(siren.handle) end
      local clear_handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_clear",
            {pos=pos, gain=1.5, loop=false, max_hear_distance=48})
      siren.handle = clear_handle
      siren.state = SS_CLEAR
      minetest.after(10, function()
         if siren.handle ~= clear_handle then return end
         minetest.sound_stop(clear_handle)
         if reactor_siren[hpos] == siren then
            reactor_siren[hpos] = nil
         end
      end)
   elseif state == SS_OFF and siren.state ~= SS_OFF then
      if siren.handle then minetest.sound_stop(siren.handle) end
      reactor_siren[hpos] = nil
   end
end
local function siren_danger(pos, meta)
   meta:set_int("siren", 1)
   siren_set_state(pos, SS_DANGER)
end
local function siren_clear(pos, meta)
   if meta:get_int("siren") ~= 0 then
      siren_set_state(pos, SS_CLEAR)
      meta:set_int("siren", 0)
   end
end
--[[
The standard reactor structure consists of a 9x9x9 cube.  A cross
section through the middle:
   CCCC CCCC
   CBBB BBBC
   CBLL LLBC
   CBLWWWLBC
   CBLW#WLBC
   CBLW|WLBC
   CBLL|LLBC
   CBBB|BBBC
   CCCC|CCCC
   C = Concrete, B = Blast-resistant concrete, L = Lead,
   W = water node, # = reactor core, | = HV cable
The man-hole is optional (but necessary for refueling).
For the reactor to operate and not melt down, it insists on the inner
7x7x7 portion (from the core out to the blast-resistant concrete)
being intact.  Intactness only depends on the number of nodes of the
right type in each layer.  The water layer must have water in all but
at most one node; the steel and blast-resistant concrete layers must
have the right material in all but at most two nodes.  The permitted
gaps are meant for the cable and man-hole, but can actually be anywhere
and contain anything.  For the reactor to be useful, a cable must
connect to the core, but it can go in any direction.
The outer concrete layer of the standard structure is not required
for the reactor to operate.  It is noted here because it used to
be mandatory, and for historical reasons (that it predates the
implementation of radiation) it needs to continue being adequate
shielding of legacy reactors.  If it ever ceases to be adequate
shielding for new reactors, legacy ones should be grandfathered.
For legacy reasons, if the reactor has a stainless steel layer instead
of a lead layer it will be converted to a lead layer.
--]]
local function reactor_structure_badness(pos)
   local vm = VoxelManip()
   local pos1 = vector.subtract(pos, 4)
   local pos2 = vector.add(pos, 4)
   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_concrete = minetest.get_content_id("technic:concrete")
   local c_blast_concrete = minetest.get_content_id("technic:blast_resistant_concrete")
   local c_stainless_steel = minetest.get_content_id("technic:stainless_steel_block")
   local c_lead = minetest.get_content_id("technic:lead_block")
   local c_steel = minetest.get_content_id("technic:stainless_steel_block")
   local c_water_source = minetest.get_content_id("default:water_source")
   local c_water_flowing = minetest.get_content_id("default:water_flowing")
   local concretelayer, blastlayer, steellayer, waterlayer = 0, 0, 0, 0
   local blast_layer, steel_layer, lead_layer, water_layer = 0, 0, 0, 0
   for z = pos1.z, pos2.z do
   for y = pos1.y, pos2.y do
   for x = pos1.x, pos2.x do
      -- If the position is in the outer layer
      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 data[area:index(x, y, z)] == c_concrete then
            concretelayer = concretelayer + 1
         if cid == c_blast_concrete then
            blast_layer = blast_layer + 1
         end
      elseif x == pos1.x+1 or x == pos2.x-1 or
         y == pos1.y+1 or y == pos2.y-1 or
         z == pos1.z+1 or z == pos2.z-1 then
         if data[area:index(x, y, z)] == c_blast_concrete then
            blastlayer = blastlayer + 1
             y == pos1.y+1 or y == pos2.y-1 or
             z == pos1.z+1 or z == pos2.z-1 then
         if cid == c_lead then
            lead_layer = lead_layer + 1
         elseif cid == c_steel then
            steel_layer = steel_layer + 1
         end
      elseif x == pos1.x+2 or x == pos2.x-2 or
         y == pos1.y+2 or y == pos2.y-2 or
         z == pos1.z+2 or z == pos2.z-2 then
         if data[area:index(x, y, z)] == c_stainless_steel then
            steellayer = steellayer + 1
         end
      elseif x == pos1.x+3 or x == pos2.x-3 or
         y == pos1.y+3 or y == pos2.y-3 or
         z == pos1.z+3 or z == pos2.z-3 then
            local cid = data[area:index(x, y, z)]
             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
            water_layer = water_layer + 1
         end
      end
   end
   end
   end
   if waterlayer >= 25 and
      steellayer >= 96 and
      blastlayer >= 216 and
      concretelayer >= 384 then
      return true
   end
end
local explode_reactor = function(pos)
   print("A reactor exploded at "..minetest.pos_to_string(pos))
   minetest.set_node(pos, {name="technic:corium_source"})
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
   if steel_layer >= 96 then
      for z = pos1.z+1, pos2.z-1 do
      for y = pos1.y+1, pos2.y-1 do
      for x = pos1.x+1, pos2.x-1 do
         local vi = area:index(x, y, z)
         if x == pos1.x+1 or x == pos2.x-1 or
            y == pos1.y+1 or y == pos2.y-1 or
            z == pos1.z+1 or z == pos2.z-1 then
            if data[vi] == c_steel then
               data[vi] = c_lead
            end
         end
         -- Check that the reactor is complete as well
         -- as the correct number of correct fuel
         if correct_fuel_count == 6 and
            check_reactor_structure(pos) then
            meta:set_int("burn_time", 1)
            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
      end
      end
      end
      vm:set_data(data)
      vm:write_to_map()
      lead_layer = steel_layer
   end
   if water_layer > 25 then water_layer = 25 end
   if lead_layer > 96 then lead_layer = 96 end
   if blast_layer > 216 then blast_layer = 216 end
   return (25 - water_layer) + (96 - lead_layer) + (216 - blast_layer)
end
local function melt_down_reactor(pos)
   minetest.log("action", "A reactor melted down at "..minetest.pos_to_string(pos))
   minetest.set_node(pos, {name = "technic:corium_source"})
end
local function start_reactor(pos, meta)
   if minetest.get_node(pos).name ~= "technic:hv_nuclear_reactor_core" then
      return false
   end
   local inv = meta:get_inventory()
   if inv:is_empty("src") then
      return false
   end
   local src_list = inv:get_list("src")
   local correct_fuel_count = 0
   for _, src_stack in pairs(src_list) do
      if src_stack and src_stack:get_name() == fuel_type then
         correct_fuel_count = correct_fuel_count + 1
      end
   end
   -- Check that the reactor is complete and has the correct fuel
   if correct_fuel_count ~= 6 or reactor_structure_badness(pos) ~= 0 then
      return false
   end
   meta:set_int("burn_time", 1)
   technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active")
   meta:set_int("HV_EU_supply", power_supply)
   for idx, src_stack in pairs(src_list) do
      src_stack:take_item()
      inv:set_stack("src", idx, src_stack)
   end
   return true
end
minetest.register_abm({
   label = "Machines: reactor melt-down check",
   nodenames = {"technic:hv_nuclear_reactor_core_active"},
   interval = 4,
   chance = 1,
   action = function (pos, node)
      local meta = minetest.get_meta(pos)
      local badness = reactor_structure_badness(pos)
      local accum_badness = meta:get_int("structure_accumulated_badness")
      if badness == 0 then
         if accum_badness ~= 0 then
            meta:set_int("structure_accumulated_badness", math.max(accum_badness - 4, 0))
            siren_clear(pos, meta)
         end
      else
         siren_danger(pos, meta)
         accum_badness = accum_badness + badness
         if accum_badness >= 25 then
            melt_down_reactor(pos)
         else
            meta:set_int("structure_accumulated_badness", accum_badness)
         end
      end
   end,
})
local function run(pos, node)
   local meta = minetest.get_meta(pos)
   local burn_time = meta:get_int("burn_time") or 0
   if burn_time >= burn_ticks or burn_time == 0 then
      if digiline_remote_path and meta:get_int("HV_EU_supply") == power_supply then
         digiline_remote.send_to_node(pos, meta:get_string("remote_channel"),
               "fuel used", 6, true)
      end
      if meta:get_string("autostart") == "true" then
         if start_reactor(pos, meta) then
            return
         end
      end
      meta:set_int("HV_EU_supply", 0)
      meta:set_int("burn_time", 0)
      meta:set_string("infotext", S("%s Idle"):format(machine_name))
      meta:set_string("infotext", S("%s Idle"):format(reactor_desc))
      technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
      meta:set_int("structure_accumulated_badness", 0)
      siren_clear(pos, meta)
   elseif burn_time > 0 then
      if not check_reactor_structure(pos) then
         explode_reactor(pos)
      end
      burn_time = burn_time + 1
      meta:set_int("burn_time", burn_time)
      local percent = math.floor(burn_time / burn_ticks * 100)
      meta:set_string("infotext", machine_name.." ("..percent.."%)")
      meta:set_string("infotext", reactor_desc.." ("..percent.."%)")
      meta:set_int("HV_EU_supply", power_supply)
   end
end
local nuclear_reactor_receive_fields = function(pos, formname, fields, sender)
   local player_name = sender:get_player_name()
   if minetest.is_protected(pos, player_name) then
      minetest.chat_send_player(player_name, "You are not allowed to edit this!")
      minetest.record_protection_violation(pos, player_name)
      return
   end
   local meta = minetest.get_meta(pos)
   local update_formspec = false
   if fields.remote_channel then
      meta:set_string("remote_channel", fields.remote_channel)
   end
   if fields.start then
      local b = start_reactor(pos, meta)
      if b then
         minetest.chat_send_player(player_name, "Start successful")
      else
         minetest.chat_send_player(player_name, "Error")
      end
   end
   if fields.autostart then
      meta:set_string("autostart", fields.autostart)
      update_formspec = true
   end
   if fields.enable_digiline then
      meta:set_string("enable_digiline", fields.enable_digiline)
      update_formspec = true
   end
   if update_formspec then
      meta:set_string("formspec", make_reactor_formspec(meta))
   end
end
local digiline_remote_def = function(pos, channel, msg)
   local meta = minetest.get_meta(pos)
   if meta:get_string("enable_digiline") ~= "true" or
         channel ~= meta:get_string("remote_channel") then
      return
   end
   -- Convert string messages to tables:
   local msgt = type(msg)
   if msgt == "string" then
      local smsg = msg:lower()
      msg = {}
      if smsg == "get" then
         msg.command = "get"
      elseif smsg:sub(1, 13) == "self_destruct" then
         msg.command = "self_destruct"
         msg.timer = tonumber(smsg:sub(15)) or 0
      elseif smsg == "start" then
         msg.command = "start"
      end
   elseif msgt ~= "table" then
      return
   end
   if msg.command == "get" then
      local inv = meta:get_inventory()
      local invtable = {}
      for i = 1, 6 do
         local stack = inv:get_stack("src", i)
         if stack:is_empty() then
            invtable[i] = 0
         elseif stack:get_name() == fuel_type then
            invtable[i] = stack:get_count()
         else
            invtable[i] = -stack:get_count()
         end
      end
      digiline_remote.send_to_node(pos, channel, {
         burn_time = meta:get_int("burn_time"),
         enabled   = meta:get_int("HV_EU_supply") == power_supply,
         siren     = meta:get_int("siren") == 1,
         structure_accumulated_badness = meta:get_int("structure_accumulated_badness"),
         rods = invtable
      }, 6, true)
   elseif digiline_meltdown and msg.command == "self_destruct" and
         minetest.get_node(pos).name == "technic:hv_nuclear_reactor_core_active" then
      if msg.timer ~= 0 and type(msg.timer) == "number" then
         siren_danger(pos, meta)
         minetest.after(msg.timer, melt_down_reactor, pos)
      else
         melt_down_reactor(pos)
      end
   elseif msg.command == "start" then
      local b = start_reactor(pos, meta)
      if b then
         digiline_remote.send_to_node(pos, channel, "Start successful", 6, true)
      else
         digiline_remote.send_to_node(pos, channel, "Error", 6, true)
      end
   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 = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1},
   description = reactor_desc,
   tiles = {
      "technic_hv_nuclear_reactor_core.png",
      "technic_hv_nuclear_reactor_core.png"..cable_entry
   },
   drawtype = "mesh",
   mesh = "technic_reactor.obj",
   groups = {cracky = 1, technic_machine = 1, technic_hv = 1, digiline_remote_receive = 1},
   legacy_facedir_simple = true,
   sounds = default.node_sound_wood_defaults(),
   drawtype="nodebox",
   paramtype = "light",
   paramtype2 = "facedir",
   stack_max = 1,
   node_box = {
      type = "fixed",
      fixed = nodebox
   },
   on_receive_fields = nuclear_reactor_receive_fields,
   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)
      meta:set_string("infotext", reactor_desc)
      meta:set_string("formspec", make_reactor_formspec(meta))
      if digiline_remote_path then
         meta:set_string("remote_channel",
               "nucelear_reactor"..minetest.pos_to_string(pos))
      end
      local inv = meta:get_inventory()
      inv:set_size("src", 6)
   end,
   end,
   _on_digiline_remote_receive = digiline_remote_def,
   can_dig = technic.machine_can_dig,
   on_destruct = function(pos) siren_set_state(pos, SS_OFF) end,
   allow_metadata_inventory_put = technic.machine_inventory_put,
   allow_metadata_inventory_take = technic.machine_inventory_take,
   allow_metadata_inventory_move = technic.machine_inventory_move,
@@ -208,21 +430,25 @@
})
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 = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_machine=1, radioactive=2, not_in_creative_inventory=1},
   tiles = {
      "technic_hv_nuclear_reactor_core.png",
      "technic_hv_nuclear_reactor_core.png"..cable_entry
   },
   drawtype = "mesh",
   mesh = "technic_reactor.obj",
   groups = {cracky = 1, technic_machine = 1, technic_hv = 1, radioactive = 4,
      not_in_creative_inventory = 1, digiline_remote_receive = 1},
   legacy_facedir_simple = true,
   sounds = default.node_sound_wood_defaults(),
   drop="technic:hv_nuclear_reactor_core",
   drawtype="nodebox",
   light_source = 15,
   drop = "technic:hv_nuclear_reactor_core",
   light_source = 14,
   paramtype = "light",
   node_box = {
      type = "fixed",
      fixed = nodebox
   },
   paramtype2 = "facedir",
   on_receive_fields = nuclear_reactor_receive_fields,
   _on_digiline_remote_receive = digiline_remote_def,
   can_dig = technic.machine_can_dig,
   after_dig_node = melt_down_reactor,
   on_destruct = function(pos) siren_set_state(pos, SS_OFF) end,
   allow_metadata_inventory_put = technic.machine_inventory_put,
   allow_metadata_inventory_take = technic.machine_inventory_take,
   allow_metadata_inventory_move = technic.machine_inventory_move,
@@ -233,152 +459,26 @@
        end,
   on_timer = function(pos, node)
      local meta = minetest.get_meta(pos)
      -- Connected back?
      if meta:get_int("HV_EU_timeout") > 0 then return end
      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")
         return
         meta:set_int("structure_accumulated_badness", 0)
         siren_clear(pos, meta)
         return false
      end
      meta:set_int("burn_time", burn_time + 1)
      local timer = minetest.get_node_timer(pos)
           timer:start(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)
-- radioactive materials that can result from destroying a reactor
minetest.register_abm({
   nodenames = {"group:radioactive"},
   interval = 1,
   chance = 1,
   action = function (pos, node)
      for r = 1, minetest.registered_nodes[node.name].groups.radioactive do
         for _, o in ipairs(minetest.get_objects_inside_radius(pos, r*2)) do
            if o:is_player() then
               o:set_hp(math.max(o:get_hp() - 1, 0))
            end
         end
      end
   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 4 or 3),
      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 = 1,
         radioactive = (state == "source" and 3 or 2),
         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=1, 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,
})
minetest.register_abm({
   nodenames = {"technic:corium_flowing"},
   neighbors = {"group:water"},
   interval = 1,
   chance = 1,
   action = function (pos, node)
      minetest.set_node(pos, {name="technic:chernobylite_block"})
   end,
})
local griefing = technic.config:get_bool("enable_corium_griefing")
minetest.register_abm({
   nodenames = {"technic:corium_flowing"},
   interval = 5,
   chance = (griefing and 10 or 1),
   action = function (pos, node)
      minetest.set_node(pos, {name="technic:chernobylite_block"})
   end,
})
if griefing then
   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