Modernizing Radiation -- TL;DR: Radiation is now a status effect healed by tox healing, and contamination is removed (#62265)

Implements the Modernizing radiation design document ( https://hackmd.io/@tgstation/rJNIyeBHt ) and replaces the current radiation sources with the new system, as well as replacing/removing a bunch of old consumers of radiation that either had no reason to exist, or could be replaced by something else.

Diverges from the doc in that items radiation don't go up like explained. I was going to, but items get irradiated so easily that it just feels pretty lame. Items still get irradiated, but it's mostly just so that radiation sources look cooler (wow, lots of stuff around going green), and for things like the geiger counter.

Instead of the complicated radiation_wave system, radiation now just checks everything between the radiation source and the potential target, losing power along the way based on the radiation insulation of whats in between. If this reaches too low a point (specified by radiation_pulse consumers), then the radiation will not pass. Otherwise, will roll a chance to irradiate. Uranium structures allow a delay before irradiating, so stay away!
This commit is contained in:
Mothblocks
2021-11-01 04:20:39 -03:00
committed by GitHub
parent 9003982726
commit 0f3c4e51f7
342 changed files with 1869 additions and 2152 deletions
+1 -21
View File
@@ -7,7 +7,6 @@ GLOBAL_LIST_EMPTY(PDAs)
#define PDA_SCANNER_MEDICAL 1
#define PDA_SCANNER_FORENSICS 2 //unused
#define PDA_SCANNER_REAGENT 3
#define PDA_SCANNER_HALOGEN 4
#define PDA_SCANNER_GAS 5
#define PDA_SPAM_DELAY 2 MINUTES
@@ -26,7 +25,7 @@ GLOBAL_LIST_EMPTY(PDAs)
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
actions_types = list(/datum/action/item_action/toggle_light)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 100, ACID = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
light_system = MOVABLE_LIGHT_DIRECTIONAL
light_range = 2.3
@@ -321,8 +320,6 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "<li><a href='byond://?src=[REF(src)];choice=53'>[PDAIMG(notes)]Newscaster Access </a></li>"
if (cartridge.access & CART_REAGENT_SCANNER)
dat += "<li><a href='byond://?src=[REF(src)];choice=Reagent Scan'>[PDAIMG(reagent)][scanmode == 3 ? "Disable" : "Enable"] Reagent Scanner</a></li>"
if (cartridge.access & CART_ENGINE)
dat += "<li><a href='byond://?src=[REF(src)];choice=Halogen Counter'>[PDAIMG(reagent)][scanmode == 4 ? "Disable" : "Enable"] Halogen Counter</a></li>"
if (cartridge.access & CART_ATMOS)
dat += "<li><a href='byond://?src=[REF(src)];choice=Gas Scan'>[PDAIMG(reagent)][scanmode == 5 ? "Disable" : "Enable"] Gas Scanner</a></li>"
if (cartridge.access & CART_REMOTE_DOOR)
@@ -566,13 +563,6 @@ GLOBAL_LIST_EMPTY(PDAs)
scanmode = PDA_SCANNER_NONE
else if((!isnull(cartridge)) && (cartridge.access & CART_REAGENT_SCANNER))
scanmode = PDA_SCANNER_REAGENT
if("Halogen Counter")
if(scanmode == PDA_SCANNER_HALOGEN)
scanmode = PDA_SCANNER_NONE
else if((!isnull(cartridge)) && (cartridge.access & CART_ENGINE))
scanmode = PDA_SCANNER_HALOGEN
if(!silent)
playsound(src, 'sound/machines/terminal_select.ogg', 15, TRUE)
if("Honk")
if ( !(last_noise && world.time < last_noise + 20) )
playsound(src, 'sound/items/bikehorn.ogg', 50, TRUE)
@@ -1103,15 +1093,6 @@ GLOBAL_LIST_EMPTY(PDAs)
healthscan(user, C, 1)
add_fingerprint(user)
if(PDA_SCANNER_HALOGEN)
C.visible_message(span_notice("[user] analyzes [C]'s radiation levels."))
user.show_message(span_notice("Analyzing Results for [C]:"))
if(C.radiation)
user.show_message("\green Radiation Level: \black [C.radiation]")
else
user.show_message(span_notice("No radiation detected."))
/obj/item/pda/afterattack(atom/A as mob|obj|turf|area, mob/user, proximity)
. = ..()
if(!proximity)
@@ -1288,6 +1269,5 @@ GLOBAL_LIST_EMPTY(PDAs)
#undef PDA_SCANNER_MEDICAL
#undef PDA_SCANNER_FORENSICS
#undef PDA_SCANNER_REAGENT
#undef PDA_SCANNER_HALOGEN
#undef PDA_SCANNER_GAS
#undef PDA_SPAM_DELAY
@@ -103,7 +103,7 @@
mouse_opacity = MOUSE_OPACITY_OPAQUE
resistance_flags = INDESTRUCTIBLE
can_atmos_pass = ATMOS_PASS_DENSITY
armor = list(MELEE = 0, BULLET = 25, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 100, RAD = 100, FIRE = 100, ACID = 100)
armor = list(MELEE = 0, BULLET = 25, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 100, FIRE = 100, ACID = 100)
var/obj/item/forcefield_projector/generator
/obj/structure/projected_forcefield/Initialize(mapload, obj/item/forcefield_projector/origin)
+59 -165
View File
@@ -1,9 +1,3 @@
#define RAD_LEVEL_NORMAL 9
#define RAD_LEVEL_MODERATE 100
#define RAD_LEVEL_HIGH 400
#define RAD_LEVEL_VERY_HIGH 800
#define RAD_LEVEL_CRITICAL 1500
/obj/item/geiger_counter //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."
@@ -18,158 +12,102 @@
item_flags = NOBLUDGEON
custom_materials = list(/datum/material/iron = 150, /datum/material/glass = 150)
var/grace = RAD_GEIGER_GRACE_PERIOD
var/datum/looping_sound/geiger/soundloop
var/last_perceived_radiation_danger = null
var/scanning = FALSE
var/radiation_count = 0
var/current_tick_amount = 0
var/last_tick_amount = 0
var/fail_to_receive = 0
var/current_warning = 1
/obj/item/geiger_counter/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
soundloop = new(src, FALSE)
/obj/item/geiger_counter/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_NULL(soundloop)
return ..()
/obj/item/geiger_counter/process(delta_time)
if(scanning)
radiation_count = LPFILTER(radiation_count, current_tick_amount, delta_time, RAD_GEIGER_RC)
if(current_tick_amount)
grace = RAD_GEIGER_GRACE_PERIOD
last_tick_amount = current_tick_amount
else if(!(obj_flags & EMAGGED))
grace -= delta_time
if(grace <= 0)
radiation_count = 0
current_tick_amount = 0
update_appearance()
update_sound()
RegisterSignal(src, COMSIG_IN_RANGE_OF_IRRADIATION, .proc/on_pre_potential_irradiation)
/obj/item/geiger_counter/examine(mob/user)
. = ..()
if(!scanning)
return
. += span_info("Alt-click it to clear stored radiation levels.")
if(obj_flags & EMAGGED)
. += span_warning("The display seems to be incomprehensible.")
return
switch(radiation_count)
if(-INFINITY to RAD_LEVEL_NORMAL)
switch(last_perceived_radiation_danger)
if(null)
. += span_notice("Ambient radiation level count reports that all is well.")
if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
if(PERCEIVED_RADIATION_DANGER_LOW)
. += span_alert("Ambient radiation levels slightly above average.")
if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
if(PERCEIVED_RADIATION_DANGER_MEDIUM)
. += span_warning("Ambient radiation levels above average.")
if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
if(PERCEIVED_RADIATION_DANGER_HIGH)
. += span_danger("Ambient radiation levels highly above average.")
if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
. += span_suicide("Ambient radiation levels nearing critical level.")
if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
. += span_boldannounce("Ambient radiation levels above critical level!")
. += span_notice("The last radiation amount detected was [last_tick_amount]")
if(PERCEIVED_RADIATION_DANGER_EXTREME)
. += span_suicide("Ambient radiation levels reaching critical level!")
/obj/item/geiger_counter/update_icon_state()
if(!scanning)
icon_state = "geiger_off"
return ..()
if(obj_flags & EMAGGED)
icon_state = "geiger_on_emag"
return ..()
switch(radiation_count)
if(-INFINITY to RAD_LEVEL_NORMAL)
switch(last_perceived_radiation_danger)
if(null)
icon_state = "geiger_on_1"
if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
if(PERCEIVED_RADIATION_DANGER_LOW)
icon_state = "geiger_on_2"
if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
if(PERCEIVED_RADIATION_DANGER_MEDIUM)
icon_state = "geiger_on_3"
if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
if(PERCEIVED_RADIATION_DANGER_HIGH)
icon_state = "geiger_on_4"
if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
icon_state = "geiger_on_4"
if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
if(PERCEIVED_RADIATION_DANGER_EXTREME)
icon_state = "geiger_on_5"
return ..()
/obj/item/geiger_counter/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_counter/rad_act(amount)
. = ..()
if(amount <= RAD_BACKGROUND_RADIATION || !scanning)
return
current_tick_amount += amount
update_appearance()
/obj/item/geiger_counter/attack_self(mob/user)
scanning = !scanning
update_appearance()
if (scanning)
AddComponent(/datum/component/geiger_sound)
else
qdel(GetComponent(/datum/component/geiger_sound))
update_appearance(UPDATE_ICON)
to_chat(user, span_notice("[icon2html(src, user)] You switch [scanning ? "on" : "off"] [src]."))
/obj/item/geiger_counter/afterattack(atom/target, mob/living/user, params)
. = ..()
if(!user.combat_mode)
if(!(obj_flags & EMAGGED))
user.visible_message(span_notice("[user] scans [target] with [src]."), span_notice("You scan [target]'s radiation levels with [src]..."))
addtimer(CALLBACK(src, .proc/scan, target, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
else
user.visible_message(span_notice("[user] scans [target] with [src]."), span_danger("You project [src]'s stored radiation into [target]!"))
target.rad_act(radiation_count)
radiation_count = 0
return TRUE
/obj/item/geiger_counter/proc/scan(atom/A, mob/user)
var/rad_strength = get_rad_contamination(A)
if (user.combat_mode)
return
if(isliving(A))
var/mob/living/M = A
if(!M.radiation)
to_chat(user, span_notice("[icon2html(src, user)] Radiation levels within normal boundaries."))
else
to_chat(user, span_boldannounce("[icon2html(src, user)] Subject is irradiated. Radiation levels: [M.radiation]."))
if (!CAN_IRRADIATE(target))
return
if(rad_strength)
to_chat(user, span_boldannounce("[icon2html(src, user)] Target contains radioactive contamination. Radioactive strength: [rad_strength]"))
else
to_chat(user, span_notice("[icon2html(src, user)] Target is free of radioactive contamination."))
user.visible_message(span_notice("[user] scans [target] with [src]."), span_notice("You scan [target]'s radiation levels with [src]..."))
addtimer(CALLBACK(src, .proc/scan, target, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
/obj/item/geiger_counter/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_SCREWDRIVER && (obj_flags & EMAGGED))
if(scanning)
to_chat(user, span_warning("Turn off [src] before you perform this action!"))
return FALSE
user.visible_message(span_notice("[user] unscrews [src]'s maintenance panel and begins fiddling with its innards..."), span_notice("You begin resetting [src]..."))
if(!I.use_tool(src, user, 40, volume=50))
return FALSE
user.visible_message(span_notice("[user] refastens [src]'s maintenance panel!"), span_notice("You reset [src] to its factory settings!"))
obj_flags &= ~EMAGGED
radiation_count = 0
update_appearance()
return TRUE
else
return ..()
/obj/item/geiger_counter/equipped(mob/user, slot, initial)
. = ..()
RegisterSignal(user, COMSIG_IN_RANGE_OF_IRRADIATION, .proc/on_pre_potential_irradiation)
/obj/item/geiger_counter/dropped(mob/user, silent = FALSE)
. = ..()
UnregisterSignal(user, COMSIG_IN_RANGE_OF_IRRADIATION, .proc/on_pre_potential_irradiation)
/obj/item/geiger_counter/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/reset_perceived_danger), TIME_WITHOUT_RADIATION_BEFORE_RESET, TIMER_UNIQUE | TIMER_OVERRIDE)
if (scanning)
update_appearance(UPDATE_ICON)
/obj/item/geiger_counter/proc/reset_perceived_danger()
last_perceived_radiation_danger = null
if (scanning)
update_appearance(UPDATE_ICON)
/obj/item/geiger_counter/proc/scan(atom/target, mob/user)
if (SEND_SIGNAL(target, COMSIG_GEIGER_COUNTER_SCAN, user, src) & COMSIG_GEIGER_COUNTER_SCAN_SUCCESSFUL)
return
to_chat(user, span_notice("[icon2html(src, user)] [isliving(target) ? "Subject" : "Target"] is free of radioactive contamination."))
/obj/item/geiger_counter/AltClick(mob/living/user)
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
@@ -177,50 +115,6 @@
if(!scanning)
to_chat(usr, span_warning("[src] must be on to reset its radiation level!"))
return
radiation_count = 0
to_chat(usr, span_notice("You flush [src]'s radiation counts, resetting it to normal."))
update_appearance()
/obj/item/geiger_counter/emag_act(mob/user)
if(obj_flags & EMAGGED)
return
if(scanning)
to_chat(user, span_warning("Turn off [src] before you perform this action!"))
return
to_chat(user, span_warning("You override [src]'s radiation storing protocols. It will now generate small doses of radiation, and stored rads are now projected into creatures you scan."))
obj_flags |= EMAGGED
/obj/item/geiger_counter/cyborg
var/mob/listeningTo
/obj/item/geiger_counter/cyborg/cyborg_unequip(mob/user)
if(!scanning)
return
scanning = FALSE
update_appearance()
/obj/item/geiger_counter/cyborg/equipped(mob/user)
. = ..()
if(listeningTo == user)
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
RegisterSignal(user, COMSIG_ATOM_RAD_ACT, .proc/redirect_rad_act)
listeningTo = user
/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount)
SIGNAL_HANDLER
rad_act(amount)
/obj/item/geiger_counter/cyborg/dropped()
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
#undef RAD_LEVEL_NORMAL
#undef RAD_LEVEL_MODERATE
#undef RAD_LEVEL_HIGH
#undef RAD_LEVEL_VERY_HIGH
#undef RAD_LEVEL_CRITICAL
last_perceived_radiation_danger = null
update_appearance(UPDATE_ICON)
+4 -4
View File
@@ -174,6 +174,8 @@ GENE SCANNER
render_list += "[span_info("Analyzing results for [M]:")]\n<span class='info ml-1'>Overall status: [mob_status]</span>\n"
SEND_SIGNAL(M, COMSIG_LIVING_HEALTHSCAN, render_list, advanced, user, mode)
// Husk detection
if(advanced && HAS_TRAIT_FROM(M, TRAIT_HUSK, BURN))
render_list += "<span class='alert ml-1'>Subject has been husked by severe burns.</span>\n"
@@ -238,10 +240,8 @@ GENE SCANNER
if(advanced)
render_list += "<span class='info ml-1'>Brain Activity Level: [(200 - M.getOrganLoss(ORGAN_SLOT_BRAIN))/2]%.</span>\n"
if (M.radiation)
render_list += "<span class='alert ml-1'>Subject is irradiated.</span>\n"
if(advanced)
render_list += "<span class='info ml-1'>Radiation Level: [M.radiation]%.</span>\n"
if (HAS_TRAIT(M, TRAIT_IRRADIATED))
render_list += "<span class='alert ml-1'>Subject is irradiated. Supply toxin healing.</span>\n"
if(advanced && M.hallucinating())
render_list += "<span class='info ml-1'>Subject is hallucinating.</span>\n"
@@ -97,7 +97,6 @@ effective or pretty fucking useless.
return
if(passed_intensity >= 5)
M.apply_effect(round(passed_intensity/0.075), EFFECT_UNCONSCIOUS) //to save you some math, this is a round(intensity * (4/3)) second long knockout
M.rad_act(passed_intensity*10)
/obj/item/healthanalyzer/rad_laser/proc/get_cooldown()
return round(max(10, (stealth*30 + intensity*5 - wavelength/4)))