/* CONTAINS: HEALTH ANALYZER GAS ANALYZER MASS SPECTROMETER REAGENT SCANNER BREATH ANALYZER */ /obj/item/healthanalyzer name = "health analyzer" desc = "A hand-held body scanner able to distinguish vital signs of the subject." icon = 'icons/obj/item/scanner.dmi' icon_state = "healthanalyzer" item_state = "healthanalyzer" contained_sprite = TRUE obj_flags = OBJ_FLAG_CONDUCTABLE slot_flags = SLOT_BELT throwforce = 3 w_class = WEIGHT_CLASS_SMALL throw_speed = 5 throw_range = 10 matter = list(MATERIAL_ALUMINIUM = 200) origin_tech = list(TECH_MAGNET = 1, TECH_BIO = 1) var/last_scan = 0 var/mode = 1 var/sound_scan = FALSE /obj/item/healthanalyzer/attack(mob/living/target_mob, mob/living/user, target_zone) sound_scan = FALSE if(last_scan <= world.time - 20) //Spam limiter. last_scan = world.time sound_scan = TRUE user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) flick("[icon_state]-scan", src) //makes it so that it plays the scan animation on a successful scan health_scan_mob(target_mob, user, mode, sound_scan = sound_scan) add_fingerprint(user) /obj/item/healthanalyzer/attack_self(mob/user) sound_scan = FALSE if(last_scan <= world.time - 20) //Spam limiter. last_scan = world.time sound_scan = TRUE user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) flick("[icon_state]-scan", src) //makes it so that it plays the scan animation on a successful scan health_scan_mob(user, user, mode, sound_scan = sound_scan) add_fingerprint(user) /// Calculates severity based on the ratios defined external limbs. /proc/get_wound_severity(damage_ratio, can_heal_overkill, uppercase = FALSE) var/degree = "none" switch(damage_ratio) if (0 to 10) degree = "minor" if (11 to 25) degree = "moderate" if (26 to 50) degree = "significant" if (51 to 75) degree = "severe" if (76 to 99) degree = "extreme" if (100 to INFINITY) degree = can_heal_overkill ? "critical" : "irreparable" if(uppercase) degree = capitalize(degree) return degree /proc/get_severity(amount, can_heal_overkill, uppercase = FALSE) var/output = "none" switch(amount) if (0) output = "none" if (1 to 10) output = "minor" if (11 to 25) output = "moderate" if (26 to 50) output = "significant" if (51 to 75) output = "severe" if (76 to 99) output = "extreme" if (100 to INFINITY) output = can_heal_overkill ? "critical" : "irreparable" if(uppercase) output = capitalize(output) return output /proc/health_scan_mob(var/mob/M, var/mob/living/user, var/show_limb_damage = TRUE, var/just_scan = FALSE, var/sound_scan) if(!just_scan) if (((user.is_clumsy()) || (user.mutations & DUMB)) && prob(50)) user.visible_message("[user] runs the scanner over the floor.", SPAN_NOTICE("You run the scanner over the floor."), SPAN_NOTICE("You hear metal repeatedly clunking against the floor.")) to_chat(user, SPAN_NOTICE("Scan results for the ERROR:")) if(sound_scan) playsound(user.loc, 'sound/items/healthscanner/healthscanner_used.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) return if(!user.IsAdvancedToolUser()) to_chat(user, SPAN_WARNING("You don't have the dexterity to do this!")) return user.visible_message("[user] runs a scanner over [M].",SPAN_NOTICE("You run the scanner over [M].")) if(!istype(M, /mob/living/carbon/human)) to_chat(user, SPAN_WARNING("This scanner is designed for humanoid patients only.")) if(sound_scan) playsound(user.loc, 'sound/items/healthscanner/healthscanner_used.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) return var/mob/living/carbon/human/H = M if(H.isSynthetic() && !H.isFBP()) to_chat(user, SPAN_WARNING("This scanner is designed for organic humanoid patients only.")) if(sound_scan) playsound(user.loc, 'sound/items/healthscanner/healthscanner_used.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) return . = list() var/header = list() var/b var/endb var/dat = list() header += "" header += "" header += "" header += "" header += "" header += "" header += "" b = "" endb = "" . += "[b]Scan results for \the [H]:[endb]" if(H.stat == DEAD || H.status_flags & FAKEDEATH) dat += "[b]Time of Death:[endb] [worldtime2text(H.timeofdeath)]" // Brain activity. var/brain_status = H.get_brain_status() dat += "Brain activity: [brain_status]" var/brain_result = H.get_brain_result() if(sound_scan) switch(brain_result) if(0) playsound(user.loc, 'sound/items/healthscanner/healthscanner_dead.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) if(-1) playsound(user.loc, 'sound/items/healthscanner/healthscanner_used.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) else if(brain_result <= 25) playsound(user.loc, 'sound/items/healthscanner/healthscanner_critical.ogg', 25, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) else if(brain_result <= 50) playsound(user.loc, 'sound/items/healthscanner/healthscanner_danger.ogg', 25, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) else if(brain_result <= 90) playsound(user.loc, 'sound/items/healthscanner/healthscanner_used.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) else playsound(user.loc, 'sound/items/healthscanner/healthscanner_stable.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) // Pulse rate. var/pulse_result = "normal" if(H.should_have_organ(BP_HEART)) if(H.status_flags & FAKEDEATH) pulse_result = SPAN_DANGER("0") else pulse_result = H.get_pulse(GETPULSE_TOOL) if(H.pulse() == PULSE_NONE) pulse_result = "[pulse_result] BPM" else if(H.pulse() < PULSE_NORM) pulse_result = "[pulse_result] BPM" else if(H.pulse() > PULSE_NORM) pulse_result = "[pulse_result] BPM" else pulse_result = "[pulse_result] BPM" else pulse_result = "0" dat += "Pulse rate: [pulse_result]" // Body temperature. Rounds to one digit after decimal. var/temperature_string if(H.bodytemperature < H.species.cold_level_1 || H.bodytemperature > H.species.heat_level_1) temperature_string = "Body temperature: [round(H.bodytemperature-T0C, 0.1)]°C ([round(H.bodytemperature*1.8-459.67, 0.1)]°F)" else temperature_string = "Body temperature: [round(H.bodytemperature-T0C, 0.1)]°C ([round(H.bodytemperature*1.8-459.67, 0.1)]°F)" dat += temperature_string // Blood pressure and blood type. Based on the idea of a normal blood pressure being 120 over 80. if(H.should_have_organ(BP_HEART)) var/blood_pressure_string switch(H.get_blood_pressure_alert()) if(1) blood_pressure_string = "[H.get_blood_pressure()]" if(2) blood_pressure_string = "[H.get_blood_pressure()]" if(3) blood_pressure_string = "[H.get_blood_pressure()]" if(4) blood_pressure_string = "[H.get_blood_pressure()]" var/blood_volume_string = "\>[BLOOD_VOLUME_SAFE]%" switch(H.get_blood_volume()) if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) blood_volume_string = "\<[BLOOD_VOLUME_SAFE]%" if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_OKAY) blood_volume_string = "\<[BLOOD_VOLUME_OKAY]%" if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) blood_volume_string = "\<[BLOOD_VOLUME_SURVIVE]%" var/oxygenation = H.get_blood_oxygenation() var/oxygenation_string = "[oxygenation]%" switch(oxygenation) if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) oxygenation_string = "[oxygenation]%" if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_OKAY) oxygenation_string = "[oxygenation]%" if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) oxygenation_string = "[oxygenation]%" if(H.status_flags & FAKEDEATH) oxygenation_string = "[rand(0,10)]%" dat += "Blood pressure: [blood_pressure_string]" dat += "Blood oxygenation: [oxygenation_string]" dat += "Blood volume: [blood_volume_string]" dat += "Blood type: [H.dna.b_type]" else dat += "Blood pressure: N/A" // Traumatic shock. if(H.is_asystole() || (H.status_flags & FAKEDEATH)) dat += "Cardiovascular shock detected. Administer CPR immediately." else if(H.shock_stage > 80) dat += "Imminent cardiovascular shock. Pain relief recommended." if(H.getOxyLoss() > 50) dat += "[b]Severe oxygen deprivation detected.[endb]" if(H.getToxLoss() > 50) dat += "[b]Major systemic organ failure detected.[endb]" if(H.getFireLoss() > 50) dat += "[b]Severe burn damage detected.[endb]" if(H.getBruteLoss() > 50) dat += "[b]Severe anatomical damage detected.[endb]" if(show_limb_damage) var/list/damaged = H.get_damaged_organs(1,1) if(damaged.len) for(var/obj/item/organ/external/org in damaged) var/limb_result = "[capitalize(org.name)][BP_IS_ROBOTIC(org) ? " (Cybernetic)" : ""]:" if(org.brute_dam > 0) limb_result = "[limb_result] \[[get_severity(org.brute_dam, TRUE)] physical trauma\]" if(org.burn_dam > 0) limb_result = "[limb_result] \[[get_severity(org.burn_dam, TRUE)] burns\]" if(org.status & ORGAN_BLEEDING) limb_result = "[limb_result] \[bleeding\]" var/is_bandaged = org.is_bandaged() var/is_salved = org.is_salved() if(is_bandaged && is_salved) var/icon/B = icon('icons/obj/item/stacks/medical.dmi', "bandaged") var/icon/S = icon('icons/obj/item/stacks/medical.dmi', "salved") limb_result = "[limb_result] \[[icon2html(B, user)] | [icon2html(S, user)]\]" else if(is_bandaged) var/icon/B = icon('icons/obj/item/stacks/medical.dmi', "bandaged") limb_result = "[limb_result] \[[icon2html(B, user)]\]" else if(is_salved) var/icon/S = icon('icons/obj/item/stacks/medical.dmi', "salved") limb_result = "[limb_result] \[[icon2html(S, user)]\]" dat += limb_result else dat += "No detectable limb injuries." 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 == BP_L_ARM) || (e.name == BP_R_ARM) || (e.name == BP_L_LEG) || (e.name == BP_R_LEG)) && !(e.status & ORGAN_SPLINTED)) dat += "Unsecured fracture in subject [limb]. Splinting recommended for transport." 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) dat += "Bone fractures detected. Advanced scanner required for location." break var/found_bleed var/found_tendon var/found_disloc for(var/obj/item/organ/external/e in H.organs) if(e) if(!found_disloc && e.dislocated == 2) dat += "Dislocation detected. Advanced scanner required for location." found_disloc = TRUE if(!found_bleed && (e.status & ORGAN_ARTERY_CUT)) dat += "Arterial bleeding detected. Advanced scanner required for location." found_bleed = TRUE if(!found_tendon && (e.tendon_status() & TENDON_CUT)) dat += "Tendon or ligament damage detected. Advanced scanner required for location." found_tendon = TRUE if(found_disloc && found_bleed && found_tendon) break . += dat dat = list() // Reagent data. . += "[b]Reagent scan:[endb]" var/print_reagent_default_message = TRUE if(H.reagents.total_volume) var/unknown = 0 var/reagentdata[0] for(var/_R in H.reagents.reagent_volumes) var/singleton/reagent/R = GET_SINGLETON(_R) if(R.scannable) print_reagent_default_message = FALSE reagentdata["[_R]"] = SPAN_NOTICE(" [round(REAGENT_VOLUME(H.reagents, _R), 1)]u [R.name]") else unknown++ if(reagentdata.len) print_reagent_default_message = FALSE dat += SPAN_NOTICE("Beneficial reagents detected in subject's blood:") for(var/d in reagentdata) dat += reagentdata[d] if(unknown) print_reagent_default_message = FALSE dat += SPAN_WARNING("Warning: Unknown substance[(unknown>1)?"s":""] detected in subject's blood.") var/datum/reagents/ingested = H.get_ingested_reagents() if(ingested && ingested.total_volume) var/unknown = 0 for(var/_R in ingested.reagent_volumes) var/singleton/reagent/R = GET_SINGLETON(_R) if(R.scannable) print_reagent_default_message = FALSE dat += SPAN_NOTICE("[R.name] found in subject's stomach.") else ++unknown if(unknown) print_reagent_default_message = FALSE dat += SPAN_WARNING("Non-medical reagent[(unknown > 1)?"s":""] found in subject's stomach.") if(print_reagent_default_message) dat += "No results." . += dat header = jointext(header, null) . = jointext(.,"
") . = jointext(list(header,.),null) if(user) to_chat(user, "
") to_chat(user, .) to_chat(user, "
") /obj/item/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" set category = "Object.Held" set src in usr mode = !mode if(mode) to_chat(usr, "The scanner now shows specific limb damage.") else to_chat(usr, "The scanner no longer shows limb damage.") /obj/item/analyzer name = "gas analyzer" desc = "A hand-held environmental scanner which reports current gas levels." icon = 'icons/obj/item/scanner.dmi' icon_state = "airanalyzer" item_state = "airanalyzer" contained_sprite = TRUE w_class = WEIGHT_CLASS_SMALL obj_flags = OBJ_FLAG_CONDUCTABLE slot_flags = SLOT_BELT throwforce = 5 throw_speed = 4 throw_range = 20 matter = list(MATERIAL_ALUMINIUM = 30, MATERIAL_GLASS = 20) origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) /obj/item/analyzer/atmosanalyze(var/mob/user) if(!user) return var/air = user.return_air() if (!air) return flick("[icon_state]-scan", src) return atmosanalyzer_scan(src, air, user) /obj/item/analyzer/attack_self(mob/user as mob) if (user.stat) return if (!usr.IsAdvancedToolUser()) to_chat(usr, SPAN_WARNING("You don't have the dexterity to do this!")) return analyze_gases(src, user) return /obj/item/mass_spectrometer name = "mass spectrometer" desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample." icon = 'icons/obj/item/scanner.dmi' icon_state = "spectrometer" // Reuses the basic health analyzer inhands. item_state = "healthanalyzer" contained_sprite = TRUE w_class = WEIGHT_CLASS_SMALL atom_flags = ATOM_FLAG_OPEN_CONTAINER obj_flags = OBJ_FLAG_CONDUCTABLE slot_flags = SLOT_BELT throwforce = 5 throw_speed = 4 throw_range = 20 matter = list(MATERIAL_ALUMINIUM = 30, MATERIAL_GLASS = 20) origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) var/details = FALSE /obj/item/mass_spectrometer/Initialize() . = ..() create_reagents(5) /obj/item/mass_spectrometer/on_reagent_change() clear_blood_overlay() if(reagents.total_volume) icon_state = initial(icon_state) + "_s" var/image/I = image(icon, null, "[initial(icon_state)]-reagent") I.color = reagents.get_color() add_blood_overlay(I) else icon_state = initial(icon_state) /obj/item/mass_spectrometer/proc/clear_blood_overlay() underlays = null /obj/item/mass_spectrometer/proc/add_blood_overlay(var/image/I) underlays += I /obj/item/mass_spectrometer/attack_self(mob/user) if(use_check_and_message(user)) return if(reagents.total_volume) if(LAZYLEN(reagents.reagent_volumes) > 1) to_chat(user, SPAN_WARNING("There isn't enough blood in the sample!")) return if(!REAGENT_DATA(reagents, /singleton/reagent/blood)) to_chat(user, SPAN_WARNING("The sample was contaminated with non-blood reagents!")) return var/list/blood_traces = reagents.reagent_data[/singleton/reagent/blood]["trace_chem"] var/list/output_text = list("Trace Chemicals Found:") for(var/_C in blood_traces) var/singleton/reagent/C = GET_SINGLETON(_C) if(C.spectro_hidden && !details) continue if(details) output_text += "- [C] ([max(round(blood_traces[_C], 0.1), 0.1)] units)" else output_text += "- [C]" if(length(output_text) == 1) output_text[1] = SPAN_NOTICE("No trace chemicals found.") to_chat(user, jointext(output_text, "\n")) /obj/item/mass_spectrometer/adv name = "advanced mass spectrometer" icon_state = "spectrometer_adv" details = TRUE origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2) /obj/item/mass_spectrometer/adv/clear_blood_overlay() ClearOverlays() /obj/item/mass_spectrometer/adv/add_blood_overlay(var/image/I) AddOverlays(I) /obj/item/reagent_scanner name = "reagent scanner" desc = "A hand-held reagent scanner which identifies chemical agents." icon = 'icons/obj/item/scanner.dmi' icon_state = "reagent_scanner" // Reuses the basic health analyzer inhands. item_state = "healthanalyzer" contained_sprite = TRUE w_class = WEIGHT_CLASS_SMALL obj_flags = OBJ_FLAG_CONDUCTABLE slot_flags = SLOT_BELT throwforce = 5 throw_speed = 4 throw_range = 20 matter = list(MATERIAL_ALUMINIUM = 30, MATERIAL_GLASS = 20) origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) var/details = 0 var/recent_fail = 0 /obj/item/reagent_scanner/afterattack(obj/O, mob/user, proximity) if(!proximity) return if(use_check_and_message(user)) return if(!istype(O)) return if(isemptylist(O.reagents?.reagent_volumes)) to_chat(user, SPAN_WARNING("No active chemical agents found in [O].")) return var/dat = "" var/one_percent = O.reagents.total_volume / 100 for (var/_R in O.reagents.reagent_volumes) var/singleton/reagent/R = GET_SINGLETON(_R) dat += "\n \t [R][details ? ": [O.reagents.reagent_volumes[_R] / one_percent]%" : ""]" to_chat(user, SPAN_NOTICE("Chemicals found: [dat]")) /obj/item/reagent_scanner/adv name = "advanced reagent scanner" icon_state = "reagent_scanner_adv" // Reuses the advanced health analyzer inhands. item_state = "healthanalyzer_adv" details = 1 origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2) /obj/item/slime_scanner name = "slime scanner" icon = 'icons/obj/item/scanner.dmi' icon_state = "slime_scanner" item_state = "slime_scanner" contained_sprite = TRUE origin_tech = list(TECH_BIO = 1) w_class = WEIGHT_CLASS_SMALL obj_flags = OBJ_FLAG_CONDUCTABLE throwforce = 0 throw_speed = 3 throw_range = 7 matter = list(MATERIAL_ALUMINIUM = 30, MATERIAL_GLASS = 20) /obj/item/slime_scanner/attack(mob/living/target_mob, mob/living/user, target_zone) if(!isslime(target_mob)) to_chat(user, SPAN_WARNING("This device can only scan slimes!")) return var/mob/living/carbon/slime/T = target_mob to_chat(user, SPAN_NOTICE("**************************")) to_chat(user, SPAN_NOTICE("Slime scan results:")) to_chat(user, SPAN_NOTICE(capitalize_first_letters("[T.colour] [T.is_adult ? "adult" : "baby"] slime"))) to_chat(user, SPAN_NOTICE("Health: [T.health]")) to_chat(user, SPAN_NOTICE("Nutrition: [T.nutrition]/[T.get_max_nutrition()]")) if(T.nutrition < T.get_starve_nutrition()) to_chat(user, SPAN_ALERT("Warning: slime is starving!")) else if (T.nutrition < T.get_hunger_nutrition()) to_chat(user, SPAN_WARNING("Warning: slime is hungry!")) to_chat(user, SPAN_NOTICE("Electric charge strength: [T.powerlevel]")) to_chat(user, SPAN_NOTICE("Growth progress: [T.amount_grown]/10")) if(T.cores > 1) to_chat(user, SPAN_WARNING("Anomalous number of slime cores detected.")) else if(!T.cores) to_chat(user, SPAN_WARNING("No slime cores detected.")) to_chat(user, SPAN_NOTICE("Genetic Information:")) if(T.slime_mutation[4] == T.colour) to_chat(user, SPAN_WARNING("This slime cannot evolve any further.")) else var/list/poss_mutations = uniquelist(T.slime_mutation) var/mutation_message = capitalize(english_list(poss_mutations)) to_chat(user, SPAN_NOTICE(mutation_message)) var/mut_chance = T.mutation_chance / (poss_mutations.len > 2 ? 1 : 2) to_chat(user, SPAN_NOTICE("Instability: [mut_chance]% chance of mutation upon reproduction.")) to_chat(user, SPAN_NOTICE("**************************")) /obj/item/price_scanner name = "price scanner" desc = "Using an up-to-date database of various costs and prices, this device estimates the market price of an item up to 0.001% accuracy." icon = 'icons/obj/item/scanner.dmi' icon_state = "price_scanner" item_state = "price_scanner" contained_sprite = TRUE item_flags = ITEM_FLAG_NO_BLUDGEON slot_flags = SLOT_BELT w_class = WEIGHT_CLASS_SMALL throwforce = 0 throw_speed = 3 throw_range = 3 matter = list(DEFAULT_WALL_MATERIAL = 25, MATERIAL_GLASS = 25) /obj/item/price_scanner/afterattack(atom/movable/target, mob/user as mob, proximity) if(!proximity) return var/value = get_value(target) user.visible_message(SPAN_NOTICE("\The [user] scans \the [target] with \the [src].")) to_chat(user, SPAN_NOTICE("\The [src] estimates the price of \the [target] at [value ? value : "N/A"]电.")) /obj/item/breath_analyzer name = "breath analyzer" desc = "A hand-held breath analyzer that provides a robust amount of information about the subject's respiratory system." icon = 'icons/obj/item/scanner.dmi' icon_state = "breath_analyzer" // Reuses the basic health analyzer inhands. item_state = "healthanalyzer" contained_sprite = TRUE w_class = WEIGHT_CLASS_SMALL obj_flags = OBJ_FLAG_CONDUCTABLE slot_flags = SLOT_BELT throwforce = 0 throw_speed = 3 throw_range = 3 matter = list(MATERIAL_ALUMINIUM = 30, MATERIAL_GLASS = 20) origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) /obj/item/breath_analyzer/attack(mob/living/target_mob, mob/living/user, target_zone) var/mob/living/carbon/human/H = target_mob if (!istype(H)) to_chat(user,SPAN_WARNING("You can't find a way to use \the [src] on [H]!")) return if ( ((user.is_clumsy()) || (user.mutations & DUMB)) && prob(20)) to_chat(user,SPAN_DANGER("Your hand slips from clumsiness!")) if(!H.eyes_protected(src, FALSE)) eyestab(H,user) to_chat(user,SPAN_DANGER("Alert: No breathing detected.")) return if (!user.IsAdvancedToolUser()) to_chat(user,SPAN_WARNING("You don't have the dexterity to do this!")) return if(user == H && !H.can_eat(src)) return else if(!H.can_force_feed(user, src)) return user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) user.visible_message(SPAN_NOTICE("[user] is trying to take a breath sample from [H]."), SPAN_NOTICE("You gently insert \the [src] into [H]'s mouth.")) if (!LAZYLEN(src.other_DNA)) LAZYADD(src.other_DNA, H.dna.unique_enzymes) src.other_DNA_type = "saliva" if (!do_after(user, 2 SECONDS, H, DO_UNIQUE & ~DO_BOTH_CAN_TURN)) return user.visible_message(SPAN_NOTICE("[user] takes a breath sample from [H]."), SPAN_NOTICE("\The [src] clicks as it finishes reading [H]'s breath sample.")) to_chat(user,"Breath Sample Results:") if(H.stat == DEAD || H.losebreath || !H.breathing) to_chat(user,SPAN_DANGER("Alert: No breathing detected.")) playsound(user.loc, 'sound/items/healthscanner/healthscanner_dead.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) return switch(H.getOxyLoss()) if(0 to 25) to_chat(user,"Subject oxygen levels nominal.") playsound(user.loc, 'sound/items/healthscanner/healthscanner_stable.ogg', 25, extrarange = SILENCED_SOUND_EXTRARANGE) if(25 to 50) to_chat(user,SPAN_NOTICE("Subject oxygen levels abnormal.")) playsound(user.loc, 'sound/items/healthscanner/healthscanner_danger.ogg', 25, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) if(50 to INFINITY) to_chat(user,SPAN_NOTICE("Severe oxygen deprivation detected.")) playsound(user.loc, 'sound/items/healthscanner/healthscanner_critical.ogg', 25, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) var/obj/item/organ/internal/L = H.internal_organs_by_name[BP_LUNGS] if(istype(L)) if(L.is_bruised()) to_chat(user,SPAN_WARNING("Ruptured lung detected.")) else if(L.is_damaged()) to_chat(user,"Damaged lung detected.") else to_chat(user,"Subject lung health nominal.") else to_chat(user,SPAN_WARNING("Subject lung health unknown.")) var/additional_string = "\[NORMAL\]" var/bac = H.get_blood_alcohol() switch(bac) if(INTOX_JUDGEIMP to INTOX_MUSCLEIMP) additional_string = "\[LIGHTLY INTOXICATED\]" if(INTOX_MUSCLEIMP to INTOX_BALANCE) additional_string = "\[MODERATELY INTOXICATED\]" if(INTOX_BALANCE to INTOX_BLACKOUT) additional_string = "\[HEAVILY INTOXICATED\]" if(INTOX_BLACKOUT to INTOX_DEATH) additional_string = "\[ALCOHOL POISONING LIKELY\]" if(INTOX_DEATH to INFINITY) additional_string = SPAN_WARNING("\[DEATH IMMINENT\]") to_chat(user,"Blood Alcohol Content: [round(bac,0.01)] [additional_string]") if(H.breathing && H.breathing.total_volume) var/unknown = 0 for(var/_R in H.breathing.reagent_volumes) var/singleton/reagent/R = GET_SINGLETON(_R) if(R.scannable) to_chat(user,SPAN_NOTICE("[R.name] found in subject's respiratory system.")) else ++unknown if(unknown) to_chat(user,SPAN_WARNING("Non-medical reagent[(unknown > 1)?"s":""] found in subject's respiratory system.")) /obj/item/advanced_healthanalyzer name = "advanced health analyzer" desc = "An expensive and varied-use health analyzer that prints full-body scans after a short scanning delay." icon = 'icons/obj/item/scanner.dmi' icon_state = "healthanalyzer_adv" item_state = "healthanalyzer_adv" contained_sprite = TRUE slot_flags = SLOT_BELT w_class = WEIGHT_CLASS_NORMAL origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 3) var/obj/machinery/body_scanconsole/connected = null //this is used to print the date and to deal with extra /obj/item/advanced_healthanalyzer/Initialize() . = ..() if(!connected) var/obj/machinery/body_scanconsole/S = new (src) S.forceMove(src) S.update_use_power(POWER_USE_OFF) connected = S /obj/item/advanced_healthanalyzer/Destroy() if(connected) QDEL_NULL(connected) return ..() /obj/item/advanced_healthanalyzer/attack(mob/living/target_mob, mob/living/user, target_zone) if(!connected) return user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) user.visible_message("[user] starts scanning \the [target_mob] with \the [src].", SPAN_NOTICE("You start scanning \the [target_mob] with \the [src].")) flick("[icon_state]-scan", src) if(do_after(user, 7 SECONDS, target_mob, DO_UNIQUE)) print_scan(target_mob, user) add_fingerprint(user) /obj/item/advanced_healthanalyzer/proc/print_scan(var/mob/M, var/mob/living/user) var/obj/item/paper/medscan/R = new /obj/item/paper/medscan(src, connected.format_occupant_data(get_occupant_data(M)), "Scan ([M.name]) ([worldtime2text()])", M) connected.print(R, message = "\The [src] beeps, printing \the [R] after a moment.", user = user) /// Variant of print_scan(), main difference is different method to print the paper /obj/item/advanced_healthanalyzer/cyborg/print_scan(var/mob/M, var/mob/living/user) var/obj/item/paper/medscan/R = new /obj/item/paper/medscan(src, connected.format_occupant_data(get_occupant_data(M)), "Scan ([M.name]) ([worldtime2text()])", M) user.visible_message(SPAN_NOTICE("\The [src] beeps, printing \the [R] after a moment.")) playsound(user.loc, SFX_PRINT, 50, 1) R.forceMove(user.loc) /obj/item/advanced_healthanalyzer/proc/get_occupant_data(var/mob/living/carbon/human/H) if (!ishuman(H)) return var/displayed_stat = H.stat var/blood_oxygenation = H.get_blood_oxygenation() if(H.status_flags & FAKEDEATH) displayed_stat = DEAD blood_oxygenation = min(blood_oxygenation, BLOOD_VOLUME_SURVIVE) switch(displayed_stat) if(CONSCIOUS) displayed_stat = "Conscious" if(UNCONSCIOUS) displayed_stat = "Unconscious" if(DEAD) displayed_stat = "DEAD" var/pulse_result if(H.should_have_organ(BP_HEART)) var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[BP_HEART] if(!heart) pulse_result = 0 else if(BP_IS_ROBOTIC(heart)) pulse_result = -2 else if(H.status_flags & FAKEDEATH) pulse_result = 0 else pulse_result = H.get_pulse(GETPULSE_TOOL) else pulse_result = -1 if(pulse_result == ">250") pulse_result = -3 var/datum/reagents/R = H.bloodstr connected.has_internal_injuries = FALSE connected.has_external_injuries = FALSE var/list/bodyparts = connected.get_external_wound_data(H) var/list/organs = connected.get_internal_wound_data(H) var/list/occupant_data = list( "stationtime" = worldtime2text(), "stat" = displayed_stat, "name" = H.name, "species" = H.get_species(), "brain_activity" = H.get_brain_status(), "pulse" = text2num(pulse_result), "blood_volume" = H.get_blood_volume(), "blood_oxygenation" = H.get_blood_oxygenation(), "blood_pressure" = H.get_blood_pressure(), "blood_type" = H.dna.b_type, "bruteloss" = get_severity(H.getBruteLoss(), TRUE), "fireloss" = get_severity(H.getFireLoss(), TRUE), "oxyloss" = get_severity(H.getOxyLoss(), TRUE), "toxloss" = get_severity(H.getToxLoss(), TRUE), "cloneloss" = get_severity(H.getCloneLoss(), TRUE), "rads" = H.total_radiation, "paralysis" = H.paralysis, "bodytemp" = H.bodytemperature, "borer_present" = H.has_brain_worms(), "inaprovaline_amount" = REAGENT_VOLUME(R, /singleton/reagent/inaprovaline), "dexalin_amount" = REAGENT_VOLUME(R, /singleton/reagent/dexalin), "soporific_amount" = REAGENT_VOLUME(R, /singleton/reagent/soporific), "bicaridine_amount" = REAGENT_VOLUME(R, /singleton/reagent/bicaridine), "dermaline_amount" = REAGENT_VOLUME(R, /singleton/reagent/dermaline), "thetamycin_amount" = REAGENT_VOLUME(R, /singleton/reagent/thetamycin), "other_amount" = R.total_volume - (REAGENT_VOLUME(R, /singleton/reagent/inaprovaline) + REAGENT_VOLUME(R, /singleton/reagent/soporific) + REAGENT_VOLUME(R, /singleton/reagent/bicaridine) + REAGENT_VOLUME(R, /singleton/reagent/dexalin) + REAGENT_VOLUME(R, /singleton/reagent/dermaline) + REAGENT_VOLUME(R, /singleton/reagent/thetamycin)), "bodyparts" = bodyparts, "organs" = organs, "has_internal_injuries" = connected.has_internal_injuries, "has_external_injuries" = connected.has_external_injuries, "missing_limbs" = connected.get_missing_limbs(H), "missing_organs" = connected.get_missing_organs(H) ) return occupant_data