diff --git a/code/__DEFINES/chat.dm b/code/__DEFINES/chat.dm
index 40f342df268..516fe8c4e19 100644
--- a/code/__DEFINES/chat.dm
+++ b/code/__DEFINES/chat.dm
@@ -51,3 +51,5 @@
#define separator_hr(str) ("
" + str + "
")
/// Emboldens runechat messages
#define RUNECHAT_BOLD(str) "+[str]+"
+/// Helper which creates a chat message which may have a tooltip in some contexts, but not others.
+#define conditional_tooltip(normal_text, tooltip_text, condition) ((condition) ? (span_tooltip(tooltip_text, normal_text)) : (normal_text))
diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm
index feddc24c6f8..237e956ca7f 100644
--- a/code/__DEFINES/surgery.dm
+++ b/code/__DEFINES/surgery.dm
@@ -28,6 +28,8 @@
#define ORGAN_VIRGIN (1<<10)
/// ALWAYS show this when scanned by advanced scanners, even if it is totally healthy
#define ORGAN_PROMINENT (1<<11)
+/// An organ that is ostensibly dangerous when inside a body
+#define ORGAN_HAZARDOUS (1<<12)
/// Helper to figure out if a limb is organic
#define IS_ORGANIC_LIMB(limb) (limb.bodytype & BODYTYPE_ORGANIC)
diff --git a/code/datums/components/irradiated.dm b/code/datums/components/irradiated.dm
index 9562f161fb4..0f70e0d80b7 100644
--- a/code/datums/components/irradiated.dm
+++ b/code/datums/components/irradiated.dm
@@ -51,11 +51,13 @@
/datum/component/irradiated/RegisterWithParent()
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
RegisterSignal(parent, COMSIG_GEIGER_COUNTER_SCAN, PROC_REF(on_geiger_counter_scan))
+ RegisterSignal(parent, COMSIG_LIVING_HEALTHSCAN, PROC_REF(on_healthscan))
/datum/component/irradiated/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_COMPONENT_CLEAN_ACT,
COMSIG_GEIGER_COUNTER_SCAN,
+ COMSIG_LIVING_HEALTHSCAN,
))
/datum/component/irradiated/Destroy(force)
@@ -186,6 +188,12 @@
return COMSIG_GEIGER_COUNTER_SCAN_SUCCESSFUL
+/datum/component/irradiated/proc/on_healthscan(datum/source, list/render_list, advanced, mob/user, mode, tochat)
+ SIGNAL_HANDLER
+
+ render_list += conditional_tooltip("Subject is irradiated.", "Supply antiradiation or antitoxin, such as [/datum/reagent/medicine/potass_iodide::name] or [/datum/reagent/medicine/pen_acid::name].", tochat)
+ render_list += "
"
+
/atom/movable/screen/alert/irradiated
name = "Irradiated"
desc = "You're irradiated! Heal your toxins quick, and stand under a shower to halt the incoming damage."
diff --git a/code/datums/status_effects/debuffs/genetic_damage.dm b/code/datums/status_effects/debuffs/genetic_damage.dm
index 91cfc593fcc..21b6f1db218 100644
--- a/code/datums/status_effects/debuffs/genetic_damage.dm
+++ b/code/datums/status_effects/debuffs/genetic_damage.dm
@@ -46,15 +46,20 @@
qdel(src)
return
-/datum/status_effect/genetic_damage/proc/on_healthscan(datum/source, list/render_list, advanced)
+/datum/status_effect/genetic_damage/proc/on_healthscan(datum/source, list/render_list, advanced, mob/user, mode, tochat)
SIGNAL_HANDLER
+ var/message = ""
if(advanced)
- render_list += "Genetic damage: [round(total_damage / minimum_before_tox_damage * 100, 0.1)]%\n"
+ message = "Genetic damage: [round(total_damage / minimum_before_tox_damage * 100, 0.1)]%"
else if(total_damage >= minimum_before_tox_damage)
- render_list += "Severe genetic damage detected.\n"
+ message = "Severe genetic damage detected."
else
- render_list += "Minor genetic damage detected.\n"
+ message = "Minor genetic damage detected."
+
+ if(message)
+ render_list += conditional_tooltip("[message]", "Irreparable under normal circumstances - will decay over time.", tochat)
+ render_list += "
"
#undef GORILLA_MUTATION_CHANCE_PER_SECOND
#undef GORILLA_MUTATION_MINIMUM_DAMAGE
diff --git a/code/datums/status_effects/debuffs/hallucination.dm b/code/datums/status_effects/debuffs/hallucination.dm
index 5d67acc789e..0d8875c6b23 100644
--- a/code/datums/status_effects/debuffs/hallucination.dm
+++ b/code/datums/status_effects/debuffs/hallucination.dm
@@ -38,13 +38,13 @@
))
/// Signal proc for [COMSIG_LIVING_HEALTHSCAN]. Show we're hallucinating to (advanced) scanners.
-/datum/status_effect/hallucination/proc/on_health_scan(datum/source, list/render_list, advanced, mob/user, mode)
+/datum/status_effect/hallucination/proc/on_health_scan(datum/source, list/render_list, advanced, mob/user, mode, tochat)
SIGNAL_HANDLER
if(!advanced)
return
-
- render_list += "Subject is hallucinating.\n"
+ render_list += conditional_tooltip("Subject is hallucinating.", "Supply antipsychotic medication.", tochat)
+ render_list += "
"
/// Signal proc for [COMSIG_CARBON_CHECKING_BODYPART],
/// checking bodyparts while hallucinating can cause them to appear more damaged than they are
diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm
index fe6c83d8169..5e5258c86de 100644
--- a/code/datums/wounds/_wounds.dm
+++ b/code/datums/wounds/_wounds.dm
@@ -23,6 +23,8 @@
var/desc = ""
/// The basic treatment suggested by health analyzers
var/treat_text = ""
+ /// Even more basic treatment
+ var/treat_text_short = ""
/// What the limb looks like on a cursory examine
var/examine_desc = "is badly hurt"
@@ -643,22 +645,42 @@
return span_bold("[desc]!")
return "[desc]."
+/**
+ * Prints the details about the wound for the wound scanner on simple mode
+ */
/datum/wound/proc/get_scanner_description(mob/user)
- return "Type: [name]\nSeverity: [severity_text(simple = FALSE)]\nDescription: [desc]\nRecommended Treatment: [treat_text]"
+ return "Type: [name]
\
+ Severity: [severity_text()]
\
+ Description: [desc]
\
+ Recommended Treatment: [treat_text]"
+/**
+ * Prints the details about the wound for the wound scanner on complex mode
+ */
/datum/wound/proc/get_simple_scanner_description(mob/user)
- return "[name] detected!\nRisk: [severity_text(simple = TRUE)]\nDescription: [simple_desc ? simple_desc : desc]\nTreatment Guide: [simple_treat_text]\nHomemade Remedies: [homemade_treat_text]"
+ var/severity_text_formatted = severity_text()
+ for(var/i in 1 to severity)
+ severity_text_formatted += "!"
-/datum/wound/proc/severity_text(simple = FALSE)
+ return "[name] detected!
\
+ Risk: [severity_text_formatted]
\
+ Description: [simple_desc || desc]
\
+ Treatment Guide: [simple_treat_text]
\
+ Homemade Remedies: [homemade_treat_text]"
+
+/**
+ * Returns what text describes this wound
+ */
+/datum/wound/proc/severity_text()
switch(severity)
if(WOUND_SEVERITY_TRIVIAL)
return "Trivial"
if(WOUND_SEVERITY_MODERATE)
- return "Moderate" + (simple ? "!" : "")
+ return "Moderate"
if(WOUND_SEVERITY_SEVERE)
- return "Severe" + (simple ? "!!" : "")
+ return "Severe"
if(WOUND_SEVERITY_CRITICAL)
- return "Critical" + (simple ? "!!!" : "")
+ return "Critical"
/// Returns TRUE if our limb is the head or chest, FALSE otherwise.
/// Essential in the sense of "we cannot live without it".
diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm
index 45635f5a70a..667684c0f9f 100644
--- a/code/datums/wounds/bones.dm
+++ b/code/datums/wounds/bones.dm
@@ -199,7 +199,9 @@
/datum/wound/blunt/bone/moderate
name = "Joint Dislocation"
desc = "Patient's limb has been unset from socket, causing pain and reduced motor function."
- treat_text = "Recommended application of bonesetter to affected limb, though manual relocation by applying an aggressive grab to the patient and helpfully interacting with afflicted limb may suffice."
+ treat_text = "Apply Bonesetter to the affected limb. \
+ Manual relocation by via an aggressive grab and a tight hug to the affected limb may also suffice."
+ treat_text_short = "Apply Bonesetter, or manually relocate the limb."
examine_desc = "is awkwardly janked out of place"
occur_text = "janks violently and becomes unseated"
severity = WOUND_SEVERITY_MODERATE
@@ -334,7 +336,9 @@
/datum/wound/blunt/bone/severe
name = "Hairline Fracture"
desc = "Patient's bone has suffered a crack in the foundation, causing serious pain and reduced limb functionality."
- treat_text = "Recommended light surgical application of bone gel, though a sling of medical gauze will prevent worsening situation."
+ treat_text = "Repair surgically. In the event of an emergency, an application of bone gel over the affected area will fix over time. \
+ A splint or sling of medical gauze can also be used to prevent the fracture from worsening."
+ treat_text_short = "Repair surgically, or apply bone gel. A splint or gauze sling can also be used."
examine_desc = "appears grotesquely swollen, jagged bumps hinting at chips in the bone"
occur_text = "sprays chips of bone and develops a nasty looking bruise"
@@ -367,8 +371,11 @@
/// Compound Fracture (Critical Blunt)
/datum/wound/blunt/bone/critical
name = "Compound Fracture"
- desc = "Patient's bones have suffered multiple gruesome fractures, causing significant pain and near uselessness of limb."
- treat_text = "Immediate binding of affected limb, followed by surgical intervention ASAP."
+ desc = "Patient's bones have suffered multiple fractures, \
+ couped with a break in the skin, causing significant pain and near uselessness of limb."
+ treat_text = "Immediately bind the affected limb with gauze or a splint. Repair surgically. \
+ In the event of an emergency, bone gel and surgical tape can be applied to the affected area to fix over a long period of time."
+ treat_text_short = "Repair surgically, or apply bone gel and surgical tape. A splint or gauze sling should also be used."
examine_desc = "is thoroughly pulped and cracked, exposing shards of bone to open air"
occur_text = "cracks apart, exposing broken bones to open air"
diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm
index 394486fef9a..a4ef3bd7b7d 100644
--- a/code/datums/wounds/burns.dm
+++ b/code/datums/wounds/burns.dm
@@ -41,7 +41,7 @@
return
. = ..()
- if(strikes_to_lose_limb == 0) // we've already hit sepsis, nothing more to do
+ if(strikes_to_lose_limb <= 0) // we've already hit sepsis, nothing more to do
victim.adjustToxLoss(0.25 * seconds_per_tick)
if(SPT_PROB(0.5, seconds_per_tick))
victim.visible_message(span_danger("The infection on the remnants of [victim]'s [limb.plaintext_zone] shift and bubble nauseatingly!"), span_warning("You can feel the infection on the remnants of your [limb.plaintext_zone] coursing through your veins!"), vision_distance = COMBAT_MESSAGE_RANGE)
@@ -135,6 +135,13 @@
threshold_penalty = 120 // piss easy to destroy
set_disabling(TRUE)
+/datum/wound/burn/flesh/set_disabling(new_value)
+ . = ..()
+ if(new_value && strikes_to_lose_limb <= 0)
+ treat_text_short = "Amputate or augment limb immediately, or place the patient into cryogenics."
+ else
+ treat_text_short = initial(treat_text_short)
+
/datum/wound/burn/flesh/get_wound_description(mob/user)
if(strikes_to_lose_limb <= 0)
return span_deadsay("[victim.p_Their()] [limb.plaintext_zone] has locked up completely and is non-functional.")
@@ -168,9 +175,25 @@
return "[condition.Join()]"
+/datum/wound/burn/flesh/severity_text(simple = FALSE)
+ . = ..()
+ . += " Burn / "
+ switch(infestation)
+ if(-INFINITY to WOUND_INFECTION_MODERATE)
+ . += "No"
+ if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
+ . += "Moderate"
+ if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
+ . += "Severe"
+ if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
+ . += "Critical"
+ if(WOUND_INFECTION_SEPTIC to INFINITY)
+ . += "Total"
+ . += " Infection"
+
/datum/wound/burn/flesh/get_scanner_description(mob/user)
if(strikes_to_lose_limb <= 0) // Unclear if it can go below 0, best to not take the chance
- var/oopsie = "Type: [name]\nSeverity: [severity_text()]"
+ var/oopsie = "Type: [name]
Severity: [severity_text()]"
oopsie += "Infection Level: [span_deadsay("The body part has suffered complete sepsis and must be removed. Amputate or augment limb immediately, or place the patient in a cryotube.")]
"
return oopsie
@@ -249,7 +272,7 @@
// people complained about burns not healing on stasis beds, so in addition to checking if it's cured, they also get the special ability to very slowly heal on stasis beds if they have the healing effects stored
/datum/wound/burn/flesh/on_stasis(seconds_per_tick, times_fired)
. = ..()
- if(strikes_to_lose_limb == 0) // we've already hit sepsis, nothing more to do
+ if(strikes_to_lose_limb <= 0) // we've already hit sepsis, nothing more to do
if(SPT_PROB(0.5, seconds_per_tick))
victim.visible_message(span_danger("The infection on the remnants of [victim]'s [limb.plaintext_zone] shift and bubble nauseatingly!"), span_warning("You can feel the infection on the remnants of your [limb.plaintext_zone] coursing through your veins!"), vision_distance = COMBAT_MESSAGE_RANGE)
return
@@ -280,7 +303,8 @@
/datum/wound/burn/flesh/moderate
name = "Second Degree Burns"
desc = "Patient is suffering considerable burns with mild skin penetration, weakening limb integrity and increased burning sensations."
- treat_text = "Recommended application of topical ointment or regenerative mesh to affected region."
+ treat_text = "Apply topical ointment or regenerative mesh to the wound."
+ treat_text_short = "Apply healing aid such as regenerative mesh."
examine_desc = "is badly burned and breaking out in blisters"
occur_text = "breaks out with violent red burns"
severity = WOUND_SEVERITY_MODERATE
@@ -304,7 +328,11 @@
/datum/wound/burn/flesh/severe
name = "Third Degree Burns"
desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity."
- treat_text = "Recommended immediate disinfection and excision of any infected skin, followed by bandaging and ointment. If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
+ treat_text = "Swiftly apply healing aids such as Synthflesh or regenerative mesh to the wound. \
+ Disinfect the wound and surgically debride any infected skin, and wrap in clean gauze / use ointment to prevent further infection. \
+ If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
+ treat_text_short = "Apply healing aid such as regenerative mesh, Synthflesh, or cryogenics and disinfect / debride. \
+ Clean gauze or ointment will slow infection rate."
examine_desc = "appears seriously charred, with aggressive red splotches"
occur_text = "chars rapidly, exposing ruined tissue and spreading angry red burns"
severity = WOUND_SEVERITY_SEVERE
@@ -330,7 +358,11 @@
/datum/wound/burn/flesh/critical
name = "Catastrophic Burns"
desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity."
- treat_text = "Immediate surgical debriding of any infected skin, followed by potent tissue regeneration formula and bandaging. If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
+ treat_text = "Immediately apply healing aids such as Synthflesh or regenerative mesh to the wound. \
+ Disinfect the wound and surgically debride any infected skin, and wrap in clean gauze / use ointment to prevent further infection. \
+ If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
+ treat_text_short = "Apply healing aid such as regenerative mesh, Synthflesh, or cryogenics and disinfect / debride. \
+ Clean gauze or ointment will slow infection rate."
examine_desc = "is a ruined mess of blanched bone, melted fat, and charred tissue"
occur_text = "vaporizes as flesh, bone, and fat melt together in a horrifying mess"
severity = WOUND_SEVERITY_CRITICAL
diff --git a/code/datums/wounds/cranial_fissure.dm b/code/datums/wounds/cranial_fissure.dm
index 45c8528717c..8feebe8d2b6 100644
--- a/code/datums/wounds/cranial_fissure.dm
+++ b/code/datums/wounds/cranial_fissure.dm
@@ -29,7 +29,8 @@
/datum/wound/cranial_fissure
name = "Cranial Fissure"
desc = "Patient's crown is agape, revealing severe damage to the skull."
- treat_text = "Immediate surgical reconstruction of the skull."
+ treat_text = "Surgical reconstruction of the skull is necessary."
+ treat_text_short = "Surgical reconstruction required."
examine_desc = "is split open"
occur_text = "is split into two separated chunks"
diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm
index a276dbfbad4..2cdc2bab382 100644
--- a/code/datums/wounds/pierce.dm
+++ b/code/datums/wounds/pierce.dm
@@ -192,7 +192,10 @@
/datum/wound/pierce/bleed/moderate
name = "Minor Skin Breakage"
desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area."
- treat_text = "Treat affected site with bandaging or exposure to extreme cold. In dire cases, brief exposure to vacuum may suffice." // space is cold in ss13, so it's like an ice pack!
+ treat_text = "Apply bandaging or suturing to the wound, make use of blood clotting agents, \
+ cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
+ Follow with food and a rest period."
+ treat_text_short = "Apply bandaging or suturing."
examine_desc = "has a small, circular hole, gently bleeding"
occur_text = "spurts out a thin stream of blood"
sound_effect = 'sound/effects/wounds/pierce1.ogg'
@@ -223,7 +226,10 @@
/datum/wound/pierce/bleed/severe
name = "Open Puncture"
desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability."
- treat_text = "Repair punctures in skin by suture or cautery, extreme cold may also work."
+ treat_text = "Swiftly apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \
+ cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
+ Follow with iron supplements and a rest period."
+ treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization."
examine_desc = "is pierced clear through, with bits of tissue obscuring the open hole"
occur_text = "looses a violent spray of blood, revealing a pierced wound"
sound_effect = 'sound/effects/wounds/pierce2.ogg'
@@ -253,7 +259,10 @@
/datum/wound/pierce/bleed/critical
name = "Ruptured Cavity"
desc = "Patient's internal tissue and circulatory system is shredded, causing significant internal bleeding and damage to internal organs."
- treat_text = "Surgical repair of puncture wound, followed by supervised resanguination."
+ treat_text = "Immediately apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \
+ cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
+ Follow with supervised resanguination."
+ treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization."
examine_desc = "is ripped clear through, barely held together by exposed bone"
occur_text = "blasts apart, sending chunks of viscera flying in all directions"
sound_effect = 'sound/effects/wounds/pierce3.ogg'
diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm
index 31c44a8cbe7..fd3cb4bd7b2 100644
--- a/code/datums/wounds/slash.dm
+++ b/code/datums/wounds/slash.dm
@@ -321,7 +321,9 @@
/datum/wound/slash/flesh/moderate
name = "Rough Abrasion"
desc = "Patient's skin has been badly scraped, generating moderate blood loss."
- treat_text = "Application of clean bandages or first-aid grade sutures, followed by food and rest."
+ treat_text = "Apply bandaging or suturing to the wound. \
+ Follow up with food and a rest period."
+ treat_text_short = "Apply bandaging or suturing."
examine_desc = "has an open cut"
occur_text = "is cut open, slowly leaking blood"
sound_effect = 'sound/effects/wounds/blood1.ogg'
@@ -350,7 +352,10 @@
/datum/wound/slash/flesh/severe
name = "Open Laceration"
desc = "Patient's skin is ripped clean open, allowing significant blood loss."
- treat_text = "Speedy application of first-aid grade sutures and clean bandages, followed by vitals monitoring to ensure recovery."
+ treat_text = "Swiftly apply bandaging or suturing to the wound, \
+ or make use of blood clotting agents or cauterization. \
+ Follow up with iron supplements or saline-glucose and a rest period."
+ treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization."
examine_desc = "has a severe cut"
occur_text = "is ripped open, veins spurting blood"
sound_effect = 'sound/effects/wounds/blood2.ogg'
@@ -380,7 +385,10 @@
/datum/wound/slash/flesh/critical
name = "Weeping Avulsion"
desc = "Patient's skin is completely torn open, along with significant loss of tissue. Extreme blood loss will lead to quick death without intervention."
- treat_text = "Immediate bandaging and either suturing or cauterization, followed by supervised resanguination."
+ treat_text = "Immediately apply bandaging or suturing to the wound, \
+ or make use of blood clotting agents or cauterization. \
+ Follow up supervised resanguination."
+ treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization."
examine_desc = "is carved down to the bone, spraying blood wildly"
occur_text = "is torn open, spraying blood wildly"
sound_effect = 'sound/effects/wounds/blood3.ogg'
diff --git a/code/game/objects/items/devices/scanners/autopsy_scanner.dm b/code/game/objects/items/devices/scanners/autopsy_scanner.dm
index c5d33b74226..a054b3c69d2 100644
--- a/code/game/objects/items/devices/scanners/autopsy_scanner.dm
+++ b/code/game/objects/items/devices/scanners/autopsy_scanner.dm
@@ -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]
"
autopsy_information += "Blood Volume: [scanned.blood_volume] cl ([blood_percent]%)
"
@@ -108,10 +108,11 @@
for(var/datum/symptom/symptom as anything in advanced_disease.symptoms)
autopsy_information += "[symptom.name] - [symptom.desc]
"
- 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
diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm
index af0ab50b772..d51a36fcb31 100644
--- a/code/game/objects/items/devices/scanners/health_analyzer.dm
+++ b/code/game/objects/items/devices/scanners/health_analyzer.dm
@@ -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:
\tOverall status: Healthy")]\
-
[span_info("Key: Suffocation/Toxin/Burn/Brute")]\
-
[span_info("\tDamage specifics: 0-0-0-0")]\
-
[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 = "Analyzing results for [scan_turf] ([station_time_timestamp()]):
"
+ floor_text += "Overall status: Unknown
"
+ floor_text += "Subject lacks a brain.
"
+ floor_text += "Body temperature: [scan_turf?.return_air()?.return_temperature() || "???"]
"
+
+ 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("Deceased") : "[round(target.health/target.maxHealth,0.01)*100]% healthy")
+ var/mob_status = (target.stat == DEAD ? span_alert("Deceased") : "[round(target.health / target.maxHealth, 0.01) * 100]% healthy")
if(HAS_TRAIT(target, TRAIT_FAKEDEATH) && !advanced)
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]:")]
Overall status: [mob_status]
"
+ render_list += "[span_info("Analyzing results for [target] ([station_time_timestamp()]):")]
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!
"
- 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 += "Subject has been husked by severe burns.
"
+ render_list += "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)].
"
else if (HAS_TRAIT_FROM(target, TRAIT_HUSK, CHANGELING_DRAIN))
- render_list += "Subject has been husked by dessication.
"
+ render_list += "Subject has been husked by [conditional_tooltip("desiccation", "Irreparable. Under normal circumstances, revival can only proceed via brain transplant.", tochat)].
"
else
render_list += "Subject has been husked by mysterious causes.
"
@@ -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 += "Cerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].
"
- if(carbontarget.quirks.len)
+ if(LAZYLEN(carbontarget.quirks))
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)].
"
- if (HAS_TRAIT(target, TRAIT_IRRADIATED))
- render_list += "Subject is irradiated. Supply toxin healing.
"
-
- //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 += "Subject is genetically deaf.
"
- else if(HAS_TRAIT_FROM(carbontarget, TRAIT_DEAF, EAR_DAMAGE))
- render_list += "Subject is deaf from ear damage.
"
- else if(HAS_TRAIT(carbontarget, TRAIT_DEAF))
- render_list += "Subject is deaf.
"
- else
- if(ears.damage)
- 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.
"
-
- // 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.
"
- else if(carbontarget.is_nearsighted())
- render_list += "Subject is nearsighted.
"
-
// 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 = "General status:\
- \
+ 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 += "
"
+ var/dmgreport = "Body status:\
+ \
+ \
+ \
| Damage: | \
Brute | \
Burn | \
Toxin | \
- Suffocation |
\
- | Overall: | \
- [CEILING(brute_loss,1)] | \
- [CEILING(fire_loss,1)] | \
- [CEILING(tox_loss,1)] | \
- [CEILING(oxy_loss,1)] |
"
+ Suffocation | \
+ \
+ \
+ | Overall: | \
+ [ceil(brute_loss)] | \
+ [ceil(fire_loss)] | \
+ [ceil(tox_loss)] | \
+ [ceil(oxy_loss)] | \
+
"
if(mode == SCANNER_VERBOSE)
- for(var/obj/item/bodypart/limb as anything in damaged)
- if(limb.bodytype & BODYTYPE_ROBOTIC)
- dmgreport += "| [capitalize(limb.name)]: | "
- else
- dmgreport += "
| [capitalize(limb.plaintext_zone)]: | "
- dmgreport += "[(limb.brute_dam > 0) ? "[CEILING(limb.brute_dam,1)]" : "0"] | "
- dmgreport += "[(limb.burn_dam > 0) ? "[CEILING(limb.burn_dam,1)]" : "0"] |
"
- dmgreport += "
"
+ // 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 += ""
+ dmgreport += "| [capitalize(parse_zone(zone))]: | "
+ dmgreport += "- | "
+ dmgreport += "- | "
+ dmgreport += "
"
+ dmgreport += "| ↳ Physical trauma: [conditional_tooltip("Dismembered", "Reattach or replace surgically.", tochat)] |
"
+ 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 += ""
+ dmgreport += "| [capitalize((limb.bodytype & BODYTYPE_ROBOTIC) ? limb.name : limb.plaintext_zone)]: | "
+ dmgreport += "[limb.brute_dam > 0 ? ceil(limb.brute_dam) : "0"] | "
+ dmgreport += "[limb.burn_dam > 0 ? ceil(limb.burn_dam) : "0"] | "
+ if(zone == BODY_ZONE_CHEST) // tox/oxy is stored in the chest
+ dmgreport += "[tox_loss > 0 ? ceil(tox_loss) : "0"] | "
+ dmgreport += "[oxy_loss > 0 ? ceil(oxy_loss) : "0"] | "
+ dmgreport += "
"
+ 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 += "| ↳ Foreign object(s): [conditional_tooltip(displayed, "Use a hemostat to remove.", tochat)] |
"
+ if(has_any_wounds)
+ for(var/datum/wound/wound as anything in limb.wounds)
+ dmgreport += "| ↳ Physical trauma: [conditional_tooltip("[wound.name] ([wound.severity_text()])", wound.treat_text_short, tochat)] |
"
+
+ dmgreport += "
"
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]
"
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 = "Organs:\
- \
- | Organ: | \
- [advanced ? "Dmg | " : ""]\
- Status | "
+ var/render = FALSE
+ var/toReport = "Organ status:\
+ \
+ \
+ \
+ | Organ: | \
+ [advanced ? "Dmg | " : ""]\
+ Status | \
+
"
- 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 += "| [organ.name]: | \
- [advanced ? "[CEILING(organ.damage,1)] | " : ""]\
- [status] |
"
-
- 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 += "| [missing_organs[sorted_slot]]: | \
+ [advanced ? "- | " : ""]\
+ Missing |
"
+ 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 ||= "OK" // otherwise flawless organs have no status reported by default
render = TRUE
- for(var/organ in missing_organs)
- toReport += "| [organ]: | \
- [advanced ? "["-"] | " : ""]\
- ["Missing"] |
"
+ toReport += "\
+ | [capitalize(organ.name)]: | \
+ [advanced ? "[organ.damage > 0 ? ceil(organ.damage) : "0"] | " : ""]\
+ [status] | \
+
"
+ if(appendix)
+ toReport += "| ↳ [appendix] |
"
- if(render)
- render_list += toReport + "
" // tables do not need extra linebreak
+ if(render)
+ render_list += "
"
+ render_list += toReport + "
" // 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 += "
"
+ render_list += "Detected cybernetic modifications:
"
+ render_list += "[english_list(cyberimps, and_text = ", and ")]
"
+
+ render_list += "
"
//Genetic stability
- if(advanced && humantarget.has_dna())
+ if(advanced && humantarget.has_dna() && humantarget.dna.stability != initial(humantarget.dna.stability))
render_list += "Genetic Stability: [humantarget.dna.stability]%.
"
// Hulk and body temperature
@@ -342,51 +360,22 @@
else
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]
"
- var/tdelta = round(world.time - target.timeofdeath)
- render_list += "Subject died [DisplayTimeText(tdelta)] ago.
"
-
- // 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 += "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()])
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
\
- 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
- 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 += "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]")]
"
- else if(carbontarget.blood_volume <= BLOOD_VOLUME_OKAY)
- 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]
"
+ 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 += "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]")]
"
+ else
+ 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)
@@ -394,22 +383,33 @@
else
render_list += "Blood alcohol content: [blood_alcohol_content]%
"
- // 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 += "Detected cybernetic modifications:
"
- render_list += "[cyberimp_detect]
"
- // we handled the last
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 += "
"
+ disease_hr = TRUE
+ render_list += "\
+ Warning: [disease.form] detected
\
+ \
+ Name: [disease.name].
\
+ Type: [disease.spread_text].
\
+ Stage: [disease.stage]/[disease.max_stages].
\
+ Possible Cure: [disease.cure_text]
\
+ "
+ // Time of death
+ if(target.station_timestamp_timeofdeath && (target.stat == DEAD || (HAS_TRAIT(target, TRAIT_FAKEDEATH) && !advanced)))
+ render_list += "
"
+ render_list += "Time of Death: [target.station_timestamp_timeofdeath]
"
+ render_list += "Subject died [DisplayTimeText(round(world.time - target.timeofdeath))] ago.
"
+
+ . = 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 = "Health scan report. Time of scan: [station_time_timestamp()]
"
+ report_paper.color = "#99ccff"
+ report_paper.name = "health scan report - [station_time_timestamp()]"
+ var/report_text = "Health scan report. Time of retrieval: [station_time_timestamp()]
"
report_text += last_scan_text
report_paper.add_raw_text(report_text)
diff --git a/code/modules/antagonists/heretic/items/corrupted_organs.dm b/code/modules/antagonists/heretic/items/corrupted_organs.dm
index 3bd3ead7f60..335279c9553 100644
--- a/code/modules/antagonists/heretic/items/corrupted_organs.dm
+++ b/code/modules/antagonists/heretic/items/corrupted_organs.dm
@@ -2,7 +2,7 @@
/obj/item/organ/internal/eyes/corrupt
name = "corrupt orbs"
desc = "These eyes have seen something they shouldn't have."
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/// The override images we are applying
var/list/hallucinations
@@ -40,7 +40,7 @@
/obj/item/organ/internal/tongue/corrupt
name = "corrupt tongue"
desc = "This one tells only lies."
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/obj/item/organ/internal/tongue/corrupt/Initialize(mapload)
. = ..()
@@ -67,7 +67,7 @@
/obj/item/organ/internal/liver/corrupt
name = "corrupt liver"
desc = "After what you've seen you could really go for a drink."
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/// How much extra ingredients to add?
var/amount_added = 5
/// What extra ingredients can we add?
@@ -111,7 +111,7 @@
/obj/item/organ/internal/stomach/corrupt
name = "corrupt stomach"
desc = "This parasite demands an unwholesome diet in order to be satisfied."
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/// Do we have an unholy thirst?
var/thirst_satiated = FALSE
/// Timer for when we get thirsty again
@@ -177,7 +177,7 @@
/obj/item/organ/internal/heart/corrupt
name = "corrupt heart"
desc = "What corruption is this spreading along with the blood?"
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/// How long until the next heart?
COOLDOWN_DECLARE(hand_cooldown)
@@ -197,7 +197,7 @@
/obj/item/organ/internal/lungs/corrupt
name = "corrupt lungs"
desc = "Some things SHOULD be drowned in tar."
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/// How likely are we not to cough every time we take a breath?
var/cough_chance = 15
/// How much gas to emit?
@@ -232,7 +232,7 @@
/obj/item/organ/internal/appendix/corrupt
name = "corrupt appendix"
desc = "What kind of dark, cosmic force is even going to bother to corrupt an appendix?"
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
/// How likely are we to spawn worms?
var/worm_chance = 2
diff --git a/code/modules/language/_language_holder.dm b/code/modules/language/_language_holder.dm
index a368186a513..b48a1ab1530 100644
--- a/code/modules/language/_language_holder.dm
+++ b/code/modules/language/_language_holder.dm
@@ -510,13 +510,9 @@ GLOBAL_LIST_INIT(prototype_language_holders, init_language_holder_prototypes())
// Explicitly empty one for readability
/datum/language_holder/empty
- understood_languages = null
- spoken_languages = null
// Has all the languages known (via "mind")
/datum/language_holder/universal
- understood_languages = null
- spoken_languages = null
/datum/language_holder/universal/New()
. = ..()
diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm
index 1885d44ce4d..d4503230e48 100644
--- a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm
+++ b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm
@@ -7,7 +7,7 @@
icon_state = "legion_remains"
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_PARASITE_EGG
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT
+ organ_flags = parent_type::organ_flags | ORGAN_HAZARDOUS
decay_factor = STANDARD_ORGAN_DECAY * 3 // About 5 minutes outside of a host
/// What stage of growth the corruption has reached.
var/stage = 0
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 46419d70e6d..ced02095e41 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -8,7 +8,7 @@
layer = ABOVE_MOB_LAYER
zone = BODY_ZONE_HEAD
slot = ORGAN_SLOT_BRAIN
- organ_flags = ORGAN_ORGANIC | ORGAN_VITAL
+ organ_flags = ORGAN_ORGANIC | ORGAN_VITAL | ORGAN_PROMINENT
attack_verb_continuous = list("attacks", "slaps", "whacks")
attack_verb_simple = list("attack", "slap", "whack")
@@ -258,6 +258,26 @@
else
return span_info("This one is completely devoid of life.")
+/obj/item/organ/internal/brain/get_status_appendix(advanced, add_tooltips)
+ var/list/trauma_text
+ for(var/datum/brain_trauma/trauma as anything in traumas)
+ var/trauma_desc = ""
+ switch(trauma.resilience)
+ if(TRAUMA_RESILIENCE_BASIC)
+ trauma_desc = conditional_tooltip("Mild ", "Repair via brain surgery or medication such as [/datum/reagent/medicine/neurine::name].", add_tooltips)
+ if(TRAUMA_RESILIENCE_SURGERY)
+ trauma_desc = conditional_tooltip("Severe ", "Repair via brain surgery.", add_tooltips)
+ if(TRAUMA_RESILIENCE_LOBOTOMY)
+ trauma_desc = conditional_tooltip("Deep-rooted ", "Repair via Lobotomy.", add_tooltips)
+ if(TRAUMA_RESILIENCE_WOUND)
+ trauma_desc = conditional_tooltip("Fracture-derived ", "Repair via treatment of wounds afflicting the head.", add_tooltips)
+ if(TRAUMA_RESILIENCE_MAGIC, TRAUMA_RESILIENCE_ABSOLUTE)
+ trauma_desc = conditional_tooltip("Permanent ", "Irreparable under normal circumstances.", add_tooltips)
+ trauma_desc += capitalize(trauma.scan_desc)
+ LAZYADD(trauma_text, trauma_desc)
+ if(LAZYLEN(trauma_text))
+ return "Mental trauma: [english_list(trauma_text, and_text = ", and ")]."
+
/obj/item/organ/internal/brain/attack(mob/living/carbon/C, mob/user)
if(!istype(C))
return ..()
diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm
index 4d28b987abc..3e67b5c4379 100644
--- a/code/modules/surgery/organs/_organ.dm
+++ b/code/modules/surgery/organs/_organ.dm
@@ -320,27 +320,40 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
replacement.set_organ_damage(damage)
/// Called by medical scanners to get a simple summary of how healthy the organ is. Returns an empty string if things are fine.
-/obj/item/organ/proc/get_status_text(advanced)
- if(advanced && (organ_flags & ORGAN_PROMINENT))
- return "Harmful Foreign Body"
+/obj/item/organ/proc/get_status_text(advanced, add_tooltips)
+ if(advanced && (organ_flags & ORGAN_HAZARDOUS))
+ return conditional_tooltip("Harmful Foreign Body", "Remove surgically.", add_tooltips)
if(organ_flags & ORGAN_EMP)
- return "EMP-Derived Failure Cascade in Progress"
+ return conditional_tooltip("EMP-Derived Failure", "Repair or replace surgically.", add_tooltips)
+ var/tech_text = ""
if(owner.has_reagent(/datum/reagent/inverse/technetium))
- return "[round((damage/maxHealth)*100, 1)]% damaged."
+ tech_text = "[round((damage / maxHealth) * 100, 1)]% damaged"
if(organ_flags & ORGAN_FAILING)
- return "Non-Functional"
+ return conditional_tooltip("[tech_text || "Non-Functional"]", "Repair or replace surgically.", add_tooltips)
if(damage > high_threshold)
- return "Severely Damaged"
+ return conditional_tooltip("[tech_text || "Severely Damaged"]", "[healing_factor ? "Treat with rest or use specialty medication." : "Repair surgically or use specialty medication."]", add_tooltips && owner.stat != DEAD)
- if (damage > low_threshold)
- return "Mildly Damaged"
+ if(damage > low_threshold)
+ return conditional_tooltip("[tech_text || "Mildly Damaged"] ", "[healing_factor ? "Treat with rest." : "Use specialty medication."]", add_tooltips && owner.stat != DEAD)
+
+ if(tech_text)
+ return "[tech_text]"
return ""
+/// Determines if this organ is shown when a user has condensed scans enabled
+/obj/item/organ/proc/show_on_condensed_scans()
+ // We don't need to show *most* damaged organs as they have no effects associated
+ return (organ_flags & (ORGAN_PROMINENT|ORGAN_HAZARDOUS|ORGAN_FAILING|ORGAN_VITAL))
+
+/// Similar to get_status_text, but appends the text after the damage report, for additional status info
+/obj/item/organ/proc/get_status_appendix(advanced, add_tooltips)
+ return
+
/// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target
/obj/item/organ/proc/replace_into(mob/living/carbon/new_owner)
return Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED)
diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm
index 169495bccaa..43630732295 100644
--- a/code/modules/surgery/organs/internal/appendix/_appendix.dm
+++ b/code/modules/surgery/organs/internal/appendix/_appendix.dm
@@ -87,11 +87,10 @@
ADD_TRAIT(organ_owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type)
organ_owner.med_hud_set_status()
-/obj/item/organ/internal/appendix/get_status_text(advanced)
- if((!(organ_flags & ORGAN_FAILING)) && inflamation_stage)
- return "Inflamed"
- else
- return ..()
+/obj/item/organ/internal/appendix/get_status_text(advanced, add_tooltips)
+ if(!(organ_flags & ORGAN_FAILING) && inflamation_stage)
+ return conditional_tooltip("Inflamed", "Remove surgically.", add_tooltips)
+ return ..()
#undef APPENDICITIS_PROB
#undef INFLAMATION_ADVANCEMENT_PROB
diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm
index 83e41b44fa3..e45bb7c4f4a 100644
--- a/code/modules/surgery/organs/internal/ears/_ears.dm
+++ b/code/modules/surgery/organs/internal/ears/_ears.dm
@@ -57,6 +57,22 @@
UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE)
+/obj/item/organ/internal/ears/get_status_appendix(advanced, add_tooltips)
+ if(owner.stat == DEAD || !HAS_TRAIT(owner, TRAIT_DEAF))
+ return
+ if(advanced)
+ if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, QUIRK_TRAIT))
+ return conditional_tooltip("Subject is permanently deaf.", "Irreparable under normal circumstances.", add_tooltips)
+ if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, GENETIC_MUTATION))
+ return conditional_tooltip("Subject is genetically deaf.", "Use medication such as [/datum/reagent/medicine/mutadone::name].", add_tooltips)
+ if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
+ return conditional_tooltip("Subject is [(organ_flags & ORGAN_FAILING) ? "permanently": "temporarily"] deaf from ear damage.", "Repair surgically, use medication such as [/datum/reagent/medicine/inacusiate::name], or protect ears with earmuffs.", add_tooltips)
+ return "Subject is deaf."
+
+/obj/item/organ/internal/ears/show_on_condensed_scans()
+ // Always show if we have an appendix
+ return ..() || (owner.stat != DEAD && HAS_TRAIT(owner, TRAIT_DEAF))
+
/**
* Snowflake proc to handle temporary deafness
*
diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm
index 9a2174a939f..69d5abf1978 100644
--- a/code/modules/surgery/organs/internal/eyes/_eyes.dm
+++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm
@@ -121,6 +121,36 @@
#define OFFSET_X 1
#define OFFSET_Y 2
+/// Similar to get_status_text, but appends the text after the damage report, for additional status info
+/obj/item/organ/internal/eyes/get_status_appendix(advanced, add_tooltips)
+ if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_KNOCKEDOUT))
+ return
+ if(owner.is_blind())
+ if(advanced)
+ if(owner.is_blind_from(QUIRK_TRAIT))
+ return conditional_tooltip("Subject is permanently blind.", "Irreparable under normal circumstances.", add_tooltips)
+ if(owner.is_blind_from(TRAUMA_TRAIT))
+ return conditional_tooltip("Subject is blind from mental trauma.", "Repair via treatment of associated trauma.", add_tooltips)
+ if(owner.is_blind_from(GENETIC_MUTATION))
+ return conditional_tooltip("Subject is genetically blind.", "Use medication such as [/datum/reagent/medicine/mutadone::name].", add_tooltips)
+ if(owner.is_blind_from(EYE_DAMAGE))
+ return conditional_tooltip("Subject is blind from eye damage.", "Repair surgically, use medication such as [/datum/reagent/medicine/oculine::name], or protect eyes with a blindfold.", add_tooltips)
+ return "Subject is blind."
+ if(owner.is_nearsighted())
+ if(advanced)
+ if(owner.is_nearsighted_from(QUIRK_TRAIT))
+ return conditional_tooltip("Subject is permanently nearsighted.", "Irreparable under normal circumstances. Prescription glasses will assuage the effects.", add_tooltips)
+ if(owner.is_nearsighted_from(GENETIC_MUTATION))
+ return conditional_tooltip("Subject is genetically nearsighted.", "Use medication such as [/datum/reagent/medicine/mutadone::name]. Prescription glasses will assuage the effects.", add_tooltips)
+ if(owner.is_nearsighted_from(EYE_DAMAGE))
+ return conditional_tooltip("Subject is nearsighted from eye damage.", "Repair surgically or use medication such as [/datum/reagent/medicine/oculine::name]. Prescription glasses will assuage the effects.", add_tooltips)
+ return "Subject is nearsighted."
+ return ""
+
+/obj/item/organ/internal/eyes/show_on_condensed_scans()
+ // Always show if we have an appendix
+ return ..() || (owner.stat != DEAD && !HAS_TRAIT(owner, TRAIT_KNOCKEDOUT) && (owner.is_blind() || owner.is_nearsighted()))
+
/// This proc generates a list of overlays that the eye should be displayed using for the given parent
/obj/item/organ/internal/eyes/proc/generate_body_overlay(mob/living/carbon/human/parent)
if(!istype(parent) || parent.get_organ_by_type(/obj/item/organ/internal/eyes) != src)
diff --git a/code/modules/surgery/organs/internal/heart/_heart.dm b/code/modules/surgery/organs/internal/heart/_heart.dm
index 34972c1ff21..ce659792529 100644
--- a/code/modules/surgery/organs/internal/heart/_heart.dm
+++ b/code/modules/surgery/organs/internal/heart/_heart.dm
@@ -92,6 +92,15 @@
/obj/item/organ/internal/heart/proc/is_beating()
return beating
+/obj/item/organ/internal/heart/get_status_text(advanced, add_tooltips)
+ if(!beating && !(organ_flags & ORGAN_FAILING) && owner.needs_heart() && owner.stat != DEAD)
+ return conditional_tooltip("Cardiac Arrest", "Apply defibrillation immediately. Similar electric shocks may work in emergencies.", add_tooltips)
+ return ..()
+
+/obj/item/organ/internal/heart/show_on_condensed_scans()
+ // Always show if the guy needs a heart (so its status can be monitored)
+ return ..() || owner.needs_heart()
+
/obj/item/organ/internal/heart/on_life(seconds_per_tick, times_fired)
..()