est31
2015-06-18 a793747d92d9b1d93153c7fb4e0c82fe90624c78
technic/machines/HV/nuclear_reactor.lua
@@ -32,7 +32,8 @@
   "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;]"
   "list[current_player;main;0,5;8,4;]"..
   "listring[]"
-- "Boxy sphere"
local nodebox = {
@@ -259,7 +260,7 @@
   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},
   groups = {cracky=1, technic_machine=1},
   legacy_facedir_simple = true,
   sounds = default.node_sound_wood_defaults(),
   drawtype="nodebox",
@@ -293,7 +294,7 @@
   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=7, not_in_creative_inventory=1},
   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",
@@ -319,7 +320,7 @@
      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
@@ -329,12 +330,11 @@
         technic.swap_node(pos, "technic:hv_nuclear_reactor_core")
         meta:set_int("structure_accumulated_badness", 0)
         siren_clear(pos, meta)
         return
         return false
      end
      
      meta:set_int("burn_time", burn_time + 1)
      local timer = minetest.get_node_timer(pos)
           timer:start(1)
      return true
   end,
})
@@ -493,7 +493,6 @@
   ["technic:mineral_uranium"] = 71,
   ["technic:mineral_zinc"] = 19,
   ["technic:stainless_steel_block"] = 40,
   ["technic:uranium_block"] = 500,
   ["technic:zinc_block"] = 36,
   ["tnt:tnt"] = 11,
   ["tnt:tnt_burning"] = 11,
@@ -501,6 +500,7 @@
local default_radiation_resistance_per_group = {
   concrete = 16,
   tree = 3.4,
   uranium_block = 500,
   wood = 1.7,
}
local cache_radiation_resistance = {}
@@ -541,21 +541,25 @@
--
-- 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 metres from a node at which an
-- unshielded player will be damaged by 0.25 HP/s.  Or, equivalently, it
-- is half the square root of the damage rate in HP/s that an unshielded
-- player 1 m away will take.
-- 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 radiation resistance values from the sampled nodes yield
-- a measure of the total amount of radiation resistance on the path.
-- As in reality, shielding causes exponential attenuation of radiation.
-- However, the effect is scaled down relative to real life: each
-- metre-point of shielding, corresponding to a real-life halving of
-- radiation, reduces radiation by 0.01 nepers (a factor of about 1.01).
-- This scales down the difference between shielded and unshielded safe
-- distances, avoiding the latter becoming impractically large.
-- 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"
@@ -565,41 +569,53 @@
-- need to be considered.
local assumed_abdomen_offset = vector.new(0, 1, 0)
local assumed_abdomen_offset_length = vector.length(assumed_abdomen_offset)
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 + 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 resistance = 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
                  resistance = resistance + node_radiation_resistance(minetest.get_node(intnodepos).name)
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
            end
            local dmg_rate = 0.25 * strength*strength * math.exp(-0.0025*resistance) / 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))
               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,
})
      end,
   })
end
-- radioactive materials that can result from destroying a reactor
@@ -636,7 +652,7 @@
         liquid = 2,
         hot = 3,
         igniter = 1,
         radioactive = (state == "source" and 32 or 16),
         radioactive = (state == "source" and 32000 or 16000),
         not_in_creative_inventory = (state == "flowing" and 1 or nil),
      },
   })
@@ -656,7 +672,7 @@
        description = S("Chernobylite Block"),
   tiles = { "technic_chernobylite_block.png" },
   is_ground_content = true,
   groups = { cracky=1, radioactive=5, level=2 },
   groups = { cracky=1, radioactive=5000, level=2 },
   sounds = default.node_sound_stone_defaults(),
   light_source = 2,