Health Analyzer Rework (medial mains inquire within) (#86666)

This commit is contained in:
MrMelbert
2024-09-25 18:18:24 +00:00
committed by GitHub
parent bcfe54f9c9
commit c42d4dcfb2
22 changed files with 436 additions and 256 deletions
@@ -95,7 +95,7 @@
var/blood_type = scanned.dna.blood_type
if(blood_id != /datum/reagent/blood)
var/datum/reagent/reagents = GLOB.chemical_reagents_list[blood_id]
blood_type = reagents ? reagents.name : blood_id
blood_type = reagents?.name || blood_id
autopsy_information += "Blood Type: [blood_type]<br>"
autopsy_information += "Blood Volume: [scanned.blood_volume] cl ([blood_percent]%) <br>"
@@ -108,10 +108,11 @@
for(var/datum/symptom/symptom as anything in advanced_disease.symptoms)
autopsy_information += "[symptom.name] - [symptom.desc]<br>"
var/obj/item/paper/autopsy_report = new(user.loc)
autopsy_report.name = "Autopsy Report ([scanned.name])"
var/obj/item/paper/autopsy_report = new(user.drop_location())
autopsy_report.name = "autopsy report of [scanned] - [station_time_timestamp()])"
autopsy_report.add_raw_text(autopsy_information.Join("\n"))
autopsy_report.update_appearance(UPDATE_ICON)
autopsy_report.color = "#99ccff"
autopsy_report.update_appearance()
user.put_in_hands(autopsy_report)
user.balloon_alert(user, "report printed")
return TRUE
@@ -60,8 +60,6 @@
/obj/item/healthanalyzer/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/M = interacting_with
@@ -71,12 +69,20 @@
// 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:<br>\tOverall status: <b>Healthy</b>")]\
<br>[span_info("Key: <font color='#00cccc'>Suffocation</font>/<font color='#00cc66'>Toxin</font>/<font color='#ffcc33'>Burn</font>/<font color='#ff3333'>Brute</font>")]\
<br>[span_info("\tDamage specifics: <font color='#66cccc'>0</font>-<font color='#00cc66'>0</font>-<font color='#ff9933'>0</font>-<font color='#ff3333'>0</font>")]\
<br>[span_info("Body temperature: ???")]")
var/turf/scan_turf = get_turf(user)
user.visible_message(
span_warning("[user] analyzes [scan_turf]'s vitals!"),
span_notice("You stupidly try to analyze [scan_turf]'s vitals!"),
)
var/floor_text = "<span class='info'>Analyzing results for <b>[scan_turf]</b> ([station_time_timestamp()]):</span><br>"
floor_text += "<span class='info ml-1'>Overall status: <i>Unknown</i></span><br>"
floor_text += "<span class='alert ml-1'>Subject lacks a brain.</span><br>"
floor_text += "<span class='info ml-1'>Body temperature: [scan_turf?.return_air()?.return_temperature() || "???"]</span><br>"
if(user.can_read(src) && !user.is_blind())
to_chat(user, examine_block(floor_text))
last_scan_text = floor_text
return
if(ispodperson(M) && !advanced)
@@ -87,22 +93,21 @@
balloon_alert(user, "analyzing vitals")
playsound(user.loc, 'sound/items/healthanalyzer.ogg', 50)
var/readability_check = user.can_read(src) && !user.is_blind()
switch (scanmode)
if (SCANMODE_HEALTH)
healthscan(user, M, mode, advanced)
last_scan_text = healthscan(user, M, mode, advanced, tochat = FALSE)
last_scan_text = healthscan(user, M, mode, advanced, tochat = readability_check)
if (SCANMODE_WOUND)
woundscan(user, M, src)
if(readability_check)
woundscan(user, M, src)
add_fingerprint(user)
/obj/item/healthanalyzer/interact_with_atom_secondary(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
chemscan(user, interacting_with)
if(user.can_read(src) && !user.is_blind())
chemscan(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/healthanalyzer/add_item_context(
@@ -139,37 +144,33 @@
return
// the final list of strings to render
var/render_list = list()
var/list/render_list = list()
// Damage specifics
var/oxy_loss = target.getOxyLoss()
var/tox_loss = target.getToxLoss()
var/fire_loss = target.getFireLoss()
var/brute_loss = target.getBruteLoss()
var/mob_status = (target.stat == DEAD ? span_alert("<b>Deceased</b>") : "<b>[round(target.health/target.maxHealth,0.01)*100]% healthy</b>")
var/mob_status = (target.stat == DEAD ? span_alert("<b>Deceased</b>") : "<b>[round(target.health / target.maxHealth, 0.01) * 100]% healthy</b>")
if(HAS_TRAIT(target, TRAIT_FAKEDEATH) && !advanced)
mob_status = span_alert("<b>Deceased</b>")
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]:")]<br><span class='info ml-1'>Overall status: [mob_status]</span><br>"
render_list += "[span_info("Analyzing results for <b>[target]</b> ([station_time_timestamp()]):")]<br><span class='info ml-1'>Overall status: [mob_status]</span><br>"
if(ishuman(target))
var/mob/living/carbon/human/humantarget = target
if(humantarget.undergoing_cardiac_arrest() && humantarget.stat != DEAD)
render_list += "<span class='alert ml-1'><b>Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!</b></span><br>"
if(humantarget.has_reagent(/datum/reagent/inverse/technetium))
advanced = TRUE
if(!advanced && target.has_reagent(/datum/reagent/inverse/technetium))
advanced = TRUE
SEND_SIGNAL(target, COMSIG_LIVING_HEALTHSCAN, render_list, advanced, user, mode)
SEND_SIGNAL(target, COMSIG_LIVING_HEALTHSCAN, render_list, advanced, user, mode, tochat)
// Husk detection
if(HAS_TRAIT(target, TRAIT_HUSK))
if(advanced)
if(HAS_TRAIT_FROM(target, TRAIT_HUSK, BURN))
render_list += "<span class='alert ml-1'>Subject has been husked by severe burns.</span><br>"
render_list += "<span class='alert ml-1'>Subject has been husked by [conditional_tooltip("severe burns", "Tend burns and apply a de-husking agent, such as [/datum/reagent/medicine/c2/synthflesh::name].", tochat)].</span><br>"
else if (HAS_TRAIT_FROM(target, TRAIT_HUSK, CHANGELING_DRAIN))
render_list += "<span class='alert ml-1'>Subject has been husked by dessication.</span><br>"
render_list += "<span class='alert ml-1'>Subject has been husked by [conditional_tooltip("desiccation", "Irreparable. Under normal circumstances, revival can only proceed via brain transplant.", tochat)].</span><br>"
else
render_list += "<span class='alert ml-1'>Subject has been husked by mysterious causes.</span><br>"
@@ -186,139 +187,156 @@
if(iscarbon(target))
var/mob/living/carbon/carbontarget = target
if(LAZYLEN(carbontarget.get_traumas()))
var/list/trauma_text = list()
for(var/datum/brain_trauma/trauma in carbontarget.get_traumas())
var/trauma_desc = ""
switch(trauma.resilience)
if(TRAUMA_RESILIENCE_SURGERY)
trauma_desc += "severe "
if(TRAUMA_RESILIENCE_LOBOTOMY)
trauma_desc += "deep-rooted "
if(TRAUMA_RESILIENCE_WOUND)
trauma_desc += "fracture-derived "
if(TRAUMA_RESILIENCE_MAGIC, TRAUMA_RESILIENCE_ABSOLUTE)
trauma_desc += "permanent "
trauma_desc += trauma.scan_desc
trauma_text += trauma_desc
render_list += "<span class='alert ml-1'>Cerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].</span><br>"
if(carbontarget.quirks.len)
if(LAZYLEN(carbontarget.quirks))
render_list += "<span class='info ml-1'>Subject Major Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MAJOR_DISABILITY, from_scan = TRUE)].</span><br>"
if(advanced)
render_list += "<span class='info ml-1'>Subject Minor Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MINOR_DISABILITY, TRUE)].</span><br>"
if (HAS_TRAIT(target, TRAIT_IRRADIATED))
render_list += "<span class='alert ml-1'>Subject is irradiated. Supply toxin healing.</span><br>"
//Eyes and ears
if(advanced && iscarbon(target))
var/mob/living/carbon/carbontarget = target
// Ear status
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 += "<span class='alert ml-2'>Subject is genetically deaf.<br></span>"
else if(HAS_TRAIT_FROM(carbontarget, TRAIT_DEAF, EAR_DAMAGE))
render_list += "<span class='alert ml-2'>Subject is deaf from ear damage.<br></span>"
else if(HAS_TRAIT(carbontarget, TRAIT_DEAF))
render_list += "<span class='alert ml-2'>Subject is deaf.<br></span>"
else
if(ears.damage)
render_list += "<span class='alert ml-2'>Subject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.<br></span>"
if(ears.deaf)
render_list += "<span class='alert ml-2'>Subject is [ears.damage > ears.maxHealth ? "permanently": "temporarily"] deaf.<br></span>"
// 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 += "<span class='alert ml-2'>Subject is blind.<br></span>"
else if(carbontarget.is_nearsighted())
render_list += "<span class='alert ml-2'>Subject is nearsighted.<br></span>"
// Body part damage report
if(iscarbon(target))
var/mob/living/carbon/carbontarget = target
var/list/damaged = carbontarget.get_damaged_bodyparts(1,1)
if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0)
var/dmgreport = "<span class='info ml-1'>General status:</span>\
<table class='ml-2'><tr><font face='Verdana'>\
var/any_damage = brute_loss > 0 || fire_loss > 0 || oxy_loss > 0 || tox_loss > 0 || fire_loss > 0
var/any_missing = length(carbontarget.bodyparts) < (carbontarget.dna?.species?.max_bodypart_count || 6)
var/any_wounded = length(carbontarget.all_wounds)
var/any_embeds = carbontarget.has_embedded_objects()
if(any_damage || (mode == SCANNER_VERBOSE && (any_missing || any_wounded || any_embeds)))
render_list += "<hr>"
var/dmgreport = "<span class='info ml-1'>Body status:</span>\
<font face='Verdana'>\
<table class='ml-2'>\
<tr>\
<td style='width:7em;'><font color='#ff0000'><b>Damage:</b></font></td>\
<td style='width:5em;'><font color='#ff3333'><b>Brute</b></font></td>\
<td style='width:4em;'><font color='#ff9933'><b>Burn</b></font></td>\
<td style='width:4em;'><font color='#00cc66'><b>Toxin</b></font></td>\
<td style='width:8em;'><font color='#00cccc'><b>Suffocation</b></font></td></tr>\
<tr><td><font color='#ff3333'><b>Overall:</b></font></td>\
<td><font color='#ff3333'><b>[CEILING(brute_loss,1)]</b></font></td>\
<td><font color='#ff9933'><b>[CEILING(fire_loss,1)]</b></font></td>\
<td><font color='#00cc66'><b>[CEILING(tox_loss,1)]</b></font></td>\
<td><font color='#33ccff'><b>[CEILING(oxy_loss,1)]</b></font></td></tr>"
<td style='width:8em;'><font color='#00cccc'><b>Suffocation</b></font></td>\
</tr>\
<tr>\
<td><font color='#ff3333'><b>Overall:</b></font></td>\
<td><font color='#ff3333'><b>[ceil(brute_loss)]</b></font></td>\
<td><font color='#ff9933'><b>[ceil(fire_loss)]</b></font></td>\
<td><font color='#00cc66'><b>[ceil(tox_loss)]</b></font></td>\
<td><font color='#33ccff'><b>[ceil(oxy_loss)]</b></font></td>\
</tr>"
if(mode == SCANNER_VERBOSE)
for(var/obj/item/bodypart/limb as anything in damaged)
if(limb.bodytype & BODYTYPE_ROBOTIC)
dmgreport += "<tr><td><font color='#cc3333'>[capitalize(limb.name)]:</font></td>"
else
dmgreport += "<tr><td><font color='#cc3333'>[capitalize(limb.plaintext_zone)]:</font></td>"
dmgreport += "<td><font color='#cc3333'>[(limb.brute_dam > 0) ? "[CEILING(limb.brute_dam,1)]" : "0"]</font></td>"
dmgreport += "<td><font color='#ff9933'>[(limb.burn_dam > 0) ? "[CEILING(limb.burn_dam,1)]" : "0"]</font></td></tr>"
dmgreport += "</font></table>"
// Follow same body zone list every time so it's consistent across all humans
for(var/zone in GLOB.all_body_zones)
var/obj/item/bodypart/limb = carbontarget.get_bodypart(zone)
if(isnull(limb))
dmgreport += "<tr>"
dmgreport += "<td><font color='#cc3333'>[capitalize(parse_zone(zone))]:</font></td>"
dmgreport += "<td><font color='#cc3333'>-</font></td>"
dmgreport += "<td><font color='#ff9933'>-</font></td>"
dmgreport += "</tr>"
dmgreport += "<tr><td colspan=6><span class='alert ml-2'>&rdsh; Physical trauma: [conditional_tooltip("Dismembered", "Reattach or replace surgically.", tochat)]</span></td></tr>"
continue
var/has_any_embeds = length(limb.embedded_objects) >= 1
var/has_any_wounds = length(limb.wounds) >= 1
var/is_damaged = limb.burn_dam > 0 || limb.brute_dam > 0
if(!is_damaged && (zone != BODY_ZONE_CHEST || (tox_loss <= 0 && oxy_loss <= 0)) && !has_any_embeds && !has_any_wounds)
continue
dmgreport += "<tr>"
dmgreport += "<td><font color='#cc3333'>[capitalize((limb.bodytype & BODYTYPE_ROBOTIC) ? limb.name : limb.plaintext_zone)]:</font></td>"
dmgreport += "<td><font color='#cc3333'>[limb.brute_dam > 0 ? ceil(limb.brute_dam) : "0"]</font></td>"
dmgreport += "<td><font color='#ff9933'>[limb.burn_dam > 0 ? ceil(limb.burn_dam) : "0"]</font></td>"
if(zone == BODY_ZONE_CHEST) // tox/oxy is stored in the chest
dmgreport += "<td><font color='#00cc66'>[tox_loss > 0 ? ceil(tox_loss) : "0"]</font></td>"
dmgreport += "<td><font color='#33ccff'>[oxy_loss > 0 ? ceil(oxy_loss) : "0"]</font></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><span class='alert ml-2'>&rdsh; Foreign object(s): [conditional_tooltip(displayed, "Use a hemostat to remove.", tochat)]</span></td></tr>"
if(has_any_wounds)
for(var/datum/wound/wound as anything in limb.wounds)
dmgreport += "<tr><td colspan=6><span class='alert ml-2'>&rdsh; Physical trauma: [conditional_tooltip("[wound.name] ([wound.severity_text()])", wound.treat_text_short, tochat)]</span></td></tr>"
dmgreport += "</table></font>"
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 += "<span class='alert ml-1'>Embedded object: [embed] located in \the [limb.plaintext_zone]</span><br>"
if(ishuman(target))
var/mob/living/carbon/human/humantarget = target
// Organ damage, missing organs
if(humantarget.organs && humantarget.organs.len)
var/render = FALSE
var/toReport = "<span class='info ml-1'>Organs:</span>\
<table class='ml-2'><tr>\
<td style='width:6em;'><font color='#ff0000'><b>Organ:</b></font></td>\
[advanced ? "<td style='width:3em;'><font color='#ff0000'><b>Dmg</b></font></td>" : ""]\
<td style='width:12em;'><font color='#ff0000'><b>Status</b></font></td>"
var/render = FALSE
var/toReport = "<span class='info ml-1'>Organ status:</span>\
<font face='Verdana'>\
<table class='ml-2'>\
<tr>\
<td style='width:8em;'><font color='#ff0000'><b>Organ:</b></font></td>\
[advanced ? "<td style='width:4em;'><font color='#ff0000'><b>Dmg</b></font></td>" : ""]\
<td style='width:30em;'><font color='#ff0000'><b>Status</b></font></td>\
</tr>"
for(var/obj/item/organ/organ as anything in humantarget.organs)
var/status = organ.get_status_text(advanced)
if (status != "")
var/list/missing_organs = list()
if(!humantarget.get_organ_slot(ORGAN_SLOT_BRAIN))
missing_organs[ORGAN_SLOT_BRAIN] = "Brain"
if(!humantarget.needs_heart() && !humantarget.get_organ_slot(ORGAN_SLOT_HEART))
missing_organs[ORGAN_SLOT_HEART] = "Heart"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOBREATH, SPECIES_TRAIT) && !isnull(humantarget.dna.species.mutantlungs) && !humantarget.get_organ_slot(ORGAN_SLOT_LUNGS))
missing_organs[ORGAN_SLOT_LUNGS] = "Lungs"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_LIVERLESS_METABOLISM, SPECIES_TRAIT) && !isnull(humantarget.dna.species.mutantliver) && !humantarget.get_organ_slot(ORGAN_SLOT_LIVER))
missing_organs[ORGAN_SLOT_LIVER] = "Liver"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOHUNGER, SPECIES_TRAIT) && !isnull(humantarget.dna.species.mutantstomach) && !humantarget.get_organ_slot(ORGAN_SLOT_STOMACH))
missing_organs[ORGAN_SLOT_STOMACH] ="Stomach"
if(!isnull(humantarget.dna.species.mutanttongue) && !humantarget.get_organ_slot(ORGAN_SLOT_TONGUE))
missing_organs[ORGAN_SLOT_TONGUE] = "Tongue"
if(!isnull(humantarget.dna.species.mutantears) && !humantarget.get_organ_slot(ORGAN_SLOT_EARS))
missing_organs[ORGAN_SLOT_EARS] = "Ears"
if(!isnull(humantarget.dna.species.mutantears) && !humantarget.get_organ_slot(ORGAN_SLOT_EYES))
missing_organs[ORGAN_SLOT_EYES] = "Eyes"
// Follow same order as in the organ_process_order so it's consistent across all humans
for(var/sorted_slot in GLOB.organ_process_order)
var/obj/item/organ/organ = humantarget.get_organ_slot(sorted_slot)
if(isnull(organ))
if(missing_organs[sorted_slot])
render = TRUE
toReport += "<tr><td><font color='#cc3333'>[organ.name]:</font></td>\
[advanced ? "<td><font color='#ff3333'>[CEILING(organ.damage,1)]</font></td>" : ""]\
<td>[status]</td></tr>"
var/missing_organs = list()
if(!humantarget.get_organ_slot(ORGAN_SLOT_BRAIN))
missing_organs += "brain"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOBLOOD, SPECIES_TRAIT) && !humantarget.get_organ_slot(ORGAN_SLOT_HEART))
missing_organs += "heart"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOBREATH, SPECIES_TRAIT) && !humantarget.get_organ_slot(ORGAN_SLOT_LUNGS))
missing_organs += "lungs"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_LIVERLESS_METABOLISM, SPECIES_TRAIT) && !humantarget.get_organ_slot(ORGAN_SLOT_LIVER))
missing_organs += "liver"
if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOHUNGER, SPECIES_TRAIT) && !humantarget.get_organ_slot(ORGAN_SLOT_STOMACH))
missing_organs += "stomach"
if(!humantarget.get_organ_slot(ORGAN_SLOT_TONGUE))
missing_organs += "tongue"
if(!humantarget.get_organ_slot(ORGAN_SLOT_EARS))
missing_organs += "ears"
if(!humantarget.get_organ_slot(ORGAN_SLOT_EYES))
missing_organs += "eyes"
if(length(missing_organs))
toReport += "<tr><td><font color='#cc3333'>[missing_organs[sorted_slot]]:</font></td>\
[advanced ? "<td><font color='#ff3333'>-</font></td>" : ""]\
<td><font color='#cc3333'>Missing</font></td></tr>"
continue
if(mode != SCANNER_VERBOSE && !organ.show_on_condensed_scans())
continue
var/status = organ.get_status_text(advanced, tochat)
var/appendix = organ.get_status_appendix(advanced, tochat)
if(status || appendix)
status ||= "<font color='#ffcc33'>OK</font>" // otherwise flawless organs have no status reported by default
render = TRUE
for(var/organ in missing_organs)
toReport += "<tr><td><font color='#cc3333'>[organ]:</font></td>\
[advanced ? "<td><font color='#ff3333'>["-"]</font></td>" : ""]\
<td><font color='#cc3333'>["Missing"]</font></td></tr>"
toReport += "<tr>\
<td><font color='#cc3333'>[capitalize(organ.name)]:</font></td>\
[advanced ? "<td><font color='#ff3333'>[organ.damage > 0 ? ceil(organ.damage) : "0"]</font></td>" : ""]\
<td>[status]</td>\
</tr>"
if(appendix)
toReport += "<tr><td colspan=4><span class='alert ml-2'>&rdsh; [appendix]</span></td></tr>"
if(render)
render_list += toReport + "</table>" // tables do not need extra linebreak
if(render)
render_list += "<hr>"
render_list += toReport + "</table></font>" // tables do not need extra linebreak
// Cybernetics
var/list/cyberimps
for(var/obj/item/organ/internal/cyberimp/cyberimp in humantarget.organs)
if(IS_ROBOTIC_ORGAN(cyberimp) && !(cyberimp.organ_flags & ORGAN_HIDDEN))
LAZYADD(cyberimps, cyberimp.examine_title(user))
if(LAZYLEN(cyberimps))
if(!render)
render_list += "<hr>"
render_list += "<span class='notice ml-1'>Detected cybernetic modifications:</span><br>"
render_list += "<span class='notice ml-2'>[english_list(cyberimps, and_text = ", and ")]</span><br>"
render_list += "<hr>"
//Genetic stability
if(advanced && humantarget.has_dna())
if(advanced && humantarget.has_dna() && humantarget.dna.stability != initial(humantarget.dna.stability))
render_list += "<span class='info ml-1'>Genetic Stability: [humantarget.dna.stability]%.</span><br>"
// Hulk and body temperature
@@ -342,51 +360,22 @@
else
render_list += "<span class='info ml-1'>[body_temperature_message]</span><br>"
// Time of death
if(target.station_timestamp_timeofdeath && (target.stat == DEAD || ((HAS_TRAIT(target, TRAIT_FAKEDEATH)) && !advanced)))
render_list += "<span class='info ml-1'>Time of Death: [target.station_timestamp_timeofdeath]</span><br>"
var/tdelta = round(world.time - target.timeofdeath)
render_list += "<span class='alert ml-1'><b>Subject died [DisplayTimeText(tdelta)] ago.</b></span><br>"
// Wounds
if(iscarbon(target))
var/mob/living/carbon/carbontarget = target
var/list/wounded_parts = carbontarget.get_wounded_bodyparts()
for(var/i in wounded_parts)
var/obj/item/bodypart/wounded_part = i
render_list += "<span class='alert ml-1'><b>Physical trauma[LAZYLEN(wounded_part.wounds) > 1 ? "s" : ""] detected in [wounded_part.name]</b>"
for(var/k in wounded_part.wounds)
var/datum/wound/W = k
render_list += "<div class='ml-2'>[W.name] ([W.severity_text()])<br>Recommended treatment: [W.treat_text]</div>" // less lines than in woundscan() so we don't overload people trying to get basic med info
render_list += "</span>"
//Diseases
for(var/datum/disease/disease as anything in target.diseases)
if(!(disease.visibility_flags & HIDDEN_SCANNER))
render_list += "<span class='alert ml-1'><b>Warning: [disease.form] detected</b><br>\
<div class='ml-2'>Name: [disease.name].<br>Type: [disease.spread_text].<br>Stage: [disease.stage]/[disease.max_stages].<br>Possible Cure: [disease.cure_text]</div>\
</span>" // divs do not need extra linebreak
// Blood Level
if(target.has_dna())
var/mob/living/carbon/carbontarget = target
var/blood_id = carbontarget.get_blood_id()
if(blood_id)
if(carbontarget.is_bleeding())
render_list += "<span class='alert ml-1'><b>Subject is bleeding!</b></span><br>"
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 += "<span class='alert ml-1'>Blood level: LOW [blood_percent]%, [carbontarget.blood_volume] cl,</span> [span_info("type: [blood_type]")]<br>"
else if(carbontarget.blood_volume <= BLOOD_VOLUME_OKAY)
render_list += "<span class='alert ml-1'>Blood level: <b>CRITICAL [blood_percent]%</b>, [carbontarget.blood_volume] cl,</span> [span_info("type: [blood_type]")]<br>"
else
render_list += "<span class='info ml-1'>Blood level: [blood_percent]%, [carbontarget.blood_volume] cl, type: [blood_type]</span><br>"
var/mob/living/carbon/carbontarget = target
var/blood_id = carbontarget.get_blood_id()
if(blood_id)
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/real_reagent = GLOB.chemical_reagents_list[blood_id]
blood_type = real_reagent?.name || blood_id
if(carbontarget.blood_volume <= BLOOD_VOLUME_SAFE && carbontarget.blood_volume > BLOOD_VOLUME_OKAY)
render_list += "<span class='alert ml-1'>Blood level: LOW [blood_percent]%, [carbontarget.blood_volume] cl,</span> [span_info("type: [blood_type]")]<br>"
else if(carbontarget.blood_volume <= BLOOD_VOLUME_OKAY)
render_list += "<span class='alert ml-1'>Blood level: <b>CRITICAL [blood_percent]%</b>, [carbontarget.blood_volume] cl,</span> [span_info("type: [blood_type]")]<br>"
else
render_list += "<span class='info ml-1'>Blood level: [blood_percent]%, [carbontarget.blood_volume] cl, type: [blood_type]</span><br>"
// Blood Alcohol Content
var/blood_alcohol_content = target.get_blood_alcohol_content()
if(blood_alcohol_content > 0)
if(blood_alcohol_content >= 0.24)
@@ -394,22 +383,33 @@
else
render_list += "<span class='info ml-1'>Blood alcohol content: [blood_alcohol_content]%</span><br>"
// Cybernetics
if(iscarbon(target))
var/mob/living/carbon/carbontarget = target
var/cyberimp_detect
for(var/obj/item/organ/internal/cyberimp/cyberimp in carbontarget.organs)
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 += "<span class='notice ml-1'>Detected cybernetic modifications:</span><br>"
render_list += "<span class='notice ml-2'>[cyberimp_detect]</span><br>"
// we handled the last <br> so we don't need handholding
//Diseases
var/disease_hr = FALSE
for(var/datum/disease/disease as anything in target.diseases)
if(disease.visibility_flags & HIDDEN_SCANNER)
continue
if(!disease_hr)
render_list += "<hr>"
disease_hr = TRUE
render_list += "<span class='alert ml-1'>\
<b>Warning: [disease.form] detected</b><br>\
<div class='ml-2'>\
Name: [disease.name].<br>\
Type: [disease.spread_text].<br>\
Stage: [disease.stage]/[disease.max_stages].<br>\
Possible Cure: [disease.cure_text]</div>\
</span>"
// Time of death
if(target.station_timestamp_timeofdeath && (target.stat == DEAD || (HAS_TRAIT(target, TRAIT_FAKEDEATH) && !advanced)))
render_list += "<hr>"
render_list += "<span class='info ml-1'>Time of Death: [target.station_timestamp_timeofdeath]</span><br>"
render_list += "<span class='alert ml-1'><b>Subject died [DisplayTimeText(round(world.time - target.timeofdeath))] ago.</b></span><br>"
. = jointext(render_list, "")
if(tochat)
to_chat(user, examine_block(jointext(render_list, "")), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO)
else
return(jointext(render_list, ""))
to_chat(user, examine_block(.), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO)
return .
/obj/item/healthanalyzer/click_ctrl_shift(mob/user)
. = ..()
@@ -426,9 +426,9 @@
/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 = "<center><B>Health scan report. Time of scan: [station_time_timestamp()]</B></center><HR><BR>"
report_paper.color = "#99ccff"
report_paper.name = "health scan report - [station_time_timestamp()]"
var/report_text = "<center><B>Health scan report. Time of retrieval: [station_time_timestamp()]</B></center><HR>"
report_text += last_scan_text
report_paper.add_raw_text(report_text)