/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