From ebf7fdbfd23a68a95bc9f0726a06004205d4ac3d Mon Sep 17 00:00:00 2001 From: Migratingcocofruit <69551563+Migratingcocofruit@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:34:45 +0200 Subject: [PATCH] Radiation Rework (#28320) * initial changes * Rad wave is working. now to implement the rest * Makes the waves square * Makes wave square * multiplies the strength in all instances of radiation_pulse by 4 because each pulse makes one wave instead of 4 now * Undef thing and apply suggestion * Make radiation_pulse() not radiate the radiation source and implements contamination * Adds contamination to uranium walls and meteors * Fixes stuff * Handle some contamination on attack still need to take care of meteors * Fixed the meteor stuff * Introduce emission types * moves contaminate_touch to an atom proc and renames it to contaminate_atom * deduplicates some contamination code * Move inherent radioactivity to a component and signals from the atom vars and behaviour * fix some things with the new component * Update inherent_radioactivity.dm * implement contaminating things that hit things that are inherently radioactive * window things * adds emission type to the rad_act call * Changes radiation insulation values on a bunch of stuff * fixes radioactive component radiating the wrong type * more adjustments * refactros rad_act * adjustments to collector power production * Adds plastitaniumglass windows and makes further adjustments * Adds sprites to the shards and plastitanium directional window * Update misc_cleanables.dm * removes alpha rad insulation from floor turfs * Fixes a bug with the starting tile of radiation waves * More adjustments * Adjusting singularity rad production * reduces window half life a bit to make power smoother and buffs full window rad conversion * Strengthens gamma and beta radiation effect on mobs. * Makes radsuit block radiation completely * Fixes Geiger Counters * Fixes contamination not irradiating the contaminated thing * Fixes inherent radioactivity not processing. Also makes it stop processing when a nuke core is contained * Fixes ghost contamination * Adds info to the collector * Handles alpha radiation better on humans and changes some instances of rad_act to base_rad_act * oops * adjustments and fixes to alpha rad handling on mobs * Make collector info more compact * Core no longer radiates and contaminates from within the nuke until the plates are removed * Contamination no longer counts as being inside a mob(it is supposed to be surface level) * Adds inherent radioactivity to a bunch of uranium things. makes it all process. * Nerf full windows * Adjustments to collector and fulltile window radiation absorption * Reduces passive contamination, especially while on the floor * Adds different rad types to the geiger counter and fixes a runtime * Makes full tile windows strong again and disallows building them on top of collectors * adds emissive blockers to the rad blacklist and gives windows and collectors priority when irradiating for increased consistency * Gives each contamination type it's own color. * Gives each contamination type it's own color. And makes the rad hud display them separately * Changes how much the radiation wave affects the source tile, adds decay for performance reasons and adjusts collector parameters as well as SM and singulo rad production * improves performance at very high rad amounts * Fixes supermatter sliver box not containing radiation * Restores supermatter sliver to old behaviour(not inherently radioactive) * Slight nerf to fulltile windows and removes an unnecessary multiplication from rad wave processing * Removes redundant line from window rad act * Fixes radiation waves ignoring walls * fixes it better * more adjustments to collector stats * Adjustment to collector gamma absorption * increases grille beta blocking * Review changes --- code/__DEFINES/dcs/atom_signals.dm | 4 +- code/__DEFINES/radiation_defines.dm | 40 +++- code/__HELPERS/radiation_helpers.dm | 193 ++++++++++++++++-- code/__HELPERS/unsorted.dm | 2 + code/controllers/subsystem/SSradiation.dm | 20 +- .../components/inherent_radioactivity.dm | 72 +++++++ code/datums/components/radioactive.dm | 101 +++++++-- code/datums/elements/rad_insulation.dm | 10 +- code/datums/radiation_wave.dm | 177 +++++++--------- .../weather/weather_types/radiation_storm.dm | 2 +- code/game/atoms.dm | 42 +++- code/game/dna/mutations/disabilities.dm | 2 +- code/game/gamemodes/nuclear/nuclearbomb.dm | 14 +- code/game/machinery/doors/airlock.dm | 3 +- code/game/machinery/doors/airlock_types.dm | 14 +- code/game/machinery/doors/door.dm | 1 + code/game/machinery/doors/shutters.dm | 12 +- code/game/machinery/transformer.dm | 2 +- .../game/mecha/equipment/tools/other_tools.dm | 4 +- .../decals/Cleanable/misc_cleanables.dm | 3 + code/game/objects/effects/meteors.dm | 4 +- code/game/objects/effects/mines.dm | 2 +- .../objects/items/devices/geiger_counter.dm | 80 ++++++-- .../game/objects/items/stacks/sheets/glass.dm | 5 +- code/game/objects/items/theft_items.dm | 42 ++-- .../items/weapons/grenades/atmosgrenade.dm | 4 +- code/game/objects/items/weapons/shards.dm | 10 + code/game/objects/structures/aliens.dm | 3 +- .../objects/structures/depot_structures.dm | 2 +- code/game/objects/structures/false_walls.dm | 25 +-- code/game/objects/structures/girders.dm | 2 +- code/game/objects/structures/grille.dm | 1 + code/game/objects/structures/holosigns.dm | 4 +- code/game/objects/structures/mineral_doors.dm | 11 +- code/game/objects/structures/statues.dm | 23 +-- code/game/objects/structures/window.dm | 62 ++++-- code/game/turfs/simulated/floor.dm | 2 +- .../turfs/simulated/floor/mineral_floors.dm | 7 +- code/game/turfs/simulated/minerals.dm | 2 +- code/game/turfs/simulated/walls.dm | 3 +- code/game/turfs/simulated/walls_mineral.dm | 27 +-- code/game/turfs/simulated/walls_reinforced.dm | 3 +- code/game/turfs/turf.dm | 1 + .../transmission_laser.dm | 2 +- code/modules/awaymissions/cordon.dm | 2 +- code/modules/clothing/spacesuits/hardsuit.dm | 5 +- code/modules/clothing/suits/utility.dm | 6 + code/modules/mining/ores_coins.dm | 11 +- .../modules/mob/living/carbon/carbon_procs.dm | 9 + .../mob/living/carbon/human/human_defense.dm | 44 ++++ .../mob/living/carbon/human/human_mob.dm | 34 ++- .../mob/living/carbon/human/species/golem.dm | 12 +- code/modules/mob/living/living.dm | 25 ++- code/modules/mob/mob.dm | 11 +- code/modules/mob/mob_misc_procs.dm | 24 +++ code/modules/mob/mob_vars.dm | 2 + .../power/engines/singularity/collector.dm | 72 ++++++- .../particle_accelerator/particle.dm | 2 +- .../power/engines/singularity/singularity.dm | 2 +- .../power/engines/supermatter/supermatter.dm | 12 +- .../generators/portable generators/pacman.dm | 4 +- code/modules/power/gravitygenerator.dm | 4 +- .../station_goals/bluespace_tap_events.dm | 2 +- icons/obj/shards.dmi | Bin 4456 -> 7734 bytes icons/obj/structures.dmi | Bin 25575 -> 26538 bytes paradise.dme | 1 + 66 files changed, 945 insertions(+), 384 deletions(-) create mode 100644 code/datums/components/inherent_radioactivity.dm diff --git a/code/__DEFINES/dcs/atom_signals.dm b/code/__DEFINES/dcs/atom_signals.dm index 42745166c8d..596a50b1dab 100644 --- a/code/__DEFINES/dcs/atom_signals.dm +++ b/code/__DEFINES/dcs/atom_signals.dm @@ -61,8 +61,10 @@ #define COMSIG_ATOM_ACID_ACT "atom_acid_act" ///from base of atom/emag_act(): (/mob/user) #define COMSIG_ATOM_EMAG_ACT "atom_emag_act" -///from base of atom/rad_act(intensity) +///from base of atom/rad_act(intensity, emission_type) #define COMSIG_ATOM_RAD_ACT "atom_rad_act" +///from base of turf/irradiate(/datum/radiation_wave) +#define COMSIG_TURF_IRRADIATE ///from base of atom/singularity_pull(): (S, current_size) #define COMSIG_ATOM_SING_PULL "atom_sing_pull" ///from base of atom/set_light(): (l_range, l_power, l_color) diff --git a/code/__DEFINES/radiation_defines.dm b/code/__DEFINES/radiation_defines.dm index b25f075ed6d..3c60170853f 100644 --- a/code/__DEFINES/radiation_defines.dm +++ b/code/__DEFINES/radiation_defines.dm @@ -38,21 +38,41 @@ Ask ninjanomnom if they're around #define RAD_MOB_GORILLIZE 1500 // How much stored radiation to check for gorillization #define RAD_MOB_GORILLIZE_PROB 0.1 // Chance of gorillization per tick when over threshold -#define RAD_NO_INSULATION 1.0 // For things that shouldn't become irradiated for whatever reason -#define RAD_VERY_LIGHT_INSULATION 0.9 // What girders have +// Values here are for how much of the radiation is let through +#define RAD_NO_INSULATION 1.0 // Default value for Gamma and Beta insulation +#define RAD_ONE_PERCENT 0.99 // Used by geiger counters +#define RAD_MOB_INSULATION 0.98 // Default value for mobs +#define RAD_VERY_LIGHT_INSULATION 0.9 #define RAD_LIGHT_INSULATION 0.8 -#define RAD_MEDIUM_INSULATION 0.7 // What common walls have -#define RAD_HEAVY_INSULATION 0.6 // What reinforced walls have -#define RAD_EXTREME_INSULATION 0.5 // What rad collectors have +#define RAD_MEDIUM_INSULATION 0.7 +#define RAD_HEAVY_INSULATION 0.6 +#define RAD_VERY_HEAVY_INSULATION 0.5 +#define RAD_EXTREME_INSULATION 0.4 +#define RAD_VERY_EXTREME_INSULATION 0.2 +#define RAD_GAMMA_WINDOW 0.4 // For directional windows that are activated by gamma radiation +#define RAD_GAMMA_FULL_WINDOW 0.16 // For full tile windows that are activated by gamma radiation +#define RAD_BETA_COLLECTOR 0.2 // Amount of Beta radiation absorbed by collectors +#define RAD_BETA_BLOCKER 0.2 // Amount of Beta radiation blocked by metallic things like walls and airlocks +#define RAD_ALPHA_BLOCKER 0.01 // default value for Alpha insulation #define RAD_FULL_INSULATION 0 // Unused -// WARNING: The defines below could have disastrous consequences if tweaked incorrectly. See: The great SM purge of Oct.6.2017 -// contamination_strength = (strength - RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT -#define RAD_MINIMUM_CONTAMINATION 350 // How strong does a radiation wave have to be to contaminate objects -#define RAD_CONTAMINATION_STR_COEFFICIENT 0.25 // Higher means higher strength scaling contamination strength -#define RAD_DISTANCE_COEFFICIENT 1 // Lower means further rad spread +// Contamination chance in percent. Mostly used by contaminate_adjacent(atom/source, intensity, emission_type) +#define CONTAMINATION_CHANCE_TURF 1 // Chance to contaminate things while on/in a turf +#define CONTAMINATION_CHANCE_OTHER 10 // Chance to contaminate things while in something like a bag #define RAD_HALF_LIFE 90 // The half-life of contaminated objects #define RAD_GEIGER_MEASURE_SMOOTHING 5 #define RAD_GEIGER_GRACE_PERIOD 2 + +/// The portion of a radiation wave that acts on the source tile. +#define RAD_SOURCE_WEIGHT 0.25 + +/// The point in steps at which radiation waves start to decay +#define RAD_DECAY_POINT 10 +/// This multiplies the intensity of the radiation wave each step after reaching the decay point. +#define RAD_DECAY_RATE 0.7943 // 1% after 20 tiles + +#define ALPHA_RAD 1 +#define BETA_RAD 2 +#define GAMMA_RAD 3 diff --git a/code/__HELPERS/radiation_helpers.dm b/code/__HELPERS/radiation_helpers.dm index 14c781de02b..983d95da2a7 100644 --- a/code/__HELPERS/radiation_helpers.dm +++ b/code/__HELPERS/radiation_helpers.dm @@ -3,52 +3,183 @@ * Components which return COMPONENT_BLOCK_RADIATION prevent further searching into that object's contents. The object itself will get returned still. * The ignore list makes those objects never return at all */ -/proc/get_rad_contents(atom/location) +/proc/get_rad_contents(atom/location, emission_type) var/static/list/ignored_things = typecacheof(list( - /mob/dead, /mob/camera, + /mob/dead, /obj/effect, /obj/docking_port, /atom/movable/lighting_object, /obj/item/projectile, - /obj/structure/railing // uhhhh they're highly radiation resistant, or some shit (stops stupid exploits) + /atom/movable/emissive_blocker, )) var/list/processing_list = list(location) + var/list/window_priority = list() + var/list/collector_priority = list() + var/list/other_priority = list() + . = list() + var/insulation = 1 + while(length(processing_list)) + var/atom/thing = processing_list[1] + processing_list -= thing + if(!thing || ignored_things[thing.type]) + continue + switch(emission_type) + if(ALPHA_RAD) + insulation = thing.rad_insulation_alpha + if(BETA_RAD) + insulation = thing.rad_insulation_beta + if(GAMMA_RAD) + insulation = thing.rad_insulation_gamma + /// 1 means no rad insulation, which means perfectly permeable, so no interaction with it directly, but the contents might be relevant. + if(insulation < 1) + if(istype(thing, /obj/structure/window)) + window_priority += thing + else if(istype(thing, /obj/machinery/power/rad_collector)) + collector_priority += thing + else + other_priority += thing + if((thing.flags_2 & RAD_PROTECT_CONTENTS_2) || (SEND_SIGNAL(thing, COMSIG_ATOM_RAD_PROBE) & COMPONENT_BLOCK_RADIATION)) + continue + if(ishuman(thing)) + var/mob/living/carbon/human/target_mob = thing + if(target_mob.get_rad_protection() >= 0.99) // I would do exactly equal to 1, but you will never hit anything between 1 and .975, and byond seems to output 0.99999 + continue + processing_list += thing.contents + . = window_priority + collector_priority + other_priority + +/proc/get_rad_contamination_adjacent(atom/location, atom/source) + var/static/list/ignored_things = typecacheof(list( + /mob/camera, + /mob/dead, + /obj/effect, + /obj/docking_port, + /atom/movable/lighting_object, + /obj/item/projectile, + /atom/movable/emissive_blocker, + )) + var/list/processing_list = list(location) + // We want to select which clothes and items we contaminate depending on where on the human we are. We assume we are in some form of storage or on the floor otherwise. + // If the source is a human(like a uranium golem) we just attempt to contaminate all our contents + if(!ishuman(location) || ishuman(source)) + processing_list += location.contents + . = list() + for(var/atom/thing in processing_list) + if(thing && source && thing.UID() == source.UID()) + continue + if(ignored_things[thing.type]) + continue + if((SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING) & COMPONENT_BLOCK_CONTAMINATION) || thing.flags_2 & RAD_NO_CONTAMINATE_2) + continue + if(ishuman(thing) || ishuman(thing.loc)) + var/mob/living/carbon/human/target_mob = ishuman(thing) ? thing : thing.loc + var/passed = TRUE + var/zone + var/pocket = FALSE + // Check if we hold the contamination source, have it in our pockets or in our belts or if it's inside us + if(target_mob.UID() == location.UID()) + // If it's in our hands check if it can permeate our gloves + if((source && (target_mob.r_hand && target_mob.r_hand.UID() == source.UID()) || (target_mob.l_hand && target_mob.l_hand.UID() == source.UID()))) + zone = HANDS + + // If it's in our pockets check against our jumpsuit only + else if((target_mob?.l_store && target_mob?.l_store?.UID() == source?.UID()) || (target_mob?.r_store && target_mob?.r_store.UID() == source?.UID())) + zone = LOWER_TORSO + pocket = TRUE + + // If it's on our belt check against both our outer layer and jumpsuit + if(location.loc.UID() == target_mob.UID() && istype(location, /obj/item/storage/belt)) + zone = LOWER_TORSO + + // If on the floor check if it can permeate our shoes + if(istype(location, /turf/)) + zone = FEET + + // zone being unchanged here means the item is inside the mob + var/list/results = target_mob.rad_contaminate_zone(zone, pocket) + passed = results[1] + results -= results[1] + . |= results + if(!passed) + continue + . += thing + +/proc/get_rad_contamination_target(atom/location, atom/source) + var/static/list/ignored_things = typecacheof(list( + /mob/camera, + /mob/dead, + /obj/effect, + /obj/docking_port, + /atom/movable/lighting_object, + /obj/item/projectile, + /atom/movable/emissive_blocker, + )) + var/list/processing_list = list(location) + location.contents . = list() while(length(processing_list)) var/atom/thing = processing_list[1] processing_list -= thing + if(thing?.UID() == source?.UID()) + continue if(ignored_things[thing.type]) continue - . += thing - if((thing.flags_2 & RAD_PROTECT_CONTENTS_2) || (SEND_SIGNAL(thing, COMSIG_ATOM_RAD_PROBE) & COMPONENT_BLOCK_RADIATION)) + if((SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING) & COMPONENT_BLOCK_CONTAMINATION) || thing.flags_2 & RAD_NO_CONTAMINATE_2) continue + /// If it's a human check for rad protection on all areas if(ishuman(thing)) - var/mob/living/carbon/human/H = thing - if(H.get_rad_protection() >= 0.99) // I would do exactly equal to 1, but you will never hit anything between 1 and .975, and byond seems to output 0.99999 + var/mob/living/carbon/human/target_mob = thing + var/zone = 0 + var/list/contaminate = list() + var/list/results = list() + var/passed = TRUE + for(var/i in 0 to 9) + zone = (1< 3000 && world.time > last_huge_pulse + 200) + if(intensity > 12000 && world.time > last_huge_pulse + 200) last_huge_pulse = world.time log = TRUE if(log) var/turf/_source_T = isturf(source) ? source : get_turf(source) - log_game("Radiation pulse with intensity: [intensity] and range modifier: [range_modifier] in [loc_name(_source_T)] ") + log_game("Radiation pulse with intensity: [intensity] in [loc_name(_source_T)] ") return TRUE /proc/get_rad_contamination(atom/location) @@ -58,6 +189,24 @@ if(!thing) continue var/datum/component/radioactive/radiation = thing.GetComponent(/datum/component/radioactive) - if(radiation && rad_strength < radiation.strength) - rad_strength = radiation.strength + if(radiation && rad_strength < (radiation.alpha_strength + radiation.beta_strength + radiation.gamma_strength)) + rad_strength = (radiation.alpha_strength + radiation.beta_strength + radiation.gamma_strength) return rad_strength + +/// Contaminate things that share our immediate location(periodic) +/proc/contaminate_adjacent(atom/source, intensity, emission_type) + // If the source is a turf it is it's location + var/atom/location = isturf(source) ? source : source.loc + // Are we on a turf or in something else + var/is_source_on_turf = isturf(location) + var/contamination_chance = is_source_on_turf ? CONTAMINATION_CHANCE_TURF : CONTAMINATION_CHANCE_OTHER + var/list/contamination_contents = get_rad_contamination_adjacent(location, source) + for(var/atom/thing in contamination_contents) + if(prob(contamination_chance)) + thing.AddComponent(/datum/component/radioactive, intensity, source, emission_type) + +/// Contaminate the contents of a target(single instance) +/proc/contaminate_target(atom/target, atom/source, intensity, emission_type) + var/list/contamination_contents = get_rad_contamination_target(target, source) + for(var/atom/thing in contamination_contents) + thing.AddComponent(/datum/component/radioactive, intensity, source, emission_type) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index c6933b4aad0..5ba050835bc 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1403,6 +1403,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) var/obj/structure/window/W = O if(W.ini_dir == dir_to_check || W.ini_dir == FULLTILE_WINDOW_DIR || dir_to_check == FULLTILE_WINDOW_DIR) return FALSE + if(istype(O, /obj/machinery/power/rad_collector)) + return FALSE return TRUE //datum may be null, but it does need to be a typed var diff --git a/code/controllers/subsystem/SSradiation.dm b/code/controllers/subsystem/SSradiation.dm index c30f40a1363..c0235cb35e9 100644 --- a/code/controllers/subsystem/SSradiation.dm +++ b/code/controllers/subsystem/SSradiation.dm @@ -26,7 +26,7 @@ PROCESSING_SUBSYSTEM_DEF(radiation) warned_atoms[ref] = TRUE var/atom/master = contamination.parent SSblackbox.record_feedback("tally", "contaminated", 1, master.type) - var/msg = "has become contaminated with enough radiation to contaminate other objects. || Source: [contamination.source] || Strength: [contamination.strength]" + var/msg = "has become contaminated with enough radiation to emit radiation waves || Source: [contamination.source] || Strength: [contamination.alpha_strength + contamination.beta_strength + contamination.gamma_strength]" master.investigate_log(msg, "radiation") /datum/controller/subsystem/processing/radiation/fire(resumed) @@ -41,13 +41,25 @@ PROCESSING_SUBSYSTEM_DEF(radiation) else return 0 -/datum/controller/subsystem/processing/radiation/proc/update_rad_cache(datum/component/radioactive/thing) +/datum/controller/subsystem/processing/radiation/proc/update_rad_cache_contaminated(datum/component/radioactive/thing) var/atom/owner = thing.parent var/turf/place = get_turf(owner) if(turf_rad_cache[place]) - turf_rad_cache[place] += thing.strength + turf_rad_cache[place][1] += thing.alpha_strength + turf_rad_cache[place][2] += thing.beta_strength + turf_rad_cache[place][3] += thing.gamma_strength else - turf_rad_cache[place] = thing.strength + turf_rad_cache[place] = list(thing.alpha_strength, thing.beta_strength, thing.gamma_strength) + +/datum/controller/subsystem/processing/radiation/proc/update_rad_cache_inherent(datum/component/inherent_radioactivity/thing) + var/atom/owner = thing.parent + var/turf/place = get_turf(owner) + if(turf_rad_cache[place]) + turf_rad_cache[place][1] += thing.radioactivity_alpha + turf_rad_cache[place][2] += thing.radioactivity_beta + turf_rad_cache[place][3] += thing.radioactivity_gamma + else + turf_rad_cache[place] = list(thing.radioactivity_alpha, thing.radioactivity_beta, thing.radioactivity_gamma) /datum/controller/subsystem/processing/radiation/proc/refresh_rad_cache() diff --git a/code/datums/components/inherent_radioactivity.dm b/code/datums/components/inherent_radioactivity.dm new file mode 100644 index 00000000000..04bb982cf99 --- /dev/null +++ b/code/datums/components/inherent_radioactivity.dm @@ -0,0 +1,72 @@ +/datum/component/inherent_radioactivity + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + var/radioactivity_alpha + var/radioactivity_beta + var/radioactivity_gamma + /// Contamination cooldown in seconds + var/contaminate_cd + var/contained = FALSE + COOLDOWN_DECLARE(contaminate_cooldown) + +/datum/component/inherent_radioactivity/Initialize(_radioactivity_alpha = 0, _radioactivity_beta = 0, _radioactivity_gamma = 0, _contaminate_cd = 1.5) + radioactivity_alpha = _radioactivity_alpha + radioactivity_beta = _radioactivity_beta + radioactivity_gamma = _radioactivity_gamma + contaminate_cd = _contaminate_cd + RegisterSignal(parent, list(COMSIG_MOVABLE_IMPACT, COMSIG_ATOM_HITBY), PROC_REF(impact_contaminate)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(try_contaminate_hand)) + if(isitem(parent)) + RegisterSignal(parent, list(COMSIG_ATTACK, COMSIG_ATTACK_OBJ), PROC_REF(impact_contaminate)) + START_PROCESSING(SSradiation, src) + +/datum/component/inherent_radioactivity/proc/impact_contaminate(atom/source, atom/target) + SIGNAL_HANDLER + if(contaminate_cd <= 0 || COOLDOWN_FINISHED(src, contaminate_cooldown)) + if(radioactivity_alpha) + target.contaminate_atom(source, radioactivity_alpha, ALPHA_RAD) + if(radioactivity_beta) + target.contaminate_atom(source, radioactivity_beta, BETA_RAD) + if(radioactivity_gamma) + target.contaminate_atom(source, radioactivity_gamma, GAMMA_RAD) + if(contaminate_cd > 0) + COOLDOWN_START(src, contaminate_cooldown, contaminate_cd SECONDS) + +/datum/component/inherent_radioactivity/proc/try_contaminate_hand(atom/source, atom/target) + SIGNAL_HANDLER + if(contaminate_cd <= 0 || COOLDOWN_FINISHED(src, contaminate_cooldown)) + if(radioactivity_alpha) + target.contaminate_atom(source, radioactivity_alpha, ALPHA_RAD, HANDS) + if(radioactivity_beta) + target.contaminate_atom(source, radioactivity_beta, BETA_RAD, HANDS) + if(radioactivity_gamma) + target.contaminate_atom(source, radioactivity_gamma, GAMMA_RAD, HANDS) + if(contaminate_cd > 0) + COOLDOWN_START(src, contaminate_cooldown, contaminate_cd SECONDS) + +/datum/component/inherent_radioactivity/InheritComponent(datum/component/C, i_am_original, _radioactivity_alpha = 0, _radioactivity_beta = 0, _radioactivity_gamma = 0, _contaminate_cd = 1.5) + if(!i_am_original) + return + if(C) + var/datum/component/inherent_radioactivity/other = C + radioactivity_alpha = other.radioactivity_alpha + radioactivity_beta = other.radioactivity_beta + radioactivity_gamma = other.radioactivity_gamma + contaminate_cd = other.contaminate_cd + else + radioactivity_alpha = _radioactivity_alpha + radioactivity_beta = _radioactivity_beta + radioactivity_gamma = _radioactivity_gamma + contaminate_cd = _contaminate_cd + +/datum/component/inherent_radioactivity/process() + if(radioactivity_alpha > 0) + contaminate_adjacent(parent, radioactivity_alpha, ALPHA_RAD) + radiation_pulse(parent, 2 * radioactivity_alpha, ALPHA_RAD) + if(radioactivity_beta > 0) + contaminate_adjacent(parent, radioactivity_beta, BETA_RAD) + radiation_pulse(parent, 2 * radioactivity_beta, BETA_RAD) + if(radioactivity_gamma > 0) + contaminate_adjacent(parent, radioactivity_gamma, GAMMA_RAD) + radiation_pulse(parent, 2 * radioactivity_gamma, GAMMA_RAD) + + SSradiation.update_rad_cache_inherent(src) diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm index 6652b4ed646..18ee3e0029f 100644 --- a/code/datums/components/radioactive.dm +++ b/code/datums/components/radioactive.dm @@ -2,6 +2,9 @@ #define RAD_AMOUNT_MEDIUM 200 #define RAD_AMOUNT_HIGH 500 #define RAD_AMOUNT_EXTREME 1000 +#define GLOW_ALPHA "#225dff5d" +#define GLOW_BETA "#39ff1430" +#define GLOW_GAMMA "#c125ff6b" /datum/component/radioactive dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS @@ -9,27 +12,31 @@ var/source ///the half-life measured in ticks var/hl3_release_date - var/strength - var/can_contaminate + var/alpha_strength + var/beta_strength + var/gamma_strength -/datum/component/radioactive/Initialize(_strength = 0, _source, _half_life = RAD_HALF_LIFE, _can_contaminate = TRUE) +/datum/component/radioactive/Initialize(_strength, _source, emission_type, _half_life = RAD_HALF_LIFE) if(!istype(parent, /atom)) return COMPONENT_INCOMPATIBLE - strength = _strength + switch(emission_type) + if(ALPHA_RAD) + alpha_strength = _strength + if(BETA_RAD) + beta_strength = _strength + if(GAMMA_RAD) + gamma_strength = _strength source = _source hl3_release_date = _half_life - can_contaminate = _can_contaminate RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(rad_examine)) RegisterSignal(parent, COMSIG_ADMIN_DECONTAMINATE, PROC_REF(admin_decontaminate)) if(isitem(parent)) RegisterSignal(parent, COMSIG_ATTACK, PROC_REF(rad_attack)) RegisterSignal(parent, COMSIG_ATTACK_OBJ, PROC_REF(rad_attack)) - if(strength > RAD_MINIMUM_CONTAMINATION) - SSradiation.warn(src) //Let's make er glow //This relies on parent not being a turf or something. IF YOU CHANGE THAT, CHANGE THIS var/atom/movable/master = parent - master.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2)) + master.add_filter("rad_glow", 2, list("type" = "outline", "color" = get_glow_color(), "size" = 2)) addtimer(CALLBACK(src, PROC_REF(glow_loop), master), rand(1, 19)) //Things should look uneven LAZYADD(SSradiation.all_radiations, src) START_PROCESSING(SSradiation, src) @@ -41,15 +48,40 @@ master.remove_filter("rad_glow") return ..() +/datum/component/radioactive/proc/get_glow_color() + var/list/glow_alpha = rgb2num(GLOW_ALPHA) + var/list/glow_beta = rgb2num(GLOW_BETA) + var/list/glow_gamma = rgb2num(GLOW_GAMMA) + var/list/rad_color = list() + var/alpha_part = alpha_strength / (alpha_strength + beta_strength + gamma_strength) + var/beta_part = beta_strength / (alpha_strength + beta_strength + gamma_strength) + var/gamma_part = 1 - (alpha_part + beta_part) + var/max_ratio = 0 + for(var/i in 1 to 4) + rad_color += glow_alpha[i] * alpha_part + glow_beta[i] * beta_part + glow_gamma[i] * gamma_part + // Find the ratio between the color value closest to 256 and 256. + if(i < 4 && max_ratio < (rad_color[i] / 256)) + max_ratio = rad_color[i] / 256 + return rgb(rad_color[1] / max_ratio, rad_color[2] / max_ratio, rad_color[3] / max_ratio, rad_color[4]) + /datum/component/radioactive/process() - if(!prob(50)) - return - radiation_pulse(parent, strength, RAD_DISTANCE_COEFFICIENT * 2, FALSE, can_contaminate) + if(alpha_strength > RAD_BACKGROUND_RADIATION) + radiation_pulse(parent, alpha_strength, ALPHA_RAD) + if(beta_strength > RAD_BACKGROUND_RADIATION) + radiation_pulse(parent, beta_strength, BETA_RAD) + if(gamma_strength > RAD_BACKGROUND_RADIATION) + radiation_pulse(parent, gamma_strength, GAMMA_RAD) + if(!hl3_release_date) return - strength -= strength / hl3_release_date - SSradiation.update_rad_cache(src) - if(strength <= RAD_BACKGROUND_RADIATION) + + alpha_strength -= alpha_strength / hl3_release_date + beta_strength -= beta_strength / hl3_release_date + gamma_strength -= gamma_strength / hl3_release_date + + SSradiation.update_rad_cache_contaminated(src) + + if(alpha_strength + beta_strength + gamma_strength <= RAD_BACKGROUND_RADIATION) qdel(src) return PROCESS_KILL @@ -59,16 +91,30 @@ animate(filter, alpha = 110, time = 15, loop = -1) animate(alpha = 40, time = 25) -/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, _half_life, _can_contaminate) +/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, emission_type, _half_life = RAD_HALF_LIFE) if(!i_am_original) return if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger return if(C) var/datum/component/radioactive/other = C - strength = max(strength, other.strength) + alpha_strength = max(alpha_strength, other.alpha_strength) + beta_strength = max(beta_strength, other.beta_strength) + gamma_strength = max(gamma_strength, other.gamma_strength) + hl3_release_date = other.hl3_release_date else - strength = max(strength, _strength) + switch(emission_type) + if(ALPHA_RAD) + alpha_strength = max(alpha_strength, _strength) + if(BETA_RAD) + beta_strength = max(beta_strength, _strength) + if(GAMMA_RAD) + gamma_strength = max(gamma_strength, _strength) + + hl3_release_date = _half_life + var/atom/movable/master = parent + var/filter = master.get_filter("rad_glow") + animate(filter, color = get_glow_color()) /datum/component/radioactive/proc/rad_examine(datum/source, mob/user, list/out) SIGNAL_HANDLER @@ -78,7 +124,7 @@ var/list/fragments = list() if(get_dist(master, user) <= 1) fragments += "The air around [master] feels warm" - switch(strength) + switch(alpha_strength + beta_strength + gamma_strength) if(0 to RAD_AMOUNT_LOW) if(length(fragments)) fragments += "." @@ -94,12 +140,20 @@ /datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user) SIGNAL_HANDLER - - radiation_pulse(parent, strength / 20) - target.rad_act(strength / 2) + if(alpha_strength > RAD_BACKGROUND_RADIATION) + radiation_pulse(parent, alpha_strength / 20, ALPHA_RAD) + target.base_rad_act(parent ,alpha_strength / 2, ALPHA_RAD) + if(beta_strength > RAD_BACKGROUND_RADIATION) + radiation_pulse(parent, beta_strength / 20, BETA_RAD) + target.base_rad_act(parent, beta_strength / 2, BETA_RAD) + if(gamma_strength > RAD_BACKGROUND_RADIATION) + radiation_pulse(parent, gamma_strength / 20, GAMMA_RAD) + target.base_rad_act(parent, gamma_strength / 2, GAMMA_RAD) if(!hl3_release_date) return - strength -= strength / hl3_release_date + alpha_strength -= alpha_strength / hl3_release_date + beta_strength -= beta_strength / hl3_release_date + gamma_strength -= gamma_strength / hl3_release_date /datum/component/radioactive/proc/admin_decontaminate() SIGNAL_HANDLER @@ -116,3 +170,6 @@ #undef RAD_AMOUNT_MEDIUM #undef RAD_AMOUNT_HIGH #undef RAD_AMOUNT_EXTREME +#undef GLOW_ALPHA +#undef GLOW_BETA +#undef GLOW_GAMMA diff --git a/code/datums/elements/rad_insulation.dm b/code/datums/elements/rad_insulation.dm index 673ae58df15..33d61255805 100644 --- a/code/datums/elements/rad_insulation.dm +++ b/code/datums/elements/rad_insulation.dm @@ -12,8 +12,6 @@ RegisterSignal(target, COMSIG_ATOM_RAD_PROBE, PROC_REF(rad_probe_react)) if(contamination_proof) // Can this object be contaminated? RegisterSignal(target, COMSIG_ATOM_RAD_CONTAMINATING, PROC_REF(rad_contaminating)) - if(_amount != 1) // If it's 1 it won't have any impact on radiation passing through anyway - RegisterSignal(target, COMSIG_ATOM_RAD_WAVE_PASSING, PROC_REF(rad_pass)) amount = _amount @@ -22,13 +20,7 @@ return COMPONENT_BLOCK_RADIATION -/datum/element/rad_insulation/proc/rad_contaminating(datum/source, strength) +/datum/element/rad_insulation/proc/rad_contaminating(datum/source) SIGNAL_HANDLER return COMPONENT_BLOCK_CONTAMINATION - -/datum/element/rad_insulation/proc/rad_pass(datum/source, datum/radiation_wave/wave, width) - SIGNAL_HANDLER - - wave.intensity = wave.intensity * (1 - ((1 - amount) / width)) // The further out the rad wave goes the less it's affected by insulation (larger width) - return COMPONENT_RAD_WAVE_HANDLED diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm index 241766da227..3cd19e5492e 100644 --- a/code/datums/radiation_wave.dm +++ b/code/datums/radiation_wave.dm @@ -1,41 +1,31 @@ +#define WRAP_INDEX(index, length)((index - 1) % length + 1) + /datum/radiation_wave /// The thing that spawned this radiation wave var/source - /// The center of the wave + /// The top left corner of the wave, from which we begin iteration on a step var/turf/master_turf /// How far we've moved var/steps = 0 - /// How strong it was originaly + /// The strength at the origin. Multiplied by the weight of a tile to determine the strength of radiation there. var/intensity - /// How much contaminated material it still has - var/remaining_contam - /// Higher than 1 makes it drop off faster, 0.5 makes it drop off half etc - var/range_modifier - /// The distance from the source point the wave can cover without losing any strength. - var/source_radius /// The direction of movement var/move_dir /// The directions to the side of the wave, stored for easy looping var/list/__dirs - /// Whether or not this radiation wave can create contaminated objects - var/can_contaminate + /// Weights of the current tiles in the step going clockwise from the top left corner. Starts as one tile with a weight of 1 + var/list/weights = list(1) + /// Sum of all weights + var/weight_sum = 1 + /// The type of particle emitted + var/emission_type = ALPHA_RAD -/datum/radiation_wave/New(atom/_source, dir, _intensity = 0, _range_modifier = RAD_DISTANCE_COEFFICIENT, _can_contaminate = TRUE, _source_radius = 0) - - source = "[_source] \[[_source.UID()]\]" +/datum/radiation_wave/New(atom/_source, _intensity = 0, _emission_type = ALPHA_RAD) + source = _source master_turf = get_turf(_source) - - move_dir = dir - __dirs = list() - __dirs += turn(dir, 90) - __dirs += turn(dir, -90) - intensity = _intensity - remaining_contam = intensity - range_modifier = _range_modifier - can_contaminate = _can_contaminate - source_radius = _source_radius + emission_type = _emission_type START_PROCESSING(SSradiation, src) /datum/radiation_wave/Destroy() @@ -43,99 +33,70 @@ STOP_PROCESSING(SSradiation, src) ..() + +/// Deals with wave propagation. Radiation waves always expand in a 90 degree cone /datum/radiation_wave/process() - master_turf = get_step(master_turf, move_dir) + // If the wave is too weak to do anything + if(weight_sum * intensity < RAD_BACKGROUND_RADIATION) + qdel(src) + return + /// We start iteration from the top left corner of the current wave step + master_turf = get_step(master_turf, NORTHWEST) if(!master_turf) qdel(src) return steps++ - var/list/atoms = get_rad_atoms() + var/list/new_weights = list() + var/turf/current_turf = master_turf + weight_sum = 0 + var/weight_left + var/weight_center + var/weight_right + var/index + var/offset + var/walk_dir = EAST + var/ratio = steps > 1 ? (steps - 1) / steps : (1 / 8) + var/weight_length = length(weights) + // Iterate around the periphery of a square for each step + for(var/i in 0 to (8 * steps - 1)) + // our index along the edge we are on, each corner starts a new edge. + index = (i % (2 * steps)) + 1 + // Get weights for rear, right rear and left rear tiles if they were part of the previous step, where rear means towards the center and left and right are along the edge we are on + weight_left = index > 2 ? weights[WRAP_INDEX((index + offset - 2), weight_length)] : 0 + weight_center = index > 1 ? weights[WRAP_INDEX((index + offset - 1), weight_length)] : 0 + weight_right = index < (2 * steps) ? weights[WRAP_INDEX((index + offset), weight_length)] : 0 + // The weight of the current tile the average of the weights of the tiles we checked for earlier + // And is reduced by irradiating things and getting blocked + if(weight_left + weight_center + weight_right) + new_weights += radiate(source, current_turf, (ratio) * (weight_left + weight_center + weight_right) / ((1 + (index > 1 && index < (2 * steps + 1) && steps > 1) + (index > 2 && index < (2 * steps)))), emission_type) + else + new_weights += 0 + weight_sum += new_weights[i + 1] + // Advance to next turf + current_turf = get_step(current_turf, walk_dir) + // If we reached a corner turn to the right + if(index == (2 * steps)) + walk_dir = turn(walk_dir, -90) + offset += 2 * (steps - 1) - var/strength - if(steps > source_radius + 1) - strength = INVERSE_SQUARE(intensity, max(range_modifier * (steps - source_radius), 1), 1) + weights = new_weights + // With the spread each step being linear waves can spread very far. This limits the distance for performace reasons + if(steps > RAD_DECAY_POINT) + intensity *= RAD_DECAY_RATE + +/// Calls rad act on each relevant atom in the turf and returns the resulting weight for that tile after reduction by insulation +/datum/radiation_wave/proc/radiate(atom/source, turf/current_turf, weight, emission_type) + var/list/turf_atoms = list() + if(length(current_turf.contents)) + turf_atoms = get_rad_contents(current_turf, emission_type) else - strength = intensity - - if(strength < RAD_BACKGROUND_RADIATION) - qdel(src) - return - radiate(atoms, strength) - check_obstructions(atoms) // reduce our overall strength if there are radiation insulators - -/datum/radiation_wave/proc/get_rad_atoms() - var/list/atoms = list() - var/distance = steps - var/cmove_dir = move_dir - var/cmaster_turf = master_turf - - if(cmove_dir == NORTH || cmove_dir == SOUTH) - distance-- //otherwise corners overlap - - atoms += get_rad_contents(cmaster_turf) - - var/turf/place - for(var/dir in __dirs) //There should be just 2 dirs in here, left and right of the direction of movement - place = cmaster_turf - for(var/i in 1 to distance) - place = get_step(place, dir) - if(!place) - break - atoms += get_rad_contents(place) - - return atoms - -/datum/radiation_wave/proc/check_obstructions(list/atoms) - var/width = steps - var/cmove_dir = move_dir - if(cmove_dir == NORTH || cmove_dir == SOUTH) - width-- - width = 1 + (2 * width) - - for(var/k in 1 to length(atoms)) - var/atom/thing = atoms[k] - if(!thing) - continue - if(SEND_SIGNAL(thing, COMSIG_ATOM_RAD_WAVE_PASSING, src, width) & COMPONENT_RAD_WAVE_HANDLED) - continue - if(thing.rad_insulation != RAD_NO_INSULATION) - intensity *= (1 - ((1 - thing.rad_insulation) / width)) - -/datum/radiation_wave/proc/radiate(list/atoms, strength) - var/can_contam = strength >= RAD_MINIMUM_CONTAMINATION - var/contamination_strength = (strength - RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT - contamination_strength = max(contamination_strength, RAD_BACKGROUND_RADIATION) - // It'll never reach 100% chance but the further out it gets the more likely it'll contaminate - var/contamination_chance = 100 - (90 / (1 + steps * 0.1)) - for(var/k in atoms) + turf_atoms = list(current_turf) + for(var/k in turf_atoms) var/atom/thing = k if(QDELETED(thing)) continue - thing.rad_act(strength) + weight = weight * thing.base_rad_act(source ,weight * intensity, emission_type) + // return the resulting weight if the radiation on the tile would end up greater than background + return (((weight * intensity) > RAD_BACKGROUND_RADIATION) ? weight : 0) - // This list should only be for types which don't get contaminated but you want to look in their contents - // If you don't want to look in their contents and you don't want to rad_act them: - // modify the ignored_things list in __HELPERS/radiation.dm instead - var/static/list/blacklisted = typecacheof(list( - /turf, - /obj/structure/cable, - /obj/machinery/atmospherics, - /obj/item/ammo_casing, - /obj/item/bio_chip, - /obj/singularity, - )) - if(!can_contaminate || !can_contam || blacklisted[thing.type]) - continue - if(thing.flags_2 & RAD_NO_CONTAMINATE_2 || SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION) - continue - - if(contamination_strength > remaining_contam) - contamination_strength = remaining_contam - if(!prob(contamination_chance)) - continue - if(SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION) - continue - remaining_contam -= contamination_strength - if(remaining_contam < RAD_BACKGROUND_RADIATION) - can_contaminate = FALSE - thing.AddComponent(/datum/component/radioactive, contamination_strength, source) +#undef WRAP_INDEX diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 4cb7314c4ab..442e5950c44 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -55,7 +55,7 @@ return if(prob(max(0, 100 - ARMOUR_VALUE_TO_PERCENTAGE(resist)))) - L.rad_act(400) + L.base_rad_act(L ,400 , BETA_RAD) if(HAS_TRAIT(H, TRAIT_GENELESS)) return randmuti(H) // Applies bad mutation diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 76a49169c7b..105066721ff 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -60,8 +60,12 @@ var/list/atom_colours //used to store the different colors on an atom //its inherent color, the colored paint applied on it, special color effect etc... - /// Radiation insulation types - var/rad_insulation = RAD_NO_INSULATION + /// Radiation insulation for alpha emissions + var/rad_insulation_alpha = RAD_ALPHA_BLOCKER + /// Radiation insulation for beta emissions + var/rad_insulation_beta = RAD_NO_INSULATION + /// Radiation insulation for gamma emissions + var/rad_insulation_gamma = RAD_NO_INSULATION /// Last name used to calculate a color for the chatmessage overlays. Used for caching. var/chat_color_name @@ -608,10 +612,32 @@ /** * Respond to a radioactive wave hitting this atom * - * Default behaviour is to send [COMSIG_ATOM_RAD_ACT] and return + * This should only be called through the atom/base_rad_act proc */ -/atom/proc/rad_act(amount) - SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, amount) +/atom/proc/rad_act(atom/source, amount, emission_type) + return + +/** +* Sends a COMSIG_ATOM_RAD_ACT signal, calls the atoms rad_act with the amount of radiation it should have absorbed and returns the rad insulation of the atom that isappropriate for emission_type +*/ +/atom/proc/base_rad_act(atom/source, amount, emission_type) + switch(emission_type) + if(ALPHA_RAD) + . = rad_insulation_alpha + if(BETA_RAD) + . = rad_insulation_beta + if(GAMMA_RAD) + . = rad_insulation_gamma + SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, amount, emission_type) + if(amount >= RAD_BACKGROUND_RADIATION) + rad_act(source, amount * (1 - .), emission_type) + +/// Attempt to contaminate a single atom +/atom/proc/contaminate_atom(atom/source, intensity, emission_type) + if(flags_2 & RAD_NO_CONTAMINATE_2 || (SEND_SIGNAL(src, COMSIG_ATOM_RAD_CONTAMINATING) & COMPONENT_BLOCK_CONTAMINATION)) + return + AddComponent(/datum/component/radioactive, intensity, source, emission_type) + /atom/proc/fart_act(mob/living/M) return FALSE @@ -1002,8 +1028,10 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) /atom/proc/clean_radiation(clean_factor = 2) var/datum/component/radioactive/healthy_green_glow = GetComponent(/datum/component/radioactive) if(!QDELETED(healthy_green_glow)) - healthy_green_glow.strength = max(0, (healthy_green_glow.strength - (RAD_BACKGROUND_RADIATION * clean_factor))) - if(healthy_green_glow.strength <= RAD_BACKGROUND_RADIATION) + healthy_green_glow.alpha_strength = max(0, (healthy_green_glow.alpha_strength - (RAD_BACKGROUND_RADIATION * clean_factor))) + healthy_green_glow.beta_strength = max(0, (healthy_green_glow.beta_strength - (RAD_BACKGROUND_RADIATION * clean_factor))) + healthy_green_glow.gamma_strength = max(0, (healthy_green_glow.gamma_strength - (RAD_BACKGROUND_RADIATION * clean_factor))) + if((healthy_green_glow.alpha_strength + healthy_green_glow.beta_strength + healthy_green_glow.gamma_strength) <= RAD_BACKGROUND_RADIATION) healthy_green_glow.RemoveComponent() /obj/effect/decal/cleanable/blood/clean_blood(radiation_clean = FALSE) diff --git a/code/game/dna/mutations/disabilities.dm b/code/game/dna/mutations/disabilities.dm index 0d064e8f24c..c19f1693067 100644 --- a/code/game/dna/mutations/disabilities.dm +++ b/code/game/dna/mutations/disabilities.dm @@ -265,7 +265,7 @@ return TRUE /datum/mutation/disability/radioactive/on_life(mob/living/carbon/human/H) - radiation_pulse(H, 20) + radiation_pulse(H, 80, ALPHA_RAD) /datum/mutation/disability/radioactive/on_draw_underlays(mob/M, g) return "rads_s" diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 07a19d19477..0fa4e0b2e33 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -18,10 +18,13 @@ GLOBAL_VAR(bomb_set) icon_state = "nuclearbomb1" density = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - flags_2 = NO_MALF_EFFECT_2 | CRITICAL_ATOM_2 + flags_2 = NO_MALF_EFFECT_2 | CRITICAL_ATOM_2 | RAD_NO_CONTAMINATE_2 | RAD_PROTECT_CONTENTS_2 anchored = TRUE power_state = NO_POWER_USE interact_offline = TRUE + rad_insulation_alpha = RAD_FULL_INSULATION + rad_insulation_beta = RAD_FULL_INSULATION + rad_insulation_gamma = RAD_FULL_INSULATION /// Are our bolts *supposed* to be in the floor, may not actually cause anchoring if the bolts are cut var/extended = TRUE @@ -80,7 +83,8 @@ GLOBAL_VAR(bomb_set) GLOB.poi_list |= src GLOB.nuke_list |= src core = new /obj/item/nuke_core/plutonium(src) - STOP_PROCESSING(SSobj, core) //Let us not irradiate the vault by default. + var/datum/component/inherent_radioactivity/radioactivity = core.GetComponent(/datum/component/inherent_radioactivity) + STOP_PROCESSING(SSradiation, radioactivity)//Let us not irradiate the vault by default. update_icon(UPDATE_OVERLAYS) radio = new(src) radio.listening = FALSE @@ -201,7 +205,8 @@ GLOBAL_VAR(bomb_set) "You repair [src]'s inner core plate. The radiation is contained.") removal_stage = NUKE_CORE_PANEL_UNWELDED if(core) - STOP_PROCESSING(SSobj, core) + var/datum/component/inherent_radioactivity/radioactivity = core.GetComponent(/datum/component/inherent_radioactivity) + STOP_PROCESSING(SSradiation, radioactivity) update_icon(UPDATE_OVERLAYS) return ITEM_INTERACT_COMPLETE if(istype(used, /obj/item/stack/sheet/metal) && removal_stage == NUKE_CORE_PANEL_EXPOSED) @@ -271,7 +276,8 @@ GLOBAL_VAR(bomb_set) removal_stage = NUKE_CORE_FULLY_EXPOSED new /obj/item/stack/sheet/mineral/titanium(loc, 5) if(core) - START_PROCESSING(SSobj, core) + var/datum/component/inherent_radioactivity/radioactivity = core.GetComponent(/datum/component/inherent_radioactivity) + START_PROCESSING(SSradiation, radioactivity) if(removal_stage == NUKE_UNWRENCHED) user.visible_message("[user] begins lifting [src] off of the anchors.", "You begin lifting the device off the anchors...") if(!I.use_tool(src, user, 8 SECONDS, volume = I.tool_volume) || removal_stage != NUKE_UNWRENCHED) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 366ad33f258..a5bd887138d 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -61,7 +61,8 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) assemblytype = /obj/structure/door_assembly siemens_strength = 1 flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_MEDIUM_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_MEDIUM_INSULATION smoothing_groups = list(SMOOTH_GROUP_AIRLOCK) cares_about_temperature = TRUE var/security_level = 0 //How much are wires secured diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 173b8c14553..0b86ca712e6 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -160,16 +160,14 @@ paintable = FALSE var/last_event = 0 -/obj/machinery/door/airlock/uranium/process() - if(world.time > last_event + 20) - if(prob(50)) - radiate() - last_event = world.time - ..() +/obj/machinery/door/airlock/uranium/Initialize(mapload) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 150, 0, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) -/obj/machinery/door/airlock/uranium/proc/radiate() - radiation_pulse(get_turf(src), 150) +/obj/machinery/door/airlock/uranium/attack_hand(mob/user) + . = ..() /obj/machinery/door/airlock/uranium/glass opacity = FALSE diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 3363f4f661f..03816be6f74 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -213,6 +213,7 @@ return attack_hand(user) /obj/machinery/door/attack_hand(mob/user) + . = ..() return try_to_activate_door(user) /obj/machinery/door/attack_tk(mob/user) diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm index 145b8c7b1ea..5fb55e4abb4 100644 --- a/code/game/machinery/doors/shutters.dm +++ b/code/game/machinery/doors/shutters.dm @@ -18,18 +18,22 @@ desc = "Lead-lined shutters with a radiation hazard symbol. Whilst this won't stop you getting irradiated, especially by a supermatter crystal, it will stop radiation travelling as far." icon = 'icons/obj/doors/shutters_radiation.dmi' icon_state = "closed" - rad_insulation = RAD_EXTREME_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_VERY_EXTREME_INSULATION /obj/machinery/door/poddoor/shutters/radiation/preopen icon_state = "open" density = FALSE opacity = FALSE - rad_insulation = RAD_NO_INSULATION + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_NO_INSULATION /obj/machinery/door/poddoor/shutters/radiation/open() . = ..() - rad_insulation = RAD_NO_INSULATION + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_NO_INSULATION /obj/machinery/door/poddoor/shutters/radiation/close() . = ..() - rad_insulation = RAD_EXTREME_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_VERY_EXTREME_INSULATION diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 70f06f79b0d..a31ee0140c2 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -204,7 +204,7 @@ flick("grinder-b0",src) playsound(loc, 'sound/effects/alert.ogg', 50, 0) sleep(5) - H.rad_act(rand(150, 200)) + H.base_rad_act(src ,rand(150, 200), GAMMA_RAD) if(prob(5)) if(prob(75)) randmutb(H) // Applies bad mutation diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 6f9641454e2..b4c1de218e8 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -434,11 +434,11 @@ fuel_per_cycle_idle = 10 fuel_per_cycle_active = 150 power_per_cycle = 250 - var/rad_per_cycle = 30 + var/rad_per_cycle = 120 /obj/item/mecha_parts/mecha_equipment/generator/nuclear/process() if(..()) - radiation_pulse(get_turf(src), rad_per_cycle) + radiation_pulse(get_turf(src), rad_per_cycle, BETA_RAD) /obj/item/mecha_parts/mecha_equipment/thrusters name = "exosuit ion thrusters" diff --git a/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm b/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm index f0ddd75c6be..4c7b736c81b 100644 --- a/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm +++ b/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm @@ -36,6 +36,9 @@ /obj/effect/decal/cleanable/glass/plasma icon_state = "plasmatiny" +/obj/effect/decal/cleanable/glass/plastitanium + icon_state = "plastitaniumtiny" + /obj/effect/decal/cleanable/dirt name = "dirt" desc = "Someone should clean that up." diff --git a/code/game/objects/effects/meteors.dm b/code/game/objects/effects/meteors.dm index 7ed085c78ad..ac396492750 100644 --- a/code/game/objects/effects/meteors.dm +++ b/code/game/objects/effects/meteors.dm @@ -282,7 +282,9 @@ GLOBAL_LIST_INIT(meteors_gore, list(/obj/effect/meteor/meaty = 5, /obj/effect/me ..() explosion(loc, 0, 0, 4, 3, 0) new /obj/effect/decal/cleanable/greenglow(get_turf(src)) - radiation_pulse(src, 5000, 7) + radiation_pulse(src, 20000, 7, ALPHA_RAD) + for(var/turf/target_turf in range(loc, 3)) + contaminate_target(target_turf, src, 2000, ALPHA_RAD) //Hot take on this one. This often hits walls. It really has to breach into somewhere important to matter. This at leats makes the area slightly dangerous for a bit /obj/effect/meteor/bananium diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index a97ced7b06a..9a322c3974e 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -75,7 +75,7 @@ var/radiation_amount /obj/effect/mine/dnascramble/mineEffect(mob/living/victim) - victim.rad_act(radiation_amount) + victim.base_rad_act(src, radiation_amount, BETA_RAD) if(!victim.dna || HAS_TRAIT(victim, TRAIT_GENELESS)) return randmutb(victim) diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index b4237bb1b88..0f834296dd8 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -15,14 +15,23 @@ slot_flags = ITEM_SLOT_BELT flags = NOBLUDGEON materials = list(MAT_METAL = 210, MAT_GLASS = 150) + rad_insulation_alpha = RAD_ONE_PERCENT + rad_insulation_beta = RAD_ONE_PERCENT + rad_insulation_gamma = RAD_ONE_PERCENT var/grace = RAD_GEIGER_GRACE_PERIOD var/datum/looping_sound/geiger/soundloop var/scanning = FALSE - var/radiation_count = 0 - var/current_tick_amount = 0 - var/last_tick_amount = 0 + var/radiation_count_alpha = 0 + var/radiation_count_beta = 0 + var/radiation_count_gamma = 0 + var/current_tick_amount_alpha = 0 + var/current_tick_amount_beta = 0 + var/current_tick_amount_gamma = 0 + var/last_tick_amount_alpha = 0 + var/last_tick_amount_beta = 0 + var/last_tick_amount_gamma = 0 var/fail_to_receive = 0 var/current_warning = 1 @@ -40,19 +49,33 @@ /obj/item/geiger_counter/process() if(scanning) - radiation_count -= radiation_count / RAD_GEIGER_MEASURE_SMOOTHING - radiation_count += current_tick_amount / RAD_GEIGER_MEASURE_SMOOTHING + radiation_count_alpha -= radiation_count_alpha / RAD_GEIGER_MEASURE_SMOOTHING + radiation_count_alpha += current_tick_amount_alpha / RAD_GEIGER_MEASURE_SMOOTHING + radiation_count_beta -= radiation_count_beta / RAD_GEIGER_MEASURE_SMOOTHING + radiation_count_beta += current_tick_amount_beta / RAD_GEIGER_MEASURE_SMOOTHING + radiation_count_gamma -= radiation_count_gamma / RAD_GEIGER_MEASURE_SMOOTHING + radiation_count_gamma += current_tick_amount_gamma / RAD_GEIGER_MEASURE_SMOOTHING - if(current_tick_amount) + if(current_tick_amount_alpha) grace = RAD_GEIGER_GRACE_PERIOD - last_tick_amount = current_tick_amount + last_tick_amount_alpha = current_tick_amount_alpha + if(current_tick_amount_beta) + grace = RAD_GEIGER_GRACE_PERIOD + last_tick_amount_beta = current_tick_amount_beta + if(current_tick_amount_gamma) + grace = RAD_GEIGER_GRACE_PERIOD + last_tick_amount_gamma = current_tick_amount_gamma else if(!emagged) grace-- if(grace <= 0) - radiation_count = 0 + radiation_count_alpha = 0 + radiation_count_beta = 0 + radiation_count_gamma = 0 - current_tick_amount = 0 + current_tick_amount_alpha = 0 + current_tick_amount_beta = 0 + current_tick_amount_gamma = 0 update_icon(UPDATE_ICON_STATE) update_sound() @@ -65,6 +88,7 @@ if(emagged) . += "The display seems to be incomprehensible." return + var/radiation_count = max(radiation_count_alpha, radiation_count_beta, radiation_count_gamma) switch(radiation_count) if(-INFINITY to RAD_LEVEL_NORMAL) . += "Ambient radiation level count reports that all is well." @@ -79,7 +103,9 @@ if(RAD_LEVEL_CRITICAL + 1 to INFINITY) . += "Ambient radiation levels above critical level!" - . += "The last radiation amount detected was [last_tick_amount]" + . += "The alpha radiation amount detected was [last_tick_amount_alpha]" + . += "The beta radiation amount detected was [last_tick_amount_beta]" + . += "The gamma radiation amount detected was [last_tick_amount_gamma]" /obj/item/geiger_counter/update_icon_state() if(!scanning) @@ -87,6 +113,7 @@ else if(emagged) icon_state = "geiger_on_emag" else + var/radiation_count = max(radiation_count_alpha + radiation_count_beta + radiation_count_gamma) switch(radiation_count) if(-INFINITY to RAD_LEVEL_NORMAL) icon_state = "geiger_on_1" @@ -103,17 +130,24 @@ /obj/item/geiger_counter/proc/update_sound() var/datum/looping_sound/geiger/loop = soundloop + var/radiation_count = max(radiation_count_alpha, radiation_count_beta, radiation_count_gamma) if(!scanning || !radiation_count) loop.stop() return loop.last_radiation = radiation_count loop.start() -/obj/item/geiger_counter/rad_act(amount) - . = ..() +/obj/item/geiger_counter/rad_act(atom/source, amount, emission_type) + amount *= 100 if(amount <= RAD_BACKGROUND_RADIATION || !scanning) return - current_tick_amount += amount + switch(emission_type) + if(ALPHA_RAD) + current_tick_amount_alpha += amount + if(BETA_RAD) + current_tick_amount_beta += amount + if(GAMMA_RAD) + current_tick_amount_gamma += amount update_icon(UPDATE_ICON_STATE) /obj/item/geiger_counter/attack_self__legacy__attackchain(mob/user) @@ -129,8 +163,12 @@ addtimer(CALLBACK(src, PROC_REF(scan), target, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents else user.visible_message("[user] scans [target] with [src].", "You project [src]'s stored radiation into [target]!") - target.rad_act(radiation_count) - radiation_count = 0 + target.base_rad_act(src, radiation_count_alpha, ALPHA_RAD) + target.base_rad_act(src, radiation_count_beta, BETA_RAD) + target.base_rad_act(src, radiation_count_gamma, GAMMA_RAD) + radiation_count_alpha = 0 + radiation_count_beta = 0 + radiation_count_gamma = 0 return TRUE /obj/item/geiger_counter/proc/scan(atom/A, mob/user) @@ -158,7 +196,9 @@ return FALSE user.visible_message("[user] refastens [src]'s maintenance panel!", "You reset [src] to its factory settings!") emagged = FALSE - radiation_count = 0 + radiation_count_alpha = 0 + radiation_count_beta = 0 + radiation_count_gamma = 0 update_icon(UPDATE_ICON_STATE) return TRUE else @@ -170,7 +210,9 @@ if(!scanning) to_chat(user, "[src] must be on to reset its radiation level!") return - radiation_count = 0 + radiation_count_alpha = 0 + radiation_count_beta = 0 + radiation_count_gamma = 0 to_chat(user, "You flush [src]'s radiation counts, resetting it to normal.") update_icon(UPDATE_ICON_STATE) @@ -198,8 +240,8 @@ RegisterSignal(user, COMSIG_ATOM_RAD_ACT, PROC_REF(redirect_rad_act)) listeningTo = user -/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount) - rad_act(amount) +/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount, emission_type) + base_rad_act(source, amount, emission_type) /obj/item/geiger_counter/cyborg/dropped() . = ..() diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 52ff0308ffa..69973e1d970 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -279,7 +279,9 @@ GLOBAL_LIST_INIT(titaniumglass_recipes, list( recipes = GLOB.titaniumglass_recipes GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( - new /datum/stack_recipe/window("plastitanium window", /obj/structure/window/full/plastitanium, 2, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE) + new /datum/stack_recipe("plastitanium shard", /obj/item/shard/plastitanium, time = 0 SECONDS), + new /datum/stack_recipe/window("directional plastitanium window", /obj/structure/window/plastitanium, 1, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), + new /datum/stack_recipe/window("fulltile plastitanium window", /obj/structure/window/full/plastitanium, 2, time = 0 SECONDS, on_floor = TRUE, window_checks = TRUE), )) ////////////////////////////// @@ -295,6 +297,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 80, ACID = 100) resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/plastitaniumglass + created_window = /obj/structure/window/plastitanium full_window = /obj/structure/window/full/plastitanium table_type = /obj/structure/table/glass/reinforced/plastitanium diff --git a/code/game/objects/items/theft_items.dm b/code/game/objects/items/theft_items.dm index 623f9f92390..ff07db0c6fb 100644 --- a/code/game/objects/items/theft_items.dm +++ b/code/game/objects/items/theft_items.dm @@ -11,16 +11,19 @@ icon_state = "plutonium_core" item_state = "plutoniumcore" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - flags_2 = RAD_NO_CONTAMINATE_2 //Don't have the item itself become irradiated when it makes radiation. + flags_2 = RAD_NO_CONTAMINATE_2 //This is made from radioactive material so cannot really be contaminated var/cooldown = 0 var/pulseicon = "plutonium_core_pulse" + // Is this made from radioactive material or not. + var/radioactive_material = TRUE /obj/item/nuke_core/Initialize(mapload) . = ..() - START_PROCESSING(SSobj, src) + if(radioactive_material) + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 0, 400, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) /obj/item/nuke_core/Destroy() - STOP_PROCESSING(SSobj, src) return ..() /obj/item/nuke_core/attackby__legacy__attackchain(obj/item/nuke_core_container/container, mob/user) @@ -29,12 +32,6 @@ else return ..() -/obj/item/nuke_core/process() - if(cooldown < world.time - 6 SECONDS) - cooldown = world.time - flick(pulseicon, src) - radiation_pulse(src, 400, 2) - /obj/item/nuke_core/suicide_act(mob/user) user.visible_message("[user] is rubbing [src] against [user.p_themselves()]! It looks like [user.p_theyre()] trying to commit suicide!") return TOXLOSS @@ -104,7 +101,11 @@ /obj/item/nuke_core_container/proc/seal() if(!QDELETED(core)) - STOP_PROCESSING(SSobj, core) + var/datum/component/inherent_radioactivity/radioactivity = core.GetComponent(/datum/component/inherent_radioactivity) + var/datum/component/radioactive/box_contamination = GetComponent(/datum/component/radioactive) + STOP_PROCESSING(SSradiation, radioactivity) + if(box_contamination) + box_contamination.RemoveComponent() icon_state = "core_container_sealed" playsound(src, 'sound/items/deconstruct.ogg', 60, TRUE) if(ismob(loc)) @@ -123,7 +124,8 @@ /obj/item/nuke_core_container/proc/crack_open() visible_message("[src] bursts open!") if(core) - START_PROCESSING(SSobj, core) + var/datum/component/inherent_radioactivity/radioactivity = core.GetComponent(/datum/component/inherent_radioactivity) + START_PROCESSING(SSradiation, radioactivity) icon_state = "core_container_cracked_loaded" else icon_state = "core_container_cracked_empty" @@ -164,6 +166,7 @@ pulseicon = "supermatter_sliver_pulse" w_class = WEIGHT_CLASS_BULKY //can't put it into bags layer = ABOVE_MOB_LAYER + 0.02 + radioactive_material = FALSE /obj/item/nuke_core/supermatter_sliver/Initialize(mapload) . = ..() @@ -201,16 +204,17 @@ else if(issilicon(user)) to_chat(user, "You try to touch [src] with one of your modules. Error!") - radiation_pulse(user, 500, 2) + radiation_pulse(user, 2000, GAMMA_RAD) playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) user.dust() qdel(src) return to_chat(user, "As it touches [src], both [src] and [I] burst into dust!") - radiation_pulse(user, 100) + radiation_pulse(user, 400, GAMMA_RAD) playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) qdel(I) qdel(src) + return ..() /obj/item/nuke_core/supermatter_sliver/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) if(!isliving(hit_atom)) @@ -230,7 +234,7 @@ "You're hit by [src] and everything suddenly goes silent.\n[src] flashes into dust, and soon as you can register this, you do as well.", "Everything suddenly goes silent.") victim.dust() - radiation_pulse(src, 500, 2) + radiation_pulse(src, 2000, GAMMA_RAD) playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) qdel(src) @@ -243,7 +247,7 @@ user.visible_message("[user] reaches out and tries to pick up [src]. [user.p_their()] body starts to glow and bursts into flames before flashing into dust!", "You reach for [src] with your hands. That was dumb.", "Everything suddenly goes silent.") - radiation_pulse(user, 500, 2) + radiation_pulse(user, 2000, GAMMA_RAD) playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) user.dust() @@ -268,9 +272,13 @@ to_chat(user, "Container is sealing...") addtimer(CALLBACK(src, PROC_REF(seal)), 10 SECONDS) + /obj/item/nuke_core_container/supermatter/seal() if(!QDELETED(sliver)) STOP_PROCESSING(SSobj, sliver) + var/datum/component/radioactive/contamination = GetComponent(/datum/component/radioactive) + if(contamination) + contamination.RemoveComponent() icon_state = "supermatter_container_sealed" playsound(src, 'sound/items/deconstruct.ogg', 60, TRUE) if(ismob(loc)) @@ -305,7 +313,7 @@ user.visible_message("[user] reaches out and tries to pick up [sliver]. [user.p_their()] body starts to glow and bursts into flames before flashing into dust!", "You reach for [sliver] with your hands. That was dumb.", "Everything suddenly goes silent.") - radiation_pulse(user, 500, 2) + radiation_pulse(user, 2000, GAMMA_RAD) playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) message_admins("[sliver] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].") investigate_log("has consumed [key_name(user)].", "supermatter") @@ -400,6 +408,6 @@ user.dust() icon_state = "supermatter_tongs" item_state = "supermatter_tongs" - radiation_pulse(src, 500, 2) + radiation_pulse(src, 2000, GAMMA_RAD) playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE) QDEL_NULL(sliver) diff --git a/code/game/objects/items/weapons/grenades/atmosgrenade.dm b/code/game/objects/items/weapons/grenades/atmosgrenade.dm index bb8d3186763..c304f625f0c 100644 --- a/code/game/objects/items/weapons/grenades/atmosgrenade.dm +++ b/code/game/objects/items/weapons/grenades/atmosgrenade.dm @@ -37,13 +37,13 @@ icon_state = "gluon" item_state = "grenade" var/freeze_range = 4 - var/rad_damage = 350 + var/rad_damage = 1400 var/stamina_damage = 30 /obj/item/grenade/gluon/prime() update_mob() playsound(loc, 'sound/effects/empulse.ogg', 50, 1) - radiation_pulse(src, rad_damage) + radiation_pulse(src, rad_damage, BETA_RAD) for(var/turf/simulated/floor/T in view(freeze_range, loc)) T.MakeSlippery(TURF_WET_ICE) for(var/mob/living/carbon/L in T) diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm index 44a563a2cb7..548e80fc985 100644 --- a/code/game/objects/items/weapons/shards.dm +++ b/code/game/objects/items/weapons/shards.dm @@ -95,3 +95,13 @@ materials = list(MAT_PLASMA = MINERAL_MATERIAL_AMOUNT * 0.5, MAT_GLASS = MINERAL_MATERIAL_AMOUNT) icon_prefix = "plasma" welded_type = /obj/item/stack/sheet/plasmaglass + +/obj/item/shard/plastitanium + name = "plastitanium shard" + desc = "A shard of plastitanium glass. Considerably tougher then normal glass shards. Apparently not tough enough to be a window." + force = 6 + throwforce = 11 + icon_state = "plastitaniumlarge" + materials = list(MAT_TITANIUM = MINERAL_MATERIAL_AMOUNT * 0.5, MAT_PLASMA = MINERAL_MATERIAL_AMOUNT * 0.5, MAT_GLASS = MINERAL_MATERIAL_AMOUNT) + icon_prefix = "plastitanium" + welded_type = /obj/item/stack/sheet/plastitaniumglass diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index e53c434b8b8..f3ad35bc031 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -116,7 +116,8 @@ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 50, ACID = 50) damage_deflection = 0 flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_MEDIUM_INSULATION + rad_insulation_beta = RAD_MEDIUM_INSULATION + rad_insulation_gamma = RAD_LIGHT_INSULATION var/initial_state var/state_open = FALSE var/is_operating = FALSE diff --git a/code/game/objects/structures/depot_structures.dm b/code/game/objects/structures/depot_structures.dm index cbfc9370fef..4df2db803f1 100644 --- a/code/game/objects/structures/depot_structures.dm +++ b/code/game/objects/structures/depot_structures.dm @@ -44,7 +44,7 @@ if(prob(50)) empulse(src, 4, 10) else - radiation_pulse(get_turf(src), 500, 2) + radiation_pulse(get_turf(src), 2000, BETA_RAD) /obj/structure/fusionreactor/wrench_act(mob/user, obj/item/I) . = TRUE diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index a567fc1b7ec..696ddcc017d 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -14,7 +14,8 @@ icon_state = "wall-0" base_icon_state = "wall" flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_MEDIUM_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_LIGHT_INSULATION layer = TURF_LAYER var/mineral = /obj/item/stack/sheet/metal @@ -63,6 +64,7 @@ toggle(user) /obj/structure/falsewall/attack_hand(mob/user) + . = ..() toggle(user) /obj/structure/falsewall/proc/toggle(mob/user) @@ -217,23 +219,10 @@ smoothing_groups = list(SMOOTH_GROUP_WALLS, SMOOTH_GROUP_URANIUM_WALLS) canSmoothWith = list(SMOOTH_GROUP_URANIUM_WALLS) -/obj/structure/falsewall/uranium/attackby__legacy__attackchain(obj/item/W as obj, mob/user as mob, params) - radiate() - ..() - -/obj/structure/falsewall/uranium/attack_hand(mob/user as mob) - radiate() - ..() - -/obj/structure/falsewall/uranium/proc/radiate() - if(!active) - if(world.time > last_event + 1.5 SECONDS) - active = TRUE - radiation_pulse(src, 150) - for(var/turf/simulated/wall/mineral/uranium/T in orange(1, src)) - T.radiate() - last_event = world.time - active = FALSE +/obj/structure/falsewall/uranium/Initialize(mapload) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 50, 0, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) /* * Other misc falsewall types */ diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 23148e306bd..3dce7563874 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -6,7 +6,7 @@ density = TRUE layer = BELOW_OBJ_LAYER flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_VERY_LIGHT_INSULATION + rad_insulation_beta = RAD_HEAVY_INSULATION cares_about_temperature = TRUE var/state = GIRDER_NORMAL var/girderpasschance = 20 // percentage chance that a projectile passes through the girder. diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index ded748b8722..e41215c7684 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -14,6 +14,7 @@ max_integrity = 50 integrity_failure = 20 cares_about_temperature = TRUE + rad_insulation_beta = RAD_BETA_BLOCKER var/rods_type = /obj/item/stack/rods var/rods_amount = 2 var/rods_broken = 1 diff --git a/code/game/objects/structures/holosigns.dm b/code/game/objects/structures/holosigns.dm index 3631b28451d..21a3094c166 100644 --- a/code/game/objects/structures/holosigns.dm +++ b/code/game/objects/structures/holosigns.dm @@ -70,7 +70,7 @@ /obj/structure/holosign/barrier/engineering icon_state = "holosign_engi" flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_LIGHT_INSULATION + rad_insulation_beta = RAD_LIGHT_INSULATION /obj/structure/holosign/barrier/atmos name = "holo firelock" @@ -81,7 +81,7 @@ anchored = TRUE alpha = 150 flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_LIGHT_INSULATION + rad_insulation_beta = RAD_LIGHT_INSULATION /obj/structure/holosign/barrier/atmos/Initialize(mapload) . = ..() diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 8d291275785..faf6d852cd5 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -10,7 +10,8 @@ max_integrity = 200 armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 10, RAD = 100, FIRE = 50, ACID = 50) flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_MEDIUM_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_LIGHT_INSULATION var/initial_state var/state_open = FALSE var/is_operating = FALSE @@ -144,13 +145,12 @@ icon_state = "silver" sheetType = /obj/item/stack/sheet/mineral/silver max_integrity = 300 - rad_insulation = RAD_HEAVY_INSULATION /obj/structure/mineral_door/gold name = "gold door" icon_state = "gold" sheetType = /obj/item/stack/sheet/mineral/gold - rad_insulation = RAD_HEAVY_INSULATION + rad_insulation_gamma = RAD_MEDIUM_INSULATION /obj/structure/mineral_door/uranium name = "uranium door" @@ -167,7 +167,7 @@ /obj/structure/mineral_door/transparent opacity = FALSE - rad_insulation = RAD_VERY_LIGHT_INSULATION + rad_insulation_beta = RAD_MEDIUM_INSULATION /obj/structure/mineral_door/transparent/operate_update() density = !density @@ -205,7 +205,6 @@ icon_state = "diamond" sheetType = /obj/item/stack/sheet/mineral/diamond max_integrity = 1000 - rad_insulation = RAD_EXTREME_INSULATION /obj/structure/mineral_door/wood name = "wood door" @@ -216,7 +215,7 @@ hardness = 1 resistance_flags = FLAMMABLE max_integrity = 200 - rad_insulation = RAD_VERY_LIGHT_INSULATION + rad_insulation_beta = RAD_VERY_LIGHT_INSULATION /obj/structure/mineral_door/wood/Initialize(mapload) . = ..() diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 5ca44a56d70..b959292b11b 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -71,25 +71,10 @@ desc = "This statue has a sickening green colour." icon_state = "eng" -/obj/structure/statue/uranium/attackby__legacy__attackchain(obj/item/W, mob/user, params) - radiate() - return ..() - -/obj/structure/statue/uranium/Bumped(atom/user) - radiate() - ..() - -/obj/structure/statue/uranium/attack_hand(mob/user) - radiate() - ..() - -/obj/structure/statue/uranium/proc/radiate() - if(!active) - if(world.time > last_event + 1.5 SECONDS) - active = TRUE - radiation_pulse(src, 30) - last_event = world.time - active = FALSE +/obj/statue/uranium/Initialize(mapload) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 150, 0, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) /obj/structure/statue/plasma max_integrity = 200 diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index da739679edd..6fde595d0bb 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -14,7 +14,7 @@ max_integrity = 25 resistance_flags = ACID_PROOF armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 80, ACID = 100) - rad_insulation = RAD_VERY_LIGHT_INSULATION + rad_insulation_beta = RAD_MEDIUM_INSULATION cares_about_temperature = TRUE var/ini_dir = null var/state = WINDOW_OUT_OF_FRAME @@ -40,6 +40,13 @@ var/env_smash_level = ENVIRONMENT_SMASH_STRUCTURES /// How well this window resists superconductivity. var/superconductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT + /// How much we get activated by gamma radiation + var/rad_conversion_amount = 0 + + +/obj/structure/window/rad_act(atom/source, amount, emission_type) + if(emission_type == GAMMA_RAD && amount * rad_conversion_amount > RAD_BACKGROUND_RADIATION) + AddComponent(/datum/component/radioactive, amount * rad_conversion_amount, src, BETA_RAD, 60) /obj/structure/window/examine(mob/user) . = ..() @@ -518,7 +525,7 @@ reinf = TRUE heat_resistance = 1300 armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 25, RAD = 100, FIRE = 80, ACID = 100) - rad_insulation = RAD_NO_INSULATION + rad_insulation_beta = RAD_NO_INSULATION max_integrity = 50 explosion_block = 1 glass_type = /obj/item/stack/sheet/rglass @@ -631,7 +638,7 @@ /obj/structure/window/plasmabasic name = "plasma window" - desc = "A window made out of a plasma-silicate alloy. It looks insanely tough to break and burn through. Lacks protection from radiation." + desc = "A window made out of a plasma-silicate alloy. It looks insanely tough to break and burn through. When hit with Gamma particles it will become charged and start emitting Beta particles" icon_state = "plasmawindow" glass_decal = /obj/effect/decal/cleanable/glass/plasma shardtype = /obj/item/shard/plasma @@ -640,12 +647,14 @@ max_integrity = 150 explosion_block = 1 armor = list(MELEE = 75, BULLET = 5, LASER = 0, ENERGY = 0, BOMB = 45, RAD = 100, FIRE = 99, ACID = 100) - rad_insulation = RAD_NO_INSULATION + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_GAMMA_WINDOW superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT + rad_conversion_amount = 2 /obj/structure/window/plasmareinforced name = "reinforced plasma window" - desc = "A plasma-glass alloy window, with rods supporting it. It looks hopelessly tough to break. It also looks completely fireproof, considering how basic plasma windows are insanely fireproof. Lacks protection from radiation." + desc = "A plasma-glass alloy window, with rods supporting it. It looks hopelessly tough to break. It also looks completely fireproof, considering how basic plasma windows are insanely fireproof. When hit with Gamma particles it will become charged and start emitting Beta particles" icon_state = "plasmarwindow" glass_decal = /obj/effect/decal/cleanable/glass/plasma shardtype = /obj/item/shard/plasma @@ -655,10 +664,31 @@ max_integrity = 500 explosion_block = 2 armor = list(MELEE = 85, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, RAD = 100, FIRE = 99, ACID = 100) - rad_insulation = RAD_NO_INSULATION + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_GAMMA_WINDOW damage_deflection = 21 env_smash_level = ENVIRONMENT_SMASH_WALLS // these windows are a fair bit tougher superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT + rad_conversion_amount = 1.5 + +/obj/structure/window/plastitanium + name = "plastitanium window" + desc = "An evil looking window of plasma and titanium. When hit with Gamma particles it will become charged and start emitting Beta particles" + icon_state = "plastitaniumwindow" + glass_decal = /obj/effect/decal/cleanable/glass/plastitanium + shardtype = /obj/item/shard/plasma + glass_type = /obj/item/stack/sheet/plastitaniumglass + reinf = TRUE + heat_resistance = 32000 + max_integrity = 600 + explosion_block = 2 + armor = list(MELEE = 85, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, RAD = 100, FIRE = 99, ACID = 100) + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_GAMMA_WINDOW + damage_deflection = 21 + env_smash_level = ENVIRONMENT_SMASH_WALLS // these windows are a fair bit tougher + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT + rad_conversion_amount = 2.25 /obj/structure/window/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) return @@ -683,7 +713,7 @@ /obj/structure/window/full/plasmabasic name = "plasma window" - desc = "A plasma-glass alloy window. It looks insanely tough to break. It appears it's also insanely tough to burn through. Has very light protection from radiation." + desc = "A plasma-glass alloy window. It looks insanely tough to break. It appears it's also insanely tough to burn through. When hit with Gamma particles it will become charged and start emitting Beta particles" icon = 'icons/obj/smooth_structures/windows/plasma_window.dmi' icon_state = "plasma_window-0" base_icon_state = "plasma_window" @@ -697,10 +727,13 @@ edge_overlay_file = 'icons/obj/smooth_structures/windows/window_edges.dmi' env_smash_level = ENVIRONMENT_SMASH_WALLS // these windows are a fair bit tougher superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_GAMMA_FULL_WINDOW + rad_conversion_amount = 2.6 /obj/structure/window/full/plasmareinforced name = "reinforced plasma window" - desc = "A plasma-glass alloy window, with rods supporting it. It looks hopelessly tough to break. It also looks completely fireproof, considering how basic plasma windows are insanely fireproof. Offers superior protection from radiation." + desc = "A plasma-glass alloy window, with rods supporting it. It looks hopelessly tough to break. It also looks completely fireproof, considering how basic plasma windows are insanely fireproof. When hit with Gamma particles it will become charged and start emitting Beta particles" icon = 'icons/obj/smooth_structures/windows/rplasma_window.dmi' icon_state = "rplasma_window-0" base_icon_state = "rplasma_window" @@ -712,10 +745,12 @@ max_integrity = 1000 explosion_block = 2 armor = list(MELEE = 85, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, RAD = 100, FIRE = 99, ACID = 100) - rad_insulation = RAD_HEAVY_INSULATION edge_overlay_file = 'icons/obj/smooth_structures/windows/reinforced_window_edges.dmi' env_smash_level = ENVIRONMENT_SMASH_RWALLS // these ones are insanely tough superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_GAMMA_FULL_WINDOW + rad_conversion_amount = 2.2 /obj/structure/window/full/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) return @@ -730,7 +765,7 @@ reinf = TRUE heat_resistance = 1600 armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 25, RAD = 100, FIRE = 80, ACID = 100) - rad_insulation = RAD_HEAVY_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER explosion_block = 1 glass_type = /obj/item/stack/sheet/rglass edge_overlay_file = 'icons/obj/smooth_structures/windows/reinforced_window_edges.dmi' @@ -775,7 +810,7 @@ /obj/structure/window/full/plastitanium name = "plastitanium window" - desc = "An evil looking window of plasma and titanium." + desc = "An evil looking window of plasma and titanium. When hit with Gamma particles it will become charged and start emitting Beta particles" icon = 'icons/obj/smooth_structures/windows/plastitanium_window.dmi' icon_state = "plastitanium_window-0" base_icon_state = "plastitanium_window" @@ -783,13 +818,16 @@ reinf = TRUE heat_resistance = 32000 armor = list(MELEE = 85, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, RAD = 100, FIRE = 99, ACID = 100) - rad_insulation = RAD_HEAVY_INSULATION + rad_insulation_beta = RAD explosion_block = 3 glass_type = /obj/item/stack/sheet/plastitaniumglass smoothing_groups = list(SMOOTH_GROUP_SHUTTLE_PARTS, SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM, SMOOTH_GROUP_PLASTITANIUM_WALLS) canSmoothWith = list(SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM, SMOOTH_GROUP_SYNDICATE_WALLS, SMOOTH_GROUP_PLASTITANIUM_WALLS) env_smash_level = ENVIRONMENT_SMASH_RWALLS //used in shuttles, same reason as above superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT + rad_insulation_beta = RAD_NO_INSULATION + rad_insulation_gamma = RAD_GAMMA_FULL_WINDOW + rad_conversion_amount = 3 /obj/structure/window/reinforced/clockwork name = "brass window" diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 4b9b76c9118..7e30e15d711 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -24,7 +24,7 @@ GLOBAL_LIST_INIT(icons_to_ignore_at_floor_init, list("damaged1","damaged2","dama var/current_overlay = null var/floor_tile = null //tile that this floor drops var/keep_dir = TRUE //When false, resets dir to default on changeturf() - + rad_insulation_alpha = RAD_NO_INSULATION var/footstep = FOOTSTEP_FLOOR var/barefootstep = FOOTSTEP_HARD_BAREFOOT var/clawfootstep = FOOTSTEP_HARD_CLAW diff --git a/code/game/turfs/simulated/floor/mineral_floors.dm b/code/game/turfs/simulated/floor/mineral_floors.dm index 5c376ffd125..3d439d6c525 100644 --- a/code/game/turfs/simulated/floor/mineral_floors.dm +++ b/code/game/turfs/simulated/floor/mineral_floors.dm @@ -247,6 +247,11 @@ var/last_event = 0 var/active = FALSE +/turf/simulated/floor/mineral/uranium/Initialize(mapload) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 100, 0, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) + /turf/simulated/floor/mineral/uranium/Entered(mob/AM) .=..() if(!.) @@ -268,7 +273,7 @@ if(!active) if(world.time > last_event + 15) active = TRUE - radiation_pulse(src, 10) + radiation_pulse(src, 40, ALPHA_RAD) for(var/turf/simulated/floor/mineral/uranium/T in orange(1, src)) T.radiate() last_event = world.time diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index e73bc76d7f5..5aae2edd51c 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -14,7 +14,7 @@ density = TRUE blocks_air = TRUE flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 - rad_insulation = RAD_MEDIUM_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER layer = EDGED_TURF_LAYER temperature = TCMB color = COLOR_ROCK diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 422cf388c2d..b073a88dab3 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -25,7 +25,8 @@ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 flags_ricochet = RICOCHET_HARD - rad_insulation = RAD_MEDIUM_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_MEDIUM_INSULATION thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm index c0632376189..d2de8ddafcd 100644 --- a/code/game/turfs/simulated/walls_mineral.dm +++ b/code/game/turfs/simulated/walls_mineral.dm @@ -73,29 +73,10 @@ smoothing_groups = list(SMOOTH_GROUP_SIMULATED_TURFS, SMOOTH_GROUP_WALLS, SMOOTH_GROUP_URANIUM_WALLS) canSmoothWith = list(SMOOTH_GROUP_URANIUM_WALLS) -/turf/simulated/wall/mineral/uranium/proc/radiate() - if(!active) - if(world.time > last_event + 1.5 SECONDS) - active = TRUE - radiation_pulse(src, 40) - for(var/turf/simulated/wall/mineral/uranium/T in orange(1, src)) - T.radiate() - last_event = world.time - active = FALSE - -/turf/simulated/wall/mineral/uranium/attack_hand(mob/user as mob) - radiate() - ..() - -/turf/simulated/wall/mineral/uranium/attack_by(obj/item/attacking, mob/user, params) - if(..()) - return FINISH_ATTACK - - radiate() - -/turf/simulated/wall/mineral/uranium/Bumped(AM as mob|obj) - radiate() - ..() +/turf/simulated/wall/mineral/uranium/Initialize(mapload) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 50, 0, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) /turf/simulated/wall/mineral/plasma name = "plasma wall" diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm index 56b033487d8..e7fb5b37b1e 100644 --- a/code/game/turfs/simulated/walls_reinforced.dm +++ b/code/game/turfs/simulated/walls_reinforced.dm @@ -8,7 +8,8 @@ opacity = TRUE density = TRUE explosion_block = 2 - rad_insulation = RAD_HEAVY_INSULATION + rad_insulation_beta = RAD_BETA_BLOCKER + rad_insulation_gamma = RAD_VERY_EXTREME_INSULATION damage_cap = 600 hardness = 10 sheet_type = /obj/item/stack/sheet/plasteel diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index b62fd647fe4..2e6ac9eba6b 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -153,6 +153,7 @@ ..() /turf/attack_hand(mob/user as mob) + . = ..() user.Move_Pulled(src) /turf/attack_robot(mob/user) diff --git a/code/goonstation/modules/power/power_transmission_laser/transmission_laser.dm b/code/goonstation/modules/power/power_transmission_laser/transmission_laser.dm index e84fe6f984e..8b4e20c1971 100644 --- a/code/goonstation/modules/power/power_transmission_laser/transmission_laser.dm +++ b/code/goonstation/modules/power/power_transmission_laser/transmission_laser.dm @@ -430,7 +430,7 @@ var/flashmod = max(cos(look_angle - angle_to_bore), 0) someone.flash_eyes(min(round(output_level/ EYE_DAMAGE_THRESHOLD), 3) * flashmod, TRUE, TRUE) if(output_level > RAD_THRESHOLD) // Starts causing weak, quickly dissipating radiation pulses around the bore when power is high enough - radiation_pulse(get_front_turf(), (output_level / RAD_THRESHOLD) * 50, RAD_DISTANCE_COEFFICIENT) + radiation_pulse(get_front_turf(), (output_level / RAD_THRESHOLD) * 200, GAMMA_RAD) charge -= output_level diff --git a/code/modules/awaymissions/cordon.dm b/code/modules/awaymissions/cordon.dm index 4d44766ac66..512ef2b6a93 100644 --- a/code/modules/awaymissions/cordon.dm +++ b/code/modules/awaymissions/cordon.dm @@ -6,7 +6,7 @@ invisibility = INVISIBILITY_ABSTRACT mouse_opacity = MOUSE_OPACITY_TRANSPARENT explosion_block = 50 - rad_insulation = RAD_FULL_INSULATION + rad_insulation_beta = RAD_FULL_INSULATION opacity = TRUE density = TRUE blocks_air = TRUE diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 5bebc4545b8..a1d178fb788 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -98,10 +98,7 @@ if(msg && ishuman(wearer)) wearer.show_message("[msg]", 1) -/obj/item/clothing/head/helmet/space/hardsuit/rad_act(amount) - . = ..() - if(amount <= RAD_BACKGROUND_RADIATION) - return +/obj/item/clothing/head/helmet/space/hardsuit/rad_act(atom/source, amount, emission_type) current_tick_amount += amount /obj/item/clothing/head/helmet/space/hardsuit/process() diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index b647419b79e..2e028575771 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -140,6 +140,9 @@ "Drask" = 'icons/mob/clothing/species/drask/head/utility.dmi', "Kidan" = 'icons/mob/clothing/species/kidan/head/utility.dmi' ) + rad_insulation_alpha = RAD_FULL_INSULATION + rad_insulation_beta = RAD_FULL_INSULATION + rad_insulation_gamma = RAD_FULL_INSULATION /obj/item/clothing/suit/radiation name = "radiation suit" @@ -170,3 +173,6 @@ "Drask" = 'icons/mob/clothing/species/drask/suits/utility.dmi', "Kidan" = 'icons/mob/clothing/species/kidan/suits/utility.dmi' ) + rad_insulation_alpha = RAD_FULL_INSULATION + rad_insulation_beta = RAD_FULL_INSULATION + rad_insulation_gamma = RAD_FULL_INSULATION diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 6c794e4b8d5..3cc7d8c7636 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -419,14 +419,11 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ icon_state = "coin_uranium_heads" materials = list(MAT_URANIUM = 400) credits = 160 - COOLDOWN_DECLARE(radiation_cooldown) -/obj/item/coin/uranium/attack_self__legacy__attackchain(mob/user) - ..() - if(!COOLDOWN_FINISHED(src, radiation_cooldown)) - return - radiation_pulse(src, 50) - COOLDOWN_START(src, radiation_cooldown, 1.5 SECONDS) +/obj/item/coin/uranium/Initialize(mapload) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = AddComponent(/datum/component/inherent_radioactivity, 50, 0, 0, 1.5) + START_PROCESSING(SSradiation, radioactivity) /obj/item/coin/clown cmineral = "bananium" diff --git a/code/modules/mob/living/carbon/carbon_procs.dm b/code/modules/mob/living/carbon/carbon_procs.dm index 0f429f764eb..26b197f3cd0 100644 --- a/code/modules/mob/living/carbon/carbon_procs.dm +++ b/code/modules/mob/living/carbon/carbon_procs.dm @@ -1406,3 +1406,12 @@ so that different stomachs can handle things in different ways VB*/ M.update_revive() add_attack_logs(M, M, "Revived with Lazarus Reagent") SSblackbox.record_feedback("tally", "players_revived", 1, "lazarus_reagent") + +/mob/living/carbon/is_inside_mob(atom/thing) + if(!(..())) + return FALSE + if(head && head.UID() == thing.UID()) + return FALSE + if(wear_suit && wear_suit.UID() == thing.UID()) + return FALSE + return TRUE diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 151abebf696..ec4f177e074 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -837,3 +837,47 @@ emp_act /mob/living/carbon/human/canBeHandcuffed() return has_left_hand() || has_right_hand() + +/// Returns a list. The first element is whether we penetrated all clothing for the zone, the rest are the clothes that got contaminated +/mob/living/carbon/human/proc/rad_contaminate_zone(zone_flag, pocket = FALSE) + // This is for items inside of the mob + if(!zone_flag) + return list(TRUE) + var/list/garments = list() + var/list/contaminate = list() + var/passed = TRUE + // items in our pocket are treated uniquely as they are outside of the mob but also under most of its clothing + if(pocket) + garments = list(w_uniform) + else + // the suit is worn on top of all other stuff so it needs to be checked first + if(wear_suit) + garments = list(wear_suit) + for(var/obj/item/clothing/garment in contents) + if(garment.body_parts_covered & zone_flag) + garments |= garment + // If we have a suit push it to the start of the list + if(wear_suit) + garments -= wear_suit + garments = list(wear_suit) + garments + + while(length(garments) && passed) + var/obj/item/clothing/garment = garments[1] + garments -= garment + passed = prob((garment.permeability_coefficient * 100) - 1) && !(garment.flags_2 & RAD_PROTECT_CONTENTS_2) + if(garment.flags_2 & RAD_NO_CONTAMINATE_2) + continue + contaminate += garment + + return list(passed) + contaminate + +/// Tries to contaminate a human +/mob/living/carbon/human/contaminate_atom(atom/source, intensity, emission_type, zone = null) + if(!zone) + zone = hit_zone_to_clothes_zone(ran_zone()) + var/list/to_contaminate = rad_contaminate_zone(zone) + if(to_contaminate[1]) + to_contaminate += src + to_contaminate -= to_contaminate[1] + for(var/atom/thing in to_contaminate) + thing.AddComponent(/datum/component/radioactive, intensity, source, emission_type) diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index d0f99d2ea5c..face32985a5 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -1502,7 +1502,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && drop_item_to_ground(hand)) step_towards(hand, src) to_chat(src, "\The [S] pulls \the [hand] from your grip!") - rad_act(current_size * 3) + base_rad_act(S, current_size * 3, GAMMA_RAD) /mob/living/carbon/human/narsie_act() if(iswizard(src) || IS_CULTIST(src)) // Wizards are immune to the magic. Cultists also don't get transformed. @@ -2132,3 +2132,35 @@ Eyes need to have significantly high darksight to shine unless the mob has the X hallucination_to_make = string_path new hallucination_to_make(get_turf(src), src) +/// Checks if an item is inside the body of the mob +/mob/living/carbon/human/is_inside_mob(atom/thing) + if(!(..())) + return FALSE + if(w_uniform && w_uniform.UID() == thing.UID()) + return FALSE + if(shoes && shoes.UID() == thing.UID()) + return FALSE + if(belt && belt.UID() == thing.UID()) + return FALSE + if(gloves && gloves.UID() == thing.UID()) + return FALSE + if(neck && neck.UID() == thing.UID()) + return FALSE + if(glasses && glasses.UID() == thing.UID()) + return FALSE + if(l_ear && l_ear.UID() == thing.UID()) + return FALSE + if(r_ear && r_ear.UID() == thing.UID()) + return FALSE + if(wear_id && wear_id.UID() == thing.UID()) + return FALSE + if(wear_pda && wear_pda.UID() == thing.UID()) + return FALSE + if(r_store && r_store.UID() == thing.UID()) + return FALSE + if(l_store && l_store.UID() == thing.UID()) + return FALSE + if(s_store && s_store.UID() == thing.UID()) + return FALSE + + return TRUE diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index 9bf1d0ff912..47c2d40e3c6 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -342,9 +342,15 @@ prefix = "Uranium" special_names = list("Oxide", "Rod", "Meltdown") -/datum/species/golem/uranium/handle_life(mob/living/carbon/human/H) - radiation_pulse(H, 20) - ..() +/datum/species/golem/uranium/on_species_gain(mob/living/carbon/human/H) + . = ..() + var/datum/component/inherent_radioactivity/radioactivity = H.AddComponent(/datum/component/inherent_radioactivity, 40, 0, 0) + START_PROCESSING(SSradiation, radioactivity) + +/datum/species/golem/uranium/on_species_loss(mob/living/carbon/human/H) + . = ..() + var/datum/component/inherent_radioactivity/rads = H.GetComponent(/datum/component/inherent_radioactivity) + rads.RemoveComponent() //Ventcrawler /datum/species/golem/plastic diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index de82e53f159..b7d480496c1 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1040,9 +1040,13 @@ ..() update_z(new_turf?.z) -/mob/living/rad_act(amount) - . = ..() - +/mob/living/rad_act(atom/source, amount, emission_type) + // Mobs block very little Beta and Gamma radiation, but we still want the rads to affect them. + if(emission_type > ALPHA_RAD) + amount /= (1 - RAD_MOB_INSULATION) + // Alpha sources outside the body don't do much + else if(!is_inside_mob(source)) + amount /= 100 if(!amount || (amount < RAD_MOB_SKIN_PROTECTION) || HAS_TRAIT(src, TRAIT_RADIMMUNE)) return @@ -1054,9 +1058,22 @@ if(amount > RAD_BURN_THRESHOLD) apply_damage(RAD_BURN_CURVE(amount), BURN, null, blocked) - apply_effect((amount * RAD_MOB_COEFFICIENT) / max(1, (radiation ** 2) * RAD_OVERDOSE_REDUCTION), IRRADIATE, ARMOUR_VALUE_TO_PERCENTAGE(blocked)) +/mob/living/proc/is_inside_mob(atom/thing) + if(!(thing in contents)) + return FALSE + if(l_hand && l_hand.UID() == thing.UID()) + return FALSE + if(r_hand && r_hand.UID() == thing.UID()) + return FALSE + if(back && back.UID() == thing.UID()) + return FALSE + if(wear_mask && wear_mask.UID() == thing.UID()) + return FALSE + + return TRUE + /mob/living/proc/fakefireextinguish() return diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a60cf368d21..d0246f6d34a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1417,14 +1417,15 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \ */ /mob/proc/show_rads(range) for(var/turf/place in range(range, src)) - var/rads = SSradiation.get_turf_radiation(place) - if(rads < RAD_BACKGROUND_RADIATION) + var/list/rads = SSradiation.get_turf_radiation(place) + if(!rads || (rads[1] + rads[2] + rads[3]) < RAD_BACKGROUND_RADIATION) continue - - var/strength = round(rads / 1000, 0.1) + var/alpha_strength = round(rads[1] / 1000, 0.1) + var/beta_strength = round(rads[2] / 1000, 0.1) + var/gamma_strength = round(rads[3] / 1000, 0.1) var/image/pic = image(loc = place) var/mutable_appearance/MA = new() - MA.maptext = MAPTEXT("[strength]k") + MA.maptext = MAPTEXT("Α [alpha_strength]k\nΒ [beta_strength]k\nΓ [gamma_strength]k") MA.color = "#04e604" MA.layer = RAD_TEXT_LAYER MA.plane = GAME_PLANE diff --git a/code/modules/mob/mob_misc_procs.dm b/code/modules/mob/mob_misc_procs.dm index b092e7b01cc..1a79d3fd4ba 100644 --- a/code/modules/mob/mob_misc_procs.dm +++ b/code/modules/mob/mob_misc_procs.dm @@ -244,6 +244,30 @@ return zone +/// Convert the impact zone of a projectile to a clothing zone we can do a contamination check on +/proc/hit_zone_to_clothes_zone(zone) + switch(zone) + if("head") + return HEAD + if("chest") + return UPPER_TORSO + if("l_hand") + return HANDS + if("r_hand") + return HANDS + if("l_arm") + return ARMS + if("r_arm") + return ARMS + if("l_leg") + return LEGS + if("r_leg") + return LEGS + if("l_foot") + return FEET + if("r_foot") + return FEET + /proc/above_neck(zone) var/list/zones = list("head", "mouth", "eyes") if(zones.Find(zone)) diff --git a/code/modules/mob/mob_vars.dm b/code/modules/mob/mob_vars.dm index b598fe566e7..136b305b3d9 100644 --- a/code/modules/mob/mob_vars.dm +++ b/code/modules/mob/mob_vars.dm @@ -9,6 +9,8 @@ throwforce = 10 var/datum/mind/mind blocks_emissive = EMISSIVE_BLOCK_GENERIC + rad_insulation_beta = RAD_MOB_INSULATION + rad_insulation_gamma = RAD_MOB_INSULATION /// Is this mob alive, unconscious or dead? var/stat = CONSCIOUS // TODO: Move to /mob/living diff --git a/code/modules/power/engines/singularity/collector.dm b/code/modules/power/engines/singularity/collector.dm index 1fb0cf1922f..328026dcfd4 100644 --- a/code/modules/power/engines/singularity/collector.dm +++ b/code/modules/power/engines/singularity/collector.dm @@ -1,12 +1,12 @@ -// stored_energy += (pulse_strength - RAD_COLLECTOR_EFFICIENCY) * RAD_COLLECTOR_COEFFICIENT -#define RAD_COLLECTOR_EFFICIENCY 80 // radiation needs to be over this amount to get power -#define RAD_COLLECTOR_COEFFICIENT 100 +// stored_energy += (pulse_strength - RAD_COLLECTOR_THRESHOLD) * RAD_COLLECTOR_COEFFICIENT +#define RAD_COLLECTOR_THRESHOLD 80 // This gets subtracted from the value of absorbed radiation +#define RAD_COLLECTOR_COEFFICIENT 400 #define RAD_COLLECTOR_STORED_OUT 0.04 // (this * 100)% of stored power outputted per tick. Doesn't actualy change output total, lower numbers just means collectors output for longer in absence of a source #define RAD_COLLECTOR_OUTPUT min(stored_energy, (stored_energy * RAD_COLLECTOR_STORED_OUT) + 1000) //Produces at least 1000 watts if it has more than that stored /obj/machinery/power/rad_collector name = "radiation collector array" - desc = "A device which uses Hawking Radiation and plasma to produce power." + desc = "A device which converts raditation to useable electical energy using plasma. It absorbs Beta particles extremely well, and Gamma particles to a lesser extent" icon = 'icons/obj/singularity.dmi' icon_state = "ca" anchored = FALSE @@ -14,13 +14,24 @@ req_access = list(ACCESS_ENGINE_EQUIP) max_integrity = 350 integrity_failure = 80 - rad_insulation = RAD_EXTREME_INSULATION + rad_insulation_beta = RAD_BETA_COLLECTOR + rad_insulation_gamma = RAD_LIGHT_INSULATION var/obj/item/tank/internals/plasma/loaded_tank = null var/stored_energy = 0 var/active = FALSE var/locked = FALSE var/drainratio = 1 var/powerproduction_drain = 0.001 + var/power_threshold = RAD_COLLECTOR_THRESHOLD + var/power_coefficient = RAD_COLLECTOR_COEFFICIENT + /// A record of the absorbed strength of each beta wave that hit the collector. This keeps record up to rad_time old, and only the maximum absorption for each time point. + var/beta_waves = list() + /// A record of the absorbed strength of each gamma wave that hit the collector. This keeps record up to rad_time old, and only the maximum absorption for each time point. + var/gamma_waves = list() + /// Amount of time across which the maximum wave is checked + var/rad_time = 5 SECONDS + /// The current time count for clearing old data from the lists + var/rad_time_counter = 0 /obj/machinery/power/rad_collector/process() if(!loaded_tank) @@ -36,6 +47,20 @@ var/power_produced = RAD_COLLECTOR_OUTPUT produce_direct_power(power_produced) stored_energy -= power_produced + if(world.time > rad_time_counter) + rad_time_counter = world.time + rad_time + for(var/listing in gamma_waves) + if(world.time > text2num(listing) + rad_time) + gamma_waves -= listing + // We put the listing in oldest to newest so as soon as we hit something new enough we can keep the rest + else + break + for(var/listing in beta_waves) + if(world.time > text2num(listing) + rad_time) + beta_waves -= listing + // We put the listing in oldest to newest so as soon as we hit something new enough we can keep the rest + else + break /obj/machinery/power/rad_collector/attack_hand(mob/user) @@ -109,7 +134,21 @@ // Therefore, its units are joules per SSmachines.wait * 0.1 seconds. // So joules = stored_energy * SSmachines.wait * 0.1 var/joules = stored_energy * SSmachines.wait * 0.1 - . += "[src]'s display states that it has stored [DisplayJoules(joules)], and is processing [DisplayPower(RAD_COLLECTOR_OUTPUT)]." + var/max_beta = 0 + var/max_gamma = 0 + // Find the maximum beta and gamma absorptions we have logged + for(var/listing in beta_waves) + if(max_beta < beta_waves[listing]) + max_beta = beta_waves[listing] + for(var/listing in gamma_waves) + if(max_gamma < gamma_waves[listing]) + max_gamma = gamma_waves[listing] + var/beta_delta = max_beta - RAD_COLLECTOR_THRESHOLD + var/gamma_delta = max_gamma - RAD_COLLECTOR_THRESHOLD + . += "[src]'s display states that it has stored [DisplayJoules(joules)], and is processing [DisplayPower(RAD_COLLECTOR_OUTPUT)]" + . +="Strongest Beta absorption over the last [rad_time /(1 SECONDS)] seconds: [max_beta], [abs(beta_delta)] [beta_delta >= 0 ? "above" : "below"] threshold" + . +="Strongest Gamma absorption over the last [rad_time /(1 SECONDS)] seconds: [max_gamma], [abs(gamma_delta)] [gamma_delta >= 0 ? "above" : "below"] threshold" + else . += "[src]'s display displays the words: \"Power production mode. Please insert Plasma.\"" @@ -132,10 +171,21 @@ else update_icons() -/obj/machinery/power/rad_collector/rad_act(amount) - . = ..() - if(loaded_tank && active && amount > RAD_COLLECTOR_EFFICIENCY) - stored_energy += (amount - RAD_COLLECTOR_EFFICIENCY) * RAD_COLLECTOR_COEFFICIENT +/// Converts absorbed Beta or Gamma radiation into electrical energy +/obj/machinery/power/rad_collector/rad_act(atom/source, amount, emission_type) + // Log the absorption at current time. If we already have one logged and the new value is bigger overwrite it. + if(emission_type == BETA_RAD) + if(!beta_waves["[world.time]"]) + beta_waves += list("[world.time]" = amount) + else if(beta_waves["[world.time]"] < amount) + beta_waves["[world.time]"] = amount + if(emission_type == GAMMA_RAD) + if(!gamma_waves["[world.time]"]) + gamma_waves += list("[world.time]" = amount) + else if(gamma_waves["[world.time]"] < amount) + gamma_waves["[world.time]"] = amount + if(emission_type != ALPHA_RAD && loaded_tank && active && amount > power_threshold) + stored_energy += (amount - power_threshold) * power_coefficient /obj/machinery/power/rad_collector/proc/update_icons() @@ -158,7 +208,7 @@ flick("ca_deactive", src) update_icons() -#undef RAD_COLLECTOR_EFFICIENCY +#undef RAD_COLLECTOR_THRESHOLD #undef RAD_COLLECTOR_COEFFICIENT #undef RAD_COLLECTOR_STORED_OUT #undef RAD_COLLECTOR_OUTPUT diff --git a/code/modules/power/engines/singularity/particle_accelerator/particle.dm b/code/modules/power/engines/singularity/particle_accelerator/particle.dm index a2bae7b95c3..d6870fe44a8 100644 --- a/code/modules/power/engines/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/engines/singularity/particle_accelerator/particle.dm @@ -39,7 +39,7 @@ /obj/effect/accelerated_particle/proc/try_irradiate(src, atom/A) if(isliving(A)) var/mob/living/L = A - L.rad_act(energy * 6) + L.base_rad_act(src, energy * 6, GAMMA_RAD) else if(istype(A, /obj/machinery/the_singularitygen)) var/obj/machinery/the_singularitygen/S = A S.energy += energy diff --git a/code/modules/power/engines/singularity/singularity.dm b/code/modules/power/engines/singularity/singularity.dm index a5931a20ae3..0940b61362c 100644 --- a/code/modules/power/engines/singularity/singularity.dm +++ b/code/modules/power/engines/singularity/singularity.dm @@ -151,7 +151,7 @@ GLOBAL_VAR_INIT(global_singulo_id, 1) // it might mean we are stuck in a corner somewere. So move around to try to expand. move() if(current_size >= STAGE_TWO) - radiation_pulse(src, (energy * 4.5) + 1000, RAD_DISTANCE_COEFFICIENT, source_radius = consume_range + 1) + radiation_pulse(src, (energy * 90) + 8000, GAMMA_RAD) if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit event() eat() diff --git a/code/modules/power/engines/supermatter/supermatter.dm b/code/modules/power/engines/supermatter/supermatter.dm index f04f2a2f668..197be220492 100644 --- a/code/modules/power/engines/supermatter/supermatter.dm +++ b/code/modules/power/engines/supermatter/supermatter.dm @@ -377,7 +377,7 @@ var/hallucination_amount = (max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1))))) SECONDS H.AdjustHallucinate(hallucination_amount) var/rads = DETONATION_RADS * sqrt(1 / (get_dist(L, src) + 1)) - L.rad_act(rads) + L.base_rad_act(src, rads, GAMMA_RAD) var/turf/T = get_turf(src) var/super_matter_charge_sound = sound('sound/magic/charge.ogg') @@ -568,8 +568,8 @@ var/crush_ratio = combined_gas / MOLE_CRUNCH_THRESHOLD gas_coefficient = 1 + (crush_ratio ** 2 * (crush_ratio <= 1) + (crush_ratio > 1) * 2 * crush_ratio / (crush_ratio + 1)) * (plasmacomp * PLASMA_CRUNCH + o2comp * O2_CRUNCH + co2comp * CO2_CRUNCH + n2comp * N2_CRUNCH + n2ocomp * N2O_CRUNCH) - if(prob(50)) - radiation_pulse(src, power * (gas_coefficient + max(0, ((power_transmission_bonus / 10))))) + + radiation_pulse(src, 6 * power * (gas_coefficient + max(0, ((power_transmission_bonus / 10)))), GAMMA_RAD) //Power * 0.55 * a value between 1 and 0.8 var/device_energy = power * REACTION_POWER_MODIFIER @@ -597,7 +597,7 @@ l.AdjustHallucinate(hallucination_amount, 0, 200 SECONDS) for(var/mob/living/l in range(src, round((power / 100) ** 0.25))) var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src), 1) ) - l.rad_act(rads) + l.base_rad_act(src, rads, GAMMA_RAD) //Transitions between one function and another, one we use for the fast inital startup, the other is used to prevent errors with fusion temperatures. //Use of the second function improves the power gain imparted by using co2 @@ -832,7 +832,7 @@ Consume(used) playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE) - radiation_pulse(src, 150, 4) + radiation_pulse(src, 600, GAMMA_RAD) /obj/machinery/atmospherics/supermatter_crystal/Bumped(atom/movable/AM) @@ -887,7 +887,7 @@ matter_power += 200 //Some poor sod got eaten, go ahead and irradiate people nearby. - radiation_pulse(src, 3000, 2, TRUE) + radiation_pulse(src, 12000, GAMMA_RAD, TRUE) for(var/mob/living/L in range(10)) investigate_log("has irradiated [key_name(L)] after consuming [AM].", "supermatter") if(L in view()) diff --git a/code/modules/power/generators/portable generators/pacman.dm b/code/modules/power/generators/portable generators/pacman.dm index ee7a0c89c8a..5527ce08c72 100644 --- a/code/modules/power/generators/portable generators/pacman.dm +++ b/code/modules/power/generators/portable generators/pacman.dm @@ -333,12 +333,12 @@ /obj/machinery/power/port_gen/pacman/super/use_fuel() //produces a tiny amount of radiation when in use if(prob(2 * power_output)) - radiation_pulse(get_turf(src), 50) + radiation_pulse(get_turf(src), 200, ALPHA_RAD) ..() /obj/machinery/power/port_gen/pacman/super/explode() //a nice burst of radiation - radiation_pulse(get_turf(src), 500, 2) + radiation_pulse(get_turf(src), 2000, ALPHA_RAD) explosion(loc, 3, 3, 5, 3) qdel(src) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 22fd1e4aa4d..7630d140dca 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -343,9 +343,9 @@ GLOBAL_LIST_EMPTY(gravity_generators) /obj/machinery/gravity_generator/main/proc/pulse_radiation() - radiation_pulse(src, 600, 2) + radiation_pulse(src, 2400, BETA_RAD) for(var/mob/living/L in view(7, src)) //Windows kinda make it a non threat, no matter how much I amp it up, so let us cheat a little - radiation_pulse(get_turf(L), 600, 2) + radiation_pulse(get_turf(L), 2400, BETA_RAD) /** * Shake everyone on the area list and play an alarm to let them know that gravity was enagaged/disenagaged. diff --git a/code/modules/station_goals/bluespace_tap_events.dm b/code/modules/station_goals/bluespace_tap_events.dm index f173fb42bef..6da9be85e6c 100644 --- a/code/modules/station_goals/bluespace_tap_events.dm +++ b/code/modules/station_goals/bluespace_tap_events.dm @@ -83,7 +83,7 @@ tap.radio.autosay("Bluespace harvester has released a spike of radiation!", tap, "Engineering") /datum/engi_event/bluespace_tap_event/radiation/on_start() - radiation_pulse(tap, 3000, 7) + radiation_pulse(tap, 12000, BETA_RAD) // electrical arc /datum/engi_event/bluespace_tap_event/electric_arc diff --git a/icons/obj/shards.dmi b/icons/obj/shards.dmi index 36fb3d843015aab6de89399f0337622622095863..bdb083f291e3bbe12231de9b2d419c641313621d 100644 GIT binary patch literal 7734 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 diff --git a/paradise.dme b/paradise.dme index 618d058d11e..9c09e347c66 100644 --- a/paradise.dme +++ b/paradise.dme @@ -469,6 +469,7 @@ #include "code\datums\components\forces_doors_open.dm" #include "code\datums\components\fullauto.dm" #include "code\datums\components\ghost_direct_control.dm" +#include "code\datums\components\inherent_radioactivity.dm" #include "code\datums\components\jetpack_component.dm" #include "code\datums\components\label.dm" #include "code\datums\components\largeobjecttransparency.dm"