mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 22:50:26 +01:00
## About The Pull Request I have no idea how to word this so here's a list instead. 1. Fixes #96445 by making it so that instead of healthscan code coming up with cure text on the spot for viruses, advanced diseases have a function that can generate cure text so you can use it in things other than healthscanning. 2. Rewords a single letter var in medical kiosk code 3. As a result of 1, the code for disease state analyzers healthscanning has been shortened because the cure text generating function only has to be written once and not twice. 4. Health scans now have a power level instead of just being advanced or basic. There is a new power level called super, and it's only available to ghosts. Super scans can see all virus symptoms instead of just 3, and the current stage of an alien embryo. 5. For some reason a bunch of healthscan code (like stuff from the eye of god and health scanner mod module) were using 1 instead of SCANMODE_VERBOSE (a define that equals 1 but is more readable) for the scanmode. That's no longer the case. 6. A new health scanner, the super health scanner, that replaces the advanced one in the box of debug tools. <img width="620" height="223" alt="image" src="https://github.com/user-attachments/assets/a0c5e56e-cf19-4db2-a2df-b72456123c50" /> <img width="73" height="65" alt="image" src="https://github.com/user-attachments/assets/27f8c81b-4f89-455b-82fa-a0ecf94656cf" /> ## Why It's Good For The Game Ghosts should be able to see everything, I think ## Changelog 🆑 qol: Ghosts can see alien embryo stage and all virus symptoms when health scanning code: Health scanners now support multiple scan levels fix: Fixes medical kiosks not being able to identify advanced disease cures. /🆑 --------- Co-authored-by: Fghj240 <fakeemail@notrealemail.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
249 lines
12 KiB
Plaintext
249 lines
12 KiB
Plaintext
/obj/item/autopsy_scanner
|
|
name = "autopsy scanner"
|
|
desc = "Used in surgery to extract information from a cadaver. Can also scan the health of cadavers like an advanced health analyzer!"
|
|
icon = 'icons/obj/devices/scanner.dmi'
|
|
icon_state = "autopsy_scanner"
|
|
inhand_icon_state = "autopsy_scanner"
|
|
worn_icon_state = "autopsy_scanner"
|
|
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
|
obj_flags = CONDUCTS_ELECTRICITY
|
|
item_flags = CRUEL_IMPLEMENT
|
|
slot_flags = ITEM_SLOT_BELT
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
custom_materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT)
|
|
custom_price = PAYCHECK_COMMAND
|
|
sound_vary = TRUE
|
|
pickup_sound = SFX_GENERIC_DEVICE_PICKUP
|
|
drop_sound = SFX_GENERIC_DEVICE_DROP
|
|
|
|
/obj/item/autopsy_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
|
if(!isliving(interacting_with))
|
|
return NONE
|
|
if(!user.can_read(src) || user.is_blind())
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
var/mob/living/scanned = interacting_with
|
|
|
|
if(scanned.stat != DEAD && !HAS_TRAIT(scanned, TRAIT_FAKEDEATH)) // good job, you found a loophole
|
|
to_chat(user, span_deadsay("[icon2html(src, user)] ERROR! CANNOT SCAN LIVE CADAVERS. PROCURE HEALTH ANALYZER OR TERMINATE PATIENT."))
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
. = ITEM_INTERACT_SUCCESS
|
|
|
|
// Clumsiness/brain damage check
|
|
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: <b>Healthy</b>")]\
|
|
\n[span_info("Key: <font color='#00cccc'>Suffocation</font>/<font color='#00cc66'>Toxin</font>/<font color='#ffcc33'>Burn</font>/<font color='#ff3333'>Brute</font>")]\
|
|
\n[span_info("\tDamage specifics: <font color='#66cccc'>0</font>-<font color='#00cc66'>0</font>-<font color='#ff9933'>0</font>-<font color='#ff3333'>0</font>")]\
|
|
\n[span_info("Body temperature: ???")]")
|
|
return
|
|
|
|
user.visible_message(span_notice("[user] scans [scanned]'s cadaver."))
|
|
to_chat(user, span_deadsay("[icon2html(src, user)] ANALYZING CADAVER."))
|
|
|
|
healthscan(user, scanned, scanpower = SCANPOWER_ADVANCED)
|
|
|
|
add_fingerprint(user)
|
|
|
|
/obj/item/autopsy_scanner/proc/scan_cadaver(mob/living/carbon/human/user, mob/living/carbon/scanned)
|
|
if(scanned.stat != DEAD)
|
|
return
|
|
|
|
var/obj/item/paper/autopsy_report = new(get_turf(src))
|
|
autopsy_report.color = "#99ccff"
|
|
autopsy_report.name = "autopsy report of [scanned] - [server_timestamp(format = "hh:mm", ic_time = TRUE)]"
|
|
var/final_report_text = "<center><b>Autopsy report</br>\
|
|
Time of Autopsy: [UNDERLINED_HTML_TEXT("[server_timestamp(format = "hh:mm", ic_time = TRUE)]", "Shift Time: [round_timestamp(format = "hh:mm")]")]</b></center>"
|
|
|
|
//A lot of this is extremely similar to /proc/healthscan() - but with different formatting, no color, and some added/removed info
|
|
//Does not list quirks/exhaustion/how to repair wounds
|
|
//DOES list wound sources/
|
|
var/list/autopsy_information = list()
|
|
autopsy_information += "Autopsy Coroner - [user.name]<hr>"
|
|
|
|
autopsy_information += "Analyzing results for <b>[scanned.name]</b>:</br></br>"
|
|
autopsy_information += "Time of Death - <b>[scanned.station_timestamp_timeofdeath]</b></br>"
|
|
autopsy_information += "Subject has been dead for <b>[DisplayTimeText(round(world.time - scanned.timeofdeath))]</b>.<hr>"
|
|
|
|
var/oxy_loss = scanned.get_oxy_loss()
|
|
var/tox_loss = scanned.get_tox_loss()
|
|
var/fire_loss = scanned.get_fire_loss()
|
|
var/brute_loss = scanned.get_brute_loss()
|
|
/// "Body Data" portion of the autopsy - damage, wounds, and limbs
|
|
var/dmgreport = "<u><b>Body Data:</b></u>\
|
|
<table class='ml-2'>\
|
|
<tr>\
|
|
<td style='width:7em;'><b>Damage:</b></td>\
|
|
<td style='width:5em;'><b>Brute</b></td>\
|
|
<td style='width:4em;'><b>Burn</b></td>\
|
|
<td style='width:4em;'><b>Toxin</b></td>\
|
|
<td style='width:8em;'><b>Suffocation</b></td>\
|
|
</tr>"
|
|
for(var/zone in scanned.get_all_limbs()) //Same order every time for consistency across all humans
|
|
var/obj/item/bodypart/limb = scanned.get_bodypart(zone)
|
|
if(isnull(limb))
|
|
dmgreport += "<tr>"
|
|
dmgreport += "<td><b>[capitalize(parse_zone(zone))]:</b></td>"
|
|
dmgreport += "<td>-</td>"
|
|
dmgreport += "<td>-</td>"
|
|
dmgreport += "</tr>"
|
|
dmgreport += "<tr><td colspan=6>↳ Physical trauma: <u>Dismembered</u></td></tr>"
|
|
continue
|
|
var/has_any_embeds = LAZYLEN(limb.embedded_objects) >= 1
|
|
var/has_any_wounds = length(limb.wounds) >= 1
|
|
dmgreport += "<tr>"
|
|
dmgreport += "<td><b>[capitalize(limb.name)]:</b></td>"
|
|
dmgreport += "<td>[limb.brute_dam > 0 ? ceil(limb.brute_dam) : "0"]</td>"
|
|
dmgreport += "<td>[limb.burn_dam > 0 ? ceil(limb.burn_dam) : "0"]</td>"
|
|
if(zone == BODY_ZONE_CHEST) // tox/oxy is stored in the chest
|
|
dmgreport += "<td>[tox_loss > 0 ? ceil(tox_loss) : "0"]</td>"
|
|
dmgreport += "<td>[oxy_loss > 0 ? ceil(oxy_loss) : "0"]</td>"
|
|
dmgreport += "</tr>"
|
|
if(has_any_embeds)
|
|
var/list/embedded_names = list()
|
|
for(var/obj/item/embed as anything in limb.embedded_objects)
|
|
embedded_names[capitalize(embed.name)] += 1
|
|
for(var/embedded_name in embedded_names)
|
|
var/displayed = embedded_name
|
|
var/embedded_amt = embedded_names[embedded_name]
|
|
if(embedded_amt > 1)
|
|
displayed = "[embedded_amt]x [embedded_name]"
|
|
dmgreport += "<tr><td colspan=6><i>↳ Foreign object(s): [displayed].</i></td></tr>"
|
|
if(has_any_wounds)
|
|
for(var/datum/wound/wound as anything in limb.wounds)
|
|
dmgreport += "<tr><td colspan=6><i>↳ Physical trauma: [wound.name] ([wound.severity_text()]) - Caused by <u>[wound.wound_source].</u></i></td></tr>"
|
|
|
|
dmgreport += "<tr>\
|
|
<td><b>Overall:</b></td>\
|
|
<td><b>[ceil(brute_loss)] Brute</b></td>\
|
|
<td><b>[ceil(fire_loss)] Burn</b></td>\
|
|
<td><b>[ceil(tox_loss)] Toxin</b></td>\
|
|
<td><b>[ceil(oxy_loss)] Suffocation</b></td>\
|
|
</tr>"
|
|
dmgreport += "</table><hr>"
|
|
autopsy_information += dmgreport
|
|
|
|
// Only humanoids list organs, implants, gene stability, species and core-temp
|
|
if(ishuman(scanned))
|
|
var/mob/living/carbon/human/humantarget = scanned
|
|
/// "Organ Data" portion of the autopsy - damage, functional status (or if it's missing), and implants
|
|
var/organreport = "<u><b>Organ Data:</b></u>\
|
|
<table class='ml-2'>\
|
|
<tr>\
|
|
<td style='width:10em;'><b>Organ:</b></td>\
|
|
<td style='width:6em;'><b>Dmg</b></td>\
|
|
<td style='width:30em;'><b>Status</b></td>\
|
|
</tr>"
|
|
|
|
var/list/missing_organs = humantarget.get_missing_organs()
|
|
for(var/sorted_slot in GLOB.organ_process_order) //Same order every time for consistency across all humans
|
|
var/obj/item/organ/organ = humantarget.get_organ_slot(sorted_slot)
|
|
if(isnull(organ))
|
|
if(missing_organs[sorted_slot])
|
|
organreport += "<tr><td><b>[missing_organs[sorted_slot]]:</b></td>\
|
|
<td>-</td>\
|
|
<td><u>Missing</u></td></tr>"
|
|
continue
|
|
var/status = organ.get_status_text(scanpower = SCANPOWER_ADVANCED, add_tooltips = FALSE, colored = FALSE)
|
|
var/appendix = organ.get_status_appendix(scanpower = SCANPOWER_ADVANCED, add_tooltips = FALSE)
|
|
if(!status)
|
|
status ||= "OK" // otherwise flawless organs have no status reported by default
|
|
organreport += "<tr>\
|
|
<td><b>[capitalize(organ.name)]:</b></td>\
|
|
<td>[organ.damage > 0 ? ceil(organ.damage) : "0"]</td>\
|
|
<td>[status]</td>\
|
|
</tr>"
|
|
if(appendix)
|
|
organreport += "<tr><td colspan=4><i>↳ [appendix]</i></td></tr>"
|
|
organreport += "</table>" //<hr> comes after Cybernetics below
|
|
autopsy_information += organreport
|
|
|
|
var/mutant = HAS_TRAIT(humantarget, TRAIT_HULK) //Also applied by genetics infusions
|
|
// Cybernetics
|
|
var/list/cyberimps
|
|
for(var/obj/item/organ/target_organ as anything in humantarget.organs)
|
|
if(IS_ROBOTIC_ORGAN(target_organ) && !(target_organ.organ_flags & ORGAN_HIDDEN))
|
|
LAZYADD(cyberimps, target_organ.examine_title(user))
|
|
if(target_organ.organ_flags & ORGAN_MUTANT)
|
|
mutant = TRUE
|
|
if(LAZYLEN(cyberimps))
|
|
autopsy_information += "<b>Detected cybernetic modifications:</b></br>"
|
|
autopsy_information += "[english_list(cyberimps, and_text = ", and ")]</br>"
|
|
|
|
autopsy_information += "<hr>"
|
|
|
|
// Genetic Stability, Species, and Body Temperature
|
|
if(humantarget.has_dna() && humantarget.dna.stability != initial(humantarget.dna.stability))
|
|
autopsy_information += "<b>Genetic Stability:</b> [humantarget.dna.stability]%.</br>"
|
|
var/datum/species/targetspecies = humantarget.dna.species
|
|
var/disguised = !ishumanbasic(humantarget) && istype(humantarget.head, /obj/item/clothing/head/hooded/human_head) && istype(humantarget.wear_suit, /obj/item/clothing/suit/hooded/bloated_human)
|
|
var/species_name = "[disguised ? "\"[/datum/species/human::name]\"" : targetspecies.name][mutant ? "-derived mutant" : ""]"
|
|
autopsy_information += "<b>Species:</b> [species_name]</br>"
|
|
autopsy_information += "<b>Core temperature:</b> [round(humantarget.coretemperature-T0C, 0.1)] °C ([round(humantarget.coretemperature*1.8-459.67,0.1)] °F)</br>"
|
|
// (End of humanoid-only information)
|
|
autopsy_information += "<b>Body temperature:</b> [round(scanned.bodytemperature-T0C, 0.1)] °C ([round(scanned.bodytemperature*1.8-459.67,0.1)] °F)</br>"
|
|
|
|
// Blood Info
|
|
if(HAS_TRAIT(scanned, TRAIT_HUSK))
|
|
autopsy_information += "Subject is husked by: "
|
|
if(HAS_TRAIT_FROM(scanned, TRAIT_HUSK, CHANGELING_DRAIN))
|
|
autopsy_information += "Desiccation, commonly caused by Changelings.</br>"
|
|
else if(HAS_TRAIT_FROM(scanned, TRAIT_HUSK, SKELETON_TRAIT))
|
|
autopsy_information += "Stripped flesh.</br>"
|
|
else if(!HAS_TRAIT_FROM(scanned, TRAIT_HUSK, BURN)) // prioritize showing unknown causes over burns
|
|
autopsy_information += "Unknown causes.</br>"
|
|
else
|
|
autopsy_information += "Severe burns.</br>"
|
|
|
|
var/datum/blood_type/blood_type = scanned.get_bloodtype()
|
|
if(blood_type)
|
|
var/cached_blood_volume = scanned.get_blood_volume(apply_modifiers = TRUE)
|
|
var/blood_percent = round((cached_blood_volume / BLOOD_VOLUME_NORMAL) * 100)
|
|
var/blood_type_format
|
|
var/level_format
|
|
if(cached_blood_volume <= BLOOD_VOLUME_SAFE && cached_blood_volume > BLOOD_VOLUME_OKAY)
|
|
level_format = "LOW [blood_percent]%, [cached_blood_volume] cl"
|
|
else if(cached_blood_volume <= BLOOD_VOLUME_OKAY)
|
|
level_format = "<u>CRITICAL [blood_percent]%</u>, [cached_blood_volume] cl"
|
|
else
|
|
level_format = "[blood_percent]%, [cached_blood_volume] cl"
|
|
if(blood_type.get_type())
|
|
blood_type_format = "type: [blood_type.get_type()]"
|
|
autopsy_information += "<b>[blood_type.get_blood_name()] level:</b> [level_format], [blood_type_format]</br>"
|
|
var/blood_alcohol_content = scanned.get_blood_alcohol_content()
|
|
if(blood_alcohol_content > 0)
|
|
autopsy_information += "↳ [blood_type?.get_blood_name() || "Blood"] alcohol content: [blood_alcohol_content]%</br>"
|
|
autopsy_information += "<hr>"
|
|
|
|
autopsy_information += "<u>Chemical Data:</u></br>"
|
|
for(var/datum/reagent/scanned_reagents as anything in scanned.reagents.reagent_list)
|
|
if(scanned_reagents.chemical_flags & REAGENT_INVISIBLE)
|
|
continue
|
|
autopsy_information += "<b>[scanned_reagents.name]:</b> [round(scanned_reagents.volume, 0.1)] unit\s in bloodstream.</br>"
|
|
autopsy_information += "<i>↳ [scanned_reagents.description]</i></br>"
|
|
autopsy_information += "<hr>"
|
|
|
|
autopsy_information += "<u>Disease Data:</u></br>"
|
|
for(var/datum/disease/diseases as anything in scanned.diseases)
|
|
autopsy_information += "<b>Disease Name:</b> \"[diseases.name]\"</br>"
|
|
autopsy_information += "<b>Transmission Type:</b> [diseases.spread_text]</br>"
|
|
if(!istype(diseases, /datum/disease/advance))
|
|
continue
|
|
autopsy_information += "<b>Symptoms:</b></br>"
|
|
var/datum/disease/advance/advanced_disease = diseases
|
|
for(var/datum/symptom/symptom as anything in advanced_disease.symptoms)
|
|
autopsy_information += "↳ [symptom.name] - <i>[symptom.desc]</i></br>"
|
|
autopsy_information += "<hr>"
|
|
|
|
autopsy_information += "<b>Coroner's Notes:</b>" //Bottom of the page, anything past here is player-written
|
|
|
|
final_report_text += jointext(autopsy_information, "")
|
|
autopsy_report.add_raw_text(final_report_text, advanced_html = TRUE)
|
|
autopsy_report.update_appearance()
|
|
user.put_in_hands(autopsy_report)
|
|
user.balloon_alert(user, "report printed")
|
|
return TRUE
|