Ghosts can see more info on health scan (#96792)

## About The Pull Request

I have no idea how to word this so here's a list instead. 

1. Fixes #96445 by making it so that instead of healthscan code coming
up with cure text on the spot for viruses, advanced diseases have a
function that can generate cure text so you can use it in things other
than healthscanning.
2. Rewords a single letter var in medical kiosk code
3. As a result of 1, the code for disease state analyzers healthscanning
has been shortened because the cure text generating function only has to
be written once and not twice.
4. Health scans now have a power level instead of just being advanced or
basic. There is a new power level called super, and it's only available
to ghosts. Super scans can see all virus symptoms instead of just 3, and
the current stage of an alien embryo.
5. For some reason a bunch of healthscan code (like stuff from the eye
of god and health scanner mod module) were using 1 instead of
SCANMODE_VERBOSE (a define that equals 1 but is more readable) for the
scanmode. That's no longer the case.
6. A new health scanner, the super health scanner, that replaces the
advanced one in the box of debug tools.

<img width="620" height="223" alt="image"
src="https://github.com/user-attachments/assets/a0c5e56e-cf19-4db2-a2df-b72456123c50"
/>
<img width="73" height="65" alt="image"
src="https://github.com/user-attachments/assets/27f8c81b-4f89-455b-82fa-a0ecf94656cf"
/>

## Why It's Good For The Game

Ghosts should be able to see everything, I think

## Changelog

🆑
qol: Ghosts can see alien embryo stage and all virus symptoms when
health scanning
code: Health scanners now support multiple scan levels
fix: Fixes medical kiosks not being able to identify advanced disease
cures.
/🆑

---------

Co-authored-by: Fghj240 <fakeemail@notrealemail.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
Fghj240
2026-07-17 00:07:13 +02:00
committed by GitHub
co-authored by Fghj240 Ghom
parent 34568792c5
commit bf98195fda
23 changed files with 87 additions and 65 deletions
@@ -44,7 +44,7 @@
user.visible_message(span_notice("[user] scans [scanned]'s cadaver."))
to_chat(user, span_deadsay("[icon2html(src, user)] ANALYZING CADAVER."))
healthscan(user, scanned, advanced = TRUE)
healthscan(user, scanned, scanpower = SCANPOWER_ADVANCED)
add_fingerprint(user)
@@ -147,8 +147,8 @@
<td>-</td>\
<td><u>Missing</u></td></tr>"
continue
var/status = organ.get_status_text(advanced = TRUE, add_tooltips = FALSE, colored = FALSE)
var/appendix = organ.get_status_appendix(advanced = TRUE, add_tooltips = FALSE)
var/status = organ.get_status_text(scanpower = SCANPOWER_ADVANCED, add_tooltips = FALSE, colored = FALSE)
var/appendix = organ.get_status_appendix(scanpower = SCANPOWER_ADVANCED, add_tooltips = FALSE)
if(!status)
status ||= "OK" // otherwise flawless organs have no status reported by default
organreport += "<tr>\
@@ -29,8 +29,8 @@
var/mode = SCANNER_VERBOSE
/// HEALTH/WOUND
var/scanmode = SCANMODE_HEALTH
/// Advanced health analyzer
var/advanced = FALSE
/// Health analyzing power
var/scanpower = SCANPOWER_BASIC
/// If this analyzer will give a bonus to wound treatments apon woundscan.
var/give_wound_treatment_bonus = FALSE
var/last_scan_text
@@ -90,7 +90,7 @@
last_scan_text = floor_text
return
if(ispodperson(M) && !advanced)
if(ispodperson(M) && !scanpower <= SCANPOWER_ADVANCED)
to_chat(user, span_info("[M]'s biological structure is too complex for the health analyzer."))
return
@@ -101,7 +101,7 @@
var/readability_check = user.can_read(src) && !user.is_blind()
switch (scanmode)
if (SCANMODE_HEALTH)
last_scan_text = healthscan(user, M, mode, advanced, tochat = readability_check)
last_scan_text = healthscan(user, M, mode, scanpower, tochat = readability_check)
if((M.health / M.maxHealth) > CLEAN_BILL_OF_HEALTH_RATIO)
last_healthy_scanned = WEAKREF(M)
else
@@ -148,7 +148,7 @@
* advanced - Whether it will give more advanced details, such as husk source.
* tochat - Whether to immediately post the result into the chat of the user, otherwise it will return the results.
*/
/proc/healthscan(mob/user, mob/living/target, mode = SCANNER_VERBOSE, advanced = FALSE, tochat = TRUE)
/proc/healthscan(mob/user, mob/living/target, mode = SCANNER_VERBOSE, scanpower = SCANPOWER_BASIC, tochat = TRUE)
if(user.incapacitated)
return
@@ -170,14 +170,14 @@
render_list += "[span_info("Analyzing results for <b>[target]</b> ([round_timestamp()]):")]<br><span class='info ml-1'>Overall status: [mob_status]</span><br>"
if(!advanced && target.has_reagent(/datum/reagent/inverse/technetium))
advanced = TRUE
if(!scanpower == SCANPOWER_BASIC && target.has_reagent(/datum/reagent/inverse/technetium))
scanpower = SCANPOWER_ADVANCED
SEND_SIGNAL(target, COMSIG_LIVING_HEALTHSCAN, render_list, advanced, user, mode, tochat)
SEND_SIGNAL(target, COMSIG_LIVING_HEALTHSCAN, render_list, scanpower, user, mode, tochat)
// Husk detection
if(HAS_TRAIT(target, TRAIT_HUSK))
if(advanced)
if(scanpower >= SCANPOWER_ADVANCED)
if(HAS_TRAIT_FROM(target, TRAIT_HUSK, CHANGELING_DRAIN))
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 if(HAS_TRAIT_FROM(target, TRAIT_HUSK, SKELETON_TRAIT))
@@ -191,7 +191,7 @@
render_list += "<span class='alert ml-1'>Subject has been husked.</span><br>"
if(target.get_stamina_loss())
if(advanced)
if(scanpower >= SCANPOWER_ADVANCED)
render_list += "<span class='alert ml-1'>Fatigue level: [target.get_stamina_loss()]%.</span><br>"
else
render_list += "<span class='alert ml-1'>Subject appears to be suffering from fatigue.</span><br>"
@@ -212,7 +212,7 @@
var/mob/living/carbon/carbontarget = target
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)
if(scanpower >= SCANPOWER_ADVANCED)
render_list += "<span class='info ml-1'>Subject Minor Disabilities: [carbontarget.get_quirk_string(FALSE, CAT_QUIRK_MINOR_DISABILITY, TRUE)].</span><br>"
// Body part damage report
@@ -294,7 +294,7 @@
<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>" : ""]\
[scanpower >= SCANPOWER_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>"
@@ -306,19 +306,19 @@
if(missing_organs[sorted_slot])
render = TRUE
toReport += "<tr><td><font color='#cc3333'>[missing_organs[sorted_slot]]:</font></td>\
[advanced ? "<td><font color='#ff3333'>-</font></td>" : ""]\
[scanpower >= SCANPOWER_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)
var/status = organ.get_status_text(scanpower, tochat)
var/appendix = organ.get_status_appendix(scanpower, tochat)
if(status || appendix)
status ||= "<font color='#ffcc33'>OK</font>" // otherwise flawless organs have no status reported by default
render = TRUE
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>" : ""]\
[scanpower >= SCANPOWER_ADVANCED ? "<td><font color='#ff3333'>[organ.damage > 0 ? ceil(organ.damage) : "0"]</font></td>" : ""]\
<td>[status]</td>\
</tr>"
if(appendix)
@@ -345,7 +345,7 @@
render_list += "<hr>"
//Genetic stability
if(advanced && humantarget.has_dna() && humantarget.dna.stability != initial(humantarget.dna.stability))
if(scanpower >= SCANPOWER_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>"
//body temperature
@@ -446,17 +446,13 @@
var/cure_text
if(istype(disease, /datum/disease/advance))
var/datum/disease/advance/advanced_disease = disease
var/remedies = list()
var/remedy_limit = advanced ? 3 : 2
for(var/datum/symptom/each_symptom as anything in advanced_disease.symptoms)
if(!each_symptom.symptom_cure)
continue
var/datum/reagent/each_cure = each_symptom.symptom_cure
if(!each_symptom.neutered && !(each_cure::name in remedies))
remedies += each_cure::name
if(length(remedies) >= remedy_limit)
break
cure_text = english_list(remedies, nothing_text = "Nothing")
var/cure_count = 2
switch(scanpower)
if(SCANPOWER_ADVANCED)
cure_count = 3
if(SCANPOWER_SUPER)
cure_count = INFINITY
cure_text = advanced_disease.generate_cure_text(cure_count)
else
cure_text = disease.cure_text
render_list += "<span class='alert ml-1'>\
@@ -624,8 +620,14 @@
name = "advanced health analyzer"
icon_state = "health_adv"
desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
advanced = TRUE
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.25, /datum/material/silver = SHEET_MATERIAL_AMOUNT, /datum/material/gold = SHEET_MATERIAL_AMOUNT * 0.75)
scanpower = SCANPOWER_ADVANCED
/obj/item/healthanalyzer/super
name = "super health analyzer"
icon_state = "health_super"
desc = "A health scanner for debuggers. Functions the same as ghost healthscans."
scanpower = SCANPOWER_SUPER
#define AID_EMOTION_NEUTRAL "neutral"
#define AID_EMOTION_HAPPY "happy"
@@ -813,11 +815,7 @@
var/disease_cure = disease.cure_text
if(istype(disease, /datum/disease/advance))
var/datum/disease/advance/advanced_disease = disease
for(var/datum/symptom/each_symptom as anything in advanced_disease.symptoms)
if(!each_symptom.neutered && each_symptom.symptom_cure)
var/datum/reagent/each_cure = each_symptom.symptom_cure
disease_cure = each_cure::name
break // We only get one
disease_cure = advanced_disease.generate_cure_text(1)
render += "<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]</div>\
</span>"
@@ -116,7 +116,7 @@
span_notice("You analyze [scanned_mob]'s vitals.")
)
healthscan(user, scanned_mob, advanced = TRUE)
healthscan(user, scanned_mob, scanpower = SCANPOWER_ADVANCED)
add_fingerprint(user)
/*
@@ -30,7 +30,7 @@
/obj/item/disk/tech_disk/debug=1,
/obj/item/flashlight/emp/debug=1,
/obj/item/geiger_counter=1,
/obj/item/healthanalyzer/advanced=1,
/obj/item/healthanalyzer/super=1,
/obj/item/modular_computer/pda/heads/captain=1,
/obj/item/pipe_dispenser=1,
/obj/item/stack/spacecash/c1000=50,