mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-12 08:27:13 +01:00
33b8164013
Adds: - Dosimeter, keeps track of how many rads a person has absorbed as well as showing the dose after armour. - Adds a message to shelter in maint to the supermatter explosion. - Adds a flag that makes damage not apply to robotic limbs, useful for preventing radiation burns to metal parts. Should also be added to chemicals that deal brute damage, such as arithrazine and the the burns from chemical exposure to chlorine, but that's another PR. - Added radiation resistance values to makeshift armour. As it only covers the chest, this isn't very useful, but better than nothing. Balance: - Re-scaled radiation damage. - Radiation now maxes out at 1000, from the previous 100. - Radiation damage when at maximum rads is converted directly into burn damage. - Radiation sources decay slowly, so all the old numbers were maxing people's radiation values instantaneously. - Re-scaled organ damage from radiation. Previously you would take no organ damage till 75% rads, then lose your liver almost immediately. Now organ damage ramps up from 500-1000, with 750-1000 being about 1/3rd the organ damage of 75-100. - Added debilitating, but not lethal, effects to moderate and high radiation levels. Lots of pain events instead of straight damage. - Reduced speed and stamina for high radiation doses. - Hyronalin and Arithrazine both remove much more radiation. The intent: People should now be able to work in low radiation zones, without using the radiation suit for short periods of time. The geiger counter is no longer an 'if this is ticking you are at max rads' detector. With the engineering voidsuit, 75% rads, I could stand next to a charged supermatter ~50rads a second, for about 2 minutes before I hit lethal radiation levels. If people stay in a radiation zone, or are exposed to extreme radiation 100+ rads a second, radiation is much more lethal, but not by just killing your organs. Conventional medicine will help a lot. --------- Signed-off-by: FenodyreeAv <fenodyree.av@gmail.com> Co-authored-by: Batrachophreno <Batrochophreno@gmail.com>
160 lines
4.9 KiB
Plaintext
160 lines
4.9 KiB
Plaintext
SUBSYSTEM_DEF(radiation)
|
|
name = "Radiation"
|
|
wait = 2 SECONDS
|
|
priority = SS_PRIORITY_RADIATION
|
|
flags = SS_NO_INIT
|
|
|
|
/// All radiation source datums.
|
|
var/list/sources = list()
|
|
/// Sources indexed by turf for de-duplication.
|
|
var/list/sources_assoc = list()
|
|
/// Cache of turf's radiation resistance.
|
|
var/list/resistance_cache = list()
|
|
|
|
var/list/current_sources = list()
|
|
var/list/current_res_cache = list()
|
|
var/list/listeners = 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()
|
|
|
|
while(length(current_sources))
|
|
var/datum/radiation_source/S = current_sources[length(current_sources)]
|
|
LIST_DEC(current_sources)
|
|
|
|
if(QDELETED(S))
|
|
sources -= S
|
|
else if(S.decay)
|
|
S.update_rad_power(S.rad_power - (RADIATION_DECAY_RATE + S.accelerated_decay_rate))
|
|
if (MC_TICK_CHECK)
|
|
return
|
|
|
|
while(length(current_res_cache))
|
|
var/turf/T = current_res_cache[length(current_res_cache)]
|
|
LIST_DEC(current_res_cache)
|
|
|
|
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)]
|
|
LIST_DEC(listeners)
|
|
|
|
if(!QDELETED(A))
|
|
var/atom/location = A.loc
|
|
var/rads = 0
|
|
if(istype(location))
|
|
rads = location.get_rads()
|
|
if(rads)
|
|
A.rad_act(rads)
|
|
if (MC_TICK_CHECK)
|
|
return
|
|
|
|
/**
|
|
* Ray trace from all active radiation sources to T and return the strongest effect.
|
|
*/
|
|
/datum/controller/subsystem/radiation/proc/get_rads_at_turf(turf/T)
|
|
. = 0
|
|
if(!istype(T))
|
|
return
|
|
|
|
for(var/value in sources)
|
|
var/datum/radiation_source/source = value
|
|
if(source.rad_power < .)
|
|
continue // Already being affected by a stronger source
|
|
if(source.source_turf.z != T.z)
|
|
continue // Radiation is not multi-z
|
|
if(source.respect_rad_shielding)
|
|
var/area/A = T.loc
|
|
if(A.area_flags & AREA_FLAG_RAD_SHIELDED)
|
|
continue // In shielded area
|
|
|
|
var/dist = get_dist(source.source_turf, T)
|
|
if(dist > source.range)
|
|
continue // Too far to possibly affect
|
|
if(source.flat)
|
|
. = max(., source.rad_power)
|
|
continue // No need to ray trace for flat field
|
|
|
|
// Okay, now ray trace to find resistence!
|
|
var/turf/origin = source.source_turf
|
|
var/working = source.rad_power
|
|
// Ray tracing.
|
|
while(origin != T)
|
|
origin = get_step_towards(origin, T)
|
|
// Only get the resistance if we don't already know it.
|
|
if(!resistance_cache[origin])
|
|
origin.calc_rad_resistance()
|
|
if(origin.cached_rad_resistance)
|
|
working = round((working / (origin.cached_rad_resistance * RADIATION_RESISTANCE_MULTIPLIER)), 0.1)
|
|
// Already affected by a stronger source (or its zero...)
|
|
if((working <= .) || (working <= RADIATION_THRESHOLD_CUTOFF))
|
|
break
|
|
// Butchered version of the inverse square law. Works for this purpose.
|
|
. = max((working / (dist ** 2)), .)
|
|
if(. <= RADIATION_THRESHOLD_CUTOFF)
|
|
. = 0
|
|
|
|
/**
|
|
* Add a /datum/radiation_source instance to the repository. It will override any existing source on the same turf.
|
|
*/
|
|
/datum/controller/subsystem/radiation/proc/add_source(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 /datum/radiation_source that will decay over time.
|
|
*
|
|
* This source will send out regular radiation pulses that take walls and distance into account.
|
|
*/
|
|
/datum/controller/subsystem/radiation/proc/radiate(source, power, increased_decay)
|
|
if(!(source && power)) //Sanity checking
|
|
return
|
|
var/datum/radiation_source/S = new()
|
|
S.source_turf = get_turf(source)
|
|
S.update_rad_power(power)
|
|
S.accelerated_decay_rate = increased_decay
|
|
add_source(S)
|
|
|
|
/**
|
|
* Creates a /datum/radiation_source that will decay over time.
|
|
*
|
|
* This source will send out regular radiation pulses that will deliver
|
|
* identical radiation doses to everyone in range, irrespective of barriers
|
|
* in the way or their distance from the source.
|
|
*/
|
|
/datum/controller/subsystem/radiation/proc/flat_radiate(source, power, range, respect_rad_shielding = FALSE)
|
|
if(!(source && power && range))
|
|
return
|
|
var/datum/radiation_source/S = new()
|
|
S.flat = TRUE
|
|
S.range = range
|
|
S.respect_rad_shielding = respect_rad_shielding
|
|
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(atom/source, power, respect_rad_shielding = FALSE)
|
|
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_rad_shielding)
|