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