Files
Paradise/code/game/objects/items/devices/bodyanalyzer.dm
DGamerL a1e27c07da Turns some wounds into datumized versions (#31297)
* Wound datumization

* Rejuv additions

* Fixes

* Adds `get_wound()` proc

* Ruptured lungs get fixed now

* Apply suggestions from code review

Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com>

* Fix this

* Potentially fix an issue, might remove the proc later

* Many fixes

* Fuck

---------

Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
2025-12-26 22:29:05 +00:00

284 lines
10 KiB
Plaintext

/obj/item/bodyanalyzer
name = "handheld body analyzer"
desc = "A handheld scanner capable of deep-scanning an entire body."
icon = 'icons/obj/device.dmi'
icon_state = "bodyanalyzer_0"
worn_icon_state = "healthanalyzer"
inhand_icon_state = "healthanalyzer"
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
throw_speed = 5
throw_range = 10
origin_tech = "magnets=6;biotech=6"
var/obj/item/stock_parts/cell/cell
var/cell_type = /obj/item/stock_parts/cell/high
var/ready = TRUE // Ready to scan
var/printing = FALSE
var/time_to_use = 0 // How much time remaining before next scan is available.
var/usecharge = 750
var/scan_time = 5 SECONDS //how long does it take to scan
var/scan_cd = 30 SECONDS //how long before we can scan again
/obj/item/bodyanalyzer/get_cell()
return cell
/obj/item/bodyanalyzer/advanced
cell_type = /obj/item/stock_parts/cell/super // twice the charge!
/obj/item/bodyanalyzer/borg
name = "cyborg body analyzer"
desc = "Scan an entire body to prepare for field surgery. Consumes power for each scan."
/obj/item/bodyanalyzer/borg/syndicate
scan_cd = 20 SECONDS
/obj/item/bodyanalyzer/New()
..()
cell = new cell_type(src)
cell.give(cell.maxcharge)
update_icon()
/obj/item/bodyanalyzer/proc/setReady()
ready = TRUE
playsound(src, 'sound/machines/defib_saftyon.ogg', 50, 0)
update_icon()
/obj/item/bodyanalyzer/update_icon_state()
if(!cell)
icon_state = "bodyanalyzer_0"
return
if(ready)
icon_state = "bodyanalyzer_1"
else
icon_state = "bodyanalyzer_2"
/obj/item/bodyanalyzer/update_overlays()
. = ..()
var/percent = cell.percent()
var/overlayid = round(percent / 10)
. += "bodyanalyzer_charge[overlayid]"
if(printing)
. += "bodyanalyzer_printing"
/obj/item/bodyanalyzer/attack__legacy__attackchain(mob/living/M, mob/living/carbon/human/user)
if(user.incapacitated() || !user.Adjacent(M))
return
if(!ready)
to_chat(user, SPAN_NOTICE("The scanner beeps angrily at you! It's currently recharging - [round((time_to_use - world.time) * 0.1)] seconds remaining."))
playsound(user.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
return
if(cell.charge >= usecharge)
mobScan(M, user)
else
to_chat(user, SPAN_NOTICE("The scanner beeps angrily at you! It's out of charge!"))
playsound(user.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
/obj/item/bodyanalyzer/borg/attack__legacy__attackchain(mob/living/M, mob/living/silicon/robot/user)
if(user.incapacitated() || !user.Adjacent(M))
return
if(!ready)
to_chat(user, SPAN_NOTICE("[src] is currently recharging - [round((time_to_use - world.time) * 0.1)] seconds remaining."))
return
if(user.cell.charge >= usecharge)
mobScan(M, user)
else
to_chat(user, SPAN_NOTICE("You need to recharge before you can use [src]"))
/obj/item/bodyanalyzer/proc/mobScan(mob/living/M, mob/user)
if(ishuman(M))
var/report = generate_printing_text(M, user)
user.visible_message("[user] begins scanning [M] with [src].", "You begin scanning [M].")
if(do_after(user, scan_time, target = M))
var/obj/item/paper/printout = new
printout.info = report
printout.name = "Scan report - [M.name]"
playsound(user.loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
user.put_in_hands(printout)
time_to_use = world.time + scan_cd
if(isrobot(user))
var/mob/living/silicon/robot/R = user
R.cell.use(usecharge)
else
cell.use(usecharge)
ready = FALSE
printing = TRUE
update_icon()
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/bodyanalyzer, setReady)), scan_cd)
addtimer(VARSET_CALLBACK(src, printing, FALSE), 1.4 SECONDS)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon), UPDATE_OVERLAYS), 1.5 SECONDS)
else if(iscorgi(M) && M.stat == DEAD)
to_chat(user, SPAN_NOTICE("You wonder if [M.p_they()] was a good dog. <b>[src] tells you they were the best...</b>")) // :'(
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
ready = FALSE
update_icon(UPDATE_ICON_STATE)
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/bodyanalyzer, setReady)), scan_cd)
time_to_use = world.time + scan_cd
else
to_chat(user, SPAN_NOTICE("Scanning error detected. Invalid specimen."))
//Unashamedly ripped from adv_med.dm
/obj/item/bodyanalyzer/proc/generate_printing_text(mob/living/M, mob/user)
var/dat = ""
var/mob/living/carbon/human/target = M
dat = "<font color='blue'><b>Target Statistics:</b></font><br>"
var/t1
switch(target.stat) // obvious, see what their status is
if(CONSCIOUS)
t1 = "Conscious"
if(UNCONSCIOUS)
t1 = "Unconscious"
else
t1 = "*dead*"
dat += "[target.health > 50 ? "<font color='blue'>" : "<font color='red'>"]\tHealth %: [target.health], ([t1])</font><br>"
var/found_disease = FALSE
for(var/thing in target.viruses)
var/datum/disease/D = thing
if(D.visibility_flags) //If any visibility flags are on.
continue
found_disease = TRUE
break
if(found_disease)
dat += "<font color='red'>Disease detected in target.</font><BR>"
var/extra_font = null
extra_font = (target.getBruteLoss() < 60 ? "<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\t-Brute Damage %: [target.getBruteLoss()]</font><br>"
extra_font = (target.getOxyLoss() < 60 ? "<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\t-Respiratory Damage %: [target.getOxyLoss()]</font><br>"
extra_font = (target.getToxLoss() < 60 ? "<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\t-Toxin Content %: [target.getToxLoss()]</font><br>"
extra_font = (target.getFireLoss() < 60 ? "<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\t-Burn Severity %: [target.getFireLoss()]</font><br>"
extra_font = (target.radiation < 10 ?"<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\tRadiation Level %: [target.radiation]</font><br>"
extra_font = (target.getCloneLoss() < 1 ?"<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\tGenetic Tissue Damage %: [target.getCloneLoss()]<br>"
extra_font = (target.getBrainLoss() < 1 ?"<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\tApprox. Brain Damage %: [target.getBrainLoss()]<br>"
dat += "Paralysis Summary %: [target.IsParalyzed()] ([round(target.AmountParalyzed() / 10)] seconds left!)<br>"
dat += "Body Temperature: [target.bodytemperature-T0C]&deg;C ([target.bodytemperature*1.8-459.67]&deg;F)<br>"
dat += "<hr>"
var/blood_percent = round((target.blood_volume / BLOOD_VOLUME_NORMAL))
blood_percent *= 100
extra_font = (target.blood_volume > 448 ? "<font color='blue'>" : "<font color='red'>")
dat += "[extra_font]\tBlood Level %: [blood_percent] ([target.blood_volume] units)</font><br>"
if(target.reagents)
dat += "Epinephrine units: [target.reagents.get_reagent_amount("Epinephrine")] units<BR>"
dat += "Ether: [target.reagents.get_reagent_amount("ether")] units<BR>"
extra_font = (target.reagents.get_reagent_amount("silver_sulfadiazine") < 30 ? "<font color='black'>" : "<font color='red'>")
dat += "[extra_font]\tSilver Sulfadiazine: [target.reagents.get_reagent_amount("silver_sulfadiazine")]</font><br>"
extra_font = (target.reagents.get_reagent_amount("styptic_powder") < 30 ? "<font color='black'>" : "<font color='red'>")
dat += "[extra_font]\tStyptic Powder: [target.reagents.get_reagent_amount("styptic_powder")] units<BR>"
extra_font = (target.reagents.get_reagent_amount("salbutamol") < 30 ? "<font color='black'>" : "<font color='red'>")
dat += "[extra_font]\tSalbutamol: [target.reagents.get_reagent_amount("salbutamol")] units<BR>"
dat += "<hr><table border='1'>"
dat += "<tr>"
dat += "<th>Organ</th>"
dat += "<th>Burn Damage</th>"
dat += "<th>Brute Damage</th>"
dat += "<th>Other Wounds</th>"
dat += "</tr>"
for(var/obj/item/organ/external/e in target.bodyparts)
dat += "<tr>"
var/AN = ""
var/open = ""
var/infected = ""
var/robot = ""
var/imp = ""
var/bled = ""
var/splint = ""
var/internal_bleeding = ""
var/lung_ruptured = ""
if(e.status & ORGAN_INT_BLEEDING)
internal_bleeding = "<br>Internal bleeding"
if(istype(e, /obj/item/organ/external/chest) && target.is_lung_ruptured())
lung_ruptured = "Lung ruptured:"
if(e.status & ORGAN_SPLINTED)
splint = "Splinted:"
if(e.status & ORGAN_BROKEN)
var/datum/wound/fracture = e.get_wound(/datum/wound/fracture)
AN = "[fracture.name]:"
if(e.is_robotic())
robot = "Robotic:"
if(e.open)
open = "Open:"
switch(e.germ_level)
if(INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200)
infected = "Mild Infection:"
if(INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300)
infected = "Mild Infection+:"
if(INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400)
infected = "Mild Infection++:"
if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200)
infected = "Acute Infection:"
if(INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300)
infected = "Acute Infection+:"
if(INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_TWO + 400)
infected = "Acute Infection++:"
if(INFECTION_LEVEL_THREE to INFINITY)
infected = "Septic:"
var/unknown_body = 0
for(var/I in e.embedded_objects)
unknown_body++
if(unknown_body || e.hidden)
imp += "Unknown body present:"
if(!AN && !open && !infected && !imp)
AN = "None:"
dat += "<td>[e.name]</td><td>[e.burn_dam]</td><td>[e.brute_dam]</td><td>[robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]</td>"
dat += "</tr>"
for(var/obj/item/organ/internal/i in target.internal_organs)
var/mech = i.desc
var/infection = "None"
switch(i.germ_level)
if(1 to INFECTION_LEVEL_ONE + 200)
infection = "Mild Infection:"
if(INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300)
infection = "Mild Infection+:"
if(INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400)
infection = "Mild Infection++:"
if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200)
infection = "Acute Infection:"
if(INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300)
infection = "Acute Infection+:"
if(INFECTION_LEVEL_TWO + 300 to INFINITY)
infection = "Acute Infection++:"
dat += "<tr>"
dat += "<td>[i.name]</td><td>N/A</td><td>[i.damage]</td><td>[infection]:[mech]</td><td></td>"
dat += "</tr>"
dat += "</table>"
if(HAS_TRAIT(target, TRAIT_BLIND))
dat += "<font color='red'>Cataracts detected.</font><BR>"
if(HAS_TRAIT(target, TRAIT_COLORBLIND))
dat += "<font color='red'>Photoreceptor abnormalities detected.</font><BR>"
if(HAS_TRAIT(target, TRAIT_NEARSIGHT))
dat += "<font color='red'>Retinal misalignment detected.</font><BR>"
if(HAS_TRAIT(target, TRAIT_PARAPLEGIC))
dat += "<font color='red'>Lumbar nerves damaged.</font><BR>"
return dat