From d6b0deb989e649e2800932d4a587c3ba9e3e24c7 Mon Sep 17 00:00:00 2001 From: Vanessa Ezekowitz <vanessaezekowitz@gmail.com> Date: Sat, 17 Jan 2015 01:16:39 +0100 Subject: [PATCH] fix cnc stick formspec img (missed the border) --- technic/machines/HV/nuclear_reactor.lua | 221 +++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 156 insertions(+), 65 deletions(-) diff --git a/technic/machines/HV/nuclear_reactor.lua b/technic/machines/HV/nuclear_reactor.lua index a018bac..7ff5c5b 100644 --- a/technic/machines/HV/nuclear_reactor.lua +++ b/technic/machines/HV/nuclear_reactor.lua @@ -54,64 +54,117 @@ { -0.303, -0.303, -0.397, 0.303, 0.303, 0.397 }, } -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, 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 @@ -119,18 +172,41 @@ end end end - if waterlayer >= 25 and - steellayer >= 96 and - blastlayer >= 216 and - concretelayer >= 384 then - return true - end + if waterlayer > 25 then waterlayer = 25 end + if steellayer > 96 then steellayer = 96 end + if blastlayer > 216 then blastlayer = 216 end + return (25 - waterlayer) + (96 - steellayer) + (216 - blastlayer) end -local explode_reactor = function(pos) - print("A reactor exploded at "..minetest.pos_to_string(pos)) +local function meltdown_reactor(pos) + print("A reactor melted down at "..minetest.pos_to_string(pos)) minetest.set_node(pos, {name="technic:corium_source"}) end + +minetest.register_abm({ + nodenames = {"technic:hv_nuclear_reactor_core_active"}, + interval = 1, + 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", 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) + else + meta:set_int("structure_accumulated_badness", accum_badness) + end + end + end, +}) local run = function(pos, node) local meta = minetest.get_meta(pos) @@ -152,7 +228,7 @@ -- 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 + reactor_structure_badness(pos) == 0 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) @@ -167,10 +243,9 @@ meta:set_int("burn_time", 0) 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 - 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) @@ -184,7 +259,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", @@ -207,6 +282,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, @@ -217,7 +293,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", @@ -229,6 +305,8 @@ fixed = nodebox }, 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, @@ -249,6 +327,8 @@ meta:set_int("HV_EU_supply", 0) meta:set_int("burn_time", 0) technic.swap_node(pos, "technic:hv_nuclear_reactor_core") + meta:set_int("structure_accumulated_badness", 0) + siren_clear(pos, meta) return end @@ -413,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, @@ -421,6 +500,7 @@ local default_radiation_resistance_per_group = { concrete = 16, tree = 3.4, + uranium_block = 500, wood = 1.7, } local cache_radiation_resistance = {} @@ -461,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" @@ -485,28 +569,35 @@ -- need to be considered. local assumed_abdomen_offset = vector.new(0, 1, 0) local assumed_abdomen_offset_length = vector.length(assumed_abdomen_offset) +local cache_scaled_shielding = {} 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 + 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 resistance = 0 + 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 - resistance = resistance + node_radiation_resistance(minetest.get_node(intnodepos).name) + 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 - local dmg_rate = 0.25 * strength*strength * math.exp(-0.0025*resistance) / math.max(0.75, dist_sq) + 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 @@ -556,7 +647,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), }, }) @@ -576,7 +667,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