mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-18 02:24:11 +01:00
Small Medbot patient analysis and injection refactor (#19353)
* Gee medbot! How come your mom lets you have 26 extra parentheses? * Check order consistency * Avoid searching through viruses if already treated for them * Simplify assessment logic for custom beakers * Simplify assessment logic for viruses * Fix medbots not considering all of patient's viruses * Bool readability * Fix medbots ignoring viruses if patient has no damage * Fix medbots not considering loaded beaker when assessing treatment for viruses * Fix inconsistent virus check between assessment and medication logic * Check order consistency 2.0 * Fix medbots getting confused when patient has regular drug but no beaker drugs * Refactor patient assessment * Condense a loaded beaker volume check * Extract virus assessment into separate proc
This commit is contained in:
@@ -32,18 +32,18 @@
|
||||
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
|
||||
var/injection_amount = 15 //How much reagent do we inject at a time?
|
||||
var/heal_threshold = 10 //Start healing when they have this much damage in a category
|
||||
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
|
||||
var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
|
||||
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
|
||||
var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
|
||||
var/use_beaker = FALSE //Use reagents in beaker instead of default treatment agents.
|
||||
var/declare_crit = TRUE //If active, the bot will transmit a critical patient alert to MedHUD users.
|
||||
var/declare_cooldown = FALSE //Prevents spam of critical patient alerts.
|
||||
var/stationary_mode = FALSE //If enabled, the Medibot will not move automatically.
|
||||
//Setting which reagents to use to treat what by default. By id.
|
||||
var/treatment_brute = "salglu_solution"
|
||||
var/treatment_oxy = "salbutamol"
|
||||
var/treatment_fire = "salglu_solution"
|
||||
var/treatment_tox = "charcoal"
|
||||
var/treatment_virus = "spaceacillin"
|
||||
var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
|
||||
var/shut_up = 0 //self explanatory :)
|
||||
var/treat_virus = TRUE //If on, the bot will attempt to treat viral infections, curing them if possible.
|
||||
var/shut_up = FALSE //self explanatory :)
|
||||
var/syndicate_aligned = FALSE // Will it only treat operatives?
|
||||
var/drops_parts = TRUE
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/syndicate/emagged
|
||||
emagged = 2
|
||||
declare_crit = 0
|
||||
declare_crit = FALSE
|
||||
drops_parts = FALSE
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/update_icon_state()
|
||||
@@ -135,7 +135,7 @@
|
||||
oldpatient = null
|
||||
oldloc = null
|
||||
last_found = world.time
|
||||
declare_cooldown = 0
|
||||
declare_cooldown = FALSE
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
|
||||
@@ -235,7 +235,7 @@
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/reagent_containers/glass))
|
||||
. = 1 //no afterattack
|
||||
. = TRUE //no afterattack
|
||||
if(locked)
|
||||
to_chat(user, "<span class='warning'>You cannot insert a beaker because the panel is locked!</span>")
|
||||
return
|
||||
@@ -259,7 +259,7 @@
|
||||
/mob/living/simple_animal/bot/medbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
declare_crit = 0
|
||||
declare_crit = FALSE
|
||||
if(user)
|
||||
to_chat(user, "<span class='notice'>You short out [src]'s reagent synthesis circuits.</span>")
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
@@ -271,7 +271,7 @@
|
||||
if(buckled)
|
||||
if((last_warning + 300) < world.time)
|
||||
speak("<span class='danger'>Movement restrained! Unit on standby!</span>")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, FALSE)
|
||||
last_warning = world.time
|
||||
return
|
||||
if(H.stat == 2)
|
||||
@@ -286,7 +286,7 @@
|
||||
var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/mcoming.ogg', "Wait [H.name]! I want to help!" = 'sound/voice/mhelp.ogg', "[H.name], you appear to be injured!" = 'sound/voice/minjured.ogg')
|
||||
var/message = pick(messagevoice)
|
||||
speak(message)
|
||||
playsound(loc, messagevoice[message], 50, 0)
|
||||
playsound(loc, messagevoice[message], 50, FALSE)
|
||||
last_newpatient_speak = world.time
|
||||
return H
|
||||
else
|
||||
@@ -308,7 +308,7 @@
|
||||
var/list/messagevoice = list("Radar, put a mask on!" = 'sound/voice/mradar.ogg', "There's always a catch, and I'm the best there is." = 'sound/voice/mcatch.ogg', "I knew it, I should've been a plastic surgeon." = 'sound/voice/msurgeon.ogg', "What kind of medbay is this? Everyone's dropping like flies." = 'sound/voice/mflies.ogg', "Delicious!" = 'sound/voice/mdelicious.ogg')
|
||||
var/message = pick(messagevoice)
|
||||
speak(message)
|
||||
playsound(loc, messagevoice[message], 50, 0)
|
||||
playsound(loc, messagevoice[message], 50, FALSE)
|
||||
var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
|
||||
patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
|
||||
oldpatient = patient
|
||||
@@ -357,65 +357,72 @@
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/assess_beaker_injection(mob/living/carbon/C)
|
||||
//If we have and are using a medicine beaker, return any reagent the patient is missing
|
||||
if(use_beaker && reagent_glass?.reagents.total_volume)
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
return R.id
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/assess_viruses(mob/living/carbon/C)
|
||||
. = FALSE
|
||||
|
||||
if(!treat_virus)
|
||||
return
|
||||
|
||||
for(var/datum/disease/D as anything in C.viruses)
|
||||
if(!(D.visibility_flags & HIDDEN_SCANNER && D.visibility_flags & HIDDEN_PANDEMIC) && D.severity != NONTHREAT && (D.stage > 1 || D.spread_flags & AIRBORNE))
|
||||
return TRUE //Medbots see viruses that aren't fully hidden and have developed enough/are airborne, ignoring safe viruses
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/select_medication(mob/living/carbon/C, beaker_injection)
|
||||
var/treatable_virus = assess_viruses(C)
|
||||
var/treatable_brute = C.getBruteLoss() >= heal_threshold
|
||||
var/treatable_fire = C.getFireLoss() >= heal_threshold
|
||||
var/treatable_oxy = C.getOxyLoss() >= (heal_threshold + 15)
|
||||
var/treatable_tox = C.getToxLoss() >= heal_threshold
|
||||
|
||||
if((!C.has_organic_damage() || !(treatable_brute || treatable_fire || treatable_oxy || treatable_tox)) && !treatable_virus)
|
||||
return //No organic damage or injuries aren't severe enough, and no virus to treat; abort mission
|
||||
|
||||
if(beaker_injection)
|
||||
return beaker_injection //Custom beaker injections have priority
|
||||
|
||||
if(treatable_virus && !C.reagents.has_reagent(treatment_virus))
|
||||
return treatment_virus
|
||||
if(treatable_brute && !C.reagents.has_reagent(treatment_brute))
|
||||
return treatment_brute
|
||||
if(treatable_fire && !C.reagents.has_reagent(treatment_fire))
|
||||
return treatment_fire
|
||||
if(treatable_oxy && !C.reagents.has_reagent(treatment_oxy))
|
||||
return treatment_oxy
|
||||
if(treatable_tox && !C.reagents.has_reagent(treatment_tox))
|
||||
return treatment_tox
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/assess_patient(mob/living/carbon/C)
|
||||
//Time to see if they need medical help!
|
||||
if(C.stat == 2)
|
||||
return 0 //welp too late for them!
|
||||
if(C.stat == DEAD)
|
||||
return FALSE //welp too late for them!
|
||||
|
||||
if(C.suiciding)
|
||||
return 0 //Kevorkian school of robotic medical assistants.
|
||||
return FALSE //Kevorkian school of robotic medical assistants.
|
||||
|
||||
// is secretly a silicon
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.dna.species && H.dna.species.reagent_tag == PROCESS_SYN)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(syndicate_aligned && (!("syndicate" in C.faction)))
|
||||
return 0
|
||||
if(syndicate_aligned && !("syndicate" in C.faction))
|
||||
return FALSE
|
||||
|
||||
if(declare_crit && C.health <= 0) //Critical condition! Call for help!
|
||||
declare(C)
|
||||
|
||||
if(!C.has_organic_damage())
|
||||
return 0
|
||||
|
||||
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
|
||||
if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
return 1
|
||||
|
||||
//They're injured enough for it!
|
||||
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
|
||||
return 1 //If they're already medicated don't bother!
|
||||
|
||||
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
|
||||
return 1
|
||||
|
||||
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
|
||||
return 1
|
||||
|
||||
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_tox)))
|
||||
return 1
|
||||
|
||||
if(treat_virus)
|
||||
for(var/thing in C.viruses)
|
||||
var/datum/disease/D = thing
|
||||
//the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
|
||||
if(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC)
|
||||
return 0
|
||||
if(D.severity == NONTHREAT) // medibot doesn't try to heal truly harmless viruses
|
||||
return 0
|
||||
if((D.stage > 1) || (D.spread_flags & AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne.
|
||||
|
||||
if(!C.reagents.has_reagent(treatment_virus))
|
||||
return 1 //STOP DISEASE FOREVER
|
||||
|
||||
return 0
|
||||
if(!isnull(select_medication(C, assess_beaker_injection(C))))
|
||||
return TRUE //If a valid medicine option for the patient exists, they require treatment
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A)
|
||||
if(iscarbon(A))
|
||||
@@ -434,7 +441,6 @@
|
||||
chemscan(src, A)
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/medicate_patient(mob/living/carbon/C)
|
||||
var/inject_beaker = FALSE
|
||||
if(!on)
|
||||
return
|
||||
|
||||
@@ -447,60 +453,25 @@
|
||||
var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/mno.ogg', "Live, damnit! LIVE!" = 'sound/voice/mlive.ogg', "I...I've never lost a patient before. Not today, I mean." = 'sound/voice/mlost.ogg')
|
||||
var/message = pick(messagevoice)
|
||||
speak(message)
|
||||
playsound(loc, messagevoice[message], 50, 0)
|
||||
playsound(loc, messagevoice[message], 50, FALSE)
|
||||
oldpatient = patient
|
||||
soft_reset()
|
||||
return
|
||||
|
||||
var/reagent_id = null
|
||||
var/reagent_id
|
||||
var/beaker_injection //If and what kind of beaker reagent needs to be injected
|
||||
|
||||
if(emagged == 2) //Emagged! Time to poison everybody.
|
||||
reagent_id = "pancuronium"
|
||||
|
||||
else
|
||||
if(treat_virus)
|
||||
var/virus = 0
|
||||
for(var/thing in C.viruses)
|
||||
var/datum/disease/D = thing
|
||||
//detectable virus
|
||||
if((!(D.visibility_flags & HIDDEN_SCANNER)) || (!(D.visibility_flags & HIDDEN_PANDEMIC)))
|
||||
if(D.severity != NONTHREAT) //virus is harmful
|
||||
if((D.stage > 1) || (D.spread_flags & AIRBORNE))
|
||||
virus = 1
|
||||
|
||||
if(!reagent_id && (virus))
|
||||
if(!C.reagents.has_reagent(treatment_virus))
|
||||
reagent_id = treatment_virus
|
||||
|
||||
if(!reagent_id && (C.getBruteLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(treatment_brute))
|
||||
reagent_id = treatment_brute
|
||||
|
||||
if(!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
|
||||
if(!C.reagents.has_reagent(treatment_oxy))
|
||||
reagent_id = treatment_oxy
|
||||
|
||||
if(!reagent_id && (C.getFireLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(treatment_fire))
|
||||
reagent_id = treatment_fire
|
||||
|
||||
if(!reagent_id && (C.getToxLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(treatment_tox))
|
||||
reagent_id = treatment_tox
|
||||
|
||||
//If the patient is injured but doesn't have our special reagent in them then we should give it to them first
|
||||
if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
reagent_id = R.id
|
||||
inject_beaker = TRUE
|
||||
break
|
||||
beaker_injection = assess_beaker_injection(C)
|
||||
reagent_id = select_medication(C, beaker_injection)
|
||||
|
||||
if(!reagent_id) //If they don't need any of that they're probably cured!
|
||||
var/list/messagevoice = list("All patched up!" = 'sound/voice/mpatchedup.ogg', "An apple a day keeps me away." = 'sound/voice/mapple.ogg', "Feel better soon!" = 'sound/voice/mfeelbetter.ogg')
|
||||
var/message = pick(messagevoice)
|
||||
speak(message)
|
||||
playsound(loc, messagevoice[message], 50, 0)
|
||||
playsound(loc, messagevoice[message], 50, FALSE)
|
||||
bot_reset()
|
||||
return
|
||||
else
|
||||
@@ -510,13 +481,13 @@
|
||||
C.visible_message("<span class='danger'>[src] is trying to inject [patient]!</span>", \
|
||||
"<span class='userdanger'>[src] is trying to inject you!</span>")
|
||||
|
||||
addtimer(CALLBACK(src, .proc/do_inject, C, inject_beaker, reagent_id), 3 SECONDS)
|
||||
addtimer(CALLBACK(src, .proc/do_inject, C, !isnull(beaker_injection), reagent_id), 3 SECONDS)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/do_inject(mob/living/carbon/C, inject_beaker, reagent_id)
|
||||
if((get_dist(src, patient) <= 1) && on && assess_patient(patient))
|
||||
if(inject_beaker)
|
||||
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
if(use_beaker && reagent_glass?.reagents.total_volume)
|
||||
var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
|
||||
reagent_glass.reagents.reaction(patient, REAGENT_INGEST, fraction)
|
||||
reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead.
|
||||
@@ -533,11 +504,11 @@
|
||||
/mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount)
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
|
||||
if(!R.overdose_threshold)
|
||||
return 0
|
||||
return FALSE
|
||||
var/current_volume = patient.reagents.get_reagent_amount(reagent_id)
|
||||
if(current_volume + injection_amount > R.overdose_threshold)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/explode()
|
||||
on = FALSE
|
||||
@@ -578,9 +549,9 @@
|
||||
reagent_glass = null
|
||||
|
||||
if(emagged && prob(25))
|
||||
playsound(loc, 'sound/voice/minsult.ogg', 50, 0)
|
||||
playsound(loc, 'sound/voice/minsult.ogg', 50, FALSE)
|
||||
|
||||
do_sparks(3, 1, src)
|
||||
do_sparks(3, TRUE, src)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/declare(crit_patient)
|
||||
@@ -590,7 +561,7 @@
|
||||
return
|
||||
var/area/location = get_area(src)
|
||||
speak("Medical emergency! [crit_patient ? "<b>[crit_patient]</b>" : "A patient"] is in critical condition at [location]!", radio_channel)
|
||||
declare_cooldown = 1
|
||||
declare_cooldown = TRUE
|
||||
spawn(200) //Twenty seconds
|
||||
declare_cooldown = 0
|
||||
declare_cooldown = FALSE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user