From fc6bfd6266823f0dcc3f73fb30e5be1ec40d52b8 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Sat, 26 Jul 2025 03:48:03 -0700 Subject: [PATCH] [MIRROR] More GM tools (#11244) Co-authored-by: SatinIsle <98125273+SatinIsle@users.noreply.github.com> --- code/modules/admin/health_scan.dm | 457 ++++++++++++++++++ code/modules/admin/player_effects.dm | 14 + code/modules/admin/verbs/buildmode.dm | 12 +- code/modules/admin/verbs/randomverbs.dm | 25 + .../PlayerEffectsTabs/ControlAbilities.tsx | 3 + .../PlayerEffectsTabs/ControlMedical.tsx | 3 + vorestation.dme | 1 + 7 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 code/modules/admin/health_scan.dm diff --git a/code/modules/admin/health_scan.dm b/code/modules/admin/health_scan.dm new file mode 100644 index 0000000000..8d7d71d9bd --- /dev/null +++ b/code/modules/admin/health_scan.dm @@ -0,0 +1,457 @@ +//// This is a detatched version of a phasic health analyser for admin use on command +// Mode dictates whether to include specific limb damage +// advscan is the strength of the scan required, 3 being similar to a phasic health analyser. +// showadvscan toggles whether to give additional scan information about chemicals in their body. +// By default this proc is set to it's most powerful scan. + +/mob/living/proc/scan_mob(mob/user, var/mode = 1, var/advscan = 3, var/showadvscan = 1) + var/mob/living/M = src + var/dat = "" + + // Start with the cyborg analyser first + if(isrobot(M)) + var/BU = M.getFireLoss() > 50 ? span_bold("[M.getFireLoss()]") : M.getFireLoss() + var/BR = M.getBruteLoss() > 50 ? span_bold("[M.getBruteLoss()]") : M.getBruteLoss() + user.show_message(span_blue("Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.halloss]% functional"]")) + user.show_message("\t Key: [span_orange("Electronics")]/[span_red("Brute")]", 1) + user.show_message("\t Damage Specifics: [span_orange("[BU]")] - [span_red("[BR]")]") + if(M.tod && M.stat == DEAD) + user.show_message(span_blue("Time of Disable: [M.tod]")) + var/mob/living/silicon/robot/R = M + var/obj/item/cell/cell = R.get_cell() + if(cell) + var/cell_charge = round(cell.percent()) + var/cell_text + if(cell_charge > 60) + cell_text = span_green("[cell_charge]") + else if (cell_charge > 30) + cell_text = span_yellow("[cell_charge]") + else if (cell_charge > 10) + cell_text = span_orange("[cell_charge]") + else if (cell_charge > 1) + cell_text = span_red("[cell_charge]") + else + cell_text = span_red(span_bold("[cell_charge]")) + user.show_message("\t Power Cell Status: [span_blue("[capitalize(cell.name)]")] at [cell_text]% charge") + var/list/damaged = R.get_damaged_components(1,1,1) + user.show_message(span_blue("Localized Damage:"),1) + if(length(damaged)>0) + for(var/datum/robot_component/org in damaged) + user.show_message(span_blue(text("\t []: [][] - [] - [] - []", \ + span_blue(capitalize(org.name)), \ + (org.installed == -1) ? "[span_red(span_bold("DESTROYED"))] " :"",\ + (org.electronics_damage > 0) ? "[span_orange("[org.electronics_damage]")]" :0, \ + (org.brute_damage > 0) ? "[span_red("[org.brute_damage]")]" :0, \ + (org.toggled) ? "Toggled ON" : "[span_red("Toggled OFF")]",\ + (org.powered) ? "Power ON" : "[span_red("Power OFF")]")),1) + else + user.show_message(span_blue("\t Components are OK."),1) + if(R.emagged && prob(5)) + user.show_message(span_red("\t ERROR: INTERNAL SYSTEMS COMPROMISED"),1) + user.show_message(span_blue("Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)"), 1) + return + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + to_chat(user, span_notice("Analyzing Results for \the [H]:")) + if(H.isSynthetic()) + to_chat(user, "System instability: [span_green("[H.getToxLoss()]")]") + to_chat(user, "Key: [span_orange("Electronics")]/[span_red("Brute")]") + to_chat(user, span_notice("External prosthetics:")) + var/organ_found + if(H.internal_organs.len) + for(var/obj/item/organ/external/E in H.organs) + if(!(E.robotic >= ORGAN_ROBOT)) + continue + organ_found = 1 + to_chat(user, "[E.name]: [span_red("[E.brute_dam] ")] [span_orange("[E.burn_dam]")]") + if(!organ_found) + to_chat(user, "No prosthetics located.") + to_chat(user, "
") + to_chat(user, span_notice("Internal prosthetics:")) + organ_found = null + if(H.internal_organs.len) + for(var/obj/item/organ/O in H.internal_organs) + if(!(O.robotic >= ORGAN_ROBOT)) + continue + organ_found = 1 + to_chat(user, "[O.name]: [span_red("[O.damage]")]") + if(!organ_found) + to_chat(user, "No prosthetics located.") + + if(isSynthetic(M)) + return //End here if they're FBP + + //Then do normal health scan + var/fake_oxy = max(rand(1,40), M.getOxyLoss(), (300 - (M.getToxLoss() + M.getFireLoss() + M.getBruteLoss()))) + var/OX = M.getOxyLoss() > 50 ? span_bold("[M.getOxyLoss()]") : M.getOxyLoss() + var/TX = M.getToxLoss() > 50 ? span_bold("[M.getToxLoss()]") : M.getToxLoss() + var/BU = M.getFireLoss() > 50 ? span_bold("[M.getFireLoss()]") : M.getFireLoss() + var/BR = M.getBruteLoss() > 50 ? span_bold("[M.getBruteLoss()]") : M.getBruteLoss() + var/analyzed_results = "" + if(M.status_flags & FAKEDEATH) + OX = fake_oxy > 50 ? span_bold("[fake_oxy]") : fake_oxy + dat += span_notice("Analyzing Results for [M]:") + dat += "
" + dat += span_notice("Overall Status: dead") + dat += "
" + else + analyzed_results += "Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "dead" : "[round((M.health/M.getMaxHealth())*100) ]% healthy"]
" + analyzed_results += "\tKey: [span_cyan("Suffocation")]/[span_green("Toxin")]/[span_orange("Burns")]/[span_red("Brute")]
" + analyzed_results += "\tDamage Specifics: [span_cyan("[OX]")] - [span_green("[TX]")] - [span_orange("[BU]")] - [span_red("[BR]")]
" + analyzed_results += "Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)
" + if(!(M.status_flags & FAKEDEATH)) + analyzed_results = span_notice(analyzed_results) + dat += analyzed_results + if(M.timeofdeath && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) + dat += span_notice("Time of Death: [worldtime2stationtime(M.timeofdeath)]") + dat += "
" + var/tdelta = round(world.time - M.timeofdeath) + if(tdelta < (10 MINUTES * 10)) + dat += span_boldnotice("Subject died [DisplayTimeText(tdelta)] ago - resuscitation may be possible!") + dat += "
" + if(ishuman(M) && mode == 1) + var/mob/living/carbon/human/H = M + var/list/damaged = H.get_damaged_organs(1,1) + dat += span_notice("Localized Damage, Brute/Burn:") + dat += "
" + if(length(damaged)>0) + for(var/obj/item/organ/external/org in damaged) + if(org.robotic >= ORGAN_ROBOT) + continue + else + var/our_damage = " [capitalize(org.name)]: [(org.brute_dam > 0) ? span_warning("[org.brute_dam]") : 0]" + our_damage += "[(org.status & ORGAN_BLEEDING)?span_danger("\[Bleeding\]"):""] - " + our_damage += "[(org.burn_dam > 0) ? "[span_orange("[org.burn_dam]")]" : 0]" + dat += span_notice(our_damage) + "
" + else + dat += span_notice(" Limbs are OK.") + dat += "
" + // This handles genetic side effects and tells you the treatment, if any. + // These are handled in side_effects.dm + if(H.genetic_side_effects) + for(var/datum/genetics/side_effect/side_effect in H.genetic_side_effects) + var/datum/reagent/Rd = SSchemistry.chemical_reagents[side_effect.antidote_reagent] + dat += "
" + dat += span_danger("Patient is suffering from [side_effect.name]. ") + if(Rd) + dat += span_danger("Treatment: [Rd]
") + else + dat += "There is no known treatment.
" + + OX = M.getOxyLoss() > 50 ? "[span_cyan(span_bold("Severe oxygen deprivation detected"))]" : "Subject bloodstream oxygen level normal" + TX = M.getToxLoss() > 50 ? "[span_green(span_bold("Dangerous amount of toxins detected"))]" : "Subject bloodstream toxin level minimal" + BU = M.getFireLoss() > 50 ? "[span_orange(span_bold("Severe burn damage detected"))]" : "Subject burn injury status O.K" + BR = M.getBruteLoss() > 50 ? "[span_red(span_bold("Severe anatomical damage detected"))]" : "Subject brute-force injury status O.K" + if(M.status_flags & FAKEDEATH) + OX = fake_oxy > 50 ? span_warning("Severe oxygen deprivation detected") : "Subject bloodstream oxygen level normal" + dat += "[OX] | [TX] | [BU] | [BR]
" + if(M.radiation) + if(advscan >= 2 && showadvscan == 1) + var/severity = "" + if(M.radiation >= 1500) + severity = "Lethal" + else if(M.radiation >= 600) + severity = "Critical" + else if(M.radiation >= 400) + severity = "Severe" + else if(M.radiation >= 300) + severity = "Moderate" + else if(M.radiation >= 100) + severity = "Low" + dat += span_warning("[severity] levels of acute radiation sickness detected. [round(M.radiation/50)]Gy. [(severity == "Critical" || severity == "Lethal") ? " Immediate treatment advised." : ""]") + dat += "
" + else + dat += span_warning("Acute radiation sickness detected.") + dat += "
" + if(M.accumulated_rads) + if(advscan >= 2 && showadvscan == 1) + var/severity = "" + if(M.accumulated_rads >= 1500) + severity = "Critical" + else if(M.accumulated_rads >= 600) + severity = "Severe" + else if(M.accumulated_rads >= 400) + severity = "Moderate" + else if(M.accumulated_rads >= 300) + severity = "Mild" + else if(M.accumulated_rads >= 100) + severity = "Low" + dat += span_warning("[severity] levels of chronic radiation sickness detected. [round(M.accumulated_rads/50)]Gy.") + dat += "
" + else + dat += span_warning("Chronic radiation sickness detected.") + dat += "
" + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(C.reagents.total_volume) + var/unknown = 0 + var/reagentdata[0] + var/unknownreagents[0] + for(var/datum/reagent/R as anything in C.reagents.reagent_list) + if(R.scannable) + reagentdata["[R.id]"] = span_notice("\t[round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") + reagentdata["[R.id]"] += "
" + else + unknown++ + unknownreagents["[R.id]"] = span_notice("\t[round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") + unknownreagents["[R.id]"] += "
" + if(reagentdata.len) + dat += span_notice("Beneficial reagents detected in subject's blood:") + dat += "
" + for(var/d in reagentdata) + dat += reagentdata[d] + if(unknown) + if(advscan >= 3 && showadvscan == 1) + dat += span_warning("Warning: Non-medical reagent[(unknown>1)?"s":""] detected in subject's blood:") + dat += "
" + for(var/d in unknownreagents) + dat += unknownreagents[d] + else + dat += span_warning("Warning: Unknown substance[(unknown>1)?"s":""] detected in subject's blood.") + dat += "
" + if(C.ingested && C.ingested.total_volume) + var/unknown = 0 + var/stomachreagentdata[0] + var/stomachunknownreagents[0] + for(var/datum/reagent/R as anything in C.ingested.reagent_list) + if(R.scannable) + stomachreagentdata["[R.id]"] = span_notice("\t[round(C.ingested.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") + stomachreagentdata["[R.id]"] += "
" + if (advscan == 0 || showadvscan == 0) + dat += span_notice("[R.name] found in subject's stomach.") + dat += "
" + else + ++unknown + stomachunknownreagents["[R.id]"] = span_notice("\t[round(C.ingested.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") + stomachunknownreagents["[R.id]"] += "
" + if(advscan >= 1 && showadvscan == 1) + dat += span_notice("Beneficial reagents detected in subject's stomach:") + dat += "
" + for(var/d in stomachreagentdata) + dat += stomachreagentdata[d] + if(unknown) + if(advscan >= 3 && showadvscan == 1) + dat += span_warning("Warning: Non-medical reagent[(unknown > 1)?"s":""] found in subject's stomach:") + dat += "
" + for(var/d in stomachunknownreagents) + dat += stomachunknownreagents[d] + else + dat += span_warning("Unknown substance[(unknown > 1)?"s":""] found in subject's stomach.") + dat += "
" + if(C.touching && C.touching.total_volume) + var/unknown = 0 + var/touchreagentdata[0] + var/touchunknownreagents[0] + for(var/datum/reagent/R as anything in C.touching.reagent_list) + if(R.scannable) + touchreagentdata["[R.id]"] = span_notice("\t[round(C.touching.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.can_overdose_touch && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") + touchreagentdata["[R.id]"] += "
" + if (advscan == 0 || showadvscan == 0) + dat += span_notice("[R.name] found in subject's dermis.") + dat += "
" + else + ++unknown + touchunknownreagents["[R.id]"] = span_notice("\t[round(C.ingested.get_reagent_amount(R.id), 1)]u [R.name][(R.overdose && R.can_overdose_touch && R.volume > R.overdose) ? " - [span_danger("Overdose")]" : ""]") + touchunknownreagents["[R.id]"] += "
" + if(advscan >= 1 && showadvscan == 1) + dat += span_notice("Beneficial reagents detected in subject's dermis:") + dat += "
" + for(var/d in touchreagentdata) + dat += touchreagentdata[d] + if(unknown) + if(advscan >= 3 && showadvscan == 1) + dat += span_warning("Warning: Non-medical reagent[(unknown > 1)?"s":""] found in subject's dermis:") + dat += "
" + for(var/d in touchunknownreagents) + dat += touchunknownreagents[d] + else + dat += span_warning("Unknown substance[(unknown > 1)?"s":""] found in subject's dermis.") + dat += "
" + if(C.IsInfected()) + for (var/datum/disease/virus in C.GetViruses()) + if(virus.visibility_flags & HIDDEN_SCANNER || virus.visibility_flags & HIDDEN_PANDEMIC) + continue + dat += span_alert(span_bold("Warning: [virus.form] detected in subject's blood.")) + dat += "
" + if (M.getCloneLoss()) + dat += span_warning("Subject appears to have been imperfectly cloned.") + dat += "
" +// if (M.reagents && M.reagents.get_reagent_amount(REAGENT_ID_INAPROVALINE)) +// user.show_message(span_notice("Bloodstream Analysis located [M.reagents:get_reagent_amount(REAGENT_ID_INAPROVALINE)] units of rejuvenation chemicals.")) + if (M.has_brain_worms()) + dat += span_warning("Subject suffering from aberrant brain activity. Recommend further scanning.") + dat += "
" + else if (M.getBrainLoss() >= 60 || !M.has_brain()) + dat += span_warning("Subject is brain dead.") + dat += "
" + else if (M.getBrainLoss() >= 25) + dat += span_warning("Severe brain damage detected. Subject likely to have a traumatic brain injury.") + dat += "
" + else if (M.getBrainLoss() >= 10) + dat += span_warning("Significant brain damage detected. Subject may have had a concussion.") + dat += "
" + else if (M.getBrainLoss() >= 1) + dat += span_warning("Minor brain damage detected.") + dat += "
" + if(ishuman(M)) + var/mob/living/carbon/human/H = M + // Addictions + if(H.get_addiction_to_reagent(REAGENT_ID_ASUSTENANCE) > 0) + dat += span_warning("Biologically unstable, requires [REAGENT_ASUSTENANCE] to function properly.") + dat += "
" + for(var/addic in H.get_all_addictions()) + if(H.get_addiction_to_reagent(addic) > 0 && (advscan >= 2 || H.get_addiction_to_reagent(addic) <= 120)) // high enough scanner upgrade detects addiction even if not almost withdrawling + var/datum/reagent/R = SSchemistry.chemical_reagents[addic] + if(R.id == REAGENT_ID_ASUSTENANCE) + continue + if(advscan >= 1) + // Shows multiple + if(advscan >= 2 && H.get_addiction_to_reagent(addic) <= 80) + dat += span_warning("Experiencing withdrawls from [R.name], [REAGENT_INAPROVALINE] treatment recomended.") + dat += "
" + else + dat += span_warning("Chemical dependance detected: [R.name].") + dat += "
" + else + // Shows single + dat += span_warning("Chemical dependance detected.") + dat += "
" + break + // Appendix + for(var/obj/item/organ/internal/appendix/a in H.internal_organs) + var/severity = "" + if(a.inflamed > 3) + severity = "Severe" + else if(a.inflamed > 2) + severity = "Moderate" + else if(a.inflamed >= 1) + severity = "Mild" + if(severity) + dat += span_warning("[severity] inflammation detected in subject [a.name].") + dat += "
" + if(HUSK in H.mutations) + dat += span_danger("Anatomical structure lost, resuscitation not possible!") + dat += "
" + // Infections, fractures, and IB + var/basic_fracture = 0 // If it's a basic scanner + var/basic_ib = 0 // If it's a basic scanner + var/fracture_dat = "" // All the fractures + var/infection_dat = "" // All the infections + var/ib_dat = "" // All the IB + var/int_damage_acc = 0 // For internal organs + for(var/obj/item/organ/internal/i in H.internal_organs) + if(!i || i.robotic >= ORGAN_ROBOT || istype(i, /obj/item/organ/internal/brain)) + continue // not there or robotic or brain which is handled separately + if(i.damage || i.status & ORGAN_DEAD) + int_damage_acc += (i.damage + ((i.status & ORGAN_DEAD) ? 30 : 0)) + if(advscan >= 2 && showadvscan == 1) + if(advscan >= 3) + var/dam_adj + if(i.damage >= i.min_broken_damage || i.status & ORGAN_DEAD) + dam_adj = "Severe" + else if(i.damage >= i.min_bruised_damage) + dam_adj = "Moderate" + else + dam_adj = "Mild" + dat += span_warning("[dam_adj] damage detected to subject's [i.name].") + dat += "
" + else + dat += span_warning("Damage detected to subject's [i.name].") + dat += "
" + if(int_damage_acc >= 1 && (advscan < 2 || !showadvscan)) + dat += span_warning("Damage detected to subject's internal organs.") + dat += "
" + for(var/obj/item/organ/external/e in H.organs) + if(!e) + continue + // Broken limbs + if(e.status & ORGAN_BROKEN) + if((e.name in list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_HEAD, BP_TORSO, BP_GROIN)) && (!e.splinted)) + fracture_dat += span_warning("Unsecured fracture in subject [e.name]. Splinting recommended for transport.") + fracture_dat += "
" + else if(advscan >= 1 && showadvscan == 1) + fracture_dat += span_warning("Bone fractures detected in subject [e.name].") + fracture_dat += "
" + else + basic_fracture = 1 + // Infections + if(e.has_infected_wound()) + dat += span_warning("Infected wound detected in subject [e.name]. Disinfection recommended.") + dat += "
" + // IB + for(var/datum/wound/W in e.wounds) + if(W.internal) + if(advscan >= 1 && showadvscan == 1) + ib_dat += span_warning("Internal bleeding detected in subject [e.name].") + ib_dat += "
" + else + basic_ib = 1 + if(basic_fracture) + fracture_dat += span_warning("Bone fractures detected. Advanced scanner required for location.") + fracture_dat += "
" + if(basic_ib) + ib_dat += span_warning("Internal bleeding detected. Advanced scanner required for location.") + ib_dat += "
" + dat += fracture_dat + dat += infection_dat + dat += ib_dat + + // Blood level + if(M:vessel) + var/blood_volume = H.vessel.get_reagent_amount(REAGENT_ID_BLOOD) + var/blood_percent = round((blood_volume / H.species.blood_volume)*100) + var/blood_type = H.dna.b_type + var/blood_reagent = H.species.blood_reagents + if(blood_volume <= H.species.blood_volume*H.species.blood_level_danger) + dat += span_danger(span_italics("Warning: Blood Level CRITICAL: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].")) + dat += "
" + else if(blood_volume <= H.species.blood_volume*H.species.blood_level_warning) + dat += span_danger(span_italics("Warning: Blood Level VERY LOW: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].")) + dat += "
" + else if(blood_volume <= H.species.blood_volume*H.species.blood_level_safe) + dat += span_danger("Warning: Blood Level LOW: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].") + dat += "
" + else + dat += span_notice("Blood Level Normal: [blood_percent]% [blood_volume]cl. Type: [blood_type]. Basis: [blood_reagent].") + dat += "
" + dat += span_notice("Subject's pulse: [H.pulse == PULSE_THREADY || H.pulse == PULSE_NONE ? span_red(H.get_pulse(GETPULSE_TOOL) + " bpm") : span_blue(H.get_pulse(GETPULSE_TOOL) + " bpm")].") // VORE Edit: Missed a linebreak here. + dat += "
" + var/datum/component/xenochimera/xc = H.get_xenochimera_component() + if(xc) + if(H.stat == DEAD && xc.revive_ready == REVIVING_READY && !H.hasnutriment()) + dat += span_danger("WARNING: Protein levels low. Subject incapable of reconstitution.") + else if(xc.revive_ready == REVIVING_NOW) + dat += span_warning("Subject is undergoing form reconstruction. Estimated time to finish is in: [round((xc.revive_finished - world.time) / 10)] seconds.") + else if(xc.revive_ready == REVIVING_DONE) + dat += span_notice("Subject is ready to hatch. Transfer to dark room for holding with food available.") + else if(H.stat == DEAD) + dat+= span_danger("WARNING: Defib will cause extreme pain and set subject feral. Sedation recommended prior to defibrillation.") + else // If they bop them and they're not dead or reviving, give 'em a little notice. + dat += span_notice("Subject is a Xenochimera. Treat accordingly.") + + // Custom medical issues + for(var/obj/item/organ/I in H.internal_organs) + for(var/datum/medical_issue/MI in I.medical_issues) + if(advscan >= MI.advscan) + dat += span_danger("Warning: [MI.name] detected in [MI.affectedorgan].
") + if(advscan >= MI.advscan_cure) + if(MI.cure_reagent) + dat += span_notice("Suggested treatment: Prescription of [MI.cure_reagent].
") + else if(MI.cure_surgery) + dat += span_notice("Required surgery: [MI.cure_surgery].
") + else + dat += span_notice("[MI.affectedorgan] may require surgical removal or transplantation.
") + for(var/obj/item/organ/E in H.organs) + for(var/datum/medical_issue/MI in E.medical_issues) + if(advscan >= MI.advscan) + dat += span_danger("Warning: [MI.name] detected in [MI.affectedorgan].
") + if(advscan >= MI.advscan_cure) + if(MI.cure_reagent) + dat += span_notice("Suggested treatment: Prescription of [MI.cure_reagent].
") + else if(MI.cure_surgery) + dat += span_notice("Required surgery: [MI.cure_surgery].
") + else + dat += span_notice("[MI.affectedorgan] may require surgical removal or transplantation.
") + + user.show_message(dat, 1) diff --git a/code/modules/admin/player_effects.dm b/code/modules/admin/player_effects.dm index f12ff24557..eacb2fca7c 100644 --- a/code/modules/admin/player_effects.dm +++ b/code/modules/admin/player_effects.dm @@ -331,6 +331,12 @@ ////////MEDICAL////////////// + if("health_scan") + var/mob/living/Tar = target + if(!istype(Tar)) + return + Tar.scan_mob(user) + if("appendicitis") var/mob/living/carbon/human/Tar = target if(istype(Tar)) @@ -590,6 +596,14 @@ return add_verb(Tar, /mob/living/proc/toggle_active_cloaking) + if("colormate") + if(istype(target,/mob/living/simple_mob)) + var/mob/living/simple_mob/Tar = target + add_verb(Tar, /mob/living/simple_mob/proc/ColorMate) + if(istype(target,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/Tar = target + add_verb(Tar, /mob/living/silicon/robot/proc/ColorMate) + ////////INVENTORY////////////// diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm index b23b276dee..b2b0506e5e 100644 --- a/code/modules/admin/verbs/buildmode.dm +++ b/code/modules/admin/verbs/buildmode.dm @@ -109,7 +109,9 @@ GLOBAL_LIST_EMPTY(active_buildmode_holders) Middle Mouse Button on turf/obj = Capture object type
\ Left Mouse Button on turf/obj = Place objects
\ Right Mouse Button = Delete objects
\ - Mouse Button + ctrl = Copy object type

\ + Mouse Button + ctrl = Copy object type
\ + Left Mouse Button + alt = Open View Variable
\ + Right Mouse Button + alt = Call Proc

\ Use the button in the upper left corner to
\ change the direction of built objects.
\ ***********************************************************")) @@ -413,19 +415,23 @@ GLOBAL_LIST_EMPTY(active_buildmode_holders) CHOMP Remove end */ if(BUILDMODE_ADVANCED) - if(pa.Find("left") && !pa.Find("ctrl")) + if(pa.Find("left") && !pa.Find("ctrl") && !pa.Find("alt")) if(ispath(holder.buildmode.objholder,/turf)) var/turf/T = get_turf(object) T.ChangeTurf(holder.buildmode.objholder) else if(ispath(holder.buildmode.objholder)) var/obj/A = new holder.buildmode.objholder (get_turf(object)) A.set_dir(holder.builddir.dir) - else if(pa.Find("right")) + else if(pa.Find("right") && !pa.Find("alt")) if(isobj(object)) qdel(object) else if(pa.Find("ctrl")) holder.buildmode.objholder = object.type to_chat(user, span_notice("[object]([object.type]) copied to buildmode.")) + else if(pa.Find("left") && pa.Find("alt")) + user.client.debug_variables(object) + else if(pa.Find("right") && pa.Find("alt")) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/call_proc_datum, object) if(pa.Find("middle")) holder.buildmode.objholder = text2path("[object.type]") if(holder.buildmode.objsay) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 71f2d0f03d..c2089d74dc 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -457,6 +457,18 @@ ADMIN_VERB(respawn_character, (R_ADMIN|R_REJUVINATE), "Spawn Character", "(Re)Sp else equipment = 0 + var/custom_job + var/custom_job_title + if(charjob) + custom_job = tgui_alert(src,"Customise Job Title?", "Custom Job", list("No", "Yes", "Cancel")) + if(!custom_job || equipment == "Cancel") + return + else if(custom_job == "Yes") + custom_job = 1 + custom_job_title = tgui_input_text(src,"Choose a Job Title for the character.","Job Title") + else + custom_job = 0 + //For logging later var/admin = key_name_admin(src) var/player_key = picked_client.key @@ -565,6 +577,19 @@ ADMIN_VERB(respawn_character, (R_ADMIN|R_REJUVINATE), "Spawn Character", "(Re)Sp new_character.mind.role_alt_title = job_master.GetPlayerAltTitle(new_character, charjob) equip_custom_items(new_character) //CHOMPEdit readded to enable custom_item.txt + //If customised job title, modify here. + if(custom_job && custom_job_title) + var/character_name = new_character.name + for(var/obj/item/card/id/I in new_character.contents) + I.name = "[character_name]'s ID Card ([custom_job_title])" + I.assignment = custom_job_title + for(var/obj/item/pda/P in new_character.contents) + P.name = "PDA-[character_name] ([custom_job_title])" + P.ownjob = custom_job_title + new_character.mind.assigned_role = custom_job_title + new_character.mind.role_alt_title = custom_job_title + to_chat(new_character, "Your job title has been changed to [custom_job_title].") + //If desired, add records. if(records) GLOB.data_core.manifest_inject(new_character) diff --git a/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx b/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx index 83a255898d..e00d47a0ba 100644 --- a/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx +++ b/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx @@ -48,6 +48,9 @@ export const ControlAbilities = (props) => { + ); }; diff --git a/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlMedical.tsx b/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlMedical.tsx index 736c80963f..4a17091b15 100644 --- a/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlMedical.tsx +++ b/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlMedical.tsx @@ -6,6 +6,9 @@ export const ControlMedical = (props) => { return (
+ diff --git a/vorestation.dme b/vorestation.dme index c038de99cf..0d83ceeff6 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2054,6 +2054,7 @@ #include "code\modules\admin\create_object.dm" #include "code\modules\admin\create_turf.dm" #include "code\modules\admin\fix_player_notes_listing.dm" +#include "code\modules\admin\health_scan.dm" #include "code\modules\admin\holder2.dm" #include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\map_capture.dm"