/proc/scan_health(var/mob/M as mob, var/verbose_reagent_info = 0, var/disease_detection = 1, var/organ_scan = 0) 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/nrad_data = null var/blood_data = null var/brain_data = null // var/heart_data = null //Moving this to organ_data for now. -kyle var/reagent_data = null var/pathogen_data = null var/disease_data = null var/organ_data = null var/interesting_data = null if (ishuman(M)) var/mob/living/carbon/human/H = M if (blood_system) H.ensure_bp_list() var/bp_col switch (H.blood_pressure["total"]) if (-INFINITY to 374) // very low (90/60) bp_col = "red" if (375 to 414) // low (100/65) bp_col = "#CC7A1D" if (415 to 584) // normal (120/80) bp_col = "#138015" if (585 to 665) // high (140/90) bp_col = "#CC7A1D" if (666 to INFINITY) // very high (160/100) bp_col = "red" if (isdead(H)) blood_data = "Blood Pressure: NO PULSE" else blood_data = "Blood Pressure: [H.blood_pressure["rendered"]] ([H.blood_pressure["status"]])" 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_pressure["total"]] unit[s_es(H.blood_pressure["total"])]" if (H.bleeding) blood_data += " | Blood loss: [H.bleeding] unit[s_es(H.bleeding)]" else if (!isvampire(H)) 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) || H.chest_item != null) var/bad_stuff = 0 for (var/obj/item/implant/I in H) if (istype(I, /obj/item/implant/projectile)) bad_stuff ++ if(H.chest_item != null) // If item is in chest, add one bad_stuff ++ if (bad_stuff) blood_data += " | Foreign object[s_es(bad_stuff)] detected" if(H.chest_item != null) // State that large foreign object is located in chest blood_data += " | Sizable foreign object located below sternum" 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.get_organ("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." // if (!H.get_organ("heart")) // heart_data = "Subject has no heart." if (organ_scan) var/organ_data1 = null var/obfuscate = (disease_detection != 255 ? 1 : 0) //this is so admin check_health verb see exact numbs, scanners don't. Can remove, not exactly necessary, but thought they might want it. organ_data1 += organ_health_scan("heart", H, obfuscate) // organ_data1 += organ_health_scan("brain", H, obfuscate) //Might want, might not. will be slightly more accurate than current brain damage scan organ_data1 += organ_health_scan("left_lung", H, obfuscate) organ_data1 += organ_health_scan("right_lung", H, obfuscate) organ_data1 += organ_health_scan("left_kidney", H, obfuscate) organ_data1 += organ_health_scan("right_kidney", H, obfuscate) organ_data1 += organ_health_scan("liver", H, obfuscate) organ_data1 += organ_health_scan("stomach", H, obfuscate) organ_data1 += organ_health_scan("intestines", H, obfuscate) organ_data1 += organ_health_scan("spleen", H, obfuscate) organ_data1 += organ_health_scan("pancreas", H, obfuscate) organ_data1 += organ_health_scan("appendix", H, obfuscate) //Don't give organ readings for Vamps. if (organ_data1 && !isvampire(H)) organ_data = "Internal Injuries:" organ_data += organ_data1 else organ_data = "Scans indicate organs are in perfect health." //Joke in case there is no organHolder if (!H.organHolder) organ_data = "Subject has no organs. Veeeerrrry curious." var/datum/statusEffect/simpledot/radiation/R = M.hasStatus("radiation") var/datum/statusEffect/simpledot/radiation/NR = M.hasStatus("n_radiation") if (R) rad_data = " Radiation poisoning: Lv [R.stage]" if (NR) nrad_data = " Neutron Radiation poisoning: Lv [NR.stage]" 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." if (M.interesting) interesting_data += "
[M.interesting]" 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]\ [nrad_data ? "
[nrad_data]" : null]\ [blood_data ? "
[blood_data]" : null]\ [brain_data ? "
[brain_data]" : null]\ [organ_data ? "
[organ_data]" : null]\ [reagent_data ? "
[reagent_data]" : null]\ [pathogen_data ? "
[pathogen_data]" : null]\ [disease_data ? "[disease_data]" : null]\ [interesting_data ? "
Historical analysis: [interesting_data]" : null]\ " return data //KYLE-NOTE- Maybe use get_organ here. Didn't exist in 2016 when I wrote this. //takes string input, for name in organholder.organ_list and checks if the organholder has anything //obfuscate, if true then don't show the exact organ health amount. Minor damage, moderate damage, severe damage, critical damage /proc/organ_health_scan(var/input, var/mob/living/carbon/human/H, var/obfuscate = 0) var/obj/item/organ/O = H.organHolder.organ_list[input] if (istype(O)) var/damage = O.get_damage() if (obfuscate) return obfuscate_organ_health(O) else if (damage > 0) return "
[input] - [O.get_damage()]" else return null else return "
[input] - missing!" //Using input here because it get's the organs name in an easy and clear way. using name or organ_name in obj/item/organ is not any better really /proc/obfuscate_organ_health(var/obj/item/organ/O) if (!O) return null var/damage = O.get_damage() if (damage >= O.MAX_DAMAGE) return "
[O.name] - Dead" else if (damage >= O.MAX_DAMAGE*0.9) return "
[O.name] - Critical" else if (damage >= O.MAX_DAMAGE*0.65) return "
[O.name] - Significant" else if (damage >= O.MAX_DAMAGE*0.30) return "
[O.name] - Moderate" else if (damage > 0) return "
[O.name] - Minor" return null /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) if (istype(A, /obj/ability_button)) // STOP THAT return var/fingerprint_data = null var/blood_data = null var/forensic_data = null var/glove_data = null var/contraband_data = null var/interesting_data = null if (!A) return "ERROR: NO SUBJECT DETECTED" if (ishuman(A)) 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) var/list/BC if (check.blood_DNA) BC = params2list(check.blood_DNA) for(var/i in BC) blood_data += "
Blood on worn [check.name]: [i]" /*var/trace_blood = check.get_forensic_trace("bDNA") if (trace_blood) BC = params2list(trace_blood) for (var/i in BC) blood_data += "
Blood trace 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 (istype(A, /obj/item/parts/human_parts)) var/obj/item/parts/human_parts/H = A if (H.original_DNA) blood_data += "
[H]'s blood DNA: [H.original_DNA]" if (istype(H, /obj/item/parts/human_parts/arm)) // has fringerpints fingerprint_data += "
[H]'s fingerprints: [H.original_fprints]" else if (istype(A, /obj/item/organ)) var/obj/item/organ/O = A if (O.donor_DNA) blood_data += "
[O]'s blood DNA: [O.donor_DNA]" else if (istype(A, /obj/item/clothing/head/butt)) var/obj/item/clothing/head/butt/B = A if (B.donor_DNA) blood_data += "
[B]'s blood DNA: [B.donor_DNA]" else if (isobj(A) && A.reagents && A.is_open_container() && A.reagents.has_reagent("blood")) var/datum/reagent/blood/B = A.reagents.reagent_list["blood"] if (B && istype(B.data, /datum/bioHolder)) var/datum/bioHolder/BH = B.data if (BH.Uid) blood_data += "
Blood DNA inside [A]: [BH.Uid]" if (A.interesting) if (istype(A, /obj)) interesting_data += "
[A.interesting]" if (istype(A, /turf)) interesting_data += "
There seems to be more to [A] than meets the eye." // if (!A.fingerprints) /*var/list/FP = params2list(A.get_forensic_trace("fprints")) if (FP) for (var/i in FP) fingerprint_data += "
[i]" else *///fingerprint_data += "
Unable to locate any fingerprints." // else if (A.fingerprints) var/list/FP = params2list(A:fingerprints) for(var/i in FP) fingerprint_data += "
[i]" // if (!A.blood_DNA) /*var/list/DNA = params2list(A.get_forensic_trace("bDNA")) if (DNA) for (var/i in DNA) blood_data += "
[i]" else *///blood_data += "
Unable to locate any blood traces." // else if (A.blood_DNA) var/list/DNA = params2list(A:blood_DNA) for(var/i in DNA) blood_data += "
[i]" if (isitem(A)) 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]\ [interesting_data ? "
Energy signature analysis: [interesting_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