mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 22:19:30 +01:00
Health Analyzer Rework (medial mains inquire within) (#86666)
This commit is contained in:
@@ -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'>↳ 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'>↳ 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'>↳ 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'>↳ [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)
|
||||
|
||||
Reference in New Issue
Block a user