/* CONTAINS: T-RAY DETECTIVE SCANNER HEALTH ANALYZER GAS ANALYZER MASS SPECTROMETER REAGENT SCANNER */ /obj/item/device/healthanalyzer name = "health analyzer" desc = "A hand-held body scanner able to distinguish vital signs of the subject." icon_state = "health" item_state = "healthanalyzer" flags = CONDUCT slot_flags = SLOT_BELT throwforce = 3 w_class = ITEMSIZE_SMALL throw_speed = 5 throw_range = 10 matter = list(DEFAULT_WALL_MATERIAL = 200) origin_tech = list(TECH_MAGNET = 1, TECH_BIO = 1) var/mode = 1; var/advscan = 0 var/showadvscan = 1 /obj/item/device/healthanalyzer/New() if(advscan >= 1) verbs += /obj/item/device/healthanalyzer/proc/toggle_adv ..() /obj/item/device/healthanalyzer/do_surgery(mob/living/M, mob/living/user) if(user.a_intent != I_HELP) //in case it is ever used as a surgery tool return ..() scan_mob(M, user) //default surgery behaviour is just to scan as usual return 1 /obj/item/device/healthanalyzer/attack(mob/living/M, mob/living/user) scan_mob(M, user) /obj/item/device/healthanalyzer/proc/scan_mob(mob/living/M, mob/living/user) if ((CLUMSY in user.mutations) && prob(50)) user << text("You try to analyze the floor's vitals!") for(var/mob/O in viewers(M, null)) O.show_message("\The [user] has analyzed the floor's vitals!", 1) user.show_message("Analyzing Results for The floor:", 1) user.show_message("Overall Status: Healthy", 1) user.show_message(" Damage Specifics: 0-0-0-0", 1) user.show_message("Key: Suffocation/Toxin/Burns/Brute", 1) user.show_message("Body Temperature: ???", 1) return if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") usr << "You don't have the dexterity to do this!" return user.visible_message("[user] has analyzed [M]'s vitals.","You have analyzed [M]'s vitals.") if (!istype(M,/mob/living/carbon/human) || M.isSynthetic()) //these sensors are designed for organic life user.show_message("Analyzing Results for ERROR:\n\t Overall Status: ERROR") user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) user.show_message(" Damage Specifics: ? - ? - ? - ?") user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) user.show_message("Warning: Blood Level ERROR: --% --cl. Type: ERROR") user.show_message("Subject's pulse: -- bpm.") return var/fake_oxy = max(rand(1,40), M.getOxyLoss(), (300 - (M.getToxLoss() + M.getFireLoss() + M.getBruteLoss()))) var/OX = M.getOxyLoss() > 50 ? "[M.getOxyLoss()]" : M.getOxyLoss() var/TX = M.getToxLoss() > 50 ? "[M.getToxLoss()]" : M.getToxLoss() var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() if(M.status_flags & FAKEDEATH) OX = fake_oxy > 50 ? "[fake_oxy]" : fake_oxy user.show_message("Analyzing Results for [M]:") user.show_message("Overall Status: dead") else user.show_message("Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "dead" : "[round((M.health/M.getMaxHealth())*100) ]% healthy"]") user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) user.show_message(" Damage Specifics: [OX] - [TX] - [BU] - [BR]") user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) user.show_message("Time of Death: [M.tod]") if(istype(M, /mob/living/carbon/human) && mode == 1) var/mob/living/carbon/human/H = M var/list/damaged = H.get_damaged_organs(1,1) user.show_message("Localized Damage, Brute/Burn:",1) if(length(damaged)>0) for(var/obj/item/organ/external/org in damaged) if(org.robotic >= ORGAN_ROBOT) continue else user.show_message(text(" []: [][] - []", capitalize(org.name), (org.brute_dam > 0) ? "[org.brute_dam]" : 0, (org.status & ORGAN_BLEEDING)?"\[Bleeding\]":"", (org.burn_dam > 0) ? "[org.burn_dam]" : 0),1) else user.show_message(" Limbs are OK.",1) OX = M.getOxyLoss() > 50 ? "Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal" TX = M.getToxLoss() > 50 ? "Dangerous amount of toxins detected" : "Subject bloodstream toxin level minimal" BU = M.getFireLoss() > 50 ? "Severe burn damage detected" : "Subject burn injury status O.K" BR = M.getBruteLoss() > 50 ? "Severe anatomical damage detected" : "Subject brute-force injury status O.K" if(M.status_flags & FAKEDEATH) OX = fake_oxy > 50 ? "Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal" user.show_message("[OX] | [TX] | [BU] | [BR]") if(M.radiation) if(advscan >= 2 && showadvscan == 1) if(M.radiation >= 75) user.show_message("Critical levels of radiation detected. Immediate treatment advised.") else if(M.radiation >= 50) user.show_message("Severe levels of radiation detected.") else if(M.radiation >= 25) user.show_message("Moderate levels of radiation detected.") else if(M.radiation >= 1) user.show_message("Low levels of radiation detected.") else user.show_message("Radiation detected.") if(istype(M, /mob/living/carbon)) var/mob/living/carbon/C = M if(C.reagents.total_volume) var/unknown = 0 var/reagentdata[0] var/unknownreagents[0] for(var/A in C.reagents.reagent_list) var/datum/reagent/R = A if(R.scannable) reagentdata["[R.id]"] = " [round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name]" else unknown++ unknownreagents["[R.id]"] = " [round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name]" if(reagentdata.len) user.show_message("Beneficial reagents detected in subject's blood:") for(var/d in reagentdata) user.show_message(reagentdata[d]) if(unknown) if(advscan >= 3 && showadvscan == 1) user.show_message("Warning: Non-medical reagent[(unknown>1)?"s":""] detected in subject's blood:") for(var/d in unknownreagents) user.show_message(unknownreagents[d]) else user.show_message("Warning: Unknown substance[(unknown>1)?"s":""] detected in subject's blood.") if(C.ingested && C.ingested.total_volume) var/unknown = 0 var/stomachreagentdata[0] var/stomachunknownreagents[0] for(var/B in C.ingested.reagent_list) var/datum/reagent/T = B if(T.scannable) stomachreagentdata["[T.id]"] = " [round(C.ingested.get_reagent_amount(T.id), 1)]u [T.name]" if (advscan == 0 || showadvscan == 0) user.show_message("[T.name] found in subject's stomach.") else ++unknown stomachunknownreagents["[T.id]"] = " [round(C.ingested.get_reagent_amount(T.id), 1)]u [T.name]" if(advscan >= 1 && showadvscan == 1) user.show_message("Beneficial reagents detected in subject's stomach:") for(var/d in stomachreagentdata) user.show_message(stomachreagentdata[d]) if(unknown) if(advscan >= 3 && showadvscan == 1) user.show_message("Warning: Non-medical reagent[(unknown > 1)?"s":""] found in subject's stomach:") for(var/d in stomachunknownreagents) user.show_message(stomachunknownreagents[d]) else user.show_message("Unknown substance[(unknown > 1)?"s":""] found in subject's stomach.") if(C.virus2.len) for (var/ID in C.virus2) if (ID in virusDB) var/datum/data/record/V = virusDB[ID] user.show_message("Warning: Pathogen [V.fields["name"]] detected in subject's blood. Known antigen : [V.fields["antigen"]]") else user.show_message("Warning: Unknown pathogen detected in subject's blood.") if (M.getCloneLoss()) user.show_message("Subject appears to have been imperfectly cloned.") // if (M.reagents && M.reagents.get_reagent_amount("inaprovaline")) // user.show_message("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.") if (M.has_brain_worms()) user.show_message("Subject suffering from aberrant brain activity. Recommend further scanning.") else if (M.getBrainLoss() >= 60 || !M.has_brain()) user.show_message("Subject is brain dead.") else if (M.getBrainLoss() >= 25) user.show_message("Severe brain damage detected. Subject likely to have a traumatic brain injury.") else if (M.getBrainLoss() >= 10) user.show_message("Significant brain damage detected. Subject may have had a concussion.") else if (M.getBrainLoss() >= 1 && advscan >= 2 && showadvscan == 1) user.show_message("Minor brain damage detected.") if(ishuman(M)) var/mob/living/carbon/human/H = M for(var/name_i in H.internal_organs_by_name) var/obj/item/organ/internal/i = H.internal_organs_by_name[name_i] if(istype(i, /obj/item/organ/internal/appendix)) var/obj/item/organ/internal/appendix/a = H.internal_organs_by_name[name_i] if(a.inflamed > 3) user.show_message(text("Severe inflammation detected in subject [a.name]."), 1) else if(a.inflamed > 2) user.show_message(text("Moderate inflammation detected in subject [a.name]."), 1) else if(a.inflamed >= 1) user.show_message(text("Mild inflammation detected in subject [a.name]."), 1) for(var/name in H.organs_by_name) var/obj/item/organ/external/e = H.organs_by_name[name] if(!e) continue var/limb = e.name if(e.status & ORGAN_BROKEN) if(((e.name == "l_arm") || (e.name == "r_arm") || (e.name == "l_leg") || (e.name == "r_leg")) && (!e.splinted)) to_chat(user, "Unsecured fracture in subject [limb]. Splinting recommended for transport.") if(e.has_infected_wound()) to_chat(user, "Infected wound detected in subject [limb]. Disinfection recommended.") for(var/name in H.organs_by_name) var/obj/item/organ/external/e = H.organs_by_name[name] if(e && e.status & ORGAN_BROKEN) if(advscan >= 1 && showadvscan == 1) user.show_message(text("Bone fractures detected in subject [e.name]."), 1) else user.show_message(text("Bone fractures detected. Advanced scanner required for location."), 1) break for(var/obj/item/organ/external/e in H.organs) if(!e) continue for(var/datum/wound/W in e.wounds) if(W.internal) if(advscan >= 1 && showadvscan == 1) user.show_message(text("Internal bleeding detected in subject [e.name]."), 1) else user.show_message(text("Internal bleeding detected. Advanced scanner required for location."), 1) break break if(M:vessel) var/blood_volume = H.vessel.get_reagent_amount("blood") var/blood_percent = round((blood_volume / H.species.blood_volume)*100) var/blood_type = H.dna.b_type if((blood_percent <= BLOOD_VOLUME_SAFE) && (blood_percent > BLOOD_VOLUME_BAD)) user.show_message("Warning: Blood Level LOW: [blood_percent]% [blood_volume]cl. Type: [blood_type]") else if(blood_percent <= BLOOD_VOLUME_BAD) user.show_message("Warning: Blood Level CRITICAL: [blood_percent]% [blood_volume]cl. Type: [blood_type]") else user.show_message("Blood Level Normal: [blood_percent]% [blood_volume]cl. Type: [blood_type]") user.show_message("Subject's pulse: [H.get_pulse(GETPULSE_TOOL)] bpm.") /obj/item/device/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" set category = "Object" mode = !mode switch (mode) if(1) to_chat(usr, "The scanner now shows specific limb damage.") if(0) to_chat(usr, "The scanner no longer shows limb damage.") /obj/item/device/healthanalyzer/proc/toggle_adv() set name = "Toggle Advanced Scan" set category = "Object" showadvscan = !showadvscan switch (showadvscan) if(1) to_chat(usr, "The scanner will now perform an advanced analysis.") if(0) to_chat(usr, "The scanner will now perform a basic analysis.") /obj/item/device/healthanalyzer/improved //reports bone fractures, IB, quantity of beneficial reagents in stomach; also regular health analyzer stuff name = "advanced health analyzer" desc = "A miracle of medical technology, this handheld scanner can produce an accurate and specific report of a patient's biosigns." advscan = 1 origin_tech = list(TECH_MAGNET = 5, TECH_BIO = 6) icon_state = "advhealth" /obj/item/device/healthanalyzer/advanced //reports all of the above, as well as radiation severity and minor brain damage name = "advanced health analyzer" advscan = 2 icon_state = "advhealth" /obj/item/device/healthanalyzer/enhanced //reports all of the above, as well as name and quantity of nonmed reagents in stomach name = "phasic health analyzer" advscan = 3 icon_state = "advhealth" /obj/item/device/analyzer name = "analyzer" desc = "A hand-held environmental scanner which reports current gas levels." icon_state = "atmos" item_state = "analyzer" w_class = ITEMSIZE_SMALL flags = CONDUCT slot_flags = SLOT_BELT throwforce = 5 throw_speed = 4 throw_range = 20 matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) /obj/item/device/analyzer/atmosanalyze(var/mob/user) var/air = user.return_air() if (!air) return return atmosanalyzer_scan(src, air, user) /obj/item/device/analyzer/attack_self(mob/user as mob) if (user.stat) return if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") to_chat(usr, "You don't have the dexterity to do this!") return analyze_gases(src, user) return /obj/item/device/mass_spectrometer name = "mass spectrometer" desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample." icon_state = "spectrometer" w_class = ITEMSIZE_SMALL flags = CONDUCT | OPENCONTAINER slot_flags = SLOT_BELT throwforce = 5 throw_speed = 4 throw_range = 20 matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) var/details = 0 var/recent_fail = 0 /obj/item/device/mass_spectrometer/New() ..() var/datum/reagents/R = new/datum/reagents(5) reagents = R R.my_atom = src /obj/item/device/mass_spectrometer/on_reagent_change() if(reagents.total_volume) icon_state = initial(icon_state) + "_s" else icon_state = initial(icon_state) /obj/item/device/mass_spectrometer/attack_self(mob/user as mob) if (user.stat) return if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") to_chat(user, "You don't have the dexterity to do this!") return if(reagents.total_volume) var/list/blood_traces = list() for(var/datum/reagent/R in reagents.reagent_list) if(R.id != "blood") reagents.clear_reagents() to_chat(user, "The sample was contaminated! Please insert another sample") return else blood_traces = params2list(R.data["trace_chem"]) break var/dat = "Trace Chemicals Found: " for(var/R in blood_traces) if(details) dat += "[R] ([blood_traces[R]] units) " else dat += "[R] " to_chat(user, "[dat]") reagents.clear_reagents() return /obj/item/device/mass_spectrometer/adv name = "advanced mass spectrometer" icon_state = "adv_spectrometer" details = 1 origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2) /obj/item/device/reagent_scanner name = "reagent scanner" desc = "A hand-held reagent scanner which identifies chemical agents." icon_state = "spectrometer" item_state = "analyzer" w_class = ITEMSIZE_SMALL flags = CONDUCT slot_flags = SLOT_BELT throwforce = 5 throw_speed = 4 throw_range = 20 matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) var/details = 0 var/recent_fail = 0 /obj/item/device/reagent_scanner/afterattack(obj/O, mob/user as mob, proximity) if(!proximity) return if (user.stat) return if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") to_chat(user, "You don't have the dexterity to do this!") return if(!istype(O)) return if(!isnull(O.reagents)) var/dat = "" if(O.reagents.reagent_list.len > 0) var/one_percent = O.reagents.total_volume / 100 for (var/datum/reagent/R in O.reagents.reagent_list) dat += "\n \t [R][details ? ": [R.volume / one_percent]%" : ""]" if(dat) to_chat(user, "Chemicals found: [dat]") else user << "No active chemical agents found in [O]." else user << "No significant chemical agents found in [O]." return /obj/item/device/reagent_scanner/adv name = "advanced reagent scanner" icon_state = "adv_spectrometer" details = 1 origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2) /obj/item/device/slime_scanner name = "slime scanner" icon_state = "xenobio" item_state = "xenobio" origin_tech = list(TECH_BIO = 1) w_class = ITEMSIZE_SMALL flags = CONDUCT throwforce = 0 throw_speed = 3 throw_range = 7 matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) /obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) if(!isslime(M)) user << "This device can only scan slimes!" return var/mob/living/simple_animal/slime/S = M user.show_message("Slime scan results:") user.show_message(text("[S.slime_color] [] slime", S.is_adult ? "adult" : "baby")) user.show_message("Health: [S.health]") user.show_message("Mutation Probability: [S.mutation_chance]") var/list/mutations = list() for(var/potential_color in S.slime_mutation) var/mob/living/simple_animal/slime/slime = potential_color mutations.Add(initial(slime.slime_color)) user.show_message("Potental to mutate into [english_list(mutations)] colors.") user.show_message("Extract potential: [S.cores]") user.show_message(text("Nutrition: [S.nutrition]/[]", S.get_max_nutrition())) if (S.nutrition < S.get_starve_nutrition()) user.show_message("Warning: Subject is starving!") else if (S.nutrition < S.get_hunger_nutrition()) user.show_message("Warning: Subject is hungry.") user.show_message("Electric change strength: [S.power_charge]") if(S.resentment) user.show_message("Warning: Subject is harboring resentment.") if(S.docile) user.show_message("Subject has been pacified.") if(S.rabid) user.show_message("Subject is enraged and extremely dangerous!") if(S.unity) user.show_message("Subject is friendly to other slime colors.") user.show_message("Growth progress: [S.amount_grown]/10")