diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 40ca839cb9a..73742548852 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -30,6 +30,8 @@ custom_price = PAYCHECK_COMMAND /// If this analyzer will give a bonus to wound treatments apon woundscan. var/give_wound_treatment_bonus = FALSE + var/last_scan_text + var/scanner_busy = FALSE /obj/item/healthanalyzer/Initialize(mapload) . = ..() @@ -38,7 +40,7 @@ /obj/item/healthanalyzer/examine(mob/user) . = ..() if(src.mode != SCANNER_NO_MODE) - . += span_notice("Alt-click [src] to toggle the limb damage readout.") + . += span_notice("Alt-click [src] to toggle the limb damage readout. Ctrl-shift-click to print readout report.") /obj/item/healthanalyzer/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")) @@ -71,10 +73,10 @@ if ((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) user.visible_message(span_warning("[user] analyzes the floor's vitals!"), \ span_notice("You stupidly try to analyze the floor's vitals!")) - to_chat(user, "[span_info("Analyzing results for The floor:\n\tOverall status: Healthy")]\ - \n[span_info("Key: Suffocation/Toxin/Burn/Brute")]\ - \n[span_info("\tDamage specifics: 0-0-0-0")]\ - \n[span_info("Body temperature: ???")]") + to_chat(user, "[span_info("Analyzing results for The floor:
\tOverall status: Healthy")]\ +
[span_info("Key: Suffocation/Toxin/Burn/Brute")]\ +
[span_info("\tDamage specifics: 0-0-0-0")]\ +
[span_info("Body temperature: ???")]") return if(ispodperson(M) && !advanced) @@ -88,6 +90,7 @@ switch (scanmode) if (SCANMODE_HEALTH) healthscan(user, M, mode, advanced) + last_scan_text = healthscan(user, M, mode, advanced, tochat = FALSE) if (SCANMODE_WOUND) woundscan(user, M, src) @@ -149,12 +152,12 @@ mob_status = span_alert("Deceased") oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss - render_list += "[span_info("Analyzing results for [target]:")]\nOverall status: [mob_status]\n" + render_list += "[span_info("Analyzing results for [target]:")]
Overall status: [mob_status]
" if(ishuman(target)) var/mob/living/carbon/human/humantarget = target if(humantarget.undergoing_cardiac_arrest() && humantarget.stat != DEAD) - render_list += "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!\n" + render_list += "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!
" if(humantarget.has_reagent(/datum/reagent/inverse/technetium)) advanced = TRUE @@ -164,22 +167,22 @@ if(HAS_TRAIT(target, TRAIT_HUSK)) if(advanced) if(HAS_TRAIT_FROM(target, TRAIT_HUSK, BURN)) - render_list += "Subject has been husked by severe burns.\n" + render_list += "Subject has been husked by severe burns.
" else if (HAS_TRAIT_FROM(target, TRAIT_HUSK, CHANGELING_DRAIN)) - render_list += "Subject has been husked by dessication.\n" + render_list += "Subject has been husked by dessication.
" else - render_list += "Subject has been husked by mysterious causes.\n" + render_list += "Subject has been husked by mysterious causes.
" else - render_list += "Subject has been husked.\n" + render_list += "Subject has been husked.
" if(target.getStaminaLoss()) if(advanced) - render_list += "Fatigue level: [target.getStaminaLoss()]%.\n" + render_list += "Fatigue level: [target.getStaminaLoss()]%.
" else - render_list += "Subject appears to be suffering from fatigue.\n" + render_list += "Subject appears to be suffering from fatigue.
" if (!target.get_organ_slot(ORGAN_SLOT_BRAIN)) // kept exclusively for soul purposes - render_list += "Subject lacks a brain.\n" + render_list += "Subject lacks a brain.
" if(iscarbon(target)) var/mob/living/carbon/carbontarget = target @@ -198,14 +201,14 @@ trauma_desc += "permanent " trauma_desc += trauma.scan_desc trauma_text += trauma_desc - render_list += "Cerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].\n" + render_list += "Cerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].
" if(carbontarget.quirks.len) - render_list += "Subject Major Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MAJOR_DISABILITY, from_scan = TRUE)].\n" + render_list += "Subject Major Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MAJOR_DISABILITY, from_scan = TRUE)].
" if(advanced) - render_list += "Subject Minor Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MINOR_DISABILITY, TRUE)].\n" + render_list += "Subject Minor Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MINOR_DISABILITY, TRUE)].
" if (HAS_TRAIT(target, TRAIT_IRRADIATED)) - render_list += "Subject is irradiated. Supply toxin healing.\n" + render_list += "Subject is irradiated. Supply toxin healing.
" //Eyes and ears if(advanced && iscarbon(target)) @@ -215,24 +218,24 @@ var/obj/item/organ/internal/ears/ears = carbontarget.get_organ_slot(ORGAN_SLOT_EARS) if(istype(ears)) if(HAS_TRAIT_FROM(carbontarget, TRAIT_DEAF, GENETIC_MUTATION)) - render_list += "Subject is genetically deaf.\n" + render_list += "Subject is genetically deaf.
" else if(HAS_TRAIT_FROM(carbontarget, TRAIT_DEAF, EAR_DAMAGE)) - render_list += "Subject is deaf from ear damage.\n" + render_list += "Subject is deaf from ear damage.
" else if(HAS_TRAIT(carbontarget, TRAIT_DEAF)) - render_list += "Subject is deaf.\n" + render_list += "Subject is deaf.
" else if(ears.damage) - render_list += "Subject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.\n" + render_list += "Subject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.
" if(ears.deaf) - render_list += "Subject is [ears.damage > ears.maxHealth ? "permanently": "temporarily"] deaf.\n" + render_list += "Subject is [ears.damage > ears.maxHealth ? "permanently": "temporarily"] deaf.
" // Eye status var/obj/item/organ/internal/eyes/eyes = carbontarget.get_organ_slot(ORGAN_SLOT_EYES) if(istype(eyes)) if(carbontarget.is_blind()) - render_list += "Subject is blind.\n" + render_list += "Subject is blind.
" else if(carbontarget.is_nearsighted()) - render_list += "Subject is nearsighted.\n" + render_list += "Subject is nearsighted.
" // Body part damage report if(iscarbon(target)) @@ -264,7 +267,7 @@ render_list += dmgreport // tables do not need extra linebreak for(var/obj/item/bodypart/limb as anything in carbontarget.bodyparts) for(var/obj/item/embed as anything in limb.embedded_objects) - render_list += "Embedded object: [embed] located in \the [limb.plaintext_zone]\n" + render_list += "Embedded object: [embed] located in \the [limb.plaintext_zone]
" if(ishuman(target)) var/mob/living/carbon/human/humantarget = target @@ -316,34 +319,34 @@ //Genetic stability if(advanced && humantarget.has_dna()) - render_list += "Genetic Stability: [humantarget.dna.stability]%.\n" + render_list += "Genetic Stability: [humantarget.dna.stability]%.
" // Hulk and body temperature var/datum/species/targetspecies = humantarget.dna.species var/mutant = HAS_TRAIT(humantarget, TRAIT_HULK) - render_list += "Species: [targetspecies.name][mutant ? "-derived mutant" : ""]\n" + render_list += "Species: [targetspecies.name][mutant ? "-derived mutant" : ""]
" var/core_temperature_message = "Core temperature: [round(humantarget.coretemperature-T0C, 0.1)] °C ([round(humantarget.coretemperature*1.8-459.67,0.1)] °F)" if(humantarget.coretemperature >= humantarget.get_body_temp_heat_damage_limit()) - render_list += "☼ [core_temperature_message] ☼\n" + render_list += "☼ [core_temperature_message] ☼
" else if(humantarget.coretemperature <= humantarget.get_body_temp_cold_damage_limit()) - render_list += "❄ [core_temperature_message] ❄\n" + render_list += "❄ [core_temperature_message] ❄
" else - render_list += "[core_temperature_message]\n" + render_list += "[core_temperature_message]
" var/body_temperature_message = "Body temperature: [round(target.bodytemperature-T0C, 0.1)] °C ([round(target.bodytemperature*1.8-459.67,0.1)] °F)" if(target.bodytemperature >= target.get_body_temp_heat_damage_limit()) - render_list += "☼ [body_temperature_message] ☼\n" + render_list += "☼ [body_temperature_message] ☼
" else if(target.bodytemperature <= target.get_body_temp_cold_damage_limit()) - render_list += "❄ [body_temperature_message] ❄\n" + render_list += "❄ [body_temperature_message] ❄
" else - render_list += "[body_temperature_message]\n" + render_list += "[body_temperature_message]
" // Time of death if(target.station_timestamp_timeofdeath && (target.stat == DEAD || ((HAS_TRAIT(target, TRAIT_FAKEDEATH)) && !advanced))) - render_list += "Time of Death: [target.station_timestamp_timeofdeath]\n" + render_list += "Time of Death: [target.station_timestamp_timeofdeath]
" var/tdelta = round(world.time - target.timeofdeath) - render_list += "Subject died [DisplayTimeText(tdelta)] ago.\n" + render_list += "Subject died [DisplayTimeText(tdelta)] ago.
" // Wounds if(iscarbon(target)) @@ -354,14 +357,14 @@ render_list += "Physical trauma[LAZYLEN(wounded_part.wounds) > 1 ? "s" : ""] detected in [wounded_part.name]" for(var/k in wounded_part.wounds) var/datum/wound/W = k - render_list += "
[W.name] ([W.severity_text()])\nRecommended treatment: [W.treat_text]
" // less lines than in woundscan() so we don't overload people trying to get basic med info + render_list += "
[W.name] ([W.severity_text()])
Recommended treatment: [W.treat_text]
" // less lines than in woundscan() so we don't overload people trying to get basic med info render_list += "
" //Diseases for(var/datum/disease/disease as anything in target.diseases) if(!(disease.visibility_flags & HIDDEN_SCANNER)) - render_list += "Warning: [disease.form] detected\n\ -
Name: [disease.name].\nType: [disease.spread_text].\nStage: [disease.stage]/[disease.max_stages].\nPossible Cure: [disease.cure_text]
\ + render_list += "Warning: [disease.form] detected
\ +
Name: [disease.name].
Type: [disease.spread_text].
Stage: [disease.stage]/[disease.max_stages].
Possible Cure: [disease.cure_text]
\
" // divs do not need extra linebreak // Blood Level @@ -370,26 +373,26 @@ var/blood_id = carbontarget.get_blood_id() if(blood_id) if(carbontarget.is_bleeding()) - render_list += "Subject is bleeding!\n" + render_list += "Subject is bleeding!
" var/blood_percent = round((carbontarget.blood_volume / BLOOD_VOLUME_NORMAL) * 100) var/blood_type = carbontarget.dna.blood_type if(blood_id != /datum/reagent/blood) // special blood substance var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id] blood_type = R ? R.name : blood_id if(carbontarget.blood_volume <= BLOOD_VOLUME_SAFE && carbontarget.blood_volume > BLOOD_VOLUME_OKAY) - render_list += "Blood level: LOW [blood_percent]%, [carbontarget.blood_volume] cl, [span_info("type: [blood_type]")]\n" + render_list += "Blood level: LOW [blood_percent]%, [carbontarget.blood_volume] cl, [span_info("type: [blood_type]")]
" else if(carbontarget.blood_volume <= BLOOD_VOLUME_OKAY) - render_list += "Blood level: CRITICAL [blood_percent]%, [carbontarget.blood_volume] cl, [span_info("type: [blood_type]")]\n" + render_list += "Blood level: CRITICAL [blood_percent]%, [carbontarget.blood_volume] cl, [span_info("type: [blood_type]")]
" else - render_list += "Blood level: [blood_percent]%, [carbontarget.blood_volume] cl, type: [blood_type]\n" + render_list += "Blood level: [blood_percent]%, [carbontarget.blood_volume] cl, type: [blood_type]
" // Blood Alcohol Content var/blood_alcohol_content = target.get_blood_alcohol_content() if(blood_alcohol_content > 0) if(blood_alcohol_content >= 0.24) - render_list += "Blood alcohol content: CRITICAL [blood_alcohol_content]%\n" + render_list += "Blood alcohol content: CRITICAL [blood_alcohol_content]%
" else - render_list += "Blood alcohol content: [blood_alcohol_content]%\n" + render_list += "Blood alcohol content: [blood_alcohol_content]%
" // Cybernetics if(iscarbon(target)) @@ -399,8 +402,8 @@ if(IS_ROBOTIC_ORGAN(cyberimp) && !(cyberimp.organ_flags & ORGAN_HIDDEN)) cyberimp_detect += "[!cyberimp_detect ? "[cyberimp.examine_title(user)]" : ", [cyberimp.examine_title(user)]"]" if(cyberimp_detect) - render_list += "Detected cybernetic modifications:\n" - render_list += "[cyberimp_detect]\n" + render_list += "Detected cybernetic modifications:
" + render_list += "[cyberimp_detect]
" // we handled the last
so we don't need handholding if(tochat) @@ -408,6 +411,37 @@ else return(jointext(render_list, "")) +/obj/item/healthanalyzer/click_ctrl_shift(mob/user) + . = ..() + if(!LAZYLEN(last_scan_text)) + balloon_alert(user, "no scans!") + return + if(scanner_busy) + balloon_alert(user, "analyzer busy!") + return + scanner_busy = TRUE + balloon_alert(user, "printing report...") + addtimer(CALLBACK(src, PROC_REF(print_report)), 2 SECONDS) + +/obj/item/healthanalyzer/proc/print_report(mob/user) + var/obj/item/paper/report_paper = new(get_turf(src)) + + report_paper.color = COLOR_STARLIGHT + report_paper.name = "Health scan report" + var/report_text = "
Health scan report. Time of scan: [station_time_timestamp()]


" + report_text += last_scan_text + + report_paper.add_raw_text(report_text) + report_paper.update_appearance() + + if(ismob(loc)) + var/mob/printer = loc + printer.put_in_hands(report_paper) + balloon_alert(printer, "logs cleared") + + report_text = list() + scanner_busy = FALSE + /proc/chemscan(mob/living/user, mob/living/target) if(user.incapacitated) return @@ -422,12 +456,12 @@ var/datum/reagent/reagent = r if(reagent.chemical_flags & REAGENT_INVISIBLE) //Don't show hidden chems on scanners continue - render_block += "[round(reagent.volume, 0.001)] units of [reagent.name][reagent.overdosed ? " - [span_boldannounce("OVERDOSING")]" : ".
"]\n" + render_block += "[round(reagent.volume, 0.001)] units of [reagent.name][reagent.overdosed ? " - [span_boldannounce("OVERDOSING")]" : "."]
" if(!length(render_block)) //If no VISIBLY DISPLAYED reagents are present, we report as if there is nothing. - render_list += "Subject contains no reagents in their blood.\n" + render_list += "Subject contains no reagents in their blood.
" else - render_list += "Subject contains the following reagents in their blood:\n" + render_list += "Subject contains the following reagents in their blood:
" render_list += render_block //Otherwise, we add the header, reagent readouts, and clear the readout block for use on the stomach. render_block.Cut() @@ -440,35 +474,35 @@ if(bit.chemical_flags & REAGENT_INVISIBLE) continue if(!belly.food_reagents[bit.type]) - render_block += "[round(bit.volume, 0.001)] units of [bit.name][bit.overdosed ? " - [span_boldannounce("OVERDOSING")]" : "."]\n" + render_block += "[round(bit.volume, 0.001)] units of [bit.name][bit.overdosed ? " - [span_boldannounce("OVERDOSING")]" : "."]
" else var/bit_vol = bit.volume - belly.food_reagents[bit.type] if(bit_vol > 0) - render_block += "[round(bit_vol, 0.001)] units of [bit.name][bit.overdosed ? " - [span_boldannounce("OVERDOSING")]" : "."]\n" + render_block += "[round(bit_vol, 0.001)] units of [bit.name][bit.overdosed ? " - [span_boldannounce("OVERDOSING")]" : "."]
" if(!length(render_block)) - render_list += "Subject contains no reagents in their stomach.\n" + render_list += "Subject contains no reagents in their stomach.
" else - render_list += "Subject contains the following reagents in their stomach:\n" + render_list += "Subject contains the following reagents in their stomach:
" render_list += render_block // Addictions if(LAZYLEN(target.mind?.active_addictions)) - render_list += "Subject is addicted to the following types of drug:\n" + render_list += "Subject is addicted to the following types of drug:
" for(var/datum/addiction/addiction_type as anything in target.mind.active_addictions) - render_list += "[initial(addiction_type.name)]\n" + render_list += "[initial(addiction_type.name)]
" // Special eigenstasium addiction if(target.has_status_effect(/datum/status_effect/eigenstasium)) - render_list += "Subject is temporally unstable. Stabilising agent is recommended to reduce disturbances.\n" + render_list += "Subject is temporally unstable. Stabilising agent is recommended to reduce disturbances.
" // Allergies for(var/datum/quirk/quirky as anything in target.quirks) if(istype(quirky, /datum/quirk/item_quirk/allergic)) var/datum/quirk/item_quirk/allergic/allergies_quirk = quirky var/allergies = allergies_quirk.allergy_string - render_list += "Subject is extremely allergic to the following chemicals:\n" - render_list += "[allergies]\n" + render_list += "Subject is extremely allergic to the following chemicals:
" + render_list += "[allergies]
" // we handled the last
so we don't need handholding to_chat(user, examine_block(jointext(render_list, "")), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) @@ -505,7 +539,7 @@ render_list += "Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.name]" for(var/limb_wound in wounded_part.wounds) var/datum/wound/current_wound = limb_wound - render_list += "
[simple_scan ? current_wound.get_simple_scanner_description() : current_wound.get_scanner_description()]
\n" + render_list += "
[simple_scan ? current_wound.get_simple_scanner_description() : current_wound.get_scanner_description()]

" if (scanner.give_wound_treatment_bonus) ADD_TRAIT(current_wound, TRAIT_WOUND_SCANNED, ANALYZER_TRAIT) if(!advised) @@ -670,8 +704,8 @@ var/list/render = list() for(var/datum/disease/disease as anything in patient.diseases) if(!(disease.visibility_flags & HIDDEN_SCANNER)) - render += "Warning: [disease.form] detected\n\ -
Name: [disease.name].\nType: [disease.spread_text].\nStage: [disease.stage]/[disease.max_stages].\nPossible Cure: [disease.cure_text]
\ + render += "Warning: [disease.form] detected
\ +
Name: [disease.name].
Type: [disease.spread_text].
Stage: [disease.stage]/[disease.max_stages].
Possible Cure: [disease.cure_text]
\
" if(!length(render))