#define DEFIB_TIME_LIMIT (10 MINUTES) //VOREStation addition- past this many seconds, defib is useless. /obj/item/healthanalyzer name = "health analyzer" desc = "A hand-held body scanner able to distinguish vital signs of the subject." icon = 'icons/obj/device.dmi' icon_state = "health" item_state = "healthanalyzer" slot_flags = SLOT_BELT throwforce = 3 w_class = ITEMSIZE_SMALL throw_speed = 5 throw_range = 10 matter = list(MAT_STEEL = 200) origin_tech = list(TECH_MAGNET = 1, TECH_BIO = 1) var/mode = 1; var/advscan = 0 var/showadvscan = 1 var/guide = FALSE pickup_sound = 'sound/items/pickup/device.ogg' drop_sound = 'sound/items/drop/device.ogg' /obj/item/healthanalyzer/Initialize(mapload) . = ..() if(advscan >= 1) verbs += /obj/item/healthanalyzer/proc/toggle_adv /obj/item/healthanalyzer/examine(mob/user) . = ..() if(guide) . += span_notice("Guidance is currently enabled.") else . += span_notice("Guidance is currently disabled.") /obj/item/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/healthanalyzer/attack(mob/living/M, mob/living/user) scan_mob(M, user) /obj/item/healthanalyzer/proc/scan_mob(mob/living/M, mob/living/user) var/dat = "" if ((CLUMSY in user.mutations) && prob(50)) user.visible_message(span_warning("\The [user] has analyzed the floor's vitals!"), span_warning("You try to analyze the floor's vitals!")) dat += "Analyzing Results for the floor:
" dat += "Overall Status: Healthy
" dat += "\tDamage Specifics: 0-0-0-0
" dat += "Key: Suffocation/Toxin/Burns/Brute
" dat += "Body Temperature: ???" user.show_message(span_notice("[dat]"), 1) return if (!user.IsAdvancedToolUser()) to_chat(user, span_warning("You don't have the dexterity to do this!")) return flick("[icon_state]-scan", src) //makes it so that it plays the scan animation on a succesful scan user.visible_message(span_notice("[user] has analyzed [M]'s vitals."),span_notice("You have analyzed [M]'s vitals.")) if (!ishuman(M) || M.isSynthetic()) //these sensors are designed for organic life var/analyzed = "Analyzing Results for ERROR:\n\tOverall Status: ERROR
" analyzed += "\tKey: [span_cyan("Suffocation")]/[span_green("Toxin")]/[span_orange("Burns")]/[span_red("Brute")]
" analyzed += "\tDamage Specifics: [span_cyan("?")] - [span_green("?")] - [span_orange("?")] - [span_red("?")]
" analyzed += "Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)" dat += span_notice(analyzed) + "
" dat += "[span_warning("Warning: Blood Level ERROR: --% --cl.")] [span_notice("Type: ERROR")]
" dat += span_notice("Subject's pulse: [span_red("-- bpm.")]") user.show_message(dat, 1) return var/fake_oxy = max(rand(1,40), M.getOxyLoss(), (300 - (M.getToxLoss() + M.getFireLoss() + M.getBruteLoss()))) var/OX = M.getOxyLoss() > 50 ? span_bold("[M.getOxyLoss()]") : M.getOxyLoss() var/TX = M.getToxLoss() > 50 ? span_bold("[M.getToxLoss()]") : M.getToxLoss() var/BU = M.getFireLoss() > 50 ? span_bold("[M.getFireLoss()]") : M.getFireLoss() var/BR = M.getBruteLoss() > 50 ? span_bold("[M.getBruteLoss()]") : M.getBruteLoss() var/analyzed_results = "" if(M.status_flags & FAKEDEATH) OX = fake_oxy > 50 ? span_bold("[fake_oxy]") : fake_oxy dat += span_notice("Analyzing Results for [M]:") dat += "
" dat += span_notice("Overall Status: dead") dat += "
" else analyzed_results += "Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "dead" : "[round((M.health/M.getMaxHealth())*100) ]% healthy"]
" analyzed_results += "\tKey: [span_cyan("Suffocation")]/[span_green("Toxin")]/[span_orange("Burns")]/[span_red("Brute")]
" analyzed_results += "\tDamage Specifics: [span_cyan("[OX]")] - [span_green("[TX]")] - [span_orange("[BU]")] - [span_red("[BR]")]
" analyzed_results += "Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)
" if(!(M.status_flags & FAKEDEATH)) analyzed_results = span_notice(analyzed_results) dat += analyzed_results if(M.timeofdeath && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) dat += span_notice("Time of Death: [worldtime2stationtime(M.timeofdeath)]") dat += "
" var/tdelta = round(world.time - M.timeofdeath) if(tdelta < (DEFIB_TIME_LIMIT * 10)) dat += span_boldnotice("Subject died [DisplayTimeText(tdelta)] ago - resuscitation may be possible!") dat += "
" if(ishuman(M) && mode == 1) var/mob/living/carbon/human/H = M var/list/damaged = H.get_damaged_organs(1,1) dat += span_notice("Localized Damage, Brute/Burn:") dat += "
" if(length(damaged)>0) for(var/obj/item/organ/external/org in damaged) if(org.robotic >= ORGAN_ROBOT) continue else var/our_damage = " [capitalize(org.name)]: [(org.brute_dam > 0) ? span_warning("[org.brute_dam]") : 0]" our_damage += "[(org.status & ORGAN_BLEEDING)?span_danger("\[Bleeding\]"):""] - " our_damage += "[(org.burn_dam > 0) ? "[span_orange("[org.burn_dam]")]" : 0]" dat += span_notice(our_damage) + "
" else dat += span_notice(" Limbs are OK.") dat += "
" // This handles genetic side effects and tells you the treatment, if any. // These are handled in side_effects.dm if(H.genetic_side_effects) for(var/datum/genetics/side_effect/side_effect in H.genetic_side_effects) var/datum/reagent/Rd = SSchemistry.chemical_reagents[side_effect.antidote_reagent] dat += "
" dat += span_danger("Patient is suffering from [side_effect.name]. ") if(Rd) dat += span_danger("Treatment: [Rd]
") else dat += "There is no known treatment.
" OX = M.getOxyLoss() > 50 ? "[span_cyan(span_bold("Severe oxygen deprivation detected"))]" : "Subject bloodstream oxygen level normal" TX = M.getToxLoss() > 50 ? "[span_green(span_bold("Dangerous amount of toxins detected"))]" : "Subject bloodstream toxin level minimal" BU = M.getFireLoss() > 50 ? "[span_orange(span_bold("Severe burn damage detected"))]" : "Subject burn injury status O.K" BR = M.getBruteLoss() > 50 ? "[span_red(span_bold("Severe anatomical damage detected"))]" : "Subject brute-force injury status O.K" if(M.status_flags & FAKEDEATH) OX = fake_oxy > 50 ? span_warning("Severe oxygen deprivation detected") : "Subject bloodstream oxygen level normal" dat += "[OX] | [TX] | [BU] | [BR]
" if(M.radiation) if(advscan >= 2 && showadvscan == 1) var/severity = "" if(M.radiation >= 1500) severity = "Lethal" else if(M.radiation >= 600) severity = "Critical" else if(M.radiation >= 400) severity = "Severe" else if(M.radiation >= 300) severity = "Moderate" else if(M.radiation >= 100) severity = "Low" dat += span_warning("[severity] levels of acute radiation sickness detected. [round(M.radiation/50)]Gy. [(severity == "Critical" || severity == "Lethal") ? " Immediate treatment advised." : ""]") dat += "
" else dat += span_warning("Acute radiation sickness detected.") dat += "
" if(M.accumulated_rads) if(advscan >= 2 && showadvscan == 1) var/severity = "" if(M.accumulated_rads >= 1500) severity = "Critical" else if(M.accumulated_rads >= 600) severity = "Severe" else if(M.accumulated_rads >= 400) severity = "Moderate" else if(M.accumulated_rads >= 300) severity = "Mild" else if(M.accumulated_rads >= 100) severity = "Low" dat += span_warning("[severity] levels of chronic radiation sickness detected. [round(M.accumulated_rads/50)]Gy.") dat += "
" else dat += span_warning("Chronic radiation sickness detected.") dat += "
" if(iscarbon(M)) var/mob/living/carbon/C = M if(C.reagents.total_volume) var/unknown = 0 var/reagentdata[0] var/unknownreagents[0] for(var/datum/reagent/R as anything in C.reagents.reagent_list) if(R.scannable) reagentdata["[R.id]"] = span_notice("\t[round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") reagentdata["[R.id]"] += "
" else unknown++ unknownreagents["[R.id]"] = span_notice("\t[round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") unknownreagents["[R.id]"] += "
" if(reagentdata.len) dat += span_notice("Beneficial reagents detected in subject's blood:") dat += "
" for(var/d in reagentdata) dat += reagentdata[d] if(unknown) if(advscan >= 3 && showadvscan == 1) dat += span_warning("Warning: Non-medical reagent[(unknown>1)?"s":""] detected in subject's blood:") dat += "
" for(var/d in unknownreagents) dat += unknownreagents[d] else dat += span_warning("Warning: Unknown substance[(unknown>1)?"s":""] detected in subject's blood.") dat += "
" if(C.ingested && C.ingested.total_volume) var/unknown = 0 var/stomachreagentdata[0] var/stomachunknownreagents[0] for(var/datum/reagent/R as anything in C.ingested.reagent_list) if(R.scannable) stomachreagentdata["[R.id]"] = span_notice("\t[round(C.ingested.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") stomachreagentdata["[R.id]"] += "
" if (advscan == 0 || showadvscan == 0) dat += span_notice("[R.name] found in subject's stomach.") dat += "
" else ++unknown stomachunknownreagents["[R.id]"] = span_notice("\t[round(C.ingested.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") stomachunknownreagents["[R.id]"] += "
" if(advscan >= 1 && showadvscan == 1) dat += span_notice("Beneficial reagents detected in subject's stomach:") dat += "
" for(var/d in stomachreagentdata) dat += stomachreagentdata[d] if(unknown) if(advscan >= 3 && showadvscan == 1) dat += span_warning("Warning: Non-medical reagent[(unknown > 1)?"s":""] found in subject's stomach:") dat += "
" for(var/d in stomachunknownreagents) dat += stomachunknownreagents[d] else dat += span_warning("Unknown substance[(unknown > 1)?"s":""] found in subject's stomach.") dat += "
" if(C.touching && C.touching.total_volume) var/unknown = 0 var/touchreagentdata[0] var/touchunknownreagents[0] for(var/datum/reagent/R as anything in C.touching.reagent_list) if(R.scannable) touchreagentdata["[R.id]"] = span_notice("\t[round(C.touching.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.can_overdose_touch && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") touchreagentdata["[R.id]"] += "
" if (advscan == 0 || showadvscan == 0) dat += span_notice("[R.name] found in subject's dermis.") dat += "
" else ++unknown touchunknownreagents["[R.id]"] = span_notice("\t[round(C.ingested.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.can_overdose_touch && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") touchunknownreagents["[R.id]"] += "
" if(advscan >= 1 && showadvscan == 1) dat += span_notice("Beneficial reagents detected in subject's dermis:") dat += "
" for(var/d in touchreagentdata) dat += touchreagentdata[d] if(unknown) if(advscan >= 3 && showadvscan == 1) dat += span_warning("Warning: Non-medical reagent[(unknown > 1)?"s":""] found in subject's dermis:") dat += "
" for(var/d in touchunknownreagents) dat += touchunknownreagents[d] else dat += span_warning("Unknown substance[(unknown > 1)?"s":""] found in subject's dermis.") dat += "
" if(C.IsInfected()) for (var/datum/disease/virus in C.GetViruses()) if(virus.visibility_flags & HIDDEN_SCANNER || virus.visibility_flags & HIDDEN_PANDEMIC) continue dat += span_alert(span_bold("Warning: [virus.form] detected in subject's blood.")) dat += "
" if (M.getCloneLoss()) dat += span_warning("Subject appears to have been imperfectly cloned.") dat += "
" // if (M.reagents && M.reagents.get_reagent_amount(REAGENT_ID_INAPROVALINE)) // user.show_message(span_notice("Bloodstream Analysis located [M.reagents:get_reagent_amount(REAGENT_ID_INAPROVALINE)] units of rejuvenation chemicals.")) if (M.has_brain_worms()) dat += span_warning("Subject suffering from aberrant brain activity. Recommend further scanning.") dat += "
" else if (M.getBrainLoss() >= 60 || !M.has_brain()) dat += span_warning("Subject is brain dead.") dat += "
" else if (M.getBrainLoss() >= 25) dat += span_warning("Severe brain damage detected. Subject likely to have a traumatic brain injury.") dat += "
" else if (M.getBrainLoss() >= 10) dat += span_warning("Significant brain damage detected. Subject may have had a concussion.") dat += "
" else if (M.getBrainLoss() >= 1) dat += span_warning("Minor brain damage detected.") dat += "
" if(ishuman(M)) var/mob/living/carbon/human/H = M //CHOMPedit begin - malignant organs for(var/obj/item/organ/internal/io in H.internal_organs) if(istype(io,/obj/item/organ/internal/appendix)) var/obj/item/organ/internal/appendix/a = io var/severity = "" if(a.inflamed > 3) severity = "Severe" else if(a.inflamed > 2) severity = "Moderate" else if(a.inflamed >= 1) severity = "Mild" if(severity) dat += span_warning("[severity] inflammation detected in subject [a.name].") dat += "
" else if(istype(io,/obj/item/organ/internal/malignant)) if(advscan >= 2) var/obj/item/organ/external/ORG = H.organs_by_name[io.parent_organ] dat += span_warning("Anatomical irregularities detected in subject's [ORG.name].") dat += "
" else dat += span_warning("Anatomical irregularities detected in subject.") dat += "
" //CHOMPedit end // Addictions if(H.get_addiction_to_reagent(REAGENT_ID_ASUSTENANCE) > 0) dat += span_warning("Biologically unstable, requires [REAGENT_ASUSTENANCE] to function properly.") dat += "
" for(var/addic in H.get_all_addictions()) if(H.get_addiction_to_reagent(addic) > 0 && (advscan >= 2 || H.get_addiction_to_reagent(addic) <= 120)) // high enough scanner upgrade detects addiction even if not almost withdrawling var/datum/reagent/R = SSchemistry.chemical_reagents[addic] if(R.id == REAGENT_ID_ASUSTENANCE) continue if(advscan >= 1) // Shows multiple if(advscan >= 2 && H.get_addiction_to_reagent(addic) <= 80) dat += span_warning("Experiencing withdrawls from [R.name], [REAGENT_INAPROVALINE] treatment recomended.") dat += "
" else dat += span_warning("Chemical dependance detected: [R.name].") dat += "
" else // Shows single dat += span_warning("Chemical dependance detected.") dat += "
" break // Appendix for(var/obj/item/organ/internal/appendix/a in H.internal_organs) var/severity = "" if(a.inflamed > 3) severity = "Severe" else if(a.inflamed > 2) severity = "Moderate" else if(a.inflamed >= 1) severity = "Mild" if(severity) dat += span_warning("[severity] inflammation detected in subject [a.name].") dat += "
" if(HUSK in H.mutations) dat += span_danger("Anatomical structure lost, resuscitation not possible!") dat += "
" // Infections, fractures, and IB var/basic_fracture = 0 // If it's a basic scanner var/basic_ib = 0 // If it's a basic scanner var/fracture_dat = "" // All the fractures var/infection_dat = "" // All the infections var/ib_dat = "" // All the IB var/int_damage_acc = 0 // For internal organs for(var/obj/item/organ/internal/i in H.internal_organs) if(!i || i.robotic >= ORGAN_ROBOT || istype(i, /obj/item/organ/internal/brain)) continue // not there or robotic or brain which is handled separately if(i.damage || i.status & ORGAN_DEAD) int_damage_acc += (i.damage + ((i.status & ORGAN_DEAD) ? 30 : 0)) if(advscan >= 2 && showadvscan == 1) if(advscan >= 3) var/dam_adj if(i.damage >= i.min_broken_damage || i.status & ORGAN_DEAD) dam_adj = "Severe" else if(i.damage >= i.min_bruised_damage) dam_adj = "Moderate" else dam_adj = "Mild" dat += span_warning("[dam_adj] damage detected to subject's [i.name].") dat += "
" else dat += span_warning("Damage detected to subject's [i.name].") dat += "
" if(int_damage_acc >= 1 && (advscan < 2 || !showadvscan)) dat += span_warning("Damage detected to subject's internal organs.") dat += "
" for(var/obj/item/organ/external/e in H.organs) if(!e) continue // Broken limbs if(e.status & ORGAN_BROKEN) if((e.name in list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_HEAD, BP_TORSO, BP_GROIN)) && (!e.splinted)) fracture_dat += span_warning("Unsecured fracture in subject [e.name]. Splinting recommended for transport.") fracture_dat += "
" else if(advscan >= 1 && showadvscan == 1) fracture_dat += span_warning("Bone fractures detected in subject [e.name].") fracture_dat += "
" else basic_fracture = 1 // Infections if(e.has_infected_wound()) dat += span_warning("Infected wound detected in subject [e.name]. Disinfection recommended.") dat += "
" // IB for(var/datum/wound/W in e.wounds) if(W.internal) if(advscan >= 1 && showadvscan == 1) ib_dat += span_warning("Internal bleeding detected in subject [e.name].") ib_dat += "
" else basic_ib = 1 if(basic_fracture) fracture_dat += span_warning("Bone fractures detected. Advanced scanner required for location.") fracture_dat += "
" if(basic_ib) ib_dat += span_warning("Internal bleeding detected. Advanced scanner required for location.") ib_dat += "
" dat += fracture_dat dat += infection_dat dat += ib_dat // Blood level if(M:vessel) var/blood_volume = H.vessel.get_reagent_amount(REAGENT_ID_BLOOD) var/blood_percent = round((blood_volume / H.species.blood_volume)*100) var/blood_type = H.dna.b_type var/blood_reagent = H.species.blood_reagents if(blood_volume <= H.species.blood_volume*H.species.blood_level_danger) dat += span_danger(span_italics("Warning: Blood Level CRITICAL: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].")) dat += "
" else if(blood_volume <= H.species.blood_volume*H.species.blood_level_warning) dat += span_danger(span_italics("Warning: Blood Level VERY LOW: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].")) dat += "
" else if(blood_volume <= H.species.blood_volume*H.species.blood_level_safe) dat += span_danger("Warning: Blood Level LOW: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].") dat += "
" else dat += span_notice("Blood Level Normal: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].") dat += "
" dat += span_notice("Subject's pulse: [H.pulse == PULSE_THREADY || H.pulse == PULSE_NONE ? span_red(H.get_pulse(GETPULSE_TOOL) + " bpm") : span_blue(H.get_pulse(GETPULSE_TOOL) + " bpm")].") // VORE Edit: Missed a linebreak here. dat += "
" var/datum/component/xenochimera/xc = H.get_xenochimera_component() if(xc) if(H.stat == DEAD && xc.revive_ready == REVIVING_READY && !H.hasnutriment()) dat += span_danger("WARNING: Protein levels low. Subject incapable of reconstitution.") else if(xc.revive_ready == REVIVING_NOW) dat += span_warning("Subject is undergoing form reconstruction. Estimated time to finish is in: [round((xc.revive_finished - world.time) / 10)] seconds.") else if(xc.revive_ready == REVIVING_DONE) dat += span_notice("Subject is ready to hatch. Transfer to dark room for holding with food available.") else if(H.stat == DEAD) dat+= span_danger("WARNING: Defib will cause extreme pain and set subject feral. Sedation recommended prior to defibrillation.") else // If they bop them and they're not dead or reviving, give 'em a little notice. dat += span_notice("Subject is a Xenochimera. Treat accordingly.") // Custom medical issues for(var/obj/item/organ/I in H.internal_organs) for(var/datum/medical_issue/MI in I.medical_issues) if(advscan >= MI.advscan) dat += span_danger("Warning: [MI.name] detected in [MI.affectedorgan].
") if(advscan >= MI.advscan_cure) if(MI.cure_reagent) dat += span_notice("Suggested treatment: Prescription of [MI.cure_reagent].
") else if(MI.cure_surgery) dat += span_notice("Required surgery: [MI.cure_surgery].
") else dat += span_notice("[MI.affectedorgan] may require surgical removal or transplantation.
") for(var/obj/item/organ/E in H.organs) for(var/datum/medical_issue/MI in E.medical_issues) if(advscan >= MI.advscan) dat += span_danger("Warning: [MI.name] detected in [MI.affectedorgan].
") if(advscan >= MI.advscan_cure) if(MI.cure_reagent) dat += span_notice("Suggested treatment: Prescription of [MI.cure_reagent].
") else if(MI.cure_surgery) dat += span_notice("Required surgery: [MI.cure_surgery].
") else dat += span_notice("[MI.affectedorgan] may require surgical removal or transplantation.
") user.show_message(dat, 1) if(guide) guide(M, user) /obj/item/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/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/healthanalyzer/improved //reports bone fractures, IB, quantity of beneficial reagents in stomach; also regular health analyzer stuff name = "improved 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 = "health1" /obj/item/healthanalyzer/advanced //reports all of the above, as well as radiation severity and minor brain damage name = "advanced health analyzer" desc = "An even more advanced handheld health scanner, complete with a full biosign monitor and on-board radiation and neurological analysis suites." advscan = 2 origin_tech = list(TECH_MAGNET = 6, TECH_BIO = 7) icon_state = "health2" /obj/item/healthanalyzer/phasic //reports all of the above, as well as name and quantity of nonmed reagents in stomach name = "phasic health analyzer" desc = "Possibly the most advanced health analyzer to ever have existed, utilising bluespace technology to determine almost everything worth knowing about a patient." advscan = 3 origin_tech = list(TECH_MAGNET = 7, TECH_BIO = 8) icon_state = "health3" #undef DEFIB_TIME_LIMIT //VOREStation addition