From a793747d92d9b1d93153c7fb4e0c82fe90624c78 Mon Sep 17 00:00:00 2001 From: est31 <MTest31@outlook.com> Date: Thu, 18 Jun 2015 04:16:47 +0200 Subject: [PATCH] Move coal furnaces to other/ --- technic/machines/HV/nuclear_reactor.lua | 248 ++++++++++++++++++++++++++++++++----------------- 1 files changed, 161 insertions(+), 87 deletions(-) diff --git a/technic/machines/HV/nuclear_reactor.lua b/technic/machines/HV/nuclear_reactor.lua index 7bed4df..a9a13c2 100644 --- a/technic/machines/HV/nuclear_reactor.lua +++ b/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 = { @@ -54,64 +55,117 @@ { -0.303, -0.303, -0.397, 0.303, 0.303, 0.397 }, } -local reactor_structure_badness = 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, 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, 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_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 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 - -- 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 + 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 data[area:index(x, y, z)] == c_blast_concrete then - blastlayer = blastlayer + 1 + 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 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)] if cid == c_water_source or cid == c_water_flowing then waterlayer = waterlayer + 1 end @@ -122,8 +176,7 @@ if waterlayer > 25 then waterlayer = 25 end if steellayer > 96 then steellayer = 96 end if blastlayer > 216 then blastlayer = 216 end - if concretelayer > 384 then concretelayer = 384 end - return (25 - waterlayer) + (96 - steellayer) + (216 - blastlayer) + (384 - concretelayer) + return (25 - waterlayer) + (96 - steellayer) + (216 - blastlayer) end local function meltdown_reactor(pos) @@ -142,8 +195,10 @@ 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) @@ -190,6 +245,7 @@ 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) @@ -204,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", @@ -227,6 +283,7 @@ 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, @@ -237,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", @@ -250,6 +307,7 @@ }, 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, @@ -262,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 @@ -271,12 +329,12 @@ meta:set_int("burn_time", 0) technic.swap_node(pos, "technic:hv_nuclear_reactor_core") meta:set_int("structure_accumulated_badness", 0) - return + 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, }) @@ -435,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, @@ -443,6 +500,7 @@ local default_radiation_resistance_per_group = { concrete = 16, tree = 3.4, + uranium_block = 500, wood = 1.7, } local cache_radiation_resistance = {} @@ -483,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" @@ -507,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 @@ -578,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), }, }) @@ -598,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, -- Gitblit v1.8.0