mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-22 04:07:57 +01:00
208 lines
6.5 KiB
Plaintext
208 lines
6.5 KiB
Plaintext
#define SSRADIATION_EMIT 1
|
|
#define SSRADIATION_FLUSH 2
|
|
#define SSRADIATION_PULSE 3
|
|
#define SSRADIATION_RADIATE 4
|
|
|
|
SUBSYSTEM_DEF(radiation)
|
|
name = "Radiation"
|
|
priority = FIRE_PRIORITY_RADIATION
|
|
subsystem_flags = SS_NO_INIT | SS_BACKGROUND
|
|
wait = 0.5 SECONDS
|
|
|
|
/// stage
|
|
var/stage = SSRADIATION_EMIT
|
|
/// atom refs we warned about already
|
|
var/list/warned_atoms = list()
|
|
/// z radiation listeners - nested list
|
|
var/list/z_listeners = list()
|
|
/// waves about to be sent out on next tick; list [ turf = list(burst) ]
|
|
var/list/queued_waves = list()
|
|
/// radioactivity sources we're ticking
|
|
var/list/datum/component/radioactive/sources = list()
|
|
/// radioactive sources we're about to tick
|
|
var/list/datum/component/radioactive/currentrun
|
|
/// queue not processed
|
|
var/list/next_wave_set
|
|
|
|
/// current waves
|
|
var/list/datum/radiation_wave/waves = list()
|
|
|
|
/datum/controller/subsystem/radiation/Recover()
|
|
z_listeners.len = world.maxz
|
|
for(var/i in 1 to length(z_listeners))
|
|
if(!islist(z_listeners[i]))
|
|
z_listeners[i] = list()
|
|
if(islist(SSradiation.z_listeners))
|
|
for(var/z in 1 to length(SSradiation.z_listeners))
|
|
var/list/atoms = SSradiation.z_listeners[z]
|
|
for(var/atom/A in atoms)
|
|
z_listeners[A.z] += A
|
|
if(islist(SSradiation.sources))
|
|
for(var/datum/component/radioactive/R in SSradiation.sources)
|
|
sources += R
|
|
|
|
/datum/controller/subsystem/radiation/fire(resumed)
|
|
if(!resumed)
|
|
stage = SSRADIATION_EMIT
|
|
if(stage == SSRADIATION_EMIT)
|
|
if(!resumed)
|
|
currentrun = sources.Copy()
|
|
if(length(currentrun))
|
|
var/i
|
|
var/datum/component/radioactive/source
|
|
var/dt = nominal_dt_s
|
|
for(i in 1 to length(currentrun))
|
|
source = currentrun[i]
|
|
source.emit(dt)
|
|
if(MC_TICK_CHECK)
|
|
currentrun.Cut(1, i + 1)
|
|
return
|
|
currentrun = null
|
|
resumed = FALSE
|
|
stage = SSRADIATION_FLUSH
|
|
if(stage == SSRADIATION_FLUSH)
|
|
flush_queue()
|
|
// change BEFORE tick check so we don't overwrite
|
|
stage = SSRADIATION_PULSE
|
|
// since we change before tick check, this means pulse CANNOT check resumed!
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
if(stage == SSRADIATION_PULSE)
|
|
if(length(next_wave_set))
|
|
emit_waves()
|
|
if(state != SS_RUNNING)
|
|
// pause if it's pausing
|
|
return
|
|
// done; we DO NOT need to set resumed
|
|
stage = SSRADIATION_RADIATE
|
|
if(stage == SSRADIATION_RADIATE)
|
|
// pulse all waves until complete
|
|
var/datum/radiation_wave/wave
|
|
while(length(waves))
|
|
wave = waves[length(waves)]
|
|
// tick to completion
|
|
if(wave.iterate(Master.current_ticklimit))
|
|
qdel(wave)
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/radiation/on_max_z_changed(old_z_count, new_z_count)
|
|
var/old = z_listeners.len
|
|
z_listeners.len = new_z_count
|
|
for(var/i in old + 1 to z_listeners.len)
|
|
z_listeners[i] = list()
|
|
|
|
/datum/controller/subsystem/radiation/proc/warn(datum/component/radioactive/contamination)
|
|
if(!contamination || QDELETED(contamination))
|
|
return
|
|
var/ref = REF(contamination.parent)
|
|
if(warned_atoms[ref])
|
|
return
|
|
warned_atoms[ref] = TRUE
|
|
var/atom/master = contamination.parent
|
|
// SSblackbox.record_feedback("tally", "contaminated", 1, master.type)
|
|
var/msg = "has become contaminated with enough radiation to contaminate other objects. || Strength: [contamination.strength]"
|
|
master.investigate_log(msg, INVESTIGATE_RADIATION)
|
|
|
|
/datum/controller/subsystem/radiation/proc/flush_queue()
|
|
next_wave_set = queued_waves
|
|
queued_waves = list()
|
|
|
|
/datum/controller/subsystem/radiation/proc/emit_waves()
|
|
var/i
|
|
var/list/next_wave_set = src.next_wave_set
|
|
for(i in 1 to length(next_wave_set))
|
|
var/turf/T = next_wave_set[i]
|
|
var/list/L = next_wave_set[T]
|
|
for(var/datum/radiation_burst/B as anything in L)
|
|
var/datum/radiation_wave/wave = new /datum/radiation_wave(T, B.intensity, B.falloff)
|
|
wave.start()
|
|
if(MC_TICK_CHECK)
|
|
break
|
|
next_wave_set.Cut(1, i + 1)
|
|
|
|
/datum/controller/subsystem/radiation/proc/queue_wave(turf/source, intensity, falloff, can_contaminate)
|
|
var/list/datum/radiation_burst/queue = queued_waves[source]
|
|
if(!queue)
|
|
queue = list()
|
|
queued_waves[source] = queue
|
|
for(var/datum/radiation_burst/B as anything in queue)
|
|
if(B.falloff == falloff)
|
|
B.intensity += intensity
|
|
if(intensity > RAD_MOB_ACT_PROTECTION_PER_WAVE_SOURCE)
|
|
++B.emitter_count
|
|
B.highest = max(B.highest, intensity)
|
|
return
|
|
queue += new /datum/radiation_burst(intensity, falloff)
|
|
|
|
/**
|
|
* todo: comment
|
|
*/
|
|
/datum/controller/subsystem/radiation/proc/radiation_pulse(atom/source, intensity, falloff_modifier, log, can_contaminate)
|
|
if(!can_fire) // we don't care
|
|
return FALSE
|
|
var/atom/nested = source
|
|
if(!nested.loc)
|
|
// we're not going to emit in nullspace at all, don't bother
|
|
return
|
|
var/waves = TRUE
|
|
var/turf/T
|
|
if(!isturf(nested))
|
|
do
|
|
nested = nested.loc
|
|
if(nested.rad_flags & RAD_BLOCK_CONTENTS)
|
|
waves = FALSE
|
|
break
|
|
while(nested.loc && !isarea(nested.loc))
|
|
T = get_turf(nested)
|
|
else
|
|
T = nested
|
|
if(waves && T)
|
|
queue_wave(T, intensity, falloff_modifier, can_contaminate)
|
|
var/static/last_huge_pulse = 0
|
|
if(intensity > 1000 && world.time > last_huge_pulse + 10 SECONDS)
|
|
last_huge_pulse = world.time
|
|
log = TRUE
|
|
else
|
|
var/list/things = get_rad_contents(nested)
|
|
for(var/atom/A as anything in things)
|
|
A.rad_act(intensity)
|
|
if(log)
|
|
log_game("Pulse intensity [intensity] falloff [falloff_modifier] in [AREACOORD(T)][waves? "" : " (contained by [nested])"]")
|
|
return TRUE
|
|
|
|
/**
|
|
* does our best faith attempt at irradiating a whole zlevel without lagging the server to death
|
|
*/
|
|
/datum/controller/subsystem/radiation/proc/z_radiation(turf/T, z, intensity, falloff_modifier, log, can_contaminate, z_radiate_flags)
|
|
if(!T && !z)
|
|
CRASH("need either turf or z")
|
|
if(!z)
|
|
z = T.z
|
|
// you can tell that this proc is hand-optimized, huh.
|
|
// :skull_crossbones:
|
|
if(z_radiate_flags)
|
|
if(falloff_modifier && T)
|
|
for(var/atom/A as anything in z_listeners[z])
|
|
if(z_radiate_flags & Z_RADIATE_CHECK_AREA_SHIELD)
|
|
var/area/checking = get_area(A)
|
|
if(checking.area_flags & AREA_RAD_SHIELDED)
|
|
continue
|
|
var/dist = max(1, get_dist(A, T) * falloff_modifier)
|
|
A.z_rad_act(INVERSE_SQUARE(intensity, dist, 1))
|
|
else
|
|
for(var/atom/A as anything in z_listeners[z])
|
|
if(z_radiate_flags & Z_RADIATE_CHECK_AREA_SHIELD)
|
|
var/area/checking = get_area(A)
|
|
if(checking.area_flags & AREA_RAD_SHIELDED)
|
|
continue
|
|
A.z_rad_act(intensity)
|
|
else
|
|
if(falloff_modifier && T)
|
|
for(var/atom/A as anything in z_listeners[z])
|
|
var/dist = max(1, get_dist(A, T) * falloff_modifier)
|
|
A.z_rad_act(INVERSE_SQUARE(intensity, dist, 1))
|
|
else
|
|
for(var/atom/A as anything in z_listeners[z])
|
|
A.z_rad_act(intensity)
|