mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-13 16:13:49 +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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user