| | |
| | | ["default:lava_source"] = 17, |
| | | ["default:mese"] = 21, |
| | | ["default:mossycobble"] = 15, |
| | | ["default:nyancat"] = 1000, |
| | | ["default:nyancat_rainbow"] = 1000, |
| | | ["default:tinblock"] = 37, |
| | | ["pbj_pup:pbj_pup"] = 10000, |
| | | ["pbj_pup:pbj_pup_candies"] = 10000, |
| | | ["gloopblocks:rainbow_block_diagonal"] = 5000, |
| | | ["gloopblocks:rainbow_block_horizontal"] = 10000, |
| | | ["default:nyancat"] = 10000, |
| | | ["default:nyancat_rainbow"] = 10000, |
| | | ["nyancat:nyancat"] = 10000, |
| | | ["nyancat:nyancat_rainbow"] = 10000, |
| | | ["default:obsidian"] = 18, |
| | | ["default:obsidian_glass"] = 18, |
| | | ["default:sand"] = 10, |
| | |
| | | ["default:stone_with_gold"] = 34, |
| | | ["default:stone_with_iron"] = 20, |
| | | ["default:stone_with_mese"] = 17, |
| | | ["default:stone_with_tin"] = 19, |
| | | ["default:stonebrick"] = 17, |
| | | ["default:water_flowing"] = 2.8, |
| | | ["default:water_source"] = 5.6, |
| | |
| | | ["moreblocks:wood_tile_up"] = 1.7, |
| | | ["moreores:mineral_mithril"] = 18, |
| | | ["moreores:mineral_silver"] = 21, |
| | | ["moreores:mineral_tin"] = 19, |
| | | ["moreores:mithril_block"] = 26, |
| | | ["moreores:silver_block"] = 53, |
| | | ["moreores:tin_block"] = 37, |
| | | ["snow:snow_brick"] = 2.8, |
| | | ["technic:brass_block"] = 43, |
| | | ["basic_materials:brass_block"] = 43, |
| | | ["technic:carbon_steel_block"] = 40, |
| | | ["technic:cast_iron_block"] = 40, |
| | | ["technic:chernobylite_block"] = 40, |
| | |
| | | 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 |
| | | Damage is processed at rates down to 0.2 HP/s, which in the absence of |
| | | shielding is attained at the distance specified by the "radioactive" |
| | | group value. Computed damage rates below 0.25 HP/s result in no |
| | | group value. Computed damage rates below 0.2 HP/s result in no |
| | | damage at all to the player. This gives the player an opportunity |
| | | to be safe, and limits the range at which source/player interactions |
| | | need to be considered. |
| | | --]] |
| | | local abdomen_offset = 1 |
| | | local cache_scaled_shielding = {} |
| | | local rad_dmg_cutoff = 0.25 |
| | | local rad_dmg_cutoff = 0.2 |
| | | local radiated_players = {} |
| | | |
| | | local function dmg_player(pos, o, strength) |
| | | local pl_pos = o:getpos() |
| | | pl_pos.y = pl_pos.y + abdomen_offset |
| | | local shielding = 0 |
| | | local dist = vector.distance(pos, pl_pos) |
| | | for ray_pos in technic.trace_node_ray(pos, |
| | | vector.direction(pos, pl_pos), dist) do |
| | | local shield_name = minetest.get_node(ray_pos).name |
| | | shielding = shielding + node_radiation_resistance(shield_name) * 0.1 |
| | | end |
| | | local dmg = (strength * strength) / |
| | | (math.max(0.75, dist * dist) * math.exp(shielding)) |
| | | if dmg < rad_dmg_cutoff then return end |
| | | local armor_enabled = technic.config:get_bool("enable_radiation_protection") |
| | | local entity_damage = technic.config:get_bool("enable_entity_radiation_damage") |
| | | local longterm_damage = technic.config:get_bool("enable_longterm_radiation_damage") |
| | | |
| | | local function apply_fractional_damage(o, dmg) |
| | | local dmg_int = math.floor(dmg) |
| | | -- The closer you are to getting one more damage point, |
| | | -- the more likely it will be added. |
| | |
| | | dmg_int = dmg_int + 1 |
| | | end |
| | | if dmg_int > 0 then |
| | | o:set_hp(math.max(o:get_hp() - dmg_int, 0)) |
| | | local new_hp = math.max(o:get_hp() - dmg_int, 0) |
| | | o:set_hp(new_hp) |
| | | return new_hp == 0 |
| | | end |
| | | return false |
| | | end |
| | | |
| | | local function calculate_base_damage(node_pos, object_pos, strength) |
| | | local shielding = 0 |
| | | local dist = vector.distance(node_pos, object_pos) |
| | | |
| | | for ray_pos in technic.trace_node_ray(node_pos, |
| | | vector.direction(node_pos, object_pos), dist) do |
| | | local shield_name = minetest.get_node(ray_pos).name |
| | | shielding = shielding + node_radiation_resistance(shield_name) * 0.025 |
| | | end |
| | | |
| | | local dmg = (strength * strength) / |
| | | (math.max(0.75, dist * dist) * math.exp(shielding)) |
| | | |
| | | if dmg < rad_dmg_cutoff then return end |
| | | return dmg |
| | | end |
| | | |
| | | local function calculate_damage_multiplier(object) |
| | | local ag = object.get_armor_groups and object:get_armor_groups() |
| | | if not ag then |
| | | return 0 |
| | | end |
| | | if ag.immortal then |
| | | return 0 |
| | | end |
| | | if ag.radiation then |
| | | return 0.01 * ag.radiation |
| | | elseif armor_enabled then |
| | | return 0 |
| | | end |
| | | if ag.fleshy then |
| | | return math.sqrt(0.01 * ag.fleshy) |
| | | end |
| | | return 0 |
| | | end |
| | | |
| | | local function calculate_object_center(object) |
| | | if object:is_player() then |
| | | return {x=0, y=abdomen_offset, z=0} |
| | | end |
| | | return {x=0, y=0, z=0} |
| | | end |
| | | |
| | | local function dmg_object(pos, object, strength) |
| | | local obj_pos = vector.add(object:get_pos(), calculate_object_center(object)) |
| | | local mul |
| | | if armor_enabled or entity_damage then |
| | | -- we need to check may the object be damaged even if armor is disabled |
| | | mul = calculate_damage_multiplier(object) |
| | | if mul == 0 then |
| | | return |
| | | end |
| | | end |
| | | local dmg = calculate_base_damage(pos, obj_pos, strength) |
| | | if not dmg then |
| | | return |
| | | end |
| | | if armor_enabled then |
| | | dmg = dmg * mul |
| | | end |
| | | apply_fractional_damage(object, dmg) |
| | | if longterm_damage and object:is_player() then |
| | | local pn = object:get_player_name() |
| | | radiated_players[pn] = (radiated_players[pn] or 0) + dmg |
| | | end |
| | | end |
| | | |
| | |
| | | local max_dist = strength * rad_dmg_mult_sqrt |
| | | for _, o in pairs(minetest.get_objects_inside_radius(pos, |
| | | max_dist + abdomen_offset)) do |
| | | if o:is_player() then |
| | | dmg_player(pos, o, strength) |
| | | if (entity_damage or o:is_player()) and o:get_hp() > 0 then |
| | | dmg_object(pos, o, strength) |
| | | end |
| | | end |
| | | end |
| | | |
| | | |
| | | if minetest.setting_getbool("enable_damage") then |
| | | if minetest.settings:get_bool("enable_damage") then |
| | | minetest.register_abm({ |
| | | label = "Radiation damage", |
| | | nodenames = {"group:radioactive"}, |
| | | interval = 1, |
| | | chance = 1, |
| | | action = dmg_abm, |
| | | }) |
| | | |
| | | if longterm_damage then |
| | | minetest.register_globalstep(function(dtime) |
| | | for pn, dmg in pairs(radiated_players) do |
| | | dmg = dmg - (dtime / 8) |
| | | local player = minetest.get_player_by_name(pn) |
| | | local killed |
| | | if player and dmg > rad_dmg_cutoff then |
| | | killed = apply_fractional_damage(player, (dmg * dtime) / 8) |
| | | else |
| | | dmg = nil |
| | | end |
| | | -- on_dieplayer will have already set this if the player died |
| | | if not killed then |
| | | radiated_players[pn] = dmg |
| | | end |
| | | end |
| | | end) |
| | | |
| | | minetest.register_on_dieplayer(function(player) |
| | | radiated_players[player:get_player_name()] = nil |
| | | end) |
| | | end |
| | | end |
| | | |
| | | -- Radioactive materials that can result from destroying a reactor |
| | |
| | | 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"] = {{ |
| | | tiles = {{ |
| | | name = "technic_corium_"..state.."_animated.png", |
| | | animation = { |
| | | type = "vertical_frames", |
| | |
| | | length = 3.0, |
| | | }, |
| | | }}, |
| | | special_tiles = { |
| | | { |
| | | name = "technic_corium_"..state.."_animated.png", |
| | | backface_culling = false, |
| | | animation = { |
| | | type = "vertical_frames", |
| | | aspect_w = 16, |
| | | aspect_h = 16, |
| | | length = 3.0, |
| | | }, |
| | | }, |
| | | { |
| | | name = "technic_corium_"..state.."_animated.png", |
| | | backface_culling = true, |
| | | 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 8 or 5), |
| | |
| | | liquidtype = state, |
| | | liquid_alternative_flowing = "technic:corium_flowing", |
| | | liquid_alternative_source = "technic:corium_source", |
| | | liquid_viscosity = LAVA_VISC, |
| | | liquid_viscosity = 7, -- like lava |
| | | liquid_renewable = false, |
| | | damage_per_second = 6, |
| | | post_effect_color = {a=192, r=80, g=160, b=80}, |
| | |
| | | liquid = 2, |
| | | hot = 3, |
| | | igniter = (griefing and 1 or 0), |
| | | radioactive = (state == "source" and 16 or 8), |
| | | radioactive = (state == "source" and 12 or 6), |
| | | not_in_creative_inventory = (state == "flowing" and 1 or nil), |
| | | }, |
| | | }) |
| | |
| | | description = S("Chernobylite Block"), |
| | | tiles = {"technic_chernobylite_block.png"}, |
| | | is_ground_content = true, |
| | | groups = {cracky=1, radioactive=6, level=2}, |
| | | groups = {cracky=1, radioactive=4, level=2}, |
| | | sounds = default.node_sound_stone_defaults(), |
| | | light_source = 2, |
| | | }) |
| | | |
| | | minetest.register_abm({ |
| | | label = "Corium: boil-off water (sources)", |
| | | nodenames = {"group:water"}, |
| | | neighbors = {"technic:corium_source"}, |
| | | interval = 1, |
| | |
| | | }) |
| | | |
| | | minetest.register_abm({ |
| | | label = "Corium: boil-off water (flowing)", |
| | | nodenames = {"technic:corium_flowing"}, |
| | | neighbors = {"group:water"}, |
| | | interval = 1, |
| | |
| | | }) |
| | | |
| | | minetest.register_abm({ |
| | | label = "Corium: become chernobylite", |
| | | nodenames = {"technic:corium_flowing"}, |
| | | interval = 5, |
| | | chance = (griefing and 10 or 1), |
| | |
| | | |
| | | if griefing then |
| | | minetest.register_abm({ |
| | | label = "Corium: griefing", |
| | | nodenames = {"technic:corium_source", "technic:corium_flowing"}, |
| | | interval = 4, |
| | | chance = 4, |
| | |
| | | end, |
| | | }) |
| | | end |
| | | |