/proc/scan_health(var/mob/M as mob, var/verbose_reagent_info = 0, var/disease_detection = 1) if (!M) return "ERROR: NO SUBJECT DETECTED" if (isghostdrone(M)) return "ERROR: INVALID DATA FROM SUBJECT" var/death_state = M.stat if (M.bioHolder && M.bioHolder.HasEffect("dead_scan")) death_state = 2 var/health_percent = round(100 * M.health / M.max_health) var/colored_health if (health_percent >= 51 && health_percent <= 100) colored_health = "[health_percent]" else if (health_percent >= 1 && health_percent <= 50) colored_health = "[health_percent]" else colored_health = "[health_percent]" var/optimal_temp = M.base_body_temp var/body_temp = "[M.bodytemperature - T0C]°C ([M.bodytemperature * 1.8-459.67]°F)" var/colored_temp = "" if (M.bodytemperature >= (optimal_temp + 60)) colored_temp = "[body_temp]" else if (M.bodytemperature >= (optimal_temp + 30)) colored_temp = "[body_temp]" else if (M.bodytemperature <= (optimal_temp - 60)) colored_temp = "[body_temp]" else if (M.bodytemperature <= (optimal_temp - 30)) colored_temp = "[body_temp]" else colored_temp = "[body_temp]" var/oxy = M.get_oxygen_deprivation() var/tox = M.get_toxin_damage() var/burn = M.get_burn_damage() var/brute = M.get_brute_damage() // contained here in order to change them easier var/oxy_font = "" var/tox_font = "" var/burn_font = "" var/brute_font = "" var/oxy_data = "[oxy > 50 ? "" : "[oxy_font]"][oxy]" var/tox_data = "[tox > 50 ? "" : "[tox_font]"][tox]" var/burn_data = "[burn > 50 ? "" : "[burn_font]"][burn]" var/brute_data = "[brute > 50 ? "" : "[brute_font]"][brute]" var/rad_data = null var/blood_data = null var/brain_data = null var/heart_data = null var/reagent_data = null var/pathogen_data = null var/disease_data = null if (ishuman(M)) var/mob/living/carbon/human/H = M if (blood_system) if (verbose_reagent_info) if (isvampire(H)) // Added a pair of vampire checks here (Convair880). blood_data = "Blood level: 500 units" else blood_data = "Blood level: [H.blood_volume] unit[H.blood_volume == 1 ? "" : "s"]" if (H.bleeding) blood_data += " | Blood loss: [H.bleeding] unit[H.bleeding == 1 ? "" : "s"]" else if (isvampire(H)) blood_data = "Blood level: NORMAL" else switch (H.blood_volume) if (401 to INFINITY) blood_data = "Blood level: NORMAL" if (251 to 400) blood_data = "Blood level: LOW" if (151 to 250) blood_data = "Blood level: VERY LOW" if (1 to 150) blood_data = "Blood level: DANGEROUSLY LOW" if (-INFINITY to 0) blood_data = "Blood level: NO BLOOD DETECTED" switch (H.bleeding) if (1 to 3) blood_data += " | Minor bleeding wounds detected" if (4 to 6) blood_data += " | Bleeding wounds detected" if (7 to INFINITY) blood_data += " | Major bleeding wounds detected" if (H.implant && H.implant.len > 0) var/bad_stuff = 0 for (var/obj/item/implant/I in H) if (istype(I, /obj/item/implant/projectile)) bad_stuff ++ if (bad_stuff) blood_data += " | Foreign object[bad_stuff == 1 ? "" : "s"] detected" if (H.pathogens.len) pathogen_data = "Scans indicate the presence of [H.pathogens.len > 1 ? "[H.pathogens.len] " : null]pathogenic bodies." var/list/therapy = list() var/remissive = 0 for (var/uid in H.pathogens) var/datum/pathogen/P = H.pathogens[uid] if (P.in_remission) remissive ++ if (!(P.suppressant.therapy in therapy)) therapy += P.suppressant.therapy var/count_part if (!remissive) count_part = "None of them appear" else if (remissive == 1) count_part = "One pathogen appears" else count_part = "[remissive] of them appear" pathogen_data += "
[count_part] to be in a remissive state." pathogen_data += "
Suggested pathogen suppression therapies: [jointext(therapy, ", ")]." if (H.organHolder) if (H.organHolder.brain) if (H.get_brain_damage() >= 100) brain_data = "Subject is braindead." else if (H.get_brain_damage() >= 60) brain_data = "Severe brain damage detected. Subject likely unable to function well." else if (H.get_brain_damage() >= 10) brain_data = "Significant brain damage detected. Subject may have had a concussion." else brain_data = "Subject has no brain." else brain_data = "Subject has no brain." if (H.organHolder && !H.organHolder.heart) heart_data = "Subject has no heart." if (M.radiation) rad_data = " Radiation: [round(M.radiation / 10, 0.1)] Gy" for (var/datum/ailment_data/A in M.ailments) if (disease_detection >= A.detectability) disease_data += "
[A.scan_info()]" if (M.reagents) if (verbose_reagent_info) reagent_data = scan_reagents(M, 0) else var/ephe_amt = M.reagents:get_reagent_amount("ephedrine") var/epi_amt = M.reagents:get_reagent_amount("epinephrine") var/atro_amt = M.reagents:get_reagent_amount("atropine") var/total_amt = ephe_amt + epi_amt + atro_amt if (total_amt) reagent_data = "Bloodstream Analysis located [total_amt] units of rejuvenation chemicals." if (!ishuman(M)) // vOv if (M.get_brain_damage() >= 100) brain_data = "Subject is braindead." else if (M.get_brain_damage() >= 60) brain_data = "Severe brain damage detected. Subject likely unable to function well." else if (M.get_brain_damage() >= 10) brain_data = "Significant brain damage detected. Subject may have had a concussion." var/data = "--------------------------------
\ Analyzing Results for [M]:
\   Overall Status: [death_state > 1 ? "DEAD" : "[colored_health]% healthy"]
\   Damage Specifics: [oxy_data] - [tox_data] - [burn_data] - [brute_data]
\   Key: [oxy_font]Suffocation
/[tox_font]Toxin
/[burn_font]Burns
/[brute_font]Brute

\ Body Temperature: [colored_temp]\ [rad_data ? "
[rad_data]" : null]\ [blood_data ? "
[blood_data]" : null]\ [brain_data ? "
[brain_data]" : null]\ [heart_data ? "
[heart_data]" : null]\ [reagent_data ? "
[reagent_data]" : null]\ [pathogen_data ? "
[pathogen_data]" : null]\ [disease_data ? "[disease_data]" : null]" return data /proc/update_medical_record(var/mob/living/carbon/human/M) if (!M || !ishuman(M)) return var/patientname = M.name if (M:wear_id && M:wear_id:registered) patientname = M.wear_id:registered for (var/datum/data/record/E in data_core.general) if (E.fields["name"] == patientname) switch (M.stat) if (0) if (M.bioHolder && M.bioHolder.HasEffect("fat")) E.fields["p_stat"] = "Physically Unfit" else E.fields["p_stat"] = "Active" if (1) E.fields["p_stat"] = "*Unconscious*" if (2) E.fields["p_stat"] = "*Deceased*" for (var/datum/data/record/R in data_core.medical) if ((R.fields["id"] == E.fields["id"])) R.fields["bioHolder.bloodType"] = M.bioHolder.bloodType R.fields["cdi"] = english_list(M.ailments, "No diseases have been diagnosed at the moment.") if (M.ailments.len) R.fields["cdi_d"] = "Diseases detected at [time2text(world.realtime,"hh:mm")]." else R.fields["cdi_d"] = "No notes." break break return /proc/scan_reagents(var/atom/A as turf|obj|mob, var/show_temp = 1, var/single_line = 0) if (!A) return "ERROR: NO SUBJECT DETECTED" var/data = null var/reagent_data = null if (A.reagents) if (A.reagents.reagent_list.len > 0) var/reagents_length = A.reagents.reagent_list.len data = "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found in [A]." for (var/current_id in A.reagents.reagent_list) var/datum/reagent/current_reagent = A.reagents.reagent_list[current_id] if (single_line) reagent_data += " [current_reagent] ([current_reagent.volume])," else reagent_data += "
 [current_reagent.name] - [current_reagent.volume]" if (single_line) data += "[copytext(reagent_data, 1, -1)]" else data += "[reagent_data]" if (show_temp) data += "
Overall temperature: [A.reagents.total_temperature - T0C]°C ([A.reagents.total_temperature * 1.8-459.67]°F)" else data = "No active chemical agents found in [A]." else data = "No significant chemical agents found in [A]." return data // Should make it easier to maintain the detective's scanner and PDA program (Convair880). /proc/scan_forensic(var/atom/A as turf|obj|mob) var/fingerprint_data = null var/blood_data = null var/forensic_data = null var/glove_data = null var/contraband_data = null if (!A) return "ERROR: NO SUBJECT DETECTED" if (istype(A, /mob/living/carbon/human)) var/mob/living/carbon/human/H = A if (!isnull(H.gloves)) var/obj/item/clothing/gloves/WG = H.gloves if (WG.glove_ID) glove_data += "[WG.glove_ID] ([H]'s worn [WG.name])" if (!WG.hide_prints) fingerprint_data += "
[H]'s fingerprints: [md5(H.bioHolder.Uid)]" else fingerprint_data += "
Unable to scan [H]'s fingerprints." else fingerprint_data += "
[H]'s fingerprints: [md5(H.bioHolder.Uid)]" if (H.gunshot_residue) // Left by firing a kinetic gun. forensic_data += "
Gunshot residue found." if (H.implant && H.implant.len > 0) var/wounds = null for (var/obj/item/implant/I in H) if (istype(I, /obj/item/implant/projectile)) wounds ++ if (wounds) forensic_data += "
[wounds] gunshot [wounds == 1 ? "wound" : "wounds"] detected." if (H.fingerprints) // Left by grabbing or pulling people. var/list/FFP = params2list(H:fingerprints) for(var/i in FFP) fingerprint_data += "
Foreign fingerprint on [H]: [i]" if (H.bioHolder.Uid) // For quick reference. Also, attacking somebody only makes their clothes bloody, not the mob (think naked dudes). blood_data += "
[H]'s blood DNA: [H.bioHolder.Uid]" if (H.blood_DNA && isnull(H.gloves)) // Don't magically detect blood through worn gloves. var/list/BH = params2list(H:blood_DNA) for(var/i in BH) blood_data += "
Blood on [H]'s hands: [i]" var/list/gear_to_check = list(H.head, H.wear_mask, H.w_uniform, H.wear_suit, H.belt, H.gloves, H.back) for (var/obj/item/check in gear_to_check) if (check && check.blood_DNA) var/list/BC = params2list(check.blood_DNA) for(var/i in BC) blood_data += "
Blood on worn [check.name]: [i]" if (H.r_hand && H.r_hand.blood_DNA) var/list/BIR = params2list(H.r_hand.blood_DNA) for(var/i in BIR) blood_data += "
Blood on held [H.r_hand.name]: [i]" if (H.l_hand && H.l_hand.blood_DNA) var/list/BIL = params2list(H.l_hand.blood_DNA) for(var/i in BIL) blood_data += "
Blood on held [H.l_hand.name]: [i]" else if (!A.fingerprints) fingerprint_data += "
Unable to locate any fingerprints." else var/list/FP = params2list(A:fingerprints) for(var/i in FP) fingerprint_data += "
[i]" if(!A.blood_DNA) blood_data += "
Unable to locate any blood traces." else var/list/DNA = params2list(A:blood_DNA) for(var/i in DNA) blood_data += "
[i]" if (istype(A, /obj/item)) var/obj/item/I = A if(I.contraband) contraband_data = "(CONTRABAND: LEVEL [I.contraband])" if (istype(A, /obj/item/clothing/gloves)) var/obj/item/clothing/gloves/G = A if (G.glove_ID) glove_data += "[G.glove_ID] [G.material_prints ? "([G.material_prints])" : null]" if (istype(A, /obj/item/casing/)) var/obj/item/casing/C = A if(C.forensic_ID) forensic_data += "
Forensic profile of [C]: [C.forensic_ID]" if (istype(A, /obj/item/implant/projectile)) var/obj/item/implant/projectile/P = A if(P.forensic_ID) forensic_data += "
Forensic profile of [P]: [P.forensic_ID]" if (istype(A, /obj/item/gun)) var/obj/item/gun/G = A if(G.forensic_ID) forensic_data += "
Forensic profile of [G]: [G.forensic_ID]" if (istype(A, /turf/simulated/wall)) var/turf/simulated/wall/W = A if (W.forensic_impacts && islist(W.forensic_impacts) && W.forensic_impacts.len) for(var/i in W.forensic_impacts) forensic_data += "
Forensic signature found: [i]" if (!fingerprint_data) // Just in case, we'd always want to have a readout for these. fingerprint_data = "
Unable to locate any fingerprints." if (!blood_data) blood_data = "
Unable to locate any blood traces." // This was the least enjoyable part of the entire exercise. Formatting is nothing but a chore. var/data = "--------------------------------
\ Forensic analysis of [A] [contraband_data ? "[contraband_data]" : null]
\
\ Isolated fingerprints:[fingerprint_data]
\
\ Isolated blood samples:[blood_data]
\ [forensic_data ? "
Additional forensic data:[forensic_data]
" : null]\ [glove_data ? "
Material analysis: [glove_data]" : null]\ " return data // Made this a global proc instead of 10 or so instances of duplicate code spread across the codebase (Convair880). /proc/scan_atmospheric(var/atom/A as turf|obj, var/pda_readout = 0, var/simple_output = 0) if (!A) if (pda_readout == 1) return "Unable to obtain a reading." else if (simple_output == 1) return "(Error: no source provided)" else return "Unable to obtain a reading." var/datum/gas_mixture/check_me = null var/pressure = null var/total_moles = null if (hasvar(A, "air_contents")) check_me = A:air_contents // Not pretty, but should be okay here. if (isturf(A)) check_me = A.return_air() if (istype(A, /obj/machinery/atmospherics/pipe)) var/obj/machinery/atmospherics/pipe/P = A check_me = P.parent.air if (istype(A, /obj/item/assembly/time_bomb)) var/obj/item/assembly/time_bomb/TB = A if (TB.part3) check_me = TB.part3.air_contents if (istype(A, /obj/item/assembly/radio_bomb)) var/obj/item/assembly/radio_bomb/RB = A if (RB.part3) check_me = RB.part3.air_contents if (istype(A, /obj/item/assembly/proximity_bomb)) var/obj/item/assembly/proximity_bomb/PB = A if (PB.part3) check_me = PB.part3.air_contents if (istype(A, /obj/item/flamethrower/)) var/obj/item/flamethrower/FT = A if (FT.part4) check_me = FT.part4.air_contents if (!check_me || !istype(check_me, /datum/gas_mixture/)) if (pda_readout == 1) return "[A] does not contain any gas." else if (simple_output == 1) return "([A] has no gas holder)" else return "[A] does not contain any gas." pressure = check_me.return_pressure() total_moles = check_me.total_moles() //DEBUG_MESSAGE("[A] contains: [pressure] kPa, [total_moles] moles.") var/data = "" if (total_moles > 0) var/o2_concentration = check_me.oxygen/total_moles var/n2_concentration = check_me.nitrogen/total_moles var/co2_concentration = check_me.carbon_dioxide/total_moles var/plasma_concentration = check_me.toxins/total_moles var/unknown_concentration = 1 - (o2_concentration + n2_concentration + co2_concentration + plasma_concentration) if (pda_readout == 1) // Output goes into PDA interface, not the user's chatbox. data = "Air Pressure: [round(pressure, 0.1)] kPa
\ Nitrogen: [round(n2_concentration * 100)]%
\ Oxygen: [round(o2_concentration * 100)]%
\ CO2: [round(co2_concentration * 100)]%
\ Plasma: [round(plasma_concentration * 100)]%
\ [unknown_concentration > 0.01 ? "Unknown: [round(unknown_concentration * 100)]%
" : ""]\ Temperature: [round(check_me.temperature - T0C)]°C
" else if (simple_output == 1) // For the log_atmos() proc. data = "(Pressure: [round(pressure, 0.1)] kPa, Temp: [round(check_me.temperature - T0C)]°C\ , Contents: [round(n2_concentration * 100)]% N2 / [round(o2_concentration * 100)]% O2 / [round(co2_concentration * 100)]% CO2 / [round(plasma_concentration * 100)]% PL\ [unknown_concentration > 0.01 ? " / [round(unknown_concentration * 100)]% other)" : ")"]" else data = "--------------------------------
\ Atmospheric analysis of [A]
\
\ Pressure: [round(pressure, 0.1)] kPa
\ Nitrogen: [round(n2_concentration * 100)]%
\ Oxygen: [round(o2_concentration * 100)]%
\ CO2: [round(co2_concentration * 100)]%
\ Plasma: [round(plasma_concentration * 100)]%
\ [unknown_concentration > 0.01 ? "
Unknown: [round(unknown_concentration * 100)]%
" : ""]\ Temperature: [round(check_me.temperature - T0C)]°C
" else // Only used for "Atmospheric Scan" accessible through the PDA interface, which targets the turf // the PDA user is standing on. Everything else (i.e. clicking with the PDA on objects) goes in the chatbox. if (pda_readout == 1) data = "This area does not contain any gas." else if (simple_output == 1) data = "(Contents: empty)" else data = "[A] does not contain any gas." return data // Yeah, another scan I made into a global proc (Convair880). /proc/scan_plant(var/atom/A as turf|obj, var/mob/user as mob) if (!A || !user || !ismob(user)) return var/datum/plant/P = null var/datum/plantgenes/DNA = null if (istype(A, /obj/machinery/plantpot)) var/obj/machinery/plantpot/PP = A if (!PP.current || PP.dead) return "Cannot scan." P = PP.current DNA = PP.plantgenes else if (istype(A, /obj/item/seed/)) var/obj/item/seed/S = A if (S.isstrange || !S.planttype) return "This seed has non-standard DNA and thus cannot be scanned." P = S.planttype DNA = S.plantgenes else if (istype(A, /obj/item/reagent_containers/food/snacks/plant/)) var/obj/item/reagent_containers/food/snacks/plant/F = A P = F.planttype DNA = F.plantgenes else return if (!P || !istype(P, /datum/plant/) || !DNA || !istype(DNA, /datum/plantgenes/)) return "Cannot scan." HYPgeneticanalysis(user, A, P, DNA) // Just use the existing proc. return