mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-19 02:56:14 +01:00
Radiation Refactor (#19270)
* Part 1 * WIP * The rest of these * More stuff * Whoops, did that wrong * typo * gweeen * This all works * SHOWER * Rads * awa * rad * Update life.dm * edits * Makes lvl 3 rads give you a warning. You should already know by this point, but this makes it EXTRA clear you're getting fucked * Update vorestation.dme * aaa * propagate * gwah * more fixes * AAA * Update radiation.dm * Update radiation.dm * mobs rads * rads * fix this * Update _reagents.dm * these * Get rid of these * rad * Update config.txt * fixed * Update radiation_effects.dm
This commit is contained in:
@@ -25,8 +25,12 @@ GLOBAL_VAR_INIT(refid_filter, TYPEID(filter(type="angular_blur")))
|
||||
|
||||
#define isradio(A) istype(A, /obj/item/radio)
|
||||
|
||||
#define isclothing(A) istype(A, /obj/item/clothing)
|
||||
|
||||
#define isairlock(A) istype(A, /obj/machinery/door/airlock)
|
||||
|
||||
#define ismachinery(A) istype(A, /obj/machinery)
|
||||
|
||||
#define isorgan(A) istype(A, /obj/item/organ/external)
|
||||
|
||||
#define isstorage(A) istype(A, /obj/item/storage)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
//Investigate logging defines
|
||||
#define INVESTIGATE_CARGO "cargo"
|
||||
#define INVESTIGATE_RESEARCH "research"
|
||||
#define INVESTIGATE_RADIATION "radiation"
|
||||
|
||||
// Logging types for log_message()
|
||||
#define LOG_ATTACK (1 << 0)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/// Flags for specifically what kind of items to get in get_equipped_items
|
||||
#define INCLUDE_POCKETS (1<<0)
|
||||
#define INCLUDE_ACCESSORIES (1<<1)
|
||||
#define INCLUDE_HELD (1<<2)
|
||||
/// Include prosthetic item limbs (which are not flavoured as being equipped items)
|
||||
#define INCLUDE_PROSTHETICS (1<<3)
|
||||
/// Include items that are not "real" items, such as hand items
|
||||
#define INCLUDE_ABSTRACT (1<<4)
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
These defines are the balancing points of various parts of the radiation system.
|
||||
Changes here can have widespread effects: make sure you test well.
|
||||
Ask Mothblocks if they're around
|
||||
*/
|
||||
|
||||
/// How much stored radiation to check for hair loss
|
||||
#define RAD_MOB_HAIRLOSS (1 MINUTES)
|
||||
/// Chance of you hair starting to fall out every second when over threshold
|
||||
#define RAD_MOB_HAIRLOSS_PROB 7.5
|
||||
|
||||
/// How much stored radiation to check for mutation
|
||||
#define RAD_MOB_MUTATE (2 MINUTES)
|
||||
/// Chance of randomly mutating every second when over threshold
|
||||
#define RAD_MOB_MUTATE_PROB 0.5
|
||||
|
||||
/// The time since irradiated before checking for vomitting
|
||||
#define RAD_MOB_VOMIT (2 MINUTES)
|
||||
/// Chance per second of vomitting
|
||||
#define RAD_MOB_VOMIT_PROB 0.5
|
||||
|
||||
/// How much stored radiation to check for stunning
|
||||
#define RAD_MOB_KNOCKDOWN (2 MINUTES)
|
||||
/// Chance of knockdown per second when over threshold
|
||||
#define RAD_MOB_KNOCKDOWN_PROB 0.5
|
||||
/// Amount of knockdown when it occurs
|
||||
#define RAD_MOB_KNOCKDOWN_AMOUNT 3
|
||||
|
||||
#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
|
||||
#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_FULL_INSULATION 0 // Completely stops radiation from coming through
|
||||
|
||||
/// The default chance something can be irradiated
|
||||
#define DEFAULT_RADIATION_CHANCE 10
|
||||
|
||||
/// The default chance for uranium structures to irradiate
|
||||
#define URANIUM_IRRADIATION_CHANCE DEFAULT_RADIATION_CHANCE
|
||||
|
||||
/// The minimum exposure time before uranium structures can irradiate
|
||||
#define URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME (3 SECONDS)
|
||||
/// The minimum exposure time before the radioactive nebula can irradiate
|
||||
#define NEBULA_RADIATION_MINIMUM_EXPOSURE_TIME (6 SECONDS)
|
||||
|
||||
/// Return values of [proc/get_perceived_radiation_danger]
|
||||
// If you change these, update /datum/looping_sound/geiger as well.
|
||||
#define PERCEIVED_RADIATION_DANGER_LOW 1
|
||||
#define PERCEIVED_RADIATION_DANGER_MEDIUM 2
|
||||
#define PERCEIVED_RADIATION_DANGER_HIGH 3
|
||||
#define PERCEIVED_RADIATION_DANGER_EXTREME 4
|
||||
|
||||
/// The time before geiger counters reset back to normal without any radiation pulses
|
||||
#define TIME_WITHOUT_RADIATION_BEFORE_RESET (5 SECONDS)
|
||||
|
||||
// Radiation exposure params
|
||||
|
||||
// For the radioactive nebula outside
|
||||
/// Base chance the nebula has of applying irradiation
|
||||
#define RADIATION_EXPOSURE_NEBULA_BASE_CHANCE 20
|
||||
/// The chance we add to the base chance every time we fail to irradiate
|
||||
#define RADIATION_EXPOSURE_NEBULA_CHANCE_INCREMENT 10
|
||||
/// Time it takes for the next irradiation check
|
||||
#define RADIATION_EXPOSURE_NEBULA_CHECK_INTERVAL 5 SECONDS
|
||||
@@ -198,3 +198,10 @@
|
||||
|
||||
/// The timer key used to know how long subsystem initialization takes
|
||||
#define SS_INIT_TIMER_KEY "ss_init"
|
||||
|
||||
// Subsystem delta times or tickrates, in seconds. I.e, how many seconds in between each process() call for objects being processed by that subsystem.
|
||||
// Only use these defines if you want to access some other objects processing seconds_per_tick, otherwise use the seconds_per_tick that is sent as a parameter to process()
|
||||
// #define SSFLUIDS_DT (SSplumbing.wait/10)
|
||||
#define SSMACHINES_DT (SSmachines.wait/10)
|
||||
#define SSMOBS_DT (SSmobs.wait/10)
|
||||
#define SSOBJ_DT (SSobj.wait/10)
|
||||
|
||||
@@ -19,3 +19,20 @@
|
||||
#define TOOL_KNIFE "knife"
|
||||
#define TOOL_BLOODFILTER "bloodfilter"
|
||||
#define TOOL_ROLLINGPIN "rollingpin"
|
||||
|
||||
/**
|
||||
* A helper for checking if an item interaction should be skipped.
|
||||
* This is only used explicitly because some interactions may not want to ever be skipped.
|
||||
*/
|
||||
#define SHOULD_SKIP_INTERACTION(target, item, user) (HAS_TRAIT(target, TRAIT_COMBAT_MODE_SKIP_INTERACTION) && (user.a_intent == I_HURT))
|
||||
|
||||
/// Return when an item interaction is successful.
|
||||
/// This cancels the rest of the chain entirely and indicates success.
|
||||
#define ITEM_INTERACT_SUCCESS (1<<0) // Same as TRUE, as most tool (legacy) tool acts return TRUE on success
|
||||
/// Return to prevent the rest of the attack chain from being executed / preventing the item user from thwacking the target.
|
||||
/// Similar to [ITEM_INTERACT_SUCCESS], but does not necessarily indicate success.
|
||||
#define ITEM_INTERACT_BLOCKING (1<<1)
|
||||
/// Only for people who get confused by the naming scheme
|
||||
#define ITEM_INTERACT_FAILURE ITEM_INTERACT_BLOCKING
|
||||
/// Return to skip the rest of the interaction chain, going straight to attack.
|
||||
#define ITEM_INTERACT_SKIP_TO_ATTACK (1<<2)
|
||||
|
||||
@@ -59,3 +59,35 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_SLOBBER "slobber"
|
||||
// Owner will be considered a tiny mob for some interactions, such as airlocks not opening unless they have a client, or being vacuumed up by the vacpack
|
||||
#define TRAIT_AMBIENT_PEST_MOB "ambient_pest_mob"
|
||||
/// Marks that this object is irradiated
|
||||
#define TRAIT_IRRADIATED "iraddiated"
|
||||
/// Whether or not this item will allow the radiation SS to go through standard
|
||||
/// radiation processing as if this wasn't already irradiated.
|
||||
/// Basically, without this, COMSIG_IN_RANGE_OF_IRRADIATION won't fire once the object is irradiated.
|
||||
#define TRAIT_BYPASS_EARLY_IRRADIATED_CHECK "radiation_bypass_early_irradiated_check"
|
||||
/// Immune to being irradiated
|
||||
#define TRAIT_RADIMMUNE "rad_immunity"
|
||||
/// This clothing protects the user from radiation.
|
||||
/// This should not be used on clothing_traits, but should be applied to the clothing itself.
|
||||
#define TRAIT_RADIATION_PROTECTED_CLOTHING "radiation_protected_clothing"
|
||||
/// Trait applied by MODsuits.
|
||||
#define MOD_TRAIT "mod"
|
||||
/// The mob has the stasis effect.
|
||||
/// Does nothing on its own, applied via status effect.
|
||||
#define TRAIT_STASIS "in_stasis"
|
||||
/// Harmful radiation effects, the toxin damage and the burns, will not occur while this trait is active
|
||||
#define TRAIT_HALT_RADIATION_EFFECTS "halt_radiation_effects"
|
||||
|
||||
/**
|
||||
*
|
||||
* This trait is used in some interactions very high in the interaction chain to allow
|
||||
* certain atoms to be skipped by said interactions if the user is in combat mode.
|
||||
*
|
||||
* Its primarily use case is for stuff like storage and tables, to allow things like emags to be bagged
|
||||
* (because in some contexts you might want to be emagging a bag, and in others you might want to be storing it.)
|
||||
*
|
||||
* This is only checked by certain items explicitly so you can't just add the trait and expect it to work.
|
||||
* (This may be changed later but I chose to do it this way to avoid messing up interactions which require combat mode)
|
||||
* While /tg/ calls it combat mode, we just specifiy it as having your a_intent set to I_HURT
|
||||
*/
|
||||
#define TRAIT_COMBAT_MODE_SKIP_INTERACTION "combat_mode_skip_interaction"
|
||||
|
||||
@@ -33,11 +33,13 @@
|
||||
|
||||
//supposedly the fastest way to do this according to https://gist.github.com/Giacom/be635398926bb463b42a
|
||||
///Returns a list of turf in a square
|
||||
#define RANGE_TURFS(RADIUS, CENTER) \
|
||||
RECT_TURFS(RADIUS, RADIUS, CENTER)
|
||||
|
||||
#define RECT_TURFS(H_RADIUS, V_RADIUS, CENTER) \
|
||||
block( \
|
||||
locate(max(CENTER.x-(H_RADIUS),1), max(CENTER.y-(V_RADIUS),1), CENTER.z), \
|
||||
locate(min(CENTER.x+(H_RADIUS),world.maxx), min(CENTER.y+(V_RADIUS),world.maxy), CENTER.z) \
|
||||
(CENTER).x - (H_RADIUS), (CENTER).y - (V_RADIUS), (CENTER).z, \
|
||||
(CENTER).x + (H_RADIUS), (CENTER).y + (V_RADIUS), (CENTER).z \
|
||||
)
|
||||
|
||||
// Wet turfs have different slipping intensities
|
||||
|
||||
@@ -21,6 +21,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
/atom = list(
|
||||
"TRAIT_ALT_CLICK_BLOCKER" = TRAIT_ALT_CLICK_BLOCKER,
|
||||
),
|
||||
/atom/movable = list(
|
||||
"TRAIT_IRRADIATED" = TRAIT_IRRADIATED,
|
||||
),
|
||||
/mob = list(
|
||||
"TRAIT_THINKING_IN_CHARACTER" = TRAIT_THINKING_IN_CHARACTER,
|
||||
"TRAIT_NOFIRE" = TRAIT_NOFIRE,
|
||||
@@ -29,6 +32,10 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE,
|
||||
"TRAIT_MADNESS_IMMUNE" = TRAIT_MADNESS_IMMUNE,
|
||||
"TRAIT_AMBIENT_PEST_MOB" = TRAIT_AMBIENT_PEST_MOB,
|
||||
"TRAIT_BYPASS_EARLY_IRRADIATED_CHECK" = TRAIT_BYPASS_EARLY_IRRADIATED_CHECK,
|
||||
"TRAIT_RADIMMUNE" = TRAIT_RADIMMUNE,
|
||||
"TRAIT_STASIS" = TRAIT_STASIS,
|
||||
"TRAIT_HALT_RADIATION_EFFECTS" = TRAIT_HALT_RADIATION_EFFECTS,
|
||||
),
|
||||
/obj = list(
|
||||
"TRAIT_CLIMBABLE" = TRAIT_CLIMBABLE,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Get a list of turfs in a line from `starting_atom` to `ending_atom`.
|
||||
*
|
||||
* Uses the ultra-fast [Bresenham Line-Drawing Algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm).
|
||||
*/
|
||||
/proc/get_line(atom/starting_atom, atom/ending_atom)
|
||||
var/current_x_step = starting_atom.x//start at x and y, then add 1 or -1 to these to get every turf from starting_atom to ending_atom
|
||||
var/current_y_step = starting_atom.y
|
||||
var/starting_z = starting_atom.z
|
||||
|
||||
var/list/line = list(get_turf(starting_atom))//get_turf(atom) is faster than locate(x, y, z)
|
||||
|
||||
var/x_distance = ending_atom.x - current_x_step //x distance
|
||||
var/y_distance = ending_atom.y - current_y_step
|
||||
|
||||
var/abs_x_distance = abs(x_distance)//Absolute value of x distance
|
||||
var/abs_y_distance = abs(y_distance)
|
||||
|
||||
var/x_distance_sign = SIGN(x_distance) //Sign of x distance (+ or -)
|
||||
var/y_distance_sign = SIGN(y_distance)
|
||||
|
||||
var/x = abs_x_distance >> 1 //Counters for steps taken, setting to distance/2
|
||||
var/y = abs_y_distance >> 1 //Bit-shifting makes me l33t. It also makes get_line() unnecessarily fast.
|
||||
|
||||
if(abs_x_distance >= abs_y_distance) //x distance is greater than y
|
||||
for(var/distance_counter in 0 to (abs_x_distance - 1))//It'll take abs_x_distance steps to get there
|
||||
y += abs_y_distance
|
||||
|
||||
if(y >= abs_x_distance) //Every abs_y_distance steps, step once in y direction
|
||||
y -= abs_x_distance
|
||||
current_y_step += y_distance_sign
|
||||
|
||||
current_x_step += x_distance_sign //Step on in x direction
|
||||
line += locate(current_x_step, current_y_step, starting_z)//Add the turf to the list
|
||||
else
|
||||
for(var/distance_counter in 0 to (abs_y_distance - 1))
|
||||
x += abs_x_distance
|
||||
|
||||
if(x >= abs_y_distance)
|
||||
x -= abs_y_distance
|
||||
current_x_step += x_distance_sign
|
||||
|
||||
current_y_step += y_distance_sign
|
||||
line += locate(current_x_step, current_y_step, starting_z)
|
||||
return line
|
||||
@@ -0,0 +1,85 @@
|
||||
/// Whether or not it's possible for this atom to be irradiated
|
||||
#define CAN_IRRADIATE(atom) (ismob(##atom))
|
||||
|
||||
/// Calculates the max chance for a radiation_pulse via a radioactive reagent
|
||||
#define CALCULATE_RAD_MAX_CHANCE(rad_power) (20 + (15 * (rad_power - 1)))
|
||||
|
||||
/// Sends out a pulse of radiation, eminating from the source.
|
||||
/// Radiation is performed by collecting all radiatables within the max range (0 means source only, 1 means adjacent, etc),
|
||||
/// then makes their way towards them. A number, starting at 1, is multiplied
|
||||
/// by the insulation amounts of whatever is in the way (for example, walls lowering it down).
|
||||
/// If this number hits equal or below the threshold, then the target can no longer be irradiated.
|
||||
/// If the number is above the threshold, then the chance is the chance that the target will be irradiated.
|
||||
/// As a consumer, this means that max_range going up usually means you want to lower the threshold too,
|
||||
/// as well as the other way around.
|
||||
/// If max_range is high, but threshold is too high, then it usually won't reach the source at the max range in time.
|
||||
/// If max_range is low, but threshold is too low, then it basically guarantees everyone nearby, even if there's walls
|
||||
/// and such in the way, can be irradiated.
|
||||
/// You can also pass in a minimum exposure time. If this is set, then this radiation pulse
|
||||
/// will not irradiate the source unless they have been around *any* radioactive source for that
|
||||
/// period of time.
|
||||
/// The chance to get irradiated diminishes over range, and from objects that block radiation.
|
||||
/// Assuming there is nothing in the way, the chance will determine what the chance is to get irradiated from half of max_range.
|
||||
/// Example: If chance is equal to 30%, and max_range is equal to 8,
|
||||
/// then the chance for a thing to get irradiated is 30% if they are 4 turfs away from the pulse source.
|
||||
/// Also, strength is how much radiation the target will get if they fail their RNG check / linger for too long.
|
||||
/proc/radiation_pulse(
|
||||
atom/source,
|
||||
max_range,
|
||||
threshold,
|
||||
chance = DEFAULT_RADIATION_CHANCE,
|
||||
minimum_exposure_time = 0,
|
||||
strength = 100
|
||||
)
|
||||
if(!SSradiation.can_fire)
|
||||
return
|
||||
|
||||
var/datum/radiation_pulse_information/pulse_information = new
|
||||
pulse_information.source_ref = WEAKREF(source)
|
||||
pulse_information.max_range = max_range
|
||||
pulse_information.threshold = threshold
|
||||
pulse_information.chance = chance
|
||||
pulse_information.minimum_exposure_time = minimum_exposure_time
|
||||
pulse_information.turfs_to_process = RANGE_TURFS(max_range, source)
|
||||
pulse_information.strength = strength
|
||||
|
||||
SSradiation.processing += pulse_information
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/radiation_pulse_information
|
||||
var/datum/weakref/source_ref
|
||||
var/max_range
|
||||
var/threshold
|
||||
var/chance
|
||||
var/minimum_exposure_time
|
||||
var/list/turfs_to_process
|
||||
var/strength
|
||||
|
||||
#define MEDIUM_RADIATION_THRESHOLD_RANGE 0.5
|
||||
#define EXTREME_RADIATION_CHANCE 30
|
||||
|
||||
/// Gets the perceived "danger" of radiation pulse, given the threshold to the target.
|
||||
/// Returns a RADIATION_DANGER_* define, see [code/__DEFINES/radiation.dm]
|
||||
/proc/get_perceived_radiation_danger(datum/radiation_pulse_information/pulse_information, insulation_to_target)
|
||||
if (insulation_to_target > pulse_information.threshold)
|
||||
// We could get irradiated! The only thing stopping us now is chance, so scale based on that.
|
||||
if (pulse_information.chance >= EXTREME_RADIATION_CHANCE)
|
||||
return PERCEIVED_RADIATION_DANGER_EXTREME
|
||||
else
|
||||
return PERCEIVED_RADIATION_DANGER_HIGH
|
||||
else
|
||||
// We're out of the threshold from being irradiated, but by how much?
|
||||
if (insulation_to_target / pulse_information.threshold <= MEDIUM_RADIATION_THRESHOLD_RANGE)
|
||||
return PERCEIVED_RADIATION_DANGER_MEDIUM
|
||||
else
|
||||
return PERCEIVED_RADIATION_DANGER_LOW
|
||||
|
||||
/// A common proc used to send COMSIG_ATOM_PROPAGATE_RAD_PULSE to adjacent atoms
|
||||
/// Only used for uranium (false/tram)walls to spread their radiation pulses
|
||||
/atom/proc/propagate_radiation_pulse()
|
||||
for(var/atom/atom in orange(1,src))
|
||||
SEND_SIGNAL(atom, COMSIG_ATOM_PROPAGATE_RAD_PULSE, src)
|
||||
|
||||
#undef MEDIUM_RADIATION_THRESHOLD_RANGE
|
||||
#undef EXTREME_RADIATION_CHANCE
|
||||
@@ -0,0 +1,8 @@
|
||||
///Returns the distance between two atoms
|
||||
/proc/get_dist_euclidean(atom/first_location, atom/second_location)
|
||||
var/dx = first_location.x - second_location.x
|
||||
var/dy = first_location.y - second_location.y
|
||||
|
||||
var/dist = sqrt(dx ** 2 + dy ** 2)
|
||||
|
||||
return dist
|
||||
@@ -7,13 +7,6 @@
|
||||
//Checks if all high bits in req_mask are set in bitfield
|
||||
#define BIT_TEST_ALL(bitfield, req_mask) ((~(bitfield) & (req_mask)) == 0)
|
||||
|
||||
//supposedly the fastest way to do this according to https://gist.github.com/Giacom/be635398926bb463b42a
|
||||
#define RANGE_TURFS(RADIUS, CENTER) \
|
||||
block( \
|
||||
locate(max(CENTER.x-(RADIUS),1), max(CENTER.y-(RADIUS),1), CENTER.z), \
|
||||
locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \
|
||||
)
|
||||
|
||||
//Returns the middle-most value
|
||||
/proc/dd_range(var/low, var/high, var/num)
|
||||
return max(low,min(high,num))
|
||||
|
||||
@@ -307,6 +307,11 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
var/mob/living/L = usr
|
||||
return L.resist()
|
||||
|
||||
/atom/movable/screen/alert/irradiated
|
||||
name = "Irradiated"
|
||||
desc = "You're irradiated! Heal your radiation quick, and stand under a shower to wash some radiation off from yourself!"
|
||||
// use_user_hud_icon = TRUE
|
||||
icon_state = "irradiated"
|
||||
|
||||
//ALIENS
|
||||
|
||||
|
||||
@@ -603,40 +603,6 @@
|
||||
/datum/config_entry/str_list/language_prefixes
|
||||
default = list(",", "#", "-")
|
||||
|
||||
// 0:1 subtraction:division for computing effective radiation on a turf
|
||||
/// 0 / RAD_RESIST_CALC_DIV = Each turf absorbs some fraction of the working radiation level
|
||||
/// 1 / RAD_RESIST_CALC_SUB = Each turf absorbs a fixed amount of radiation
|
||||
/datum/config_entry/flag/radiation_resistance_calc_mode
|
||||
default = RAD_RESIST_CALC_SUB
|
||||
|
||||
/datum/config_entry/flag/radiation_resistance_calc_mode/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
var/val_as_num = text2num(str_val)
|
||||
if(val_as_num in list(RAD_RESIST_CALC_DIV, RAD_RESIST_CALC_SUB))
|
||||
config_entry_value = val_as_num
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
///How much radiation is reduced by each tick
|
||||
/datum/config_entry/number/radiation_decay_rate
|
||||
default = 1
|
||||
integer = FALSE
|
||||
|
||||
/datum/config_entry/number/radiation_resistance_multiplier
|
||||
default = 8.5 //VOREstation edit
|
||||
integer = FALSE
|
||||
|
||||
/datum/config_entry/number/radiation_material_resistance_divisor
|
||||
default = 1
|
||||
min_val = 0.1
|
||||
integer = FALSE
|
||||
|
||||
///If the radiation level for a turf would be below this, ignore it.
|
||||
/datum/config_entry/number/radiation_lower_limit
|
||||
default = 0.35
|
||||
integer = FALSE
|
||||
|
||||
/// If true, submaps loaded automatically can be rotated.
|
||||
/datum/config_entry/flag/random_submap_orientation
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
#define RADIATION_IMMEDIATE_TOX_DAMAGE 10
|
||||
|
||||
#define RADIATION_TOX_DAMAGE_PER_INTERVAL 2
|
||||
#define RADIATION_TOX_INTERVAL (25 SECONDS)
|
||||
|
||||
#define RADIATION_BURN_SPLOTCH_DAMAGE 11
|
||||
#define RADIATION_BURN_INTERVAL_MIN (30 SECONDS)
|
||||
#define RADIATION_BURN_INTERVAL_MAX (60 SECONDS)
|
||||
|
||||
// Showers process on SSmachines
|
||||
#define RADIATION_CLEAN_IMMUNITY_TIME (SSMACHINES_DT + (1 SECONDS))
|
||||
|
||||
/// This atom is irradiated, and will glow green.
|
||||
/// Humans will take toxin damage until all their toxin damage is cleared.
|
||||
/datum/component/irradiated
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
|
||||
var/beginning_of_irradiation
|
||||
|
||||
var/burn_splotch_timer_id
|
||||
|
||||
COOLDOWN_DECLARE(clean_cooldown)
|
||||
COOLDOWN_DECLARE(last_tox_damage)
|
||||
|
||||
/datum/component/irradiated/Initialize()
|
||||
if (!CAN_IRRADIATE(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
// This isn't incompatible, it's just wrong
|
||||
if (HAS_TRAIT(parent, TRAIT_RADIMMUNE))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
ADD_TRAIT(parent, TRAIT_IRRADIATED, REF(src))
|
||||
|
||||
create_glow()
|
||||
|
||||
beginning_of_irradiation = world.time
|
||||
|
||||
if (ishuman(parent))
|
||||
var/mob/living/carbon/human/human_parent = parent
|
||||
human_parent.apply_damage(RADIATION_IMMEDIATE_TOX_DAMAGE, TOX)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
COOLDOWN_START(src, last_tox_damage, RADIATION_TOX_INTERVAL)
|
||||
|
||||
start_burn_splotch_timer()
|
||||
|
||||
human_parent.throw_alert("irradiated", /atom/movable/screen/alert/irradiated)
|
||||
|
||||
/datum/component/irradiated/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
|
||||
RegisterSignal(parent, COMSIG_GEIGER_COUNTER_SCAN, PROC_REF(on_geiger_counter_scan))
|
||||
RegisterSignal(parent, COMSIG_LIVING_HEALTHSCAN, PROC_REF(on_healthscan))
|
||||
|
||||
/datum/component/irradiated/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_COMPONENT_CLEAN_ACT,
|
||||
COMSIG_GEIGER_COUNTER_SCAN,
|
||||
COMSIG_LIVING_HEALTHSCAN,
|
||||
))
|
||||
|
||||
/datum/component/irradiated/Destroy(force)
|
||||
var/atom/movable/parent_movable = parent
|
||||
if (istype(parent_movable))
|
||||
parent_movable.remove_filter("rad_glow")
|
||||
|
||||
var/mob/living/carbon/human/human_parent = parent
|
||||
if (istype(human_parent))
|
||||
human_parent.clear_alert("irradiated")
|
||||
|
||||
REMOVE_TRAIT(parent, TRAIT_IRRADIATED, REF(src))
|
||||
|
||||
deltimer(burn_splotch_timer_id)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/component/irradiated/process(seconds_per_tick)
|
||||
if (!ishuman(parent))
|
||||
return PROCESS_KILL
|
||||
|
||||
if (HAS_TRAIT(parent, TRAIT_RADIMMUNE))
|
||||
qdel(src)
|
||||
return PROCESS_KILL
|
||||
|
||||
var/mob/living/carbon/human/human_parent = parent
|
||||
if (human_parent.radiation == 0)
|
||||
qdel(src)
|
||||
return PROCESS_KILL
|
||||
|
||||
if (should_halt_effects(parent))
|
||||
return
|
||||
|
||||
|
||||
// if (human_parent.stat != DEAD)
|
||||
// human_parent.handle_radiation()
|
||||
|
||||
// human_parent.dna?.species?.handle_radiation(human_parent, world.time - beginning_of_irradiation, seconds_per_tick)
|
||||
|
||||
// process_tox_damage(human_parent, seconds_per_tick)
|
||||
|
||||
/datum/component/irradiated/proc/should_halt_effects(mob/living/carbon/human/target)
|
||||
if (HAS_TRAIT(target, TRAIT_STASIS))
|
||||
return TRUE
|
||||
|
||||
if (HAS_TRAIT(target, TRAIT_HALT_RADIATION_EFFECTS))
|
||||
return TRUE
|
||||
|
||||
if (!COOLDOWN_FINISHED(src, clean_cooldown))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/component/irradiated/proc/process_tox_damage(mob/living/carbon/human/target, seconds_per_tick)
|
||||
if (!COOLDOWN_FINISHED(src, last_tox_damage))
|
||||
return
|
||||
|
||||
target.apply_damage(RADIATION_TOX_DAMAGE_PER_INTERVAL, TOX)
|
||||
COOLDOWN_START(src, last_tox_damage, RADIATION_TOX_INTERVAL)
|
||||
|
||||
/datum/component/irradiated/proc/start_burn_splotch_timer()
|
||||
addtimer(CALLBACK(src, PROC_REF(give_burn_splotches)), rand(RADIATION_BURN_INTERVAL_MIN, RADIATION_BURN_INTERVAL_MAX), TIMER_STOPPABLE)
|
||||
|
||||
/datum/component/irradiated/proc/give_burn_splotches()
|
||||
// This shouldn't be possible, but just in case.
|
||||
if (QDELETED(src))
|
||||
return
|
||||
|
||||
start_burn_splotch_timer()
|
||||
|
||||
var/mob/living/carbon/human/human_parent = parent
|
||||
|
||||
if (should_halt_effects(parent))
|
||||
return
|
||||
|
||||
var/obj/item/organ/external/affected_limb = pick(human_parent.organs)
|
||||
human_parent.visible_message(
|
||||
span_boldwarning("[human_parent]'s [affected_limb.name] bubbles unnaturally, then bursts into blisters!"),
|
||||
span_boldwarning("Your [affected_limb.name] bubbles unnaturally, then bursts into blisters!"),
|
||||
)
|
||||
|
||||
if(human_parent.is_blind())
|
||||
to_chat(human_parent, span_boldwarning("Your [affected_limb.name] feels like it's bubbling, then burns like hell!"))
|
||||
|
||||
human_parent.apply_damage(RADIATION_BURN_SPLOTCH_DAMAGE, BURN, affected_limb, blocked = FALSE, used_weapon = "Radiation Burns")
|
||||
playsound(
|
||||
human_parent,
|
||||
get_sfx("sizzle"),
|
||||
50,
|
||||
vary = TRUE,
|
||||
)
|
||||
|
||||
/datum/component/irradiated/proc/create_glow()
|
||||
var/atom/movable/parent_movable = parent
|
||||
if (!istype(parent_movable))
|
||||
return
|
||||
|
||||
parent_movable.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
|
||||
addtimer(CALLBACK(src, PROC_REF(start_glow_loop), parent_movable), rand(0.1 SECONDS, 1.9 SECONDS)) // Things should look uneven
|
||||
|
||||
/datum/component/irradiated/proc/start_glow_loop(atom/movable/parent_movable)
|
||||
var/filter = parent_movable.get_filter("rad_glow")
|
||||
if (!filter)
|
||||
return
|
||||
|
||||
animate(filter, alpha = 110, time = 1.5 SECONDS, loop = -1)
|
||||
animate(alpha = 40, time = 2.5 SECONDS)
|
||||
|
||||
/datum/component/irradiated/proc/on_clean(datum/source, clean_types)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!(clean_types & CLEAN_TYPE_RADIATION))
|
||||
return NONE
|
||||
|
||||
if (isitem(parent))
|
||||
qdel(src)
|
||||
return COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP
|
||||
|
||||
COOLDOWN_START(src, clean_cooldown, RADIATION_CLEAN_IMMUNITY_TIME)
|
||||
|
||||
/datum/component/irradiated/proc/on_geiger_counter_scan(datum/source, mob/user, obj/item/geiger/geiger_counter)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (isliving(source))
|
||||
var/mob/living/living_source = source
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Subject is irradiated. Contamination traces back to roughly [DisplayTimeText(world.time - beginning_of_irradiation, 5)] ago. Current toxin levels: [living_source.getToxLoss()]."))
|
||||
else
|
||||
// In case the green wasn't obvious enough...
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Target is irradiated."))
|
||||
|
||||
return COMSIG_GEIGER_COUNTER_SCAN_SUCCESSFUL
|
||||
|
||||
/datum/component/irradiated/proc/on_healthscan(datum/source, list/render_list, advanced, mob/user, mode, tochat)
|
||||
SIGNAL_HANDLER
|
||||
render_list += span_notice("Subject is irradiated. Supply antiradiation or antitoxin, such as [/datum/reagent/prussian_blue::name].")
|
||||
|
||||
// render_list += "<span class='alert ml-1'>"
|
||||
//render_list += conditional_tooltip("Subject is irradiated.", "Supply antiradiation or antitoxin, such as [/datum/reagent/prussian_blue::name].", tochat)
|
||||
// render_list += "</span><br>"
|
||||
|
||||
#undef RADIATION_BURN_SPLOTCH_DAMAGE
|
||||
#undef RADIATION_BURN_INTERVAL_MIN
|
||||
#undef RADIATION_BURN_INTERVAL_MAX
|
||||
#undef RADIATION_CLEAN_IMMUNITY_TIME
|
||||
#undef RADIATION_IMMEDIATE_TOX_DAMAGE
|
||||
#undef RADIATION_TOX_INTERVAL
|
||||
#undef RADIATION_TOX_DAMAGE_PER_INTERVAL
|
||||
@@ -1,148 +1,186 @@
|
||||
SUBSYSTEM_DEF(radiation)
|
||||
name = "Radiation"
|
||||
wait = 2 SECONDS
|
||||
flags = SS_NO_INIT
|
||||
flags = SS_BACKGROUND | SS_NO_INIT
|
||||
|
||||
var/list/sources = list() // all radiation source datums
|
||||
var/list/sources_assoc = list() // Sources indexed by turf for de-duplication.
|
||||
var/list/resistance_cache = list() // Cache of turf's radiation resistance.
|
||||
wait = 0.5 SECONDS
|
||||
|
||||
var/tmp/list/current_sources = list()
|
||||
var/tmp/list/current_res_cache = list()
|
||||
var/tmp/list/listeners = list()
|
||||
/// A list of radiation sources (/datum/radiation_pulse_information) that have yet to process.
|
||||
/// Do not interact with this directly, use `radiation_pulse` instead.
|
||||
var/list/datum/radiation_pulse_information/processing = list()
|
||||
|
||||
/datum/controller/subsystem/radiation/fire(resumed = FALSE)
|
||||
if (!resumed)
|
||||
current_sources = sources.Copy()
|
||||
current_res_cache = resistance_cache.Copy()
|
||||
listeners = GLOB.living_mob_list.Copy()
|
||||
/datum/controller/subsystem/radiation/fire(resumed)
|
||||
while (processing.len)
|
||||
var/datum/radiation_pulse_information/pulse_information = processing[1]
|
||||
|
||||
while(length(current_sources))
|
||||
var/datum/radiation_source/S = current_sources[length(current_sources)]
|
||||
current_sources.len--
|
||||
var/datum/weakref/source_ref = pulse_information.source_ref
|
||||
var/atom/source = source_ref.resolve()
|
||||
if (isnull(source))
|
||||
processing.Cut(1, 2)
|
||||
continue
|
||||
|
||||
pulse(source, pulse_information)
|
||||
|
||||
if(QDELETED(S))
|
||||
sources -= S
|
||||
else if(S.decay)
|
||||
S.update_rad_power(S.rad_power - CONFIG_GET(number/radiation_decay_rate))
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
while(length(current_res_cache))
|
||||
var/turf/T = current_res_cache[length(current_res_cache)]
|
||||
current_res_cache.len--
|
||||
|
||||
if(QDELETED(T))
|
||||
resistance_cache -= T
|
||||
else if((length(T.contents) + 1) != resistance_cache[T])
|
||||
resistance_cache -= T // If its stale REMOVE it! It will get added if its needed.
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
if(!length(sources))
|
||||
listeners.Cut()
|
||||
|
||||
while(length(listeners))
|
||||
var/atom/A = listeners[length(listeners)]
|
||||
listeners.len--
|
||||
|
||||
if(!QDELETED(A))
|
||||
var/turf/T = get_turf(A)
|
||||
var/rads = get_rads_at_turf(T)
|
||||
if(rads)
|
||||
A.rad_act(rads)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
processing.Cut(1, 2)
|
||||
|
||||
/datum/controller/subsystem/radiation/stat_entry(msg)
|
||||
msg = "S:[length(sources)], RC:[length(resistance_cache)]"
|
||||
msg = "Pulses:[processing.len]"
|
||||
return ..()
|
||||
|
||||
// Ray trace from all active radiation sources to T and return the strongest effect.
|
||||
/datum/controller/subsystem/radiation/proc/get_rads_at_turf(var/turf/T)
|
||||
. = 0
|
||||
if(!istype(T))
|
||||
return
|
||||
/datum/controller/subsystem/radiation/proc/pulse(atom/source, datum/radiation_pulse_information/pulse_information)
|
||||
var/list/cached_rad_insulations = list()
|
||||
var/list/cached_turfs_to_process = pulse_information.turfs_to_process
|
||||
var/turfs_iterated = 0
|
||||
var/pulse_strength = pulse_information.strength
|
||||
for (var/turf/turf_to_irradiate as anything in cached_turfs_to_process)
|
||||
turfs_iterated += 1
|
||||
|
||||
for(var/datum/radiation_source/source as anything in sources)
|
||||
if(source.rad_power < .)
|
||||
continue // Already being affected by a stronger source
|
||||
for(var/obj/machinery/power/rad_collector in turf_to_irradiate)
|
||||
SEND_SIGNAL(rad_collector, COMSIG_IN_RANGE_OF_IRRADIATION, pulse_information, 1) //We just do it here and skip all the math to make it faster. Sure, we could have something blocking the rad collectors, but this is faster and has better CPU gains in exchange for negligible gameplay impact.
|
||||
continue
|
||||
|
||||
if(source.source_turf.z != T.z)
|
||||
continue // Radiation is not multi-z
|
||||
for(var/obj/item/geiger/geiger_counter in turf_to_irradiate)
|
||||
var/current_insulation = 1
|
||||
for(var/turf/turf_in_between in get_line(source, geiger_counter) - get_turf(source))
|
||||
var/insulation = cached_rad_insulations[turf_in_between]
|
||||
if(isnull(insulation))
|
||||
insulation = turf_in_between.rad_insulation
|
||||
for (var/atom/on_turf as anything in turf_in_between.contents)
|
||||
insulation *= on_turf.rad_insulation
|
||||
cached_rad_insulations[turf_in_between] = insulation
|
||||
|
||||
if(source.respect_maint)
|
||||
var/area/A = T.loc
|
||||
if(A.flag_check(RAD_SHIELDED))
|
||||
continue // In shielded area
|
||||
current_insulation *= insulation
|
||||
|
||||
var/dist = get_dist(source.source_turf, T)
|
||||
if(dist > source.range)
|
||||
continue // Too far to possibly affect
|
||||
if(current_insulation <= pulse_information.threshold)
|
||||
continue
|
||||
|
||||
if(source.flat)
|
||||
. += source.rad_power
|
||||
continue // No need to ray trace for flat field
|
||||
SEND_SIGNAL(geiger_counter, COMSIG_IN_RANGE_OF_IRRADIATION, pulse_information, current_insulation)
|
||||
|
||||
// Okay, now ray trace to find resistence!
|
||||
var/turf/origin = source.source_turf
|
||||
var/working = source.rad_power
|
||||
while(origin != T)
|
||||
origin = get_step_towards(origin, T) //Raytracing
|
||||
if(!resistance_cache[origin]) //Only get the resistance if we don't already know it.
|
||||
origin.calc_rad_resistance()
|
||||
|
||||
if(origin.cached_rad_resistance)
|
||||
if(CONFIG_GET(flag/radiation_resistance_calc_mode) == RAD_RESIST_CALC_DIV)
|
||||
working = round((working / (origin.cached_rad_resistance * CONFIG_GET(number/radiation_resistance_multiplier))), 0.01)
|
||||
else if(CONFIG_GET(flag/radiation_resistance_calc_mode) == RAD_RESIST_CALC_SUB)
|
||||
working = round((working - (origin.cached_rad_resistance * CONFIG_GET(number/radiation_resistance_multiplier))), 0.01)
|
||||
for(var/mob/living/target in turf_to_irradiate)
|
||||
if(!can_irradiate_basic(target))
|
||||
continue
|
||||
|
||||
if(working <= CONFIG_GET(number/radiation_lower_limit)) // Too far from this source
|
||||
working = 0 // May as well be 0
|
||||
var/current_insulation = 1
|
||||
for (var/turf/turf_in_between in get_line(source, target) - get_turf(source))
|
||||
var/insulation = cached_rad_insulations[turf_in_between]
|
||||
if (isnull(insulation))
|
||||
insulation = turf_in_between.rad_insulation
|
||||
for (var/atom/on_turf as anything in turf_in_between.contents)
|
||||
insulation *= on_turf.rad_insulation
|
||||
cached_rad_insulations[turf_in_between] = insulation
|
||||
|
||||
current_insulation *= insulation
|
||||
|
||||
if (current_insulation <= pulse_information.threshold)
|
||||
break
|
||||
|
||||
SEND_SIGNAL(target, COMSIG_IN_RANGE_OF_IRRADIATION, pulse_information, current_insulation)
|
||||
|
||||
// Check a second time, because of TRAIT_BYPASS_EARLY_IRRADIATED_CHECK
|
||||
if (HAS_TRAIT(target, TRAIT_IRRADIATED))
|
||||
continue
|
||||
|
||||
if (current_insulation <= pulse_information.threshold)
|
||||
continue
|
||||
|
||||
/// Perceived chance of target getting irradiated.
|
||||
var/perceived_chance
|
||||
/// Intensity variable which will describe the radiation pulse.
|
||||
/// It is used by perceived intensity, which diminishes over range. The chance of the target getting irradiated is determined by perceived_intensity.
|
||||
/// Intensity is calculated so that the chance of getting irradiated at half of the max range is the same as the chance parameter.
|
||||
var/intensity
|
||||
/// Diminishes over range. Used by perceived chance, which is the actual chance to get irradiated.
|
||||
var/perceived_intensity
|
||||
|
||||
if(pulse_information.chance < 100) // Prevents log(0) runtime if chance is 100%
|
||||
intensity = -log(1 - pulse_information.chance / 100) * (1 + pulse_information.max_range / 2) ** 2
|
||||
perceived_intensity = intensity * INVERSE((1 + get_dist_euclidean(source, target)) ** 2) // Diminishes over range.
|
||||
perceived_intensity *= (current_insulation - pulse_information.threshold) * INVERSE(1 - pulse_information.threshold) // Perceived intensity decreases as objects that absorb radiation block its trajectory.
|
||||
perceived_chance = 100 * (1 - NUM_E ** -perceived_intensity)
|
||||
pulse_strength = pulse_strength * (1 - NUM_E ** -perceived_intensity)
|
||||
else
|
||||
perceived_chance = 100
|
||||
|
||||
var/irradiation_result = SEND_SIGNAL(target, COMSIG_IN_THRESHOLD_OF_IRRADIATION, pulse_information)
|
||||
if (irradiation_result & CANCEL_IRRADIATION)
|
||||
continue
|
||||
|
||||
if (pulse_information.minimum_exposure_time && !(irradiation_result & SKIP_MINIMUM_EXPOSURE_TIME_CHECK))
|
||||
target.AddComponent(/datum/component/radiation_countdown, pulse_information.minimum_exposure_time)
|
||||
continue
|
||||
|
||||
if (!prob(perceived_chance))
|
||||
continue
|
||||
|
||||
if (irradiate_after_basic_checks(target, pulse_strength))
|
||||
target.investigate_log("was irradiated by [source].", INVESTIGATE_RADIATION)
|
||||
|
||||
if(MC_TICK_CHECK)
|
||||
break
|
||||
|
||||
cached_turfs_to_process.Cut(1, turfs_iterated + 1)
|
||||
|
||||
/// Will attempt to irradiate the given target, limited through IC means, such as radiation protected clothing.
|
||||
/datum/controller/subsystem/radiation/proc/irradiate(atom/target, strength)
|
||||
if (!can_irradiate_basic(target))
|
||||
return FALSE
|
||||
|
||||
irradiate_after_basic_checks(target, strength)
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/radiation/proc/irradiate_after_basic_checks(mob/living/target, strength)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
if(!ishuman(target))
|
||||
if(ismob(target))
|
||||
target.radiation += strength
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/// 0 = full protection, 1 = no protection.
|
||||
var/rad_vulnerability = 1 - wearing_rad_protected_clothing(target)
|
||||
if(rad_vulnerability <= 0)
|
||||
return FALSE
|
||||
target.radiation += round(strength * rad_vulnerability, 0.1)
|
||||
|
||||
// target.AddComponent(/datum/component/irradiated)
|
||||
return TRUE
|
||||
|
||||
/// Returns whether or not the target can be irradiated by any means.
|
||||
/// Does not check for clothing.
|
||||
/datum/controller/subsystem/radiation/proc/can_irradiate_basic(atom/target)
|
||||
if (!CAN_IRRADIATE(target))
|
||||
return FALSE
|
||||
|
||||
if (HAS_TRAIT(target, TRAIT_IRRADIATED) && !HAS_TRAIT(target, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK))
|
||||
return FALSE
|
||||
|
||||
if (HAS_TRAIT(target, TRAIT_RADIMMUNE))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Retruns a value from 1 (full protection) to 0 (no protection)
|
||||
/// If we have 4 limbs and 3 are protected, we would expect to have 0.75 returned.
|
||||
/datum/controller/subsystem/radiation/proc/wearing_rad_protected_clothing(mob/living/carbon/human/human)
|
||||
///Check how many limbs we have.
|
||||
var/limb_count = 0
|
||||
///Check how many of our limbs are protected.
|
||||
var/protected_limbs = 0
|
||||
for(var/obj/item/organ/external/limb as anything in human.organs)
|
||||
limb_count++
|
||||
|
||||
for(var/obj/item/clothing as anything in human.get_clothing_on_part(limb))
|
||||
if(HAS_TRAIT(clothing, TRAIT_RADIATION_PROTECTED_CLOTHING)) //If our clothing
|
||||
protected_limbs++
|
||||
break
|
||||
|
||||
// Accumulate radiation from all sources in range, not just the biggest.
|
||||
// Shouldn't really ever have practical uses, but standing in a room literally made from uranium is more dangerous than standing next to a single uranium vase
|
||||
. += working / (dist ** 2)
|
||||
var/rad_resistance = clothing.armor["rad"]
|
||||
if(prob(rad_resistance))
|
||||
protected_limbs++
|
||||
break
|
||||
|
||||
if(. <= CONFIG_GET(number/radiation_lower_limit))
|
||||
. = 0
|
||||
|
||||
// Add a radiation source instance to the repository. It will override any existing source on the same turf.
|
||||
/datum/controller/subsystem/radiation/proc/add_source(var/datum/radiation_source/S)
|
||||
if(!isturf(S.source_turf))
|
||||
return
|
||||
var/datum/radiation_source/existing = sources_assoc[S.source_turf]
|
||||
if(existing)
|
||||
qdel(existing)
|
||||
sources += S
|
||||
sources_assoc[S.source_turf] = S
|
||||
|
||||
// Creates a temporary radiation source that will decay
|
||||
/datum/controller/subsystem/radiation/proc/radiate(source, power) //Sends out a radiation pulse, taking walls into account
|
||||
if(!(source && power)) //Sanity checking
|
||||
return
|
||||
var/datum/radiation_source/S = new()
|
||||
S.source_turf = get_turf(source)
|
||||
S.update_rad_power(power)
|
||||
add_source(S)
|
||||
|
||||
// Sets the radiation in a range to a constant value.
|
||||
/datum/controller/subsystem/radiation/proc/flat_radiate(source, power, range, var/respect_maint = TRUE) //VOREStation edit; Respect shielded areas by default please.
|
||||
if(!(source && power && range))
|
||||
return
|
||||
var/datum/radiation_source/S = new()
|
||||
S.flat = TRUE
|
||||
S.range = range
|
||||
S.respect_maint = respect_maint
|
||||
S.source_turf = get_turf(source)
|
||||
S.update_rad_power(power)
|
||||
add_source(S)
|
||||
|
||||
// Irradiates a full Z-level. Hacky way of doing it, but not too expensive.
|
||||
/datum/controller/subsystem/radiation/proc/z_radiate(var/atom/source, power, var/respect_maint = TRUE) //VOREStation edit; Respect shielded areas by default please.
|
||||
if(!(power && source))
|
||||
return
|
||||
var/turf/epicentre = locate(round(world.maxx / 2), round(world.maxy / 2), source.z)
|
||||
flat_radiate(epicentre, power, world.maxx, respect_maint)
|
||||
return (protected_limbs/limb_count)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/// Atoms with this component will play sounds depending on nearby radiation
|
||||
/datum/component/geiger_sound
|
||||
var/datum/looping_sound/geiger/sound
|
||||
|
||||
var/last_parent = null
|
||||
|
||||
/datum/component/geiger_sound/Initialize(...)
|
||||
if (!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/geiger_sound/Destroy(force)
|
||||
QDEL_NULL(sound)
|
||||
|
||||
if (!isnull(last_parent))
|
||||
UnregisterSignal(last_parent, COMSIG_IN_RANGE_OF_IRRADIATION)
|
||||
|
||||
last_parent = null
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/component/geiger_sound/RegisterWithParent()
|
||||
sound = new(list(parent), TRUE)
|
||||
|
||||
RegisterSignal(parent, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation))
|
||||
|
||||
ADD_TRAIT(parent, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, REF(src))
|
||||
|
||||
if (isitem(parent))
|
||||
var/atom/atom_parent = parent
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
||||
register_to_loc(atom_parent.loc)
|
||||
|
||||
/datum/component/geiger_sound/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_MOVABLE_MOVED,
|
||||
COMSIG_IN_RANGE_OF_IRRADIATION,
|
||||
))
|
||||
|
||||
REMOVE_TRAIT(parent, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, REF(src))
|
||||
|
||||
/datum/component/geiger_sound/proc/on_pre_potential_irradiation(datum/source, datum/radiation_pulse_information/pulse_information, insulation_to_target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
sound.last_insulation_to_target = insulation_to_target
|
||||
sound.last_radiation_pulse = pulse_information
|
||||
sound.start(source)
|
||||
|
||||
addtimer(CALLBACK(sound, TYPE_PROC_REF(/datum/looping_sound,stop)), TIME_WITHOUT_RADIATION_BEFORE_RESET, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
|
||||
/datum/component/geiger_sound/proc/on_moved(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
register_to_loc(source.loc)
|
||||
|
||||
/datum/component/geiger_sound/proc/register_to_loc(new_loc)
|
||||
if (last_parent == new_loc)
|
||||
return
|
||||
|
||||
if (!isnull(last_parent))
|
||||
UnregisterSignal(last_parent, COMSIG_IN_RANGE_OF_IRRADIATION)
|
||||
|
||||
last_parent = new_loc
|
||||
|
||||
if (!isnull(new_loc))
|
||||
RegisterSignal(new_loc, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation))
|
||||
|
||||
/datum/looping_sound/geiger
|
||||
mid_sounds = list(
|
||||
list('sound/items/geiger/low1.ogg'=1, 'sound/items/geiger/low2.ogg'=1, 'sound/items/geiger/low3.ogg'=1, 'sound/items/geiger/low4.ogg'=1),
|
||||
list('sound/items/geiger/med1.ogg'=1, 'sound/items/geiger/med2.ogg'=1, 'sound/items/geiger/med3.ogg'=1, 'sound/items/geiger/med4.ogg'=1),
|
||||
list('sound/items/geiger/high1.ogg'=1, 'sound/items/geiger/high2.ogg'=1, 'sound/items/geiger/high3.ogg'=1, 'sound/items/geiger/high4.ogg'=1),
|
||||
list('sound/items/geiger/ext1.ogg'=1, 'sound/items/geiger/ext2.ogg'=1, 'sound/items/geiger/ext3.ogg'=1, 'sound/items/geiger/ext4.ogg'=1)
|
||||
)
|
||||
mid_length = 2
|
||||
volume = 25
|
||||
|
||||
var/datum/radiation_pulse_information/last_radiation_pulse
|
||||
var/last_insulation_to_target
|
||||
|
||||
/datum/looping_sound/geiger/Destroy()
|
||||
last_radiation_pulse = null
|
||||
return ..()
|
||||
|
||||
/datum/looping_sound/geiger/get_sound()
|
||||
if (isnull(last_radiation_pulse))
|
||||
return null
|
||||
|
||||
return ..(mid_sounds[get_perceived_radiation_danger(last_radiation_pulse, last_insulation_to_target)])
|
||||
|
||||
/datum/looping_sound/geiger/stop(null_parent = FALSE)
|
||||
. = ..()
|
||||
|
||||
last_radiation_pulse = null
|
||||
@@ -0,0 +1,55 @@
|
||||
// Should be more than any minimum exposure time coming in
|
||||
#define TIME_UNTIL_DELETION (10 SECONDS)
|
||||
|
||||
/// Begins the countdown before a target can be irradiated.
|
||||
/// Added by the radiation subsystem when a pulse information has a minimum exposure time.
|
||||
/// Will clear itself out after a while.
|
||||
/datum/component/radiation_countdown
|
||||
/// The time this component was added
|
||||
var/time_added
|
||||
|
||||
/// The shortest minimum time before being irradiated.
|
||||
/// If the source has an attempted irradiation again outside this timeframe, it will go through.
|
||||
var/minimum_exposure_time
|
||||
|
||||
/datum/component/radiation_countdown/Initialize(minimum_exposure_time)
|
||||
if (!CAN_IRRADIATE(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.minimum_exposure_time = minimum_exposure_time
|
||||
|
||||
time_added = world.time
|
||||
|
||||
// to_chat(parent, span_userdanger("The air around you feels warm...perhaps you should go somewhere else.")) //Silent.
|
||||
|
||||
start_deletion_timer()
|
||||
|
||||
/datum/component/radiation_countdown/proc/start_deletion_timer()
|
||||
addtimer(CALLBACK(src, PROC_REF(remove_self)), TIME_UNTIL_DELETION, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
|
||||
/datum/component/radiation_countdown/proc/remove_self()
|
||||
// if (!HAS_TRAIT(parent, TRAIT_IRRADIATED))
|
||||
// to_chat(parent, span_notice("The air here feels safer."))
|
||||
|
||||
qdel(src)
|
||||
|
||||
/datum/component/radiation_countdown/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_IN_THRESHOLD_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation_within_range))
|
||||
|
||||
/datum/component/radiation_countdown/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_IN_THRESHOLD_OF_IRRADIATION)
|
||||
|
||||
/datum/component/radiation_countdown/proc/on_pre_potential_irradiation_within_range(datum/source, datum/radiation_pulse_information/pulse_information)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
minimum_exposure_time = min(minimum_exposure_time, pulse_information.minimum_exposure_time)
|
||||
|
||||
start_deletion_timer()
|
||||
|
||||
// Played with fire, now you might be getting irradiated.
|
||||
if (world.time - time_added >= minimum_exposure_time)
|
||||
return SKIP_MINIMUM_EXPOSURE_TIME_CHECK
|
||||
|
||||
return CANCEL_IRRADIATION
|
||||
|
||||
#undef TIME_UNTIL_DELETION
|
||||
@@ -0,0 +1,79 @@
|
||||
/// For directly applying to carbons to irradiate them, without pulses
|
||||
/datum/component/radioactive_exposure
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
|
||||
/// Base irradiation chance
|
||||
var/irradiation_chance_base
|
||||
/// Chance we have of applying irradiation
|
||||
var/irradiation_chance
|
||||
/// The amount the base chance is increased after every failed irradiation check
|
||||
var/irradiation_chance_increment
|
||||
/// Time till we attempt the next irradiation check
|
||||
var/irradiation_interval
|
||||
/// The source of irradiation, for logging
|
||||
var/source
|
||||
/// Area's where the component isnt removed if we cross to them
|
||||
var/list/radioactive_areas
|
||||
|
||||
/datum/component/radioactive_exposure/Initialize(
|
||||
minimum_exposure_time,
|
||||
irradiation_chance_base,
|
||||
irradiation_chance_increment,
|
||||
irradiation_interval,
|
||||
source,
|
||||
radioactive_areas
|
||||
)
|
||||
|
||||
if(!iscarbon(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.irradiation_chance_base = irradiation_chance_base
|
||||
src.irradiation_chance = irradiation_chance_base
|
||||
src.irradiation_chance_increment = irradiation_chance_increment
|
||||
src.irradiation_interval = irradiation_interval
|
||||
src.source = source
|
||||
src.radioactive_areas = radioactive_areas
|
||||
|
||||
// We use generally long times, so it's probably easier and more interpretable to just use a timer instead of processing the component
|
||||
addtimer(CALLBACK(src, PROC_REF(attempt_irradiate)), minimum_exposure_time)
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_EXITED_AREA, PROC_REF(on_exited))
|
||||
|
||||
var/mob/living/living_parent = parent
|
||||
living_parent.throw_alert("radioactive_area", /atom/movable/screen/alert/radioactive_area)
|
||||
|
||||
/// Try and irradiate them. If we chance fail, we come back harder
|
||||
/datum/component/radioactive_exposure/proc/attempt_irradiate()
|
||||
if(!SSradiation.wearing_rad_protected_clothing(parent) && SSradiation.can_irradiate_basic(parent))
|
||||
if(prob(irradiation_chance))
|
||||
SSradiation.irradiate(parent)
|
||||
var/atom/atom = parent
|
||||
atom.investigate_log("was irradiated by [source].", INVESTIGATE_RADIATION)
|
||||
else
|
||||
irradiation_chance += irradiation_chance_increment
|
||||
else // we're immune, either through species, clothing, already being irradiated, etcetera
|
||||
// we slowly decrease the prob chance untill we hit the base probability again
|
||||
irradiation_chance = max(irradiation_chance - irradiation_chance_increment, irradiation_chance_base)
|
||||
|
||||
// Even if they are immune, or got irradiated plan a new check in-case they lose their protection or irradiation
|
||||
addtimer(CALLBACK(src, PROC_REF(attempt_irradiate)), irradiation_interval)
|
||||
|
||||
/datum/component/radioactive_exposure/proc/on_exited(atom/movable/also_parent, area/old_area, direction)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(get_area(parent), radioactive_areas)) //we left to another area that is also radioactive, so dont do anything
|
||||
return
|
||||
|
||||
qdel(src)
|
||||
|
||||
/datum/component/radioactive_exposure/Destroy(force)
|
||||
var/mob/living/carbon/human/human_parent = parent
|
||||
human_parent.clear_alert("radioactive_area")
|
||||
|
||||
return ..()
|
||||
|
||||
/atom/movable/screen/alert/radioactive_area
|
||||
name = "Radioactive Area"
|
||||
desc = "This place is no good! We need to get some protection or get out fast!"
|
||||
// use_user_hud_icon = TRUE
|
||||
icon_state = "radioactive_area"
|
||||
@@ -69,11 +69,14 @@
|
||||
///How much the damage we take from rads is multiplied by.
|
||||
var/damage_multiplier = 1.0
|
||||
|
||||
///If we use a toony glow instead of a more emmissive one.
|
||||
var/toony = FALSE
|
||||
|
||||
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
dupe_type = /datum/component/radiation_effects
|
||||
|
||||
/datum/component/radiation_effects/Initialize(glows, radiation_glow_minor_threshold, contamination, contamination_strength, radiation_color, intensity_mod, range_mod, radiation_immunity, radiation_healing, radiation_dissipation, radiation_nutrition, radiation_nutrition_cap, glow_toggle, nutrition_toggle)
|
||||
/datum/component/radiation_effects/Initialize(glows, radiation_glow_minor_threshold, contamination, contamination_strength, radiation_color, intensity_mod, range_mod, radiation_immunity, radiation_healing, radiation_dissipation, radiation_nutrition, radiation_nutrition_cap, glow_toggle, nutrition_toggle, toony)
|
||||
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -115,16 +118,25 @@
|
||||
if(show_panel)
|
||||
add_verb(parent, /mob/living/proc/radiation_control_panel)
|
||||
|
||||
if(toony)
|
||||
src.toony = toony
|
||||
|
||||
/datum/component/radiation_effects/Destroy(force)
|
||||
var/atom/movable/parent_movable = parent
|
||||
if(show_panel)
|
||||
remove_verb(parent, /mob/living/proc/radiation_control_panel)
|
||||
|
||||
if(istype(parent_movable))//For the toony glow.
|
||||
var/filter = parent_movable.get_filter("rad_glow")
|
||||
if(filter)
|
||||
parent_movable.remove_filter("rad_glow")
|
||||
return ..()
|
||||
|
||||
/datum/component/radiation_effects/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_HANDLE_RADIATION, PROC_REF(process_component))
|
||||
RegisterSignal(parent, COMSIG_LIVING_LIFE, PROC_REF(process_glow))
|
||||
RegisterSignal(parent, COMSIG_LIVING_IRRADIATE_EFFECT, PROC_REF(handle_irradiate_effect))
|
||||
RegisterSignal(parent, COMSIG_GEIGER_COUNTER_SCAN, PROC_REF(on_geiger_counter_scan))
|
||||
|
||||
/datum/component/radiation_effects/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_HANDLE_RADIATION, COMSIG_LIVING_LIFE, COMSIG_LIVING_IRRADIATE_EFFECT))
|
||||
@@ -136,10 +148,12 @@
|
||||
if(living_guy.glow_override) //Toggled glow off while we were still actively glowing.
|
||||
living_guy.glow_override = FALSE
|
||||
living_guy.set_light(0)
|
||||
living_guy.remove_filter("rad_glow")
|
||||
return
|
||||
if(living_guy.radiation < radiation_glow_threshold)
|
||||
living_guy.glow_override = FALSE
|
||||
living_guy.set_light(0)
|
||||
living_guy.remove_filter("rad_glow")
|
||||
return
|
||||
|
||||
if(glows)
|
||||
@@ -148,12 +162,16 @@
|
||||
|
||||
living_guy.set_light(l_range = light_range, l_power = light_power, l_color = radiation_color, l_on = TRUE)
|
||||
living_guy.glow_override = TRUE
|
||||
if(toony)
|
||||
var/filter = living_guy.get_filter("rad_glow")
|
||||
if(!filter)
|
||||
create_toony_glow()
|
||||
|
||||
///Handles the radiation removal, immunity, and healing effects.
|
||||
/datum/component/radiation_effects/proc/process_component()
|
||||
SIGNAL_HANDLER
|
||||
var/mob/living/living_guy = parent
|
||||
if(living_guy.radiation > RADIATION_CAP)
|
||||
if((living_guy.radiation > RADIATION_CAP || living_guy.radiation < 0) || (living_guy.accumulated_rads > RADIATION_CAP || living_guy.accumulated_rads < 0))
|
||||
living_guy.radiation = CLAMP(living_guy.radiation,0,RADIATION_CAP)
|
||||
living_guy.accumulated_rads = CLAMP(living_guy.accumulated_rads,0,RADIATION_CAP)
|
||||
|
||||
@@ -175,7 +193,15 @@
|
||||
//End of the calculation.
|
||||
|
||||
if(contamination && living_guy.radiation > contamination_threshold)
|
||||
SSradiation.radiate(living_guy, rads * contamination_strength * rad_removal_mod)
|
||||
//SSradiation.radiate(living_guy, rads * contamination_strength * rad_removal_mod)
|
||||
radiation_pulse(
|
||||
living_guy,
|
||||
max_range = 2,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = CLAMP(rads * contamination_strength, 0, 25),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rads * contamination_strength
|
||||
)
|
||||
|
||||
///Used for radiation nutrition and healing.
|
||||
var/rads_to_utilize
|
||||
@@ -296,6 +322,31 @@
|
||||
to_chat(parent, span_info("You are [radiation_nutrition ? "now" : "no longer"] gaining nutrition from radiation."))
|
||||
return FALSE
|
||||
|
||||
/datum/component/radiation_effects/proc/create_toony_glow()
|
||||
var/atom/movable/parent_movable = parent
|
||||
if (!istype(parent_movable))
|
||||
return
|
||||
|
||||
parent_movable.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
|
||||
addtimer(CALLBACK(src, PROC_REF(toony_glow_loop), parent_movable), rand(0.1 SECONDS, 1.9 SECONDS)) // Things should look uneven
|
||||
|
||||
/datum/component/radiation_effects/proc/toony_glow_loop(atom/movable/parent_movable)
|
||||
var/filter = parent_movable.get_filter("rad_glow")
|
||||
if (!filter)
|
||||
return
|
||||
|
||||
animate(filter, alpha = 110, time = 1.5 SECONDS, loop = -1)
|
||||
animate(alpha = 40, time = 2.5 SECONDS)
|
||||
|
||||
|
||||
/datum/component/radiation_effects/proc/on_geiger_counter_scan(mob/living/living_source, mob/user, obj/item/geiger/geiger_counter)
|
||||
SIGNAL_HANDLER
|
||||
if(living_source.radiation > 0)
|
||||
if(contamination && living_source.radiation > contamination_threshold) //Are we spreading radiation?
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Subject is irradiated and offputting radiation."))
|
||||
else
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Subject is irradiated."))
|
||||
|
||||
/mob/living/proc/get_radiation_component()
|
||||
var/datum/component/radiation_effects/rad = GetComponent(/datum/component/radiation_effects)
|
||||
if(rad)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/// Marks the item as being radiation protected.
|
||||
/// Adds the TRAIT_RADIATION_PROTECTED_CLOTHING trait, as well as adding an
|
||||
/// extra bit to the examine descrpition.
|
||||
/datum/element/radiation_protected_clothing
|
||||
|
||||
/datum/element/radiation_protected_clothing/Attach(datum/target)
|
||||
. = ..()
|
||||
|
||||
if (!isclothing(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
ADD_TRAIT(target, TRAIT_RADIATION_PROTECTED_CLOTHING, REF(src))
|
||||
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
||||
|
||||
/datum/element/radiation_protected_clothing/Detach(datum/source, ...)
|
||||
REMOVE_TRAIT(source, TRAIT_RADIATION_PROTECTED_CLOTHING, REF(src))
|
||||
UnregisterSignal(source, COMSIG_ATOM_EXAMINE)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/element/radiation_protected_clothing/proc/on_examine(datum/source, mob/user, list/examine_text)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
examine_text += span_notice("A patch with a hazmat sign on the side suggests it would <b>protect you from radiation</b>.")
|
||||
@@ -1,33 +1,3 @@
|
||||
/datum/looping_sound/geiger
|
||||
mid_sounds = list(
|
||||
list('sound/items/geiger/low1.ogg'=1, 'sound/items/geiger/low2.ogg'=1, 'sound/items/geiger/low3.ogg'=1, 'sound/items/geiger/low4.ogg'=1),
|
||||
list('sound/items/geiger/med1.ogg'=1, 'sound/items/geiger/med2.ogg'=1, 'sound/items/geiger/med3.ogg'=1, 'sound/items/geiger/med4.ogg'=1),
|
||||
list('sound/items/geiger/high1.ogg'=1, 'sound/items/geiger/high2.ogg'=1, 'sound/items/geiger/high3.ogg'=1, 'sound/items/geiger/high4.ogg'=1),
|
||||
list('sound/items/geiger/ext1.ogg'=1, 'sound/items/geiger/ext2.ogg'=1, 'sound/items/geiger/ext3.ogg'=1, 'sound/items/geiger/ext4.ogg'=1)
|
||||
)
|
||||
mid_length = 1 SECOND
|
||||
volume = 25
|
||||
var/last_radiation
|
||||
|
||||
/datum/looping_sound/geiger/get_sound(starttime)
|
||||
var/danger
|
||||
switch(last_radiation)
|
||||
if(0 to RAD_LEVEL_MODERATE)
|
||||
danger = 1
|
||||
if(RAD_LEVEL_MODERATE to RAD_LEVEL_HIGH)
|
||||
danger = 2
|
||||
if(RAD_LEVEL_HIGH to RAD_LEVEL_VERY_HIGH)
|
||||
danger = 3
|
||||
if(RAD_LEVEL_VERY_HIGH to INFINITY)
|
||||
danger = 4
|
||||
else
|
||||
return null
|
||||
return ..(starttime, mid_sounds[danger])
|
||||
|
||||
/datum/looping_sound/geiger/stop()
|
||||
. = ..()
|
||||
last_radiation = 0
|
||||
|
||||
/datum/looping_sound/small_motor
|
||||
start_sound = 'sound/items/small_motor/motor_start_nopull.ogg'
|
||||
start_length = 2 SECONDS
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
/// You will need to manage adding/removing from this yourself, but I'll do the updating for you
|
||||
var/list/image/update_on_z
|
||||
|
||||
/// Radiation insulation types
|
||||
var/rad_insulation = RAD_NO_INSULATION
|
||||
|
||||
/atom/Destroy()
|
||||
if(reagents)
|
||||
QDEL_NULL(reagents)
|
||||
|
||||
@@ -310,13 +310,11 @@ GLOBAL_LIST_INIT(meteors_catastrophic, list(
|
||||
meteordrop = /obj/item/ore/uranium
|
||||
wall_power = 75
|
||||
|
||||
|
||||
/obj/effect/meteor/irradiated/meteor_effect(var/explode)
|
||||
..()
|
||||
if(explode)
|
||||
explosion(src.loc, 0, 0, 4, 3, 0)
|
||||
new /obj/effect/decal/cleanable/greenglow(get_turf(src))
|
||||
SSradiation.radiate(src, 50)
|
||||
|
||||
// This meteor fries toasters.
|
||||
/obj/effect/meteor/emp
|
||||
|
||||
@@ -197,6 +197,7 @@
|
||||
light_power = 1
|
||||
light_color = "#FFFFFF"
|
||||
light_on = TRUE
|
||||
rad_insulation = RAD_LIGHT_INSULATION
|
||||
|
||||
/obj/structure/atmospheric_retention_field/update_icon()
|
||||
cut_overlays() //overlays.Cut()
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
if(occupant.bodytemperature < 261 && occupant.bodytemperature >= 70) //Patch by Aranclanos to stop people from taking burn damage after being ejected
|
||||
occupant.bodytemperature = 261 // Changed to 70 from 140 by Zuhayr due to reoccurance of bug.
|
||||
unbuckle_mob(occupant, force = TRUE)
|
||||
//REMOVE_TRAIT(occupant, TRAIT_STASIS, REF(src)) //Stops life almost entirely, so not done here.
|
||||
occupant = null
|
||||
current_heat_capacity = initial(current_heat_capacity)
|
||||
update_use_power(USE_POWER_IDLE)
|
||||
@@ -297,6 +298,7 @@
|
||||
if(M.health > -100 && (M.health < 0 || M.sleeping))
|
||||
to_chat(M, span_boldnotice("You feel a cold liquid surround you. Your skin starts to freeze up."))
|
||||
occupant = M
|
||||
//ADD_TRAIT(occupant, TRAIT_STASIS, REF(src)) //Stops life almost entirely, so not done here.
|
||||
buckle_mob(occupant, forced = TRUE, check_loc = FALSE)
|
||||
vis_contents |= occupant
|
||||
occupant.pixel_y += 19
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
var/knock_hammer_sound = 'sound/weapons/sonic_jackhammer.ogg'
|
||||
var/knock_unpowered_sound = 'sound/machines/door/knock_glass.ogg'
|
||||
var/mob/hold_open
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
// Frozen airlocks and how to deice them
|
||||
var/frozen = FALSE
|
||||
|
||||
@@ -381,14 +381,26 @@
|
||||
icon = 'icons/obj/doors/Dooruranium.dmi'
|
||||
mineral = MAT_URANIUM
|
||||
var/last_event = 0
|
||||
var/rad_power = 7.5
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/machinery/door/airlock/uranium/process()
|
||||
if(world.time > last_event+20)
|
||||
if(prob(50))
|
||||
SSradiation.radiate(src, rad_power)
|
||||
last_event = world.time
|
||||
..()
|
||||
/obj/machinery/door/airlock/uranium/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 5,
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/machinery/door/airlock/uranium_appearance
|
||||
icon = 'icons/obj/doors/Dooruranium.dmi'
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
icon_state = icon_state_closed
|
||||
else
|
||||
icon_state = icon_state_open
|
||||
SSradiation.resistance_cache.Remove(get_turf(src))
|
||||
return
|
||||
|
||||
// Proc: emag_act()
|
||||
@@ -90,6 +89,7 @@
|
||||
update_nearby_tiles()
|
||||
update_icon()
|
||||
set_opacity(0)
|
||||
rad_insulation = RAD_NO_INSULATION
|
||||
addtimer(CALLBACK(src, PROC_REF(complete_force_open)), 1.5 SECONDS, TIMER_DELETE_ME|TIMER_UNIQUE)
|
||||
|
||||
/obj/machinery/door/blast/proc/complete_force_open()
|
||||
@@ -112,6 +112,7 @@
|
||||
density = TRUE
|
||||
update_nearby_tiles()
|
||||
update_icon()
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
if(istransparent)
|
||||
set_opacity(0)
|
||||
else
|
||||
|
||||
@@ -448,7 +448,6 @@
|
||||
icon_state = "door1"
|
||||
else
|
||||
icon_state = "door0"
|
||||
SSradiation.resistance_cache.Remove(get_turf(src))
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -114,9 +114,16 @@
|
||||
..()
|
||||
if(phasing)
|
||||
phasing = FALSE
|
||||
SSradiation.radiate(get_turf(src), 30)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE * 5,
|
||||
strength = 250
|
||||
)
|
||||
log_append_to_last("WARNING: BLUESPACE DRIVE INSTABILITY DETECTED. DISABLING DRIVE.",1)
|
||||
visible_message(span_alien("The [src.name] appears to flicker, before its silhouette stabilizes!"))
|
||||
|
||||
return
|
||||
|
||||
/obj/mecha/combat/phazon/janus/dynbulletdamage(var/obj/item/projectile/Proj)
|
||||
|
||||
@@ -138,7 +138,13 @@
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/generator/nuclear/process()
|
||||
if(..())
|
||||
SSradiation.radiate(src, (rad_per_cycle * 3))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 25
|
||||
)
|
||||
return
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/generator/nuclear/critfail()
|
||||
|
||||
@@ -23,10 +23,40 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/Initialize(mapload, _age)
|
||||
. = ..()
|
||||
QDEL_IN(src, 2 MINUTES)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/process()
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 2
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/dirt
|
||||
name = "dirt"
|
||||
|
||||
@@ -2,7 +2,35 @@
|
||||
/obj/effect/map_effect/radiation_emitter
|
||||
name = "radiation emitter"
|
||||
icon_state = "radiation_emitter"
|
||||
var/range = 3
|
||||
var/radiation_power = 30 // Bigger numbers means more radiation.
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
var/strength = 50
|
||||
|
||||
/obj/effect/map_effect/radiation_emitter/process()
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/effect/map_effect/radiation_emitter/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = range,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = radiation_power,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = strength
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
|
||||
/obj/effect/map_effect/radiation_emitter/Initialize(mapload)
|
||||
START_PROCESSING(SSobj, src)
|
||||
@@ -12,8 +40,7 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/map_effect/radiation_emitter/process()
|
||||
SSradiation.radiate(src, radiation_power)
|
||||
|
||||
/obj/effect/map_effect/radiation_emitter/strong
|
||||
range = 7
|
||||
radiation_power = 100
|
||||
strength = 250
|
||||
|
||||
@@ -195,6 +195,7 @@
|
||||
syringe = null
|
||||
|
||||
/obj/structure/closet/body_bag/cryobag/Entered(atom/movable/AM)
|
||||
ADD_TRAIT(AM, TRAIT_STASIS, REF(src))
|
||||
if(ishuman(AM))
|
||||
var/mob/living/carbon/human/H = AM
|
||||
H.Stasis(stasis_level)
|
||||
@@ -209,6 +210,7 @@
|
||||
..()
|
||||
|
||||
/obj/structure/closet/body_bag/cryobag/Exited(atom/movable/AM)
|
||||
REMOVE_TRAIT(AM, TRAIT_STASIS, REF(src))
|
||||
if(ishuman(AM))
|
||||
var/mob/living/carbon/human/H = AM
|
||||
H.Stasis(0)
|
||||
|
||||
@@ -575,6 +575,9 @@
|
||||
/obj/item/shockpaddles/standalone
|
||||
desc = "A pair of shockpaddles powered by an experimental miniaturized reactor" //Inspired by the advanced e-gun
|
||||
var/fail_counter = 0
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/shockpaddles/standalone/Destroy()
|
||||
. = ..()
|
||||
@@ -585,12 +588,25 @@
|
||||
return 1
|
||||
|
||||
/obj/item/shockpaddles/standalone/checked_use(var/charge_amt)
|
||||
SSradiation.radiate(src, charge_amt/12) //just a little bit of radiation. It's the price you pay for being powered by magic I guess
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 50
|
||||
)
|
||||
return 1
|
||||
|
||||
/obj/item/shockpaddles/standalone/process()
|
||||
if(fail_counter > 0)
|
||||
SSradiation.radiate(src, fail_counter--)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 15
|
||||
)
|
||||
fail_counter--
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
@@ -1,102 +1,136 @@
|
||||
//Geiger counter
|
||||
//Rewritten version of TG's geiger counter
|
||||
//I opted to show exact radiation levels
|
||||
|
||||
/obj/item/geiger
|
||||
name = "geiger counter"
|
||||
desc = "A handheld device used for detecting and measuring radiation in an area."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
/obj/item/geiger //DISCLAIMER: I know nothing about how real-life Geiger counters work. This will not be realistic. ~Xhuis
|
||||
name = "\improper Geiger counter"
|
||||
desc = "A handheld device used for detecting and measuring radiation pulses."
|
||||
icon = 'icons/obj/devices/scanner.dmi'
|
||||
icon_state = "geiger_off"
|
||||
item_state = "multitool"
|
||||
item_icons = list(
|
||||
slot_l_hand_str = 'icons/mob/inhands/equipment/tools_lefthand.dmi',
|
||||
slot_r_hand_str = 'icons/mob/inhands/equipment/tools_righthand.dmi',
|
||||
)
|
||||
w_class = ITEMSIZE_SMALL
|
||||
var/scanning = 0
|
||||
var/radiation_count = 0
|
||||
var/datum/looping_sound/geiger/soundloop
|
||||
slot_flags = SLOT_BELT
|
||||
item_flags = NOBLUDGEON
|
||||
matter = list(/datum/material/steel = SHEET_MATERIAL_AMOUNT * 1.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.5)
|
||||
|
||||
var/last_perceived_radiation_danger = null
|
||||
|
||||
var/scanning = FALSE
|
||||
|
||||
var/mounted = FALSE
|
||||
|
||||
pickup_sound = 'sound/items/pickup/device.ogg'
|
||||
drop_sound = 'sound/items/drop/device.ogg'
|
||||
|
||||
/obj/item/geiger/Initialize(mapload)
|
||||
soundloop = new(list(src), FALSE)
|
||||
return ..()
|
||||
. = ..()
|
||||
|
||||
/obj/item/geiger/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(soundloop)
|
||||
return ..()
|
||||
|
||||
/obj/item/geiger/process()
|
||||
get_radiation()
|
||||
|
||||
/obj/item/geiger/proc/get_radiation()
|
||||
if(!scanning)
|
||||
return
|
||||
radiation_count = SSradiation.get_rads_at_turf(get_turf(src))
|
||||
update_icon()
|
||||
update_sound()
|
||||
RegisterSignal(src, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation))
|
||||
|
||||
/obj/item/geiger/examine(mob/user)
|
||||
. = ..()
|
||||
get_radiation()
|
||||
. += span_warning("[scanning ? "Ambient" : "Stored"] radiation level: [radiation_count ? radiation_count : "0"]Bq.")
|
||||
|
||||
/obj/item/geiger/rad_act(amount)
|
||||
if(!amount || !scanning)
|
||||
return FALSE
|
||||
|
||||
if(amount > radiation_count)
|
||||
radiation_count = amount
|
||||
|
||||
update_icon()
|
||||
update_sound()
|
||||
|
||||
/obj/item/geiger/proc/update_sound()
|
||||
var/datum/looping_sound/geiger/loop = soundloop
|
||||
if(!scanning)
|
||||
loop.stop()
|
||||
return
|
||||
if(!radiation_count)
|
||||
loop.stop()
|
||||
return
|
||||
loop.last_radiation = radiation_count
|
||||
loop.start()
|
||||
|
||||
/obj/item/geiger/attack_self(mob/user)
|
||||
. = ..(user)
|
||||
if(.)
|
||||
return TRUE
|
||||
if(mounted)
|
||||
return
|
||||
scanning = !scanning
|
||||
if(scanning)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
update_sound()
|
||||
to_chat(user, span_notice("[icon2html(src, user.client)] You switch [scanning ? "on" : "off"] \the [src]."))
|
||||
. += span_info("Alt-click it to clear stored radiation levels.")
|
||||
switch(last_perceived_radiation_danger)
|
||||
if(null)
|
||||
. += span_notice("Ambient radiation level count reports that all is well.")
|
||||
if(PERCEIVED_RADIATION_DANGER_LOW)
|
||||
. += span_alert("Ambient radiation levels slightly above average.")
|
||||
if(PERCEIVED_RADIATION_DANGER_MEDIUM)
|
||||
. += span_warning("Ambient radiation levels above average.")
|
||||
if(PERCEIVED_RADIATION_DANGER_HIGH)
|
||||
. += span_danger("Ambient radiation levels highly above average.")
|
||||
if(PERCEIVED_RADIATION_DANGER_EXTREME)
|
||||
. += span_suicide("Ambient radiation levels reaching critical level!")
|
||||
|
||||
/obj/item/geiger/update_icon()
|
||||
if(!scanning)
|
||||
icon_state = "geiger_off"
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
switch(radiation_count)
|
||||
switch(last_perceived_radiation_danger)
|
||||
if(null)
|
||||
icon_state = "geiger_on_1"
|
||||
if(-INFINITY to RAD_LEVEL_LOW)
|
||||
icon_state = "geiger_on_1"
|
||||
if(RAD_LEVEL_LOW to RAD_LEVEL_MODERATE)
|
||||
if(PERCEIVED_RADIATION_DANGER_LOW)
|
||||
icon_state = "geiger_on_2"
|
||||
if(RAD_LEVEL_MODERATE to RAD_LEVEL_HIGH)
|
||||
if(PERCEIVED_RADIATION_DANGER_MEDIUM)
|
||||
icon_state = "geiger_on_3"
|
||||
if(RAD_LEVEL_HIGH to RAD_LEVEL_VERY_HIGH)
|
||||
if(PERCEIVED_RADIATION_DANGER_HIGH)
|
||||
icon_state = "geiger_on_4"
|
||||
if(RAD_LEVEL_VERY_HIGH to INFINITY)
|
||||
if(PERCEIVED_RADIATION_DANGER_EXTREME)
|
||||
icon_state = "geiger_on_5"
|
||||
return ..()
|
||||
|
||||
///////////////////////
|
||||
/obj/item/geiger/attack_self(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
scanning = !scanning
|
||||
|
||||
if (scanning)
|
||||
AddComponent(/datum/component/geiger_sound)
|
||||
else
|
||||
qdel(GetComponent(/datum/component/geiger_sound))
|
||||
|
||||
update_icon()
|
||||
balloon_alert(user, "switch [scanning ? "on" : "off"]")
|
||||
|
||||
/obj/item/geiger/afterattack(atom/interacting_with, mob/user, proximity_flag, click_parameters)
|
||||
. = ..()
|
||||
if(SHOULD_SKIP_INTERACTION(interacting_with, src, user))
|
||||
return NONE
|
||||
return attack_at_range(interacting_with, user, proximity_flag, click_parameters)
|
||||
|
||||
/obj/item/geiger/proc/attack_at_range(atom/interacting_with, mob/living/user, proximity_flag, click_parameters) //This is ranged_interact_with_atom on TG but we don't have that yet.
|
||||
if(!CAN_IRRADIATE(interacting_with))
|
||||
return NONE
|
||||
|
||||
user.visible_message(span_notice("[user] scans [interacting_with] with [src]."), span_notice("You scan [interacting_with]'s radiation levels with [src]..."))
|
||||
addtimer(CALLBACK(src, PROC_REF(scan), interacting_with, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/item/geiger/equipped(mob/user, slot, initial)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(user, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation))
|
||||
|
||||
/obj/item/geiger/dropped(mob/user, silent = FALSE)
|
||||
. = ..()
|
||||
|
||||
UnregisterSignal(user, COMSIG_IN_RANGE_OF_IRRADIATION)
|
||||
|
||||
/obj/item/geiger/proc/on_pre_potential_irradiation(datum/source, datum/radiation_pulse_information/pulse_information, insulation_to_target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
last_perceived_radiation_danger = get_perceived_radiation_danger(pulse_information, insulation_to_target)
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_perceived_danger)), TIME_WITHOUT_RADIATION_BEFORE_RESET, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
|
||||
if (scanning)
|
||||
update_icon()
|
||||
|
||||
/obj/item/geiger/proc/reset_perceived_danger()
|
||||
last_perceived_radiation_danger = null
|
||||
if (scanning)
|
||||
update_icon()
|
||||
|
||||
/obj/item/geiger/proc/scan(atom/target, mob/user)
|
||||
if (SEND_SIGNAL(target, COMSIG_GEIGER_COUNTER_SCAN, user, src) & COMSIG_GEIGER_COUNTER_SCAN_SUCCESSFUL)
|
||||
return
|
||||
|
||||
if(isliving(target))
|
||||
var/mob/living/living_target = target
|
||||
if(living_target.radiation)
|
||||
to_chat(user, span_notice("[icon2html(src, user)] [living_target] is reporting a radiation level of [living_target.radiation]."))
|
||||
return
|
||||
|
||||
to_chat(user, span_notice("[icon2html(src, user)] [isliving(target) ? "Subject" : "Target"] is free of radioactive contamination."))
|
||||
|
||||
/obj/item/geiger/click_alt(mob/living/user)
|
||||
if(!scanning)
|
||||
to_chat(user, span_warning("[src] must be on to reset its radiation level!"))
|
||||
return CLICK_ACTION_BLOCKING
|
||||
to_chat(user, span_notice("You flush [src]'s radiation counts, resetting it to normal."))
|
||||
last_perceived_radiation_danger = null
|
||||
update_icon()
|
||||
return CLICK_ACTION_SUCCESS
|
||||
|
||||
/obj/item/geiger/wall
|
||||
name = "mounted geiger counter"
|
||||
@@ -105,8 +139,7 @@
|
||||
icon_state = "geiger_wall"
|
||||
item_state = "geiger_wall"
|
||||
anchored = TRUE
|
||||
scanning = 1
|
||||
radiation_count = 0
|
||||
scanning = TRUE
|
||||
plane = TURF_PLANE
|
||||
layer = ABOVE_TURF_LAYER
|
||||
w_class = ITEMSIZE_LARGE
|
||||
@@ -118,41 +151,25 @@
|
||||
mounted = TRUE
|
||||
|
||||
/obj/item/geiger/wall/Initialize(mapload)
|
||||
START_PROCESSING(SSobj, src)
|
||||
soundloop = new(list(src), FALSE)
|
||||
return ..()
|
||||
. = ..()
|
||||
if(scanning)
|
||||
AddComponent(/datum/component/geiger_sound)
|
||||
|
||||
/obj/item/geiger/wall/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(soundloop)
|
||||
return ..()
|
||||
|
||||
/obj/item/geiger/wall/attack_self(mob/user)
|
||||
. = ..(user)
|
||||
if(.)
|
||||
return TRUE
|
||||
scanning = !scanning
|
||||
update_icon()
|
||||
update_sound()
|
||||
to_chat(user, span_notice("[icon2html(src, user.client)] You switch [scanning ? "on" : "off"] \the [src]."))
|
||||
|
||||
/obj/item/geiger/wall/update_icon()
|
||||
if(!scanning)
|
||||
icon_state = "geiger_wall-p"
|
||||
return 1
|
||||
|
||||
switch(radiation_count)
|
||||
switch(last_perceived_radiation_danger)
|
||||
if(null)
|
||||
icon_state = "geiger_level_1"
|
||||
if(-INFINITY to RAD_LEVEL_LOW)
|
||||
icon_state = "geiger_level_1"
|
||||
if(RAD_LEVEL_LOW to RAD_LEVEL_MODERATE)
|
||||
if(PERCEIVED_RADIATION_DANGER_LOW)
|
||||
icon_state = "geiger_level_2"
|
||||
if(RAD_LEVEL_MODERATE to RAD_LEVEL_HIGH)
|
||||
if(PERCEIVED_RADIATION_DANGER_MEDIUM)
|
||||
icon_state = "geiger_level_3"
|
||||
if(RAD_LEVEL_HIGH to RAD_LEVEL_VERY_HIGH)
|
||||
if(PERCEIVED_RADIATION_DANGER_HIGH)
|
||||
icon_state = "geiger_level_4"
|
||||
if(RAD_LEVEL_VERY_HIGH to INFINITY)
|
||||
if(PERCEIVED_RADIATION_DANGER_EXTREME)
|
||||
icon_state = "geiger_level_5"
|
||||
|
||||
/obj/item/geiger/wall/attack_ai(mob/user as mob)
|
||||
|
||||
@@ -27,18 +27,58 @@
|
||||
name = "misshapen manhole cover"
|
||||
desc = "The top of this twisted chunk of metal is faintly stamped with a five pointed star. 'Property of US Army, Pascal B - 1957'."
|
||||
catalogue_data = list(/datum/category_item/catalogue/information/objects/pascalb)
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/poi/pascalb/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/poi/pascalb/process()
|
||||
SSradiation.radiate(src, 5)
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/item/poi/pascalb/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 25
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/poi/pascalb/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/poi/pascalb/deadly //For testing purposes, mainly.
|
||||
|
||||
/obj/item/poi/pascalb/deadly/radiate()
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = 100,
|
||||
strength = 250
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/datum/category_item/catalogue/information/objects/oldreactor
|
||||
name = "Object - Zorren Fission Reactor Rack"
|
||||
desc = "Prior to Humanity's arrival in the virgo-erigone space, introducing advanced phoron technologies, \
|
||||
@@ -78,15 +118,38 @@
|
||||
name = "ruptured fission reactor rack"
|
||||
desc = "This broken hunk of machinery looks extremely dangerous."
|
||||
catalogue_data = list(/datum/category_item/catalogue/information/objects/oldreactor)
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/poi/brokenoldreactor/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/poi/brokenoldreactor/process()
|
||||
SSradiation.radiate(src, 25)
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/item/poi/brokenoldreactor/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 50
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/poi/brokenoldreactor/Destroy()
|
||||
UnregisterSignal(src, COMSIG_ATOM_PROPAGATE_RAD_PULSE)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -1100,9 +1100,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM
|
||||
user.drop_from_inventory(e)
|
||||
log_and_message_admins("[user] dusted themselves and caused massive radiation with [src]!",user)
|
||||
user.dust()
|
||||
var/rads = 500
|
||||
SSradiation.radiate(src, rads)
|
||||
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 12,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE * 2,
|
||||
strength = 300
|
||||
)
|
||||
set_light(5)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
var/upgrading = FALSE
|
||||
var/applies_material_colour = 1
|
||||
var/wall_type = /turf/simulated/wall
|
||||
rad_insulation = RAD_VERY_LIGHT_INSULATION
|
||||
|
||||
/obj/structure/girder/Initialize(mapload, var/material_key)
|
||||
. = ..()
|
||||
@@ -42,9 +43,16 @@
|
||||
/obj/structure/girder/proc/radiate()
|
||||
var/total_radiation = girder_material.radioactivity + (reinf_material ? reinf_material.radioactivity / 2 : 0)
|
||||
if(!total_radiation)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
SSradiation.radiate(src, total_radiation)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = total_radiation
|
||||
)
|
||||
return total_radiation
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
density = FALSE
|
||||
layer = ABOVE_TURF_LAYER
|
||||
can_atmos_pass = ATMOS_PASS_NO
|
||||
rad_insulation = RAD_LIGHT_INSULATION
|
||||
alpha = 150
|
||||
|
||||
/obj/structure/holosign/barrier/combifan/Destroy()
|
||||
@@ -75,6 +76,7 @@
|
||||
icon_state = "holo_medical"
|
||||
alpha = 125
|
||||
var/buzzed = 0
|
||||
rad_insulation = RAD_NO_INSULATION
|
||||
|
||||
/obj/structure/holosign/barrier/medical/CanPass(atom/movable/mover, border_dir)
|
||||
. = ..()
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
var/can_pick = TRUE //can it be picked/bypassed?
|
||||
var/lock_difficulty = 1 //multiplier to picking/bypassing time
|
||||
var/keysound = 'sound/items/toolbelt_equip.ogg'
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
/obj/structure/simple_door/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
TemperatureAct(exposed_temperature)
|
||||
@@ -240,19 +241,57 @@
|
||||
/obj/structure/simple_door/process()
|
||||
if(!material.radioactivity)
|
||||
return
|
||||
SSradiation.radiate(src, round(material.radioactivity/3))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = round((material.radioactivity * 0.33), 0.1),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = material.radioactivity
|
||||
)
|
||||
|
||||
/obj/structure/simple_door/iron/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_IRON)
|
||||
|
||||
/obj/structure/simple_door/silver
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
|
||||
/obj/structure/simple_door/silver/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_SILVER)
|
||||
|
||||
/obj/structure/simple_door/gold
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
|
||||
/obj/structure/simple_door/gold/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_GOLD)
|
||||
|
||||
/obj/structure/simple_door/uranium
|
||||
rad_insulation = RAD_NO_INSULATION
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/structure/simple_door/uranium/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_URANIUM)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/structure/simple_door/uranium/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 5
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/structure/simple_door/sandstone/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_SANDSTONE)
|
||||
@@ -260,9 +299,13 @@
|
||||
/obj/structure/simple_door/phoron/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_PHORON)
|
||||
|
||||
/obj/structure/simple_door/diamond
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/obj/structure/simple_door/diamond/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_DIAMOND)
|
||||
|
||||
//I was going to give wooden doors RAD_VERY_LIGHT_INSULATION but they need a proper parent instead of this garbage.
|
||||
/obj/structure/simple_door/wood/Initialize(mapload,var/material_name)
|
||||
. = ..(mapload, material_name || MAT_WOOD)
|
||||
knock_sound = 'sound/machines/door/knock_wood.wav'
|
||||
|
||||
@@ -261,10 +261,8 @@
|
||||
|
||||
//Yes, showers are super powerful as far as washing goes.
|
||||
/obj/machinery/shower/proc/wash_atom(atom/A)
|
||||
/* //TG cleans rads and only does CLEAN_WASH, not sure if that's wanted here.
|
||||
A.wash(CLEAN_RAD | CLEAN_TYPE_WEAK) // Clean radiation non-instantly
|
||||
A.wash(CLEAN_WASH)
|
||||
*/
|
||||
A.wash(CLEAN_SCRUB)
|
||||
reagents.splash(A, reaction_volume / 20, 1, TRUE, min_spill = 0, max_spill = 0) //Reaction volume needs to be divided by 20 due to a larger internal volume
|
||||
|
||||
@@ -274,6 +272,7 @@
|
||||
check_heat(L)
|
||||
L.extinguish_mob()
|
||||
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
|
||||
L.radiation = CLAMP(L.radiation - 5, 0, RADIATION_CAP)
|
||||
|
||||
if(!iscarbon(A))
|
||||
return
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass.
|
||||
var/silicate = 0 // number of units of silicate
|
||||
var/fulltile = FALSE // Set to true on full-tile variants.
|
||||
rad_insulation = RAD_VERY_LIGHT_INSULATION //Windows can have multiple placed on one tile, meaning you have to account for the potential that someone could just build a bunch of windows on one tile to prevent rads entirely.
|
||||
|
||||
/obj/structure/window/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -514,6 +515,7 @@
|
||||
maxhealth = 80
|
||||
fulltile = TRUE
|
||||
flags = NONE
|
||||
rad_insulation = RAD_LIGHT_INSULATION
|
||||
|
||||
/obj/structure/window/phoronreinforced
|
||||
name = "reinforced borosilicate window"
|
||||
@@ -527,12 +529,14 @@
|
||||
damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
|
||||
maxhealth = 80.0
|
||||
force_threshold = 10
|
||||
rad_insulation = RAD_LIGHT_INSULATION
|
||||
|
||||
/obj/structure/window/phoronreinforced/full
|
||||
icon_state = "phoronrwindow-full"
|
||||
maxhealth = 160
|
||||
fulltile = TRUE
|
||||
flags = NONE
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
/obj/structure/window/reinforced
|
||||
name = "reinforced window"
|
||||
@@ -578,6 +582,7 @@
|
||||
basestate = "w"
|
||||
dir = 5
|
||||
force_threshold = 7
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
/obj/structure/window/reinforced/polarized
|
||||
name = "electrochromic window"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
damage_per_fire_tick = 1.0
|
||||
maxhealth = 100.0
|
||||
force_threshold = 10
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/obj/structure/window/titanium/full
|
||||
icon_state = "window-full"
|
||||
@@ -30,6 +31,7 @@
|
||||
damage_per_fire_tick = 1.0
|
||||
maxhealth = 120.0
|
||||
force_threshold = 10
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/obj/structure/window/plastitanium/full
|
||||
icon_state = "window-full"
|
||||
|
||||
@@ -306,6 +306,10 @@
|
||||
soundin = pick(
|
||||
'sound/effects/mech/powerloader_step.ogg',
|
||||
'sound/effects/mech/powerloader_step2.ogg')
|
||||
if ("sizzle")
|
||||
soundin = pick(
|
||||
'sound/effects/wounds/sizzle1.ogg',
|
||||
'sound/effects/wounds/sizzle2.ogg')
|
||||
return soundin
|
||||
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
var/join_flags = 0 //Bitstring to represent adjacency of joining walls
|
||||
var/join_group = "shuttle" //A tag for what other walls to join with. Null if you don't want them to.
|
||||
var/static/list/antilight_cache
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
/turf/simulated/shuttle/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -312,6 +313,36 @@
|
||||
/turf/simulated/floor/tiled/material/uranium
|
||||
icon_state = "uranium"
|
||||
initial_flooring = /datum/decl/flooring/tiling/material/uranium
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/turf/simulated/floor/tiled/material/uranium/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_ATOM_PROPAGATE_RAD_PULSE, PROC_REF(radiate))
|
||||
|
||||
/turf/simulated/floor/tiled/material/uranium/Destroy()
|
||||
UnregisterSignal(src, COMSIG_ATOM_PROPAGATE_RAD_PULSE)
|
||||
. = ..()
|
||||
|
||||
/turf/simulated/floor/tiled/material/uranium/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 1,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 1
|
||||
)
|
||||
propagate_radiation_pulse()
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/datum/decl/flooring/tiling/material/uranium
|
||||
name = "uranium floor"
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
if(can_open == WALL_OPENING)
|
||||
return
|
||||
|
||||
SSradiation.resistance_cache.Remove(src)
|
||||
|
||||
if(density)
|
||||
can_open = WALL_OPENING
|
||||
//flick("[material.icon_base]fwall_opening", src)
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
else if(material.opacity < 0.5 && opacity)
|
||||
set_light(0)
|
||||
|
||||
SSradiation.resistance_cache.Remove(src)
|
||||
update_connections(1)
|
||||
update_icon()
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/turf/simulated/wall/r_wall
|
||||
icon_state = "rgeneric"
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
/turf/simulated/wall/r_wall/Initialize(mapload)
|
||||
. = ..(mapload, MAT_PLASTEEL,MAT_PLASTEEL) //3strong
|
||||
|
||||
@@ -9,30 +10,44 @@
|
||||
. = ..(mapload, MAT_STEELHULL, null, MAT_STEELHULL)
|
||||
/turf/simulated/wall/rshull
|
||||
icon_state = "hull-r_steel"
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
/turf/simulated/wall/rshull/Initialize(mapload)
|
||||
. = ..(mapload, MAT_STEELHULL, MAT_STEELHULL, MAT_STEELHULL)
|
||||
/turf/simulated/wall/pshull
|
||||
icon_state = "hull-plasteel"
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
/turf/simulated/wall/pshull/Initialize(mapload) //Spaaaace-er ship.
|
||||
. = ..(mapload, MAT_PLASTEELHULL, null, MAT_PLASTEELHULL)
|
||||
/turf/simulated/wall/rpshull
|
||||
icon_state = "hull-r_plasteel"
|
||||
/turf/simulated/wall/rpshull/Initialize(mapload)
|
||||
. = ..(mapload, MAT_PLASTEELHULL, MAT_PLASTEELHULL, MAT_PLASTEELHULL)
|
||||
|
||||
/turf/simulated/wall/dshull
|
||||
icon_state = "hull-durasteel"
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
|
||||
/turf/simulated/wall/dshull/Initialize(mapload) //Spaaaace-est ship.
|
||||
. = ..(mapload, MAT_DURASTEELHULL, null, MAT_DURASTEELHULL)
|
||||
|
||||
/turf/simulated/wall/rdshull
|
||||
icon_state = "hull-r_durasteel"
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/turf/simulated/wall/rdshull/Initialize(mapload)
|
||||
. = ..(mapload, MAT_DURASTEELHULL, MAT_DURASTEELHULL, MAT_DURASTEELHULL)
|
||||
|
||||
/turf/simulated/wall/thull
|
||||
icon_state = "hull-titanium"
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
|
||||
/turf/simulated/wall/thull/Initialize(mapload)
|
||||
. = ..(mapload, MAT_TITANIUMHULL, null, MAT_TITANIUMHULL)
|
||||
|
||||
/turf/simulated/wall/rthull
|
||||
icon_state = "hull-r_titanium"
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/turf/simulated/wall/rthull/Initialize(mapload)
|
||||
. = ..(mapload, MAT_TITANIUMHULL, MAT_TITANIUMHULL, MAT_TITANIUMHULL)
|
||||
|
||||
@@ -56,8 +71,16 @@
|
||||
. = ..(mapload, MAT_GOLD)
|
||||
/turf/simulated/wall/silver/Initialize(mapload)
|
||||
. = ..(mapload, MAT_SILVER)
|
||||
|
||||
/turf/simulated/wall/lead
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/turf/simulated/wall/lead/Initialize(mapload)
|
||||
. = ..(mapload, MAT_LEAD)
|
||||
|
||||
/turf/simulated/wall/r_lead
|
||||
rad_insulation = RAD_EXTREME_INSULATION
|
||||
|
||||
/turf/simulated/wall/r_lead/Initialize(mapload)
|
||||
. = ..(mapload, MAT_LEAD, MAT_LEAD)
|
||||
/turf/simulated/wall/phoron/Initialize(mapload)
|
||||
@@ -80,11 +103,13 @@
|
||||
|
||||
/turf/simulated/wall/concrete
|
||||
icon_state = "brick"
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
|
||||
/turf/simulated/wall/concrete/Initialize(mapload)
|
||||
. = ..(mapload, MAT_CONCRETE) //3strong
|
||||
|
||||
/turf/simulated/wall/r_concrete
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
icon_state = "rbrick"
|
||||
|
||||
/turf/simulated/wall/r_concrete/Initialize(mapload)
|
||||
@@ -98,6 +123,9 @@
|
||||
/turf/simulated/wall/titanium/Initialize(mapload)
|
||||
. = ..(mapload, MAT_TITANIUM)
|
||||
|
||||
/turf/simulated/wall/durasteel
|
||||
rad_insulation = RAD_HEAVY_INSULATION
|
||||
|
||||
/turf/simulated/wall/durasteel/Initialize(mapload)
|
||||
. = ..(mapload, MAT_DURASTEEL, MAT_DURASTEEL)
|
||||
|
||||
|
||||
@@ -215,6 +215,33 @@ GLOBAL_LIST_EMPTY(flesh_overlay_cache)
|
||||
/turf/simulated/wall/uranium
|
||||
icon_state = "uranium"
|
||||
icon = 'icons/turf/wall_masks_vr.dmi'
|
||||
var/last_event = 0
|
||||
|
||||
/turf/simulated/wall/uranium/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_ATOM_PROPAGATE_RAD_PULSE, PROC_REF(radiate))
|
||||
|
||||
/turf/simulated/wall/uranium/Destroy()
|
||||
UnregisterSignal(src, COMSIG_ATOM_PROPAGATE_RAD_PULSE)
|
||||
. = ..()
|
||||
|
||||
/turf/simulated/wall/uranium/radiate()
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 5
|
||||
)
|
||||
propagate_radiation_pulse()
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/turf/simulated/wall/virgo2
|
||||
icon_state = "virgo2"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
// There's basically always going to be wall connections, making this lazy doesn't seem like it'd help much unless you wanted to make it bitflags instead.
|
||||
var/list/wall_connections = list("0", "0", "0", "0")
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
// Walls always hide the stuff below them.
|
||||
/turf/simulated/wall/levelupdate()
|
||||
@@ -297,11 +298,19 @@
|
||||
return
|
||||
|
||||
/turf/simulated/wall/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
var/total_radiation = material.radioactivity + (reinf_material ? reinf_material.radioactivity / 2 : 0) + (girder_material ? girder_material.radioactivity / 2 : 0)
|
||||
if(!total_radiation)
|
||||
return
|
||||
|
||||
SSradiation.radiate(src, total_radiation)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = total_radiation,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = total_radiation
|
||||
)
|
||||
return total_radiation
|
||||
|
||||
/turf/simulated/wall/proc/burn(temperature)
|
||||
|
||||
@@ -21,7 +21,20 @@
|
||||
attack_verb = "splashes"
|
||||
|
||||
/datum/blob_type/radioactive_ooze/on_pulse(var/obj/structure/blob/B)
|
||||
SSradiation.radiate(B, 200)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 75
|
||||
)
|
||||
|
||||
/datum/blob_type/radioactive_ooze/on_chunk_tick(obj/item/blobcore_chunk/B)
|
||||
SSradiation.radiate(B, rand(25,100))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE * 0.5,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 25
|
||||
)
|
||||
|
||||
@@ -34,17 +34,26 @@
|
||||
var/obj/item/clothing/head/helmet/space/rig/helmet = holder.helmet
|
||||
var/obj/item/clothing/gloves/gauntlets/rig/gloves = holder.gloves
|
||||
|
||||
var/list/items_to_update = list()
|
||||
|
||||
to_chat(H, span_boldnotice("You activate your suit's powered radiation shielding."))
|
||||
stored_rad_armor = holder.armor["rad"]
|
||||
if(boots)
|
||||
boots.armor["rad"] = 100
|
||||
items_to_update += boots
|
||||
if(chest)
|
||||
chest.armor["rad"] = 100
|
||||
items_to_update += chest
|
||||
if(helmet)
|
||||
helmet.armor["rad"] = 100
|
||||
items_to_update += helmet
|
||||
if(gloves)
|
||||
gloves.armor["rad"] = 100
|
||||
items_to_update += gloves
|
||||
holder.armor["rad"] = 100
|
||||
items_to_update += holder
|
||||
for(var/obj/item/part in items_to_update)
|
||||
ADD_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT)
|
||||
|
||||
/obj/item/rig_module/rad_shield/deactivate()
|
||||
|
||||
@@ -57,20 +66,30 @@
|
||||
var/obj/item/clothing/head/helmet/space/rig/helmet = holder.helmet
|
||||
var/obj/item/clothing/gloves/gauntlets/rig/gloves = holder.gloves
|
||||
|
||||
var/list/items_to_update = list()
|
||||
|
||||
to_chat(H, span_danger("You deactivate your suit's powered radiation shielding."))
|
||||
|
||||
if(boots)
|
||||
boots.armor["rad"] = stored_rad_armor
|
||||
items_to_update += boots
|
||||
if(chest)
|
||||
chest.armor["rad"] = stored_rad_armor
|
||||
items_to_update += chest
|
||||
if(helmet)
|
||||
helmet.armor["rad"] = stored_rad_armor
|
||||
items_to_update += helmet
|
||||
if(gloves)
|
||||
gloves.armor["rad"] = stored_rad_armor
|
||||
items_to_update += gloves
|
||||
holder.armor["rad"] = stored_rad_armor
|
||||
items_to_update += holder
|
||||
|
||||
stored_rad_armor = 0
|
||||
|
||||
for(var/obj/item/part in items_to_update)
|
||||
REMOVE_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT)
|
||||
|
||||
/obj/item/rig_module/rad_shield/advanced
|
||||
name = "advanced radiation absorption device"
|
||||
desc = "The acronym of this device - R.A.D. - and its full name both convey the application of the module. It has a changelog inscribed \
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
body_parts_covered = HEAD|FACE|EYES
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
|
||||
|
||||
|
||||
/obj/item/clothing/head/radiation/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/radiation_protected_clothing)
|
||||
|
||||
/obj/item/clothing/suit/radiation
|
||||
name = "Radiation suit"
|
||||
desc = "A suit that protects against radiation. Label: Made with lead, do not eat insulation."
|
||||
@@ -102,6 +107,10 @@
|
||||
flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
|
||||
item_flags = THICKMATERIAL
|
||||
|
||||
/obj/item/clothing/suit/radiation/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/radiation_protected_clothing)
|
||||
|
||||
/obj/item/clothing/suit/radiation/teshari
|
||||
name = "Small radiation suit"
|
||||
desc = "A specialist suit that protects against radiation, designed specifically for use by Teshari. Made to order by Aether."
|
||||
|
||||
@@ -96,6 +96,38 @@
|
||||
desc = "A " + MAT_URANIUM + " coin. You probably don't want to store this in your pants pocket..."
|
||||
icon_state = "coin_uranium"
|
||||
matter = list(MAT_URANIUM = 250)
|
||||
var/last_event = 0
|
||||
var/active = 0
|
||||
|
||||
/obj/item/coin/uranium/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/coin/uranium/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/coin/uranium/process()
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/item/coin/uranium/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 1,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 2
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/coin/platinum
|
||||
name = MAT_PLATINUM + " coin"
|
||||
|
||||
@@ -29,9 +29,21 @@
|
||||
else if(activeFor == leaveBelt)
|
||||
GLOB.command_announcement.Announce("The [using_map.facility_type] has passed the radiation belt. Please allow for up to one minute while radiation levels dissipate, and report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
|
||||
/datum/event/radiation_storm/proc/radiate()
|
||||
|
||||
//This sucks. Just mutate.
|
||||
/*
|
||||
var/radiation_level = rand(15, 35)
|
||||
for(var/z in using_map.station_levels)
|
||||
SSradiation.z_radiate(locate(1, 1, z), radiation_level, 1)
|
||||
var/turf/epicentre = locate(round(world.maxx / 2), round(world.maxy / 2), z)
|
||||
if(epicentre)
|
||||
radiation_pulse(
|
||||
epicentre,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
)
|
||||
*/
|
||||
|
||||
for(var/mob/living/carbon/C in GLOB.living_mob_list)
|
||||
if(!(C.z in using_map.station_levels) || C.isSynthetic() || isbelly(C.loc))
|
||||
|
||||
@@ -37,7 +37,13 @@
|
||||
continue
|
||||
|
||||
//Todo: Apply some burn damage from the heat of the sun. Until then, enjoy some moderate radiation.
|
||||
L.rad_act(rand(15, 30))
|
||||
radiation_pulse(
|
||||
L,
|
||||
max_range = 1,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = rand(10, 50)
|
||||
)
|
||||
|
||||
/datum/event/solar_storm/end()
|
||||
GLOB.command_announcement.Announce("The solar storm has passed the [using_map.facility_type]. It is now safe to resume EVA activities. Please report to medbay if you experience any unusual symptoms. ", "Anomaly Alert")
|
||||
|
||||
@@ -29,9 +29,41 @@
|
||||
radiate()
|
||||
|
||||
/datum/event2/event/radiation_storm/proc/radiate()
|
||||
//This sucks. Just mutate.
|
||||
/*
|
||||
var/radiation_level = rand(15, 35)
|
||||
for(var/z in using_map.station_levels)
|
||||
SSradiation.z_radiate(locate(1, 1, z), radiation_level, 1)
|
||||
var/turf/epicentre = locate(round(world.maxx / 2), round(world.maxy / 2), z)
|
||||
if(epicentre)
|
||||
radiation_pulse(
|
||||
epicentre,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
)
|
||||
*/
|
||||
|
||||
for(var/mob/living/carbon/C in GLOB.living_mob_list)
|
||||
if(!(C.z in using_map.station_levels) || C.isSynthetic() || isbelly(C.loc))
|
||||
continue
|
||||
var/area/A = get_area(C)
|
||||
if(!A)
|
||||
continue
|
||||
if(A.flag_check(RAD_SHIELDED))
|
||||
continue
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
var/chance = 5.0
|
||||
chance -= (chance / 100) * C.getarmor(null, "rad")
|
||||
if(prob(chance))
|
||||
if (prob(75))
|
||||
randmutb(H) // Applies bad mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
else
|
||||
randmutg(H) // Applies good mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
H.UpdateAppearance()
|
||||
|
||||
/datum/event2/event/radiation_storm/end()
|
||||
GLOB.command_announcement.Announce("The station has passed the radiation belt. \
|
||||
|
||||
@@ -49,4 +49,10 @@
|
||||
continue
|
||||
|
||||
//Todo: Apply some burn damage from the heat of the sun. Until then, enjoy some moderate radiation.
|
||||
L.rad_act(rand(15, 30))
|
||||
radiation_pulse(
|
||||
L,
|
||||
max_range = 1,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = rand(10, 50)
|
||||
)
|
||||
|
||||
@@ -5,6 +5,40 @@
|
||||
item_state = "diamond"
|
||||
default_type = MAT_SUPERMATTER
|
||||
apply_colour = TRUE
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/stack/material/supermatter/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/stack/material/supermatter/process()
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/item/stack/material/supermatter/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = (amount * 0.2), //10 range at 50 amount
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = NEBULA_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = amount * 0.5 //2 sheets = 1 rad, 50 sheets = 25 rads.
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/stack/material/supermatter/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack.
|
||||
slowdown = amount / 10
|
||||
@@ -20,7 +54,6 @@
|
||||
. = ..()
|
||||
|
||||
update_mass()
|
||||
SSradiation.radiate(src, 5 + amount)
|
||||
var/mob/living/M = user
|
||||
if(!istype(M))
|
||||
return
|
||||
@@ -47,9 +80,15 @@
|
||||
|
||||
/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature.
|
||||
if(prob((4 / severity) * 20))
|
||||
SSradiation.radiate(get_turf(src), amount * 4)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = amount,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE * 5,
|
||||
minimum_exposure_time = 0,
|
||||
strength = amount * 10
|
||||
)
|
||||
explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25))
|
||||
qdel(src)
|
||||
return
|
||||
SSradiation.radiate(get_turf(src), amount * 2)
|
||||
..()
|
||||
|
||||
@@ -641,7 +641,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
gas_analyzing += "Temperature: [round(environment.temperature-T0C,0.1)]°C ([round(environment.temperature,0.1)]K)"
|
||||
gas_analyzing += "Heat Capacity: [round(environment.heat_capacity(),0.1)]"
|
||||
to_chat(src, span_notice("[jointext(gas_analyzing, "<br>")]"))
|
||||
|
||||
/*
|
||||
/mob/observer/dead/verb/check_radiation()
|
||||
set name = "Check Radiation"
|
||||
set category = "Ghost.Game"
|
||||
@@ -650,7 +650,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(t)
|
||||
var/rads = SSradiation.get_rads_at_turf(t)
|
||||
to_chat(src, span_notice("Radiation level: [rads ? rads : "0"] Bq."))
|
||||
|
||||
*/
|
||||
/mob/observer/dead/verb/view_manfiest()
|
||||
set name = "Show Crew Manifest"
|
||||
set category = "Ghost.Game"
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
if(.)
|
||||
return
|
||||
if (radiation)
|
||||
if (radiation > 100)
|
||||
throw_alert("irradiated", /atom/movable/screen/alert/irradiated)
|
||||
if(radiation > 100)
|
||||
radiation = 100
|
||||
if(!container)//If it's not in an MMI
|
||||
to_chat(src, span_red("You feel weak."))
|
||||
else//Fluff-wise, since the brain can't detect anything itself, the MMI handles thing like that
|
||||
to_chat(src, span_red("STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED."))
|
||||
|
||||
switch(radiation)
|
||||
if(1 to 49)
|
||||
radiation--
|
||||
@@ -35,6 +35,8 @@
|
||||
radiation -= 3
|
||||
adjustToxLoss(3)
|
||||
updatehealth()
|
||||
else
|
||||
clear_alert("irradiated")
|
||||
|
||||
|
||||
/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment)
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
|
||||
/mob/living/carbon/human/inStasisNow()
|
||||
var/stasisValue = getStasis()
|
||||
if(stasisValue && (life_tick % stasisValue))
|
||||
if(stasisValue && (life_tick % stasisValue) || HAS_TRAIT(src, TRAIT_STASIS))
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
@@ -610,3 +610,11 @@ emp_act
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
///Get all the clothing on a specific body part
|
||||
/mob/living/carbon/human/proc/get_clothing_on_part(obj/item/organ/external/def_zone)
|
||||
var/list/covering_part = list()
|
||||
for(var/obj/item/clothing/equipped in get_equipped_items(INCLUDE_ABSTRACT))
|
||||
if(equipped.body_parts_covered & def_zone.body_part)
|
||||
covering_part += equipped
|
||||
return covering_part
|
||||
|
||||
@@ -47,37 +47,38 @@
|
||||
|
||||
voice = GetVoice()
|
||||
|
||||
var/stasis = inStasisNow()
|
||||
var/stasis = (inStasisNow())
|
||||
if(getStasis() > 2)
|
||||
Sleeping(20)
|
||||
|
||||
//No need to update all of these procs if the guy is dead.
|
||||
fall() //Prevents people from floating
|
||||
if(stat != DEAD && !stasis)
|
||||
//Updates the number of stored chemicals for powers
|
||||
handle_changeling()
|
||||
if(!stasis)
|
||||
if(stat != DEAD)
|
||||
//Updates the number of stored chemicals for powers
|
||||
handle_changeling()
|
||||
|
||||
//Organs and blood
|
||||
handle_organs()
|
||||
stabilize_body_temperature() //Body temperature adjusts itself (self-regulation)
|
||||
weightgain()
|
||||
handle_shock()
|
||||
//Organs and blood
|
||||
handle_organs()
|
||||
stabilize_body_temperature() //Body temperature adjusts itself (self-regulation)
|
||||
weightgain()
|
||||
handle_shock()
|
||||
|
||||
handle_pain()
|
||||
handle_pain()
|
||||
|
||||
SEND_SIGNAL(src,COMSIG_HANDLE_ALLERGENS, chem_effects[CE_ALLERGEN])
|
||||
SEND_SIGNAL(src,COMSIG_HANDLE_ALLERGENS, chem_effects[CE_ALLERGEN])
|
||||
|
||||
handle_medical_side_effects()
|
||||
handle_medical_side_effects()
|
||||
|
||||
handle_heartbeat()
|
||||
handle_nif()
|
||||
if(phobias)
|
||||
handle_phobias()
|
||||
if(!client)
|
||||
species.handle_npc(src)
|
||||
handle_heartbeat()
|
||||
handle_nif()
|
||||
if(phobias)
|
||||
handle_phobias()
|
||||
if(!client)
|
||||
species.handle_npc(src)
|
||||
|
||||
else if(stat == DEAD && !stasis)
|
||||
handle_defib_timer()
|
||||
else if(stat == DEAD)
|
||||
handle_defib_timer()
|
||||
|
||||
//Handle any species related components we may have. Ex: Shadekin, Xenochimera, etc. Not STAT checked because those do statchecks in their own code.
|
||||
handle_species_components()
|
||||
@@ -262,11 +263,12 @@
|
||||
accumulated_rads = CLAMP(accumulated_rads,0,RADIATION_CAP) //Max of 100Gy as well. You should never get higher than this. You will be dead before you can reach this.
|
||||
var/obj/item/organ/internal/I = null //Used for further down below when an organ is picked.
|
||||
if(!radiation)
|
||||
clear_alert("irradiated")
|
||||
if(accumulated_rads)
|
||||
accumulated_rads -= RADIATION_SPEED_COEFFICIENT //Accumulated rads slowly dissipate very slowly. Get to medical to get it treated!
|
||||
else if(((life_tick % 5 == 0) && radiation) || (radiation > 600)) //Radiation is a slow, insidious killer. Unless you get a massive dose, then the onset is sudden!
|
||||
|
||||
if(reagents.has_reagent(REAGENT_ID_PRUSSIANBLUE)) //Prussian Blue temporarily stops radiation effects.
|
||||
if(HAS_TRAIT(src, TRAIT_HALT_RADIATION_EFFECTS)) //If we have a trait that halts radiation effects, then we just stop here. No need to do any of the checks below.
|
||||
return
|
||||
|
||||
var/damage = 0
|
||||
@@ -334,6 +336,7 @@
|
||||
|
||||
|
||||
else if (radiation >= GLOB.radiation_levels[species.rad_levels]["danger_3"] && radiation < GLOB.radiation_levels[species.rad_levels]["danger_4"]) //Equivalent of 8.0 to 30 Gy.
|
||||
throw_alert("irradiated", /atom/movable/screen/alert/irradiated)
|
||||
damage = 10
|
||||
radiation -= 100 * RADIATION_SPEED_COEFFICIENT * species.rad_removal_mod
|
||||
accumulated_rads += 100 * RADIATION_SPEED_COEFFICIENT
|
||||
|
||||
@@ -206,13 +206,6 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/slime/promethean/rad_act(severity)
|
||||
rad_glow += severity
|
||||
rad_glow = CLAMP(rad_glow,0,250)
|
||||
if(rad_glow > 1)
|
||||
set_light(max(1,min(5,rad_glow/15)), max(1,min(10,rad_glow/25)), color)
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_mob/slime/promethean/bullet_act(obj/item/projectile/P)
|
||||
if(humanform)
|
||||
return humanform.bullet_act(P)
|
||||
|
||||
@@ -307,14 +307,6 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/protean_blob/rad_act(severity)
|
||||
if(istype(loc, /obj/item/rig))
|
||||
return //Don't irradiate us while we're in rig mode
|
||||
if(humanform)
|
||||
return humanform.rad_act(severity)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/protean_blob/bullet_act(obj/item/projectile/P)
|
||||
if(humanform)
|
||||
return humanform.bullet_act(P)
|
||||
|
||||
@@ -442,6 +442,14 @@
|
||||
hidden = FALSE
|
||||
activation_message="Your body feels mundane."
|
||||
|
||||
/datum/trait/positive/rad_immune/apply(var/datum/species/S,var/mob/living/carbon/human/H)
|
||||
..()
|
||||
ADD_TRAIT(H, TRAIT_RADIMMUNE, ROUNDSTART_TRAIT)
|
||||
|
||||
/datum/trait/positive/rad_immune/unapply(var/datum/species/S,var/mob/living/carbon/human/H)
|
||||
..()
|
||||
REMOVE_TRAIT(H, TRAIT_RADIMMUNE, ROUNDSTART_TRAIT)
|
||||
|
||||
/datum/trait/positive/vibration_sense
|
||||
name = "Vibration Sense"
|
||||
desc = "Allows you to sense subtle vibrations nearby, even if the source cannot be seen."
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
return name
|
||||
|
||||
/mob/living/Destroy()
|
||||
SSradiation.listeners -= src
|
||||
remove_all_modifiers(TRUE)
|
||||
QDEL_NULL(say_list)
|
||||
|
||||
|
||||
@@ -522,8 +522,14 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_mob/slime/xenobio/green/proc/irradiate()
|
||||
SSradiation.radiate(src, rads)
|
||||
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = rads * 0.5,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rads
|
||||
)
|
||||
|
||||
|
||||
/mob/living/simple_mob/slime/xenobio/pink
|
||||
|
||||
@@ -578,7 +578,13 @@ GLOBAL_DATUM(planet_virgo3b, /datum/planet/virgo3b)
|
||||
if(!T.is_outdoors())
|
||||
return // They're indoors, so no need to irradiate them with fallout.
|
||||
|
||||
L.rad_act(rand(direct_rad_low, direct_rad_high))
|
||||
radiation_pulse(
|
||||
L,
|
||||
max_range = 1,
|
||||
threshold = RAD_VERY_LIGHT_INSULATION,
|
||||
chance = rand(fallout_rad_low, fallout_rad_high),
|
||||
strength = rand(fallout_rad_low, fallout_rad_high)
|
||||
)
|
||||
|
||||
// This makes random tiles near people radioactive for awhile.
|
||||
// Tiles far away from people are left alone, for performance.
|
||||
@@ -590,7 +596,14 @@ GLOBAL_DATUM(planet_virgo3b, /datum/planet/virgo3b)
|
||||
if(!istype(T))
|
||||
return
|
||||
if(T.is_outdoors())
|
||||
SSradiation.radiate(T, rand(fallout_rad_low, fallout_rad_high))
|
||||
radiation_pulse(
|
||||
T,
|
||||
max_range = 7,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rand(fallout_rad_low, fallout_rad_high)
|
||||
)
|
||||
|
||||
/datum/weather/virgo3b/fallout/temp
|
||||
name = "short-term fallout"
|
||||
|
||||
@@ -582,7 +582,14 @@ GLOBAL_DATUM(planet_virgo3c, /datum/planet/virgo3c)
|
||||
if(!T.is_outdoors())
|
||||
return // They're indoors, so no need to irradiate them with fallout.
|
||||
|
||||
L.rad_act(rand(direct_rad_low, direct_rad_high))
|
||||
radiation_pulse(
|
||||
L,
|
||||
max_range = 1,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = rand(direct_rad_low, direct_rad_high),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rand(direct_rad_low, direct_rad_high)
|
||||
)
|
||||
|
||||
// This makes random tiles near people radioactive for awhile.
|
||||
// Tiles far away from people are left alone, for performance.
|
||||
@@ -594,7 +601,14 @@ GLOBAL_DATUM(planet_virgo3c, /datum/planet/virgo3c)
|
||||
if(!istype(T))
|
||||
return
|
||||
if(T.is_outdoors())
|
||||
SSradiation.radiate(T, rand(fallout_rad_low, fallout_rad_high))
|
||||
radiation_pulse(
|
||||
T,
|
||||
max_range = 1,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = rand(direct_rad_low, direct_rad_high),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rand(fallout_rad_low, fallout_rad_high)
|
||||
)
|
||||
|
||||
/datum/weather/virgo3c/fallout/temp
|
||||
name = "short-term fallout"
|
||||
|
||||
@@ -553,7 +553,15 @@ GLOBAL_DATUM(planet_virgo4, /datum/planet/virgo4)
|
||||
if(!T.is_outdoors())
|
||||
return // They're indoors, so no need to irradiate them with fallout.
|
||||
|
||||
L.rad_act(rand(direct_rad_low, direct_rad_high))
|
||||
radiation_pulse(
|
||||
L,
|
||||
max_range = 1,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = rand(direct_rad_low, direct_rad_high),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rand(direct_rad_low, direct_rad_high)
|
||||
)
|
||||
|
||||
|
||||
// This makes random tiles near people radioactive for awhile.
|
||||
// Tiles far away from people are left alone, for performance.
|
||||
@@ -565,7 +573,14 @@ GLOBAL_DATUM(planet_virgo4, /datum/planet/virgo4)
|
||||
if(!istype(T))
|
||||
return
|
||||
if(T.is_outdoors())
|
||||
SSradiation.radiate(T, rand(fallout_rad_low, fallout_rad_high))
|
||||
radiation_pulse(
|
||||
T,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = rand(direct_rad_low, direct_rad_high),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = rand(fallout_rad_low, fallout_rad_high)
|
||||
)
|
||||
|
||||
/datum/weather/virgo4/fallout/temp
|
||||
name = "short-term fallout"
|
||||
|
||||
@@ -333,7 +333,13 @@
|
||||
radiation += plasma_temperature/2
|
||||
plasma_temperature = 0
|
||||
|
||||
SSradiation.radiate(src, radiation)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = energy * 0.001 //Might need to be increased.
|
||||
)
|
||||
Radiate()
|
||||
|
||||
/obj/effect/fusion_em_field/proc/Radiate()
|
||||
@@ -539,7 +545,13 @@
|
||||
|
||||
//Reaction radiation is fairly buggy and there's at least three procs dealing with radiation here, this is to ensure constant radiation output.
|
||||
/obj/effect/fusion_em_field/proc/radiation_scale()
|
||||
SSradiation.radiate(src, 2 + plasma_temperature / PLASMA_TEMP_RADIATION_DIVISIOR)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = (URANIUM_IRRADIATION_CHANCE + (plasma_temperature / PLASMA_TEMP_RADIATION_DIVISIOR)),
|
||||
strength = energy * 0.01 //Might need to be increased.
|
||||
)
|
||||
|
||||
//Somehow fixing the radiation issue managed to break this, but moving it to it's own proc seemed to have fixed it. I don't know.
|
||||
/obj/effect/fusion_em_field/proc/temp_dump()
|
||||
|
||||
@@ -11,6 +11,34 @@
|
||||
var/fuel_colour
|
||||
var/radioactivity = 0
|
||||
var/const/initial_amount = 3000000
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/fuel_assembly/process()
|
||||
radiate()
|
||||
|
||||
/obj/item/fuel_assembly/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = (radioactivity * 0.5),
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DEFAULT_RADIATION_CHANCE,
|
||||
strength = radioactivity * 0.5
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/fuel_assembly/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/fuel_assembly/Initialize(mapload, var/_material, var/_colour)
|
||||
. = ..()
|
||||
@@ -38,17 +66,6 @@
|
||||
add_overlay(list(I, image(icon, "fuel_assembly_bracket")))
|
||||
rod_quantities[fuel_type] = initial_amount
|
||||
|
||||
/obj/item/fuel_assembly/process()
|
||||
if(!radioactivity)
|
||||
return PROCESS_KILL
|
||||
|
||||
if(istype(loc, /turf))
|
||||
SSradiation.radiate(src, max(1,CEILING(radioactivity/30, 1)))
|
||||
|
||||
/obj/item/fuel_assembly/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
// Mapper shorthand.
|
||||
/obj/item/fuel_assembly/deuterium/Initialize(mapload)
|
||||
. = ..(mapload, MAT_DEUTERIUM)
|
||||
|
||||
@@ -116,11 +116,13 @@ GLOBAL_LIST(fusion_reactions)
|
||||
|
||||
var/turf/origin = get_turf(holder)
|
||||
holder.Rupture()
|
||||
qdel(holder)
|
||||
var/radiation_level = 200
|
||||
|
||||
// Copied from the SM for proof of concept. //Not any more --Cirra //Use the whole z proc --Leshana
|
||||
SSradiation.z_radiate(locate(1, 1, holder.z), radiation_level, 1)
|
||||
radiation_pulse(
|
||||
holder,
|
||||
max_range = 50,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 500
|
||||
)
|
||||
|
||||
for(var/mob/living/mob in GLOB.living_mob_list)
|
||||
var/turf/T = get_turf(mob)
|
||||
@@ -135,8 +137,7 @@ GLOBAL_LIST(fusion_reactions)
|
||||
spawn(5)
|
||||
if(I && I.loc)
|
||||
qdel(I)
|
||||
|
||||
sleep(5)
|
||||
qdel(holder)
|
||||
explosion(origin, 1, 2, 5)
|
||||
|
||||
return 1
|
||||
|
||||
@@ -378,7 +378,14 @@ GLOBAL_LIST_EMPTY(gravity_generators)
|
||||
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/pulse_radiation()
|
||||
SSradiation.radiate(src, 200)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DEFAULT_RADIATION_CHANCE * 2,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = charge_count * 2
|
||||
)
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/update_gravity(var/on)
|
||||
for(var/area/A in src.areas)
|
||||
|
||||
@@ -385,13 +385,25 @@
|
||||
/obj/machinery/power/port_gen/pacman/super/UseFuel()
|
||||
//produces a tiny amount of radiation when in use
|
||||
if (prob(2*power_output))
|
||||
SSradiation.radiate(src, 4)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 2,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DEFAULT_RADIATION_CHANCE,
|
||||
strength = power_gen * 0.01
|
||||
)
|
||||
..()
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/super/explode()
|
||||
//a nice burst of radiation
|
||||
var/rads = 50 + (sheets + sheet_left)*1.5
|
||||
SSradiation.radiate(src, (max(20, rads)))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = (rads/10),
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DEFAULT_RADIATION_CHANCE,
|
||||
strength = rads
|
||||
)
|
||||
|
||||
explosion(src.loc, 3, 3, 5, 3)
|
||||
qdel(src)
|
||||
|
||||
@@ -144,7 +144,14 @@
|
||||
..()
|
||||
add_avail(power_gen)
|
||||
if(panel_open && irradiate)
|
||||
SSradiation.radiate(src, 60)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 3,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = DEFAULT_RADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = power_gen * 0.01 //1000 power = 10 rads. 10000 power = 100 rads. You can get creative with rad collectors if you want.
|
||||
)
|
||||
|
||||
/obj/machinery/power/rtg/RefreshParts()
|
||||
var/part_level = 0
|
||||
@@ -593,9 +600,15 @@
|
||||
var/turf/T = get_turf(src)
|
||||
qdel(src)
|
||||
if(T)
|
||||
radiation_pulse(
|
||||
T,
|
||||
max_range = 50,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DEFAULT_RADIATION_CHANCE * 3,
|
||||
strength = power_gen * 0.01 ///1MW = 1000 rads. If you blow up a BLACK HOLE ENGINE, you deserve the radiation that comes with it.
|
||||
)
|
||||
empulse(T, 12, 14, 16, 18)
|
||||
explosion(T, 7, 12, 18, 20)
|
||||
SSradiation.radiate(T, 200)
|
||||
new /obj/effect/bhole(T)
|
||||
|
||||
/obj/machinery/power/rtg/antimatter_core/blob_act(obj/structure/blob/B)
|
||||
|
||||
@@ -14,33 +14,36 @@
|
||||
var/active = 0
|
||||
var/locked = 0
|
||||
var/drainratio = 1
|
||||
rad_insulation = RAD_EXTREME_INSULATION //It sucks up the radiation. If you're standing behind it, you're pretty safe.
|
||||
|
||||
/obj/machinery/power/rad_collector/Initialize(mapload)
|
||||
. = ..()
|
||||
GLOB.rad_collectors += src
|
||||
AddElement(/datum/element/climbable)
|
||||
RegisterSignal(src, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(process_rads))
|
||||
|
||||
/obj/machinery/power/rad_collector/Destroy()
|
||||
GLOB.rad_collectors -= src
|
||||
UnregisterSignal(src, COMSIG_IN_RANGE_OF_IRRADIATION)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/rad_collector/process()
|
||||
/obj/machinery/power/rad_collector/proc/process_rads(datum/source, datum/radiation_pulse_information/pulse_information)
|
||||
SIGNAL_HANDLER
|
||||
//so that we don't zero out the meter if the SM is processed first.
|
||||
last_power = last_power_new
|
||||
last_power_new = 0
|
||||
|
||||
|
||||
if(P && active)
|
||||
var/rads = SSradiation.get_rads_at_turf(get_turf(src))
|
||||
if(rads)
|
||||
receive_pulse(rads * 5) //Maths is hard
|
||||
if(pulse_information)
|
||||
var/amount_of_rads = pulse_information.strength
|
||||
receive_pulse((amount_of_rads))
|
||||
|
||||
if(P)
|
||||
if(P.air_contents.gas[GAS_PHORON] == 0)
|
||||
investigate_log(span_red("out of fuel") + ".","singulo")
|
||||
eject()
|
||||
else
|
||||
P.air_contents.adjust_gas(GAS_PHORON, -0.001*drainratio)
|
||||
if(P.air_contents.gas[GAS_PHORON] == 0)
|
||||
investigate_log(span_red("out of fuel") + ".","singulo")
|
||||
eject()
|
||||
else
|
||||
P.air_contents.adjust_gas(GAS_PHORON, -0.0001*drainratio)
|
||||
return
|
||||
|
||||
|
||||
@@ -126,12 +129,15 @@
|
||||
else
|
||||
update_icons()
|
||||
|
||||
// Continuing here, SM giving us ~170 rads per pulse, a phoron canister full of 30 mols, and * 20 we get:
|
||||
// 102000W per collector...So 10 collectors will give us ~1MW.
|
||||
/obj/machinery/power/rad_collector/proc/receive_pulse(var/pulse_strength)
|
||||
if(P && active)
|
||||
var/power_produced = 0
|
||||
power_produced = P.air_contents.gas[GAS_PHORON]*pulse_strength*20
|
||||
add_avail(power_produced)
|
||||
last_power_new = power_produced
|
||||
if(power_produced)
|
||||
add_avail(power_produced)
|
||||
last_power_new = power_produced
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
@@ -148,13 +148,27 @@
|
||||
/obj/machinery/particle_smasher/process()
|
||||
if(!src.anchored) // Rapidly loses focus.
|
||||
if(energy)
|
||||
SSradiation.radiate(src, round(((src.energy-150)/50)*5,1))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = round(((src.energy-150)/50)*5,1),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = energy * 0.1 //60 rads at max energy.
|
||||
)
|
||||
energy = max(0, energy - 30)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(energy)
|
||||
SSradiation.radiate(src, round(((src.energy-150)/50)*5,1))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = round(((src.energy-150)/50)*5,1),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = energy * 0.1 //60 rads at max energy.
|
||||
)
|
||||
energy = CLAMP(energy - 5, 0, max_energy)
|
||||
|
||||
return
|
||||
@@ -184,7 +198,14 @@
|
||||
if(successful_craft)
|
||||
visible_message(span_warning("\The [src] fizzles."))
|
||||
if(prob(33)) // Why are you blasting it after it's already done!
|
||||
SSradiation.radiate(src, 10 + round(src.energy / 60, 1))
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE + round(src.energy / 60, 1),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = energy * 0.1
|
||||
)
|
||||
energy = max(0, energy - 30)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
@@ -403,11 +403,16 @@ GLOBAL_LIST_BOILERPLATE(all_singularities, /obj/singularity)
|
||||
/obj/singularity/proc/toxmob()
|
||||
var/toxrange = 10
|
||||
var/toxdamage = 4
|
||||
var/radiation = 15
|
||||
if (src.energy>200)
|
||||
toxdamage = round(((src.energy-150)/50)*4,1)
|
||||
radiation = round(((src.energy-150)/50)*5,1)
|
||||
SSradiation.radiate(src, radiation) //Always radiate at max, so a decent dose of radiation is applied
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 7,
|
||||
threshold = RAD_EXTREME_INSULATION - 0.1,
|
||||
chance = URANIUM_IRRADIATION_CHANCE + round(energy / 60, 1),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 250
|
||||
)
|
||||
for(var/mob/living/M in view(toxrange, src.loc))
|
||||
if(SEND_SIGNAL(M, COMSIG_CHECK_FOR_GODMODE) & COMSIG_GODMODE_CANCEL)
|
||||
return 0 // Cancelled by a component
|
||||
@@ -450,13 +455,28 @@ GLOBAL_LIST_BOILERPLATE(all_singularities, /obj/singularity)
|
||||
to_chat(M, span_danger("You hear an unearthly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat."))
|
||||
to_chat(M, span_danger("You don't even have a moment to react as you are reduced to ashes by the intense radiation."))
|
||||
M.dust()
|
||||
SSradiation.radiate(src, rand(energy))
|
||||
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 10,
|
||||
threshold = RAD_EXTREME_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE * 8,
|
||||
strength = 1000
|
||||
)
|
||||
return
|
||||
|
||||
/obj/singularity/proc/pulse()
|
||||
for(var/obj/machinery/power/rad_collector/R in GLOB.rad_collectors)
|
||||
if (get_dist(R, src) <= 15) //Better than using orange() every process.
|
||||
R.receive_pulse(energy)
|
||||
//Yes, this means rad collectors can double dip on the singulo, but you could always use the safer SM or tesla, so it gets a small buff.
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 15,
|
||||
threshold = RAD_EXTREME_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE * 8,
|
||||
strength = energy * 0.25
|
||||
)
|
||||
|
||||
/obj/singularity/proc/on_capture()
|
||||
chained = 1
|
||||
|
||||
@@ -170,12 +170,27 @@
|
||||
var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, exosuit, or other container shouldn't block it's effects that way.
|
||||
if(!istype(TS))
|
||||
return
|
||||
radiation_pulse(
|
||||
TS,
|
||||
max_range = 255,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DETONATION_RADS,
|
||||
strength = DETONATION_RADS * 5
|
||||
)
|
||||
|
||||
var/list/affected_z = GetConnectedZlevels(TS.z)
|
||||
|
||||
// Effect 1: Radiation, weakening to all mobs on Z level
|
||||
for(var/z in affected_z)
|
||||
SSradiation.z_radiate(locate(1, 1, z), DETONATION_RADS, 1)
|
||||
for(var/z_to_affect in affected_z)
|
||||
var/turf/turf_to_hit = locate(TS.x, TS.y, z_to_affect)
|
||||
if(turf_to_hit)
|
||||
radiation_pulse(
|
||||
turf_to_hit,
|
||||
max_range = 255,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = DETONATION_RADS,
|
||||
strength = DETONATION_RADS * 5
|
||||
)
|
||||
|
||||
for(var/mob/living/mob in GLOB.living_mob_list)
|
||||
var/turf/TM = get_turf(mob)
|
||||
@@ -398,7 +413,16 @@
|
||||
if(!istype(l.glasses, /obj/item/clothing/glasses/meson) || l.is_incorporeal()) // VOREStation Edit - Only mesons can protect you! OR if they're not in the same plane of existence
|
||||
l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)) ) ) )
|
||||
|
||||
SSradiation.radiate(src, max(power * 1.5, 50) ) //Better close those shutters!
|
||||
if(power)
|
||||
// At a power mult of 0.025 for range, this means a 1000power SM (about normal) will reach 25 tiles and be putting off rad pulses of 500. With 0 protection, you have a 10% chance of getting hit.
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = CLAMP(max(round(power * 0.025), 3), 3, 50),
|
||||
threshold = CLAMP(RAD_HEAVY_INSULATION - (power * 0.00025), 0.1, 1),
|
||||
chance = round(power * 0.01),
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = round(power * 0.5)
|
||||
)
|
||||
|
||||
power -= (power/DECAY_FACTOR)**3 //energy losses due to radiation
|
||||
|
||||
@@ -509,8 +533,13 @@
|
||||
span_warning("The unearthly ringing subsides and you notice you have new radiation burns."), 2)
|
||||
else
|
||||
l.show_message(span_warning("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns."), 2)
|
||||
var/rads = 500
|
||||
SSradiation.radiate(src, rads)
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_HEAVY_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = 200
|
||||
)
|
||||
|
||||
/proc/supermatter_pull(var/atom/target, var/pull_range = 255, var/pull_power = STAGE_FIVE)
|
||||
for(var/atom/A in range(pull_range, target))
|
||||
@@ -547,18 +576,31 @@
|
||||
desc = "The shattered remains of a supermatter shard plinth. It doesn't look safe to be around."
|
||||
icon = 'icons/obj/supermatter.dmi'
|
||||
icon_state = "darkmatter_broken"
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/broken_sm/Initialize(mapload)
|
||||
. = ..()
|
||||
message_admins("Broken SM shard created at ([x],[y],[z] - <A href='byond://?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/broken_sm/process()
|
||||
SSradiation.radiate(src, 50)
|
||||
|
||||
/obj/item/broken_sm/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
/obj/item/broken_sm/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 25
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
#undef POWER_FACTOR
|
||||
#undef DECAY_FACTOR
|
||||
|
||||
@@ -166,8 +166,14 @@
|
||||
icon_scale_y = 2
|
||||
var/rad_power = 50
|
||||
|
||||
/obj/item/projectile/arc/radioactive/on_impact(turf/T)
|
||||
SSradiation.radiate(T, rad_power)
|
||||
/obj/item/projectile/arc/radioactive/on_impact(turf/T) //This means you can shoot a rad collector to generate power...Might need to be adjusted.
|
||||
radiation_pulse(
|
||||
T,
|
||||
max_range = 3,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
strength = rad_power
|
||||
)
|
||||
|
||||
// Blob mortar
|
||||
/obj/item/projectile/arc/spore
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// Describes a point source of radiation. Created either in response to a pulse of radiation, or over an irradiated atom.
|
||||
// Sources will decay over time, unless something is renewing their power!
|
||||
/datum/radiation_source
|
||||
var/turf/source_turf // Location of the radiation source.
|
||||
var/rad_power // Strength of the radiation being emitted.
|
||||
var/decay = TRUE // True for automatic decay. False if owner promises to handle it (i.e. supermatter)
|
||||
var/respect_maint = FALSE // True for not affecting RAD_SHIELDED areas.
|
||||
var/flat = FALSE // True for power falloff with distance.
|
||||
var/range // Cached maximum range, used for quick checks against mobs.
|
||||
|
||||
/datum/radiation_source/Destroy()
|
||||
SSradiation.sources -= src
|
||||
if(SSradiation.sources_assoc[src.source_turf] == src)
|
||||
SSradiation.sources_assoc -= src.source_turf
|
||||
src.source_turf = null
|
||||
. = ..()
|
||||
|
||||
/datum/radiation_source/proc/update_rad_power(var/new_power = null)
|
||||
if(new_power == null || new_power == rad_power)
|
||||
return // No change
|
||||
else if(new_power <= CONFIG_GET(number/radiation_lower_limit))
|
||||
qdel(src) // Decayed to nothing
|
||||
else
|
||||
rad_power = new_power
|
||||
if(rad_power > 1e15) // Arbitrary cap to prevent going to infinity
|
||||
rad_power = 1e15
|
||||
if(!flat)
|
||||
range = min(round(sqrt(rad_power / CONFIG_GET(number/radiation_lower_limit))), 31) // R = rad_power / dist**2 - Solve for dist
|
||||
return
|
||||
|
||||
/turf
|
||||
var/cached_rad_resistance = 0
|
||||
|
||||
/turf/proc/calc_rad_resistance()
|
||||
cached_rad_resistance = 0
|
||||
for(var/obj/O in src.contents)
|
||||
if(O.rad_resistance) //Override
|
||||
cached_rad_resistance += O.rad_resistance
|
||||
|
||||
else if(O.density) //So open doors don't get counted
|
||||
var/datum/material/M = O.get_material()
|
||||
if(!M) continue
|
||||
cached_rad_resistance += (M.weight + M.radiation_resistance) / CONFIG_GET(number/radiation_material_resistance_divisor)
|
||||
// Looks like storing the contents length is meant to be a basic check if the cache is stale due to items enter/exiting. Better than nothing so I'm leaving it as is. ~Leshana
|
||||
SSradiation.resistance_cache[src] = (length(contents) + 1)
|
||||
return
|
||||
|
||||
/turf/simulated/wall/calc_rad_resistance()
|
||||
SSradiation.resistance_cache[src] = (length(contents) + 1)
|
||||
var/temp_rad_resistance
|
||||
temp_rad_resistance += material.weight + material.radiation_resistance
|
||||
if(reinf_material)
|
||||
temp_rad_resistance += reinf_material.weight + reinf_material.radiation_resistance
|
||||
cached_rad_resistance = (density ? (temp_rad_resistance) / CONFIG_GET(number/radiation_material_resistance_divisor) : 0)
|
||||
return
|
||||
|
||||
/turf/simulated/mineral/calc_rad_resistance()
|
||||
if(!density)
|
||||
return ..()
|
||||
SSradiation.resistance_cache[src] = (length(contents) + 1)
|
||||
cached_rad_resistance = 60 //Three times that of a steel wall. Rock is less dense than steel, but this is assuming that a normal wall isn't just solid steel all the way through like rock turfs are.
|
||||
return
|
||||
|
||||
// If people expand the system, this may be useful. Here as a placeholder until then
|
||||
/atom/proc/rad_act(var/severity)
|
||||
return 1
|
||||
|
||||
/mob/living/rad_act(var/severity)
|
||||
if(severity && !isbelly(loc)) //eaten mobs are made immune to radiation //VOREStation Edit
|
||||
src.apply_effect(severity, IRRADIATE, src.getarmor(null, "rad"))
|
||||
for(var/atom/I in src)
|
||||
I.rad_act(severity)
|
||||
return
|
||||
@@ -70,6 +70,8 @@
|
||||
total_volume = 0
|
||||
for(var/datum/reagent/R in reagent_list)
|
||||
if(R.volume < MINIMUM_CHEMICAL_VOLUME)
|
||||
if(isliving(R.holder.my_atom))
|
||||
R.on_mob_end_metabolize(R.holder.my_atom, src)
|
||||
del_reagent(R.id)
|
||||
else
|
||||
total_volume += R.volume
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
var/wiki_flag = 0 // Bitflags for secret/food/drink reagent sorting
|
||||
var/supply_conversion_value = null
|
||||
var/industrial_use = null // unique description for export off station
|
||||
/// A list of traits to apply while the reagent is being metabolized.
|
||||
var/list/metabolized_traits
|
||||
|
||||
|
||||
var/coolant_modifier = -0.5 // this is multiplied by the volume of the reagent. Most things are not good coolant. EX: Water is 1, coolant is 2. -1 would be a bad reagent for cooling.
|
||||
|
||||
@@ -186,6 +189,7 @@
|
||||
affect_ingest(M, alien, removed * ingest_abs_mult)
|
||||
if(CHEM_TOUCH)
|
||||
affect_touch(M, alien, removed)
|
||||
on_mob_metabolize(M, location)
|
||||
if(overdose && (volume > overdose * M?.species.chemOD_threshold) && (active_metab.metabolism_class != CHEM_TOUCH || can_overdose_touch))
|
||||
overdose(M, alien, removed)
|
||||
if(M.species.allergens & allergen_type) //uhoh, we can't handle this!
|
||||
@@ -241,3 +245,14 @@
|
||||
/// Called by [/datum/reagents/proc/conditional_update]
|
||||
/datum/reagent/proc/on_update(atom/A)
|
||||
return
|
||||
|
||||
/datum/reagent/proc/on_mob_metabolize(mob/living/affected_mob, datum/reagents/metabolism/location)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(metabolized_traits)
|
||||
affected_mob.add_traits(metabolized_traits, "metabolize_location:[location]reagent:[type]")
|
||||
|
||||
/// Called when this reagent stops being metabolized (due to running out)
|
||||
/// Has the args 'affected_mob' and 'location' which allows us to remove any traits that is only being added by that reagent holder location. I.e stomach, bloodstream, dermal, etc.
|
||||
/datum/reagent/proc/on_mob_end_metabolize(mob/living/affected_mob, datum/reagents/location)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
REMOVE_TRAITS_IN(affected_mob, "metabolize_location:[location]reagent:[type]")
|
||||
|
||||
@@ -4132,6 +4132,19 @@
|
||||
|
||||
allergen_type = ALLERGEN_FRUIT|ALLERGEN_GRAINS //Made from vodka(grains) and orange juice(fruit)
|
||||
|
||||
/datum/reagent/ethanol/screwdrivercocktail/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, metabolization_ratio)
|
||||
. = ..()
|
||||
// var/obj/item/organ/internal/liver/liver = drinker.internal_organs_by_name[O_LIVER]
|
||||
// if(HAS_TRAIT(liver, TRAIT_ENGINEER_METABOLISM))
|
||||
ADD_TRAIT(drinker, TRAIT_HALT_RADIATION_EFFECTS, "[type]")
|
||||
if (HAS_TRAIT(drinker, TRAIT_IRRADIATED))
|
||||
if(drinker.adjustToxLoss(-2 * metabolization_ratio * seconds_per_tick))
|
||||
return //UPDATE_MOB_HEALTH
|
||||
|
||||
/datum/reagent/ethanol/screwdrivercocktail/on_mob_end_metabolize(mob/living/drinker)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(drinker, TRAIT_HALT_RADIATION_EFFECTS, "[type]")
|
||||
|
||||
/datum/reagent/ethanol/silencer
|
||||
name = REAGENT_SILENCER
|
||||
id = REAGENT_ID_SILENCER
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
scannable = SCANNABLE_BENEFICIAL
|
||||
supply_conversion_value = REFINERYEXPORT_VALUE_COMMON
|
||||
industrial_use = REFINERYEXPORT_REASON_DRUG
|
||||
metabolized_traits = list(TRAIT_HALT_RADIATION_EFFECTS)
|
||||
|
||||
/datum/reagent/prussian_blue/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
|
||||
if(alien == IS_DIONA)
|
||||
|
||||
@@ -1098,7 +1098,7 @@
|
||||
industrial_use = REFINERYEXPORT_REASON_BIOHAZARD
|
||||
|
||||
/datum/reagent/irradiated_nanites/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
|
||||
SSradiation.radiate(get_turf(M), 20) // Irradiate people around you.
|
||||
//SSradiation.radiate(get_turf(M), 20) // Irradiate people around you. //TODO
|
||||
M.radiation = max(M.radiation + 5 * removed, 0) // Irradiate you. Because it's inside you.
|
||||
|
||||
/datum/reagent/neurophage_nanites
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
// Station Suits
|
||||
/datum/design_techweb/mechfab/modsuit/eva_controller
|
||||
name = "EVA Suit Control Module"
|
||||
desc = "An engineering Hardsuit featuring a visor with welding protection, iommunity to radiation, and insulated gauntlets. It is well insulated against the heat."
|
||||
desc = "An engineering Hardsuit featuring a visor with welding protection, immunity to radiation, and insulated gauntlets. It is well insulated against the heat."
|
||||
id = "eva_rig_module"
|
||||
materials = list(MAT_PLASTEEL = 16000, MAT_GOLD = 3000, MAT_GRAPHITE = 4500, MAT_OSMIUM = 1000, MAT_PLASTIC = 4500, MAT_LEAD = 2000, MAT_STEEL = 2000)
|
||||
build_path = /obj/item/rig/eva
|
||||
|
||||
@@ -21,7 +21,14 @@
|
||||
if(istype(holder, /obj/item/anobattery))
|
||||
holder = holder.loc
|
||||
if(holder)
|
||||
SSradiation.flat_radiate(holder, radiation_amount, src.effectrange)
|
||||
radiation_pulse(
|
||||
holder,
|
||||
max_range = effectrange,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = chargelevelmax * 0.5,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = chargelevelmax * 0.5
|
||||
)
|
||||
return 1
|
||||
|
||||
/datum/artifact_effect/radiate/DoEffectPulse()
|
||||
@@ -29,5 +36,11 @@
|
||||
if(istype(holder, /obj/item/anobattery))
|
||||
holder = holder.loc
|
||||
if(holder)
|
||||
SSradiation.radiate(holder, ((radiation_amount * 3) * (sqrt(src.effectrange))))
|
||||
radiation_pulse(
|
||||
holder,
|
||||
max_range = effectrange,
|
||||
threshold = RAD_LIGHT_INSULATION,
|
||||
chance = chargelevelmax,
|
||||
strength = chargelevelmax * 2,
|
||||
)
|
||||
return 1
|
||||
|
||||
@@ -910,7 +910,35 @@
|
||||
description_info = "When injected with phoron, this extract creates a single radioactive pulse. When injected with blood, this extract creates a radioactive glob. When injected with water \
|
||||
this extract creates some radium. When injected with slime jelly, this extract creates some uranium."
|
||||
slime_type = /mob/living/simple_mob/slime/xenobio/green
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/slime_extract/green/process()
|
||||
radiate()
|
||||
..()
|
||||
|
||||
/obj/item/slime_extract/green/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 50
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/slime_extract/green/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/datum/decl/chemical_reaction/instant/slime/green_radpulse
|
||||
name = "Slime Radiation Pulse"
|
||||
@@ -924,8 +952,9 @@
|
||||
playsound(holder.my_atom, 'sound/effects/phasein.ogg', 75, 1)
|
||||
holder.my_atom.visible_message(span_danger("\The [holder.my_atom] begins to vibrate violently!"))
|
||||
spawn(5 SECONDS)
|
||||
SSradiation.flat_radiate(src, 30, 7, TRUE)
|
||||
..()
|
||||
if(!QDELETED(holder.my_atom) && istype(holder.my_atom, /obj/item/slime_extract/green))
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
|
||||
/datum/decl/chemical_reaction/instant/slime/green_emitter
|
||||
|
||||
@@ -168,6 +168,9 @@
|
||||
light_power = 0.4
|
||||
light_range = 2
|
||||
w_class = ITEMSIZE_TINY
|
||||
var/last_event = 0
|
||||
/// Mutex to prevent infinite recursion when propagating radiation pulses
|
||||
var/active = null
|
||||
|
||||
/obj/item/slime_irradiator/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -175,7 +178,25 @@
|
||||
set_light(light_range, light_power, light_color)
|
||||
|
||||
/obj/item/slime_irradiator/process()
|
||||
SSradiation.radiate(src, 5)
|
||||
radiate()
|
||||
|
||||
/obj/item/slime_irradiator/proc/radiate()
|
||||
SIGNAL_HANDLER
|
||||
if(active)
|
||||
return
|
||||
if(world.time <= last_event + 1.5 SECONDS)
|
||||
return
|
||||
active = TRUE
|
||||
radiation_pulse(
|
||||
src,
|
||||
max_range = 5,
|
||||
threshold = RAD_MEDIUM_INSULATION,
|
||||
chance = URANIUM_IRRADIATION_CHANCE,
|
||||
minimum_exposure_time = URANIUM_RADIATION_MINIMUM_EXPOSURE_TIME,
|
||||
strength = 25
|
||||
)
|
||||
last_event = world.time
|
||||
active = FALSE
|
||||
|
||||
/obj/item/slime_irradiator/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
Reference in New Issue
Block a user