From 4e231e5bfac6c00687e5bea2a6076059a5667a59 Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 31 Oct 2015 00:57:43 +0200 Subject: [PATCH] Life Support Enabled Operating Table - Initial Commit Adds an advanced surgery table which enables you to keep a patient alive, even if they're lacking a heart. Also includes changes to the operating computer, making it run off of NanoUI, and makes both the advanced and normal surgery tables constructable with materials from RnD and the medical bay. The advanced surgery table will require cryogenic freezing fluids to keep in operation, so either cryoxadone or clonexadone will work (though clonexadone will last you longer). You also have the capacity to add an air tank to the machinery and a bloodbag. The operation of both can be automated. The internals will be toggled as soon as you enable life support, and the blood bag will be connected if a patient is below 90% bloodlevel, if the respective systems are made to be automatic. Both can also be manually enabled and disabled. ---- To construct a surgery table, you will require: * Circuit Board (Operating Table) - Biotech 2, Data theory 1 * Cable Coil * Capacitor * Health Analyzer To construct an advanced surgery table, you will require: * Circuit Board (Life Support Enabled Operating Table) - Biotech 4, Data theory 3 * Cable Coil * Capacitor * Health Analyzer * Beaker (internal chemical store size dependant on beaker used) * Advanced Sensor Module Simple add them to a machine frame, as you would with any other machinery item. ---- A short list of to-dos remains: * Sprites * Investigate brain transplants/removal * Emagged features --- aurora.dme | 1 + code/game/machinery/OpTable.dm | 71 +++- code/game/machinery/OpTable_LifeSupport.dm | 380 +++++++++++++++++++++ code/game/machinery/computer/Operating.dm | 144 +++++--- code/game/machinery/constructable_frame.dm | 26 +- code/modules/organs/blood.dm | 23 +- code/modules/organs/organ_internal.dm | 22 +- nano/templates/operating_computer.tmpl | 224 ++++++++++++ 8 files changed, 820 insertions(+), 71 deletions(-) create mode 100644 code/game/machinery/OpTable_LifeSupport.dm create mode 100644 nano/templates/operating_computer.tmpl diff --git a/aurora.dme b/aurora.dme index e37f87e6..d4f427f5 100644 --- a/aurora.dme +++ b/aurora.dme @@ -388,6 +388,7 @@ #include "code\game\machinery\navbeacon.dm" #include "code\game\machinery\newscaster.dm" #include "code\game\machinery\OpTable.dm" +#include "code\game\machinery\OpTable_LifeSupport.dm" #include "code\game\machinery\overview.dm" #include "code\game\machinery\portable_turret.dm" #include "code\game\machinery\recharger.dm" diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index c73cd13b..55ab6d7d 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -2,7 +2,7 @@ name = "Operating Table" desc = "Used for advanced medical procedures." icon = 'icons/obj/surgery.dmi' - icon_state = "table2-idle" + icon_state = "table2" density = 1 anchored = 1.0 use_power = 1 @@ -10,18 +10,24 @@ active_power_usage = 5 var/mob/living/carbon/human/victim = null var/strapped = 0.0 + var/opened = 0 var/obj/machinery/computer/operating/computer = null /obj/machinery/optable/New() ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/optable(src) + component_parts += new /obj/item/weapon/cable_coil(src) + component_parts += new /obj/item/weapon/stock_parts/console_screen(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/device/healthanalyzer(src) + for(dir in list(NORTH,EAST,SOUTH,WEST)) computer = locate(/obj/machinery/computer/operating, get_step(src, dir)) if (computer) computer.table = src break -// spawn(100) //Wont the MC just call this process() before and at the 10 second mark anyway? -// process() /obj/machinery/optable/ex_act(severity) @@ -89,10 +95,10 @@ var/mob/living/carbon/human/M = locate(/mob/living/carbon/human, src.loc) if(M.lying) src.victim = M - icon_state = M.pulse ? "table2-active" : "table2-idle" + icon_state = M.pulse ? "[initial(icon_state)]-active" : "[initial(icon_state)]-idle" return 1 src.victim = null - icon_state = "table2-idle" + icon_state = "[initial(icon_state)]-idle" return 0 /obj/machinery/optable/process() @@ -103,20 +109,15 @@ user.visible_message("[user] climbs on the operating table.","You climb on the operating table.") else visible_message("\red [C] has been laid on the operating table by [user].", 3) - if (C.client) - C.client.perspective = EYE_PERSPECTIVE - C.client.eye = src C.resting = 1 C.loc = src.loc - for(var/obj/O in src) - O.loc = src.loc src.add_fingerprint(user) if(ishuman(C)) var/mob/living/carbon/human/H = C src.victim = H - icon_state = H.pulse ? "table2-active" : "table2-idle" + icon_state = H.pulse ? "[initial(icon_state)]-active" : "[initial(icon_state)]-idle" else - icon_state = "table2-idle" + icon_state = "[initial(icon_state)]-idle" /obj/machinery/optable/verb/climb_on() set name = "Climb On Table" @@ -126,15 +127,56 @@ if(usr.stat || !ishuman(usr) || usr.restrained() || !check_table(usr)) return + if (opened) + return + take_victim(usr,usr) /obj/machinery/optable/attackby(obj/item/weapon/W as obj, mob/living/carbon/user as mob) + if (opened) + if (istype(W, /obj/item/weapon/crowbar)) + playsound(loc, 'sound/items/Crowbar.ogg') + var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(src.loc) + M.state = 2 + M.icon_state = "box_1" + for(var/obj/I in component_parts) + msg_scopes("Why are we in this loop?") + if(istype(I, /obj/item/weapon/reagent_containers/glass/beaker)) + reagents.trans_to(I, reagents.total_volume) + if(I.reliability != 100 && crit_fail) + I.crit_fail = 1 + I.loc = src.loc + del(src) + return 1 + if (istype(W, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = W if(iscarbon(G.affecting) && check_table(G.affecting)) take_victim(G.affecting,usr) del(W) - return + return 1 + + if (!victim) + if (istype(W, /obj/item/weapon/screwdriver)) + switch (opened) + if (0) + opened = 1 + if (computer) + computer.table = null + computer = null + icon_state = "[initial(icon_state)]-open" + user << "You open the maintenance hatch of [src]." + return 1 + if (1) + opened = 0 + for(dir in list(NORTH,EAST,SOUTH,WEST)) + computer = locate(/obj/machinery/computer/operating, get_step(src, dir)) + if (computer) + computer.table = src + break + icon_state = "[initial(icon_state)]-idle" + user << "You close the maintenance hatch of [src]." + return 1 /obj/machinery/optable/proc/check_table(mob/living/carbon/patient as mob) if(src.victim) @@ -146,3 +188,6 @@ return 0 return 1 + +/obj/machinery/optable/proc/onlifesupport() + return 0 diff --git a/code/game/machinery/OpTable_LifeSupport.dm b/code/game/machinery/OpTable_LifeSupport.dm new file mode 100644 index 00000000..72cafdd2 --- /dev/null +++ b/code/game/machinery/OpTable_LifeSupport.dm @@ -0,0 +1,380 @@ +#define AUTO_TRANSFUSE 1 +#define AUTO_AIR 2 +#define TRANSFUSE_ACTIVE 4 +#define AIR_ACTIVE 8 + +/* + * The more advanced life support table + */ +/obj/machinery/optable/lifesupport + name = "Life Support Enabled Operating Table" + desc = "A more advanced version of the standard operating table." + icon_state = "table2" + flags = OPENCONTAINER + idle_power_usage = 3 + active_power_usage = 8 + + var/movable = 0 //For buckling! + var/buckled = 0 //Is the patient hooked up to the machine properly? + var/active = 0 //Is the machine active, and providing lifesupport? + var/activeoverlay //Stores an overlay to be added/removed, depending on that machine's status. + var/program = 0 //Bitfield for containing the programmable settings. + var/obj/item/weapon/reagent_containers/blood/bloodbag //Stores the bloodbag that you can add to the machine, for IV dripping shenanigans. + var/obj/item/weapon/tank/airsupply //Stores the airtank used for anesthesia. + var/obj/item/clothing/mask/breath/medical/airmask //Stores the medical mask used for anesthesia. + var/requiredchems = list( + "clonexadone" = 0.06, + "cryoxadone" = 0.2) //Details what chemicals (use ids, not names) it keeps track of, and the minimum quantities required for operation. Each time process() is called, the associated amount of that chemical is removed from storage. + //Cryoxadone will last you around 10 minutes, Clonexadone around 30. (Provided you use the standard, 60 unit beaker.) + +/obj/machinery/optable/lifesupport/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/optable_lifesupport(src) + component_parts += new /obj/item/weapon/cable_coil(src) + component_parts += new /obj/item/weapon/stock_parts/console_screen(src) + component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + component_parts += new /obj/item/device/healthanalyzer(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module/adv(src) + component_parts += new /obj/item/clothing/mask/breath/medical(src) + RefreshParts() + + var/image/i = image('icons/obj/surgery.dmi', icon_state = "table-lifesupport-disabledoverlay") + activeoverlay = i + overlays += activeoverlay + +/obj/machinery/optable/lifesupport/attackby(obj/item/weapon/W as obj, mob/living/carbon/user as mob) + . = ..() + if (.) + return + + if (istype(W, /obj/item/weapon/reagent_containers/blood)) + if (!bloodbag) + user.drop_item() + bloodbag = W + W.loc = src + user << "You load [W] into [src], and hook it up to the machine." + return + else + user << "There is already a bloodbag in [src]!" + return + + if (W.is_open_container()) + return 0 + + if (istype(W, /obj/item/weapon/tank)) + if (!airsupply) + user.drop_item() + airsupply = W + W.loc = src + user << "You load [W] into [src], and hook it up the machine." + return + else + user << "There is already [airsupply] in [src]!" + return + +/obj/machinery/optable/lifesupport/process() + ..() + + if (active) + if ((stat & NOPOWER) || (stat & BROKEN)) + //Safety catch number 2: immediate failure of life support, upon power failure or machine damage. + toggleactive(1) + return + + //A safety catch. + if (!victim || !buckled) + toggleactive() + if (program & TRANSFUSE_ACTIVE) + toggleprogram(TRANSFUSE_ACTIVE) + if (program & AIR_ACTIVE) + toggleprogram(AIR_ACTIVE) + return + + var/id = checkrequiredchems() + if (!id) + toggleactive(1) + return + else + reagents.remove_reagent(id, requiredchems[id]) + + var/bloodvolume = round(victim.vessel.get_reagent_amount("blood")) + if ((program & AUTO_TRANSFUSE) && bloodbag && bloodbag.reagents.total_volume) + if (bloodvolume < BLOOD_VOLUME_SAFE && !(program & TRANSFUSE_ACTIVE)) + toggleprogram(TRANSFUSE_ACTIVE) + else if (bloodvolume >= BLOOD_VOLUME_SAFE && (program & TRANSFUSE_ACTIVE)) + toggleprogram(TRANSFUSE_ACTIVE) + + if (program & TRANSFUSE_ACTIVE) + if (!bloodbag || !bloodbag.reagents.total_volume) + toggleprogram(TRANSFUSE_ACTIVE) + else + bloodbag.reagents.trans_to(victim, 4) + + if ((program & AUTO_AIR) && airsupply && airsupply.air_contents.return_pressure() > 10) + if (!(program & AIR_ACTIVE)) + toggleprogram(AIR_ACTIVE) + + if ((program & AIR_ACTIVE) && (!airsupply || airsupply.air_contents.return_pressure() < 10)) + toggleprogram(AIR_ACTIVE) + +/obj/machinery/optable/lifesupport/check_table(mob/living/carbon/patient as mob) + if (victim) + usr << "\blue The table is already occupied!" + return 0 + + return 1 + +/obj/machinery/optable/lifesupport/onlifesupport() + return active + +/obj/machinery/optable/lifesupport/RefreshParts() + var/T = 0 + for (var/obj/item/weapon/reagent_containers/glass/G in component_parts) + T += G.reagents.maximum_volume + var/datum/reagents/R = new/datum/reagents(T) //Holder for the reagents used as materials. + reagents = R + R.my_atom = src + for (var/obj/item/clothing/mask/breath/medical/E in component_parts) + airmask = E + +/obj/machinery/optable/lifesupport/proc/broadcastalert(var/message as text) + playsound(loc, 'sound/machines/chime.ogg', 75, 1) + visible_message("\icon[src]The Operating Table pings: [message]") + +/obj/machinery/optable/lifesupport/proc/checkrequiredchems() + for (var/id in requiredchems) + if (reagents.has_reagent(id, requiredchems[id])) + return id + + return 0 + +/obj/machinery/optable/lifesupport/proc/eject(var/item as text) + switch (item) + if ("airsupply") + if (airsupply) + if (program & AIR_ACTIVE) + broadcastalert("ERROR: Internal air supply still connected. Aborting!") + return + else + airsupply.loc = loc + airsupply = null + broadcastalert("Internal air supply ejected.") + return + if ("bloodbag") + if (bloodbag) + if (program & TRANSFUSE_ACTIVE) + broadcastalert("ERROR: Transfusion processes still underway. Aborting!") + return + else + bloodbag.loc = loc + bloodbag = null + broadcastalert("Internal bloodsupply ejected.") + return + if ("chems") + if (reagents.total_volume) + if (active) + broadcastalert("ERROR: Lifesupport systems enabled, unable to flush chemicals. Aborting!") + return + else + broadcastalert("Stored chemicals flushed.") + reagents.clear_reagents() + +/obj/machinery/optable/lifesupport/proc/buckle(mob/living/carbon/human/patient as mob, mob/living/carbon/human/user as mob) + if (!victim) + user << "No patient to buckle in!" + return + + if (patient == user) + user << "You cannot do this yourself!" + return + + if (active) + user << "You cannot do this while lifesupport is enabled!" + return + + if (!buckled) + if (patient.wear_mask) + user << "You need to remove their [patient.wear_mask] first!" + return + else if (patient.back) + user << "You need to remove their [patient.back] first!" + return + + switch (buckled) + if (0) + user.visible_message("[user] buckles \the [victim] into \the [src], linking them up to the required tubing and straps.", "You fit \the [victim] into \the [src]'s restraints, and hook them up to the life-support machine.") + if (!patient.sleeping && !patient.stat) + patient << "[user] buckles you into \the [src] and hooks you up to the lifesupport machinery." + buckled = 1 + patient.buckled = src + patient.update_canmove() + patient.equip_to_slot(airmask, slot_wear_mask) + return + if (1) + user.visible_message("[user] unbuckles \the [victim] from \the [src], disconnecting them from the tubing and straps.", "You remove \the [victim]'s restraints, and unhook them from the life-support machine.") + if (!patient.sleeping && !patient.stat) + patient << "[user] unbuckles you from \the [src] and disconnects you from the lifesupport machinery." + buckled = 0 + patient.buckled = null + patient.anchored = initial(patient.anchored) + patient.update_canmove() + patient.u_equip(airmask) + airmask.loc = src + return + +/obj/machinery/optable/lifesupport/verb/bucklepatient() + set name = "Buckle Patient In" + set category = "Object" + set src in oview(1) + + if(usr.stat || !ishuman(usr) || usr.restrained()) + return + + buckle(victim, usr) + +/obj/machinery/optable/lifesupport/proc/toggleactive(var/override = 0) + if (!victim) + broadcastalert("ERROR: No patient detected. Aborting!") + return + + if (!buckled) + broadcastalert("ERROR: Patient not linked to the machinery. Aborting!") + return + + switch (active) + if (0) + if (stat & BROKEN) + broadcastalert("ERROR: Machine damaged. Aborting!") + return + + if (stat & NOPOWER) + broadcastalert("ERROR: Machine not powered. Aborting!") + return + + if (victim.stat == DEAD) + broadcastalert("ERROR: No lifesigns detected from the patient. Unable to enable lifesupport systems.") + return + + if (checkrequiredchems()) + if (activeoverlay) + overlays -= activeoverlay + activeoverlay = null + var/image/i = image('icons/obj/surgery.dmi', icon_state = "table-lifesupport-activeoverlay") + activeoverlay = i + overlays += activeoverlay + active = 1 + broadcastalert("Patient detected. Lifesupport systems enabled.") + return + else + broadcastalert("ERROR: Required chemicals not detected in the machine. Aborting!") + return + if (1) + if ((program & AUTO_TRANSFUSE) && (program & TRANSFUSE_ACTIVE)) + toggleprogram(TRANSFUSE_ACTIVE) + else if (program & TRANSFUSE_ACTIVE) + if (!override) + broadcastalert("ERROR: Transfusion processes still underway. Aborting!") + return + else + toggleprogram(TRANSFUSE_ACTIVE) + + if ((program & AUTO_AIR) && (program & AIR_ACTIVE)) + toggleprogram(AIR_ACTIVE) + else if (program & AIR_ACTIVE) + if (!override) + broadcastalert("ERROR: Internal air supply still connected. Aborting!") + return + else + toggleprogram(AIR_ACTIVE) + + if (activeoverlay) + overlays -= activeoverlay + activeoverlay = null + var/image/i = image('icons/obj/surgery.dmi', icon_state = "table-lifesupport-disabledoverlay") + activeoverlay = i + overlays += activeoverlay + active = 0 + + if (override) + broadcastalert("ERROR: Not enough chemicals to sustain lifesupport functionality! Shutting down lifesupport systems!") + else + broadcastalert("Lifesupport systems disabled.") + + return + +/obj/machinery/optable/lifesupport/proc/toggleprogram(setting, var/textsetting = null) + if (textsetting) + switch (textsetting) + if ("AUTO_TRANSFUSE") + setting = AUTO_TRANSFUSE + if ("AUTO_AIR") + setting = AUTO_AIR + if ("TRANSFUSE_ACTIVE") + setting = TRANSFUSE_ACTIVE + if ("AIR_ACTIVE") + setting = AIR_ACTIVE + + if (program & setting) + switch (setting) + if (TRANSFUSE_ACTIVE) + broadcastalert("Transfusion processes deactivated.") + program &= ~setting + return + if (AIR_ACTIVE) + victim.u_equip(airsupply) + airsupply.loc = src + if (victim.internals) + victim.internals.icon_state = "internal0" + broadcastalert("Internal air supply deactivated.") + program &= ~setting + return + else + program &= ~setting + else + switch (setting) + if (TRANSFUSE_ACTIVE) + if (bloodbag && bloodbag.reagents.total_volume) + broadcastalert("Transfusion processes activated.") + program |= setting + return + else + broadcastalert("Bloodbag empty or not connected!") + return + if (AIR_ACTIVE) + if (airsupply && airsupply.air_contents.return_pressure() > 10) + victim.equip_to_slot(airsupply, slot_back) + victim.internal = airsupply + if (victim.internals) + victim.internals.icon_state = "internal1" + broadcastalert("Internal air supply activated.") + program |= setting + return + else + broadcastalert("Air supply empty or not connected!") + return + else + program |= setting + +/obj/machinery/optable/lifesupport/proc/checkprogram(var/textsetting as text) + var/setting + switch (textsetting) + if ("AUTO_TRANSFUSE") + setting = AUTO_TRANSFUSE + if ("AUTO_AIR") + setting = AUTO_AIR + if ("TRANSFUSE_ACTIVE") + setting = TRANSFUSE_ACTIVE + if ("AIR_ACTIVE") + setting = AIR_ACTIVE + + if (program & setting) + return 1 + else + return 0 + +#undef AUTO_TRANSFUSE +#undef AUTO_AIR +#undef TRANSFUSE_ACTIVE +#undef AIR_ACTIVE diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index f7add636..3c4c4ddf 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -6,7 +6,7 @@ anchored = 1.0 icon_state = "operating" circuit = "/obj/item/weapon/circuitboard/operating" - var/mob/living/carbon/human/victim = null + interact_offline = 0 var/obj/machinery/optable/table = null /obj/machinery/computer/operating/New() @@ -28,55 +28,111 @@ add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return - interact(user) + ui_interact(user) +/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) -/obj/machinery/computer/operating/interact(mob/user) - if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) - if (!istype(user, /mob/living/silicon)) - user.unset_machine() - user << browse(null, "window=op") - return + if (user.stat) + return - user.set_machine(src) - var/dat = "Operating Computer\n" - dat += "Close

" //| Update" - if(src.table && (src.table.check_victim())) - src.victim = src.table.victim - dat += {" -Patient Information:
-
-Name: [src.victim.real_name]
-Age: [src.victim.age]
-Blood Type: [src.victim.b_type]
-
-Health: [src.victim.health]
-Brute Damage: [src.victim.getBruteLoss()]
-Toxins Damage: [src.victim.getToxLoss()]
-Fire Damage: [src.victim.getFireLoss()]
-Suffocation Damage: [src.victim.getOxyLoss()]
-Patient Status: [src.victim.stat ? "Non-Responsive" : "Stable"]
-Heartbeat rate: [victim.get_pulse(GETPULSE_TOOL)]
-"} - else - src.victim = null - dat += {" -Patient Information:
-
-No Patient Detected -"} - user << browse(dat, "window=op") - onclose(user, "op") + if (table && table.victim == user) + return + var/data[0] + + data["table"] = 0 + if (table) + if (istype(table, /obj/machinery/optable/lifesupport)) + data["table"] = 2 + else + data["table"] = 1 + + var/patientgeneral[0] + var/patienthealth[0] + if (table.victim) + var/mob/living/carbon/human/patient = table.victim + patientgeneral["Name"] = patient.real_name + patientgeneral["Age"] = patient.age + patientgeneral["BloodType"] = patient.b_type + data["patientgeneral"] = patientgeneral; + + patienthealth["Health"] = patient.health + patienthealth["Brute"] = patient.getBruteLoss() + patienthealth["Toxins"] = patient.getToxLoss() + patienthealth["Burn"] = patient.getFireLoss() + patienthealth["Suffocation"] = patient.getOxyLoss() + patienthealth["Status"] = patient.stat ? "Non-response" : "Stable" + patienthealth["Heartrate"] = patient.get_pulse(GETPULSE_TOOL) + data["patienthealth"] = patienthealth; + + if (data["table"] == 2) + var/obj/machinery/optable/lifesupport/A = table + data["buckled"] = A.buckled + data["lifesupport"] = A.onlifesupport() + + if (A.reagents.reagent_list.len) + data["hasreagents"] = 1 + var/loadedreagents[0] + for(var/datum/reagent/chem in A.reagents.reagent_list) + loadedreagents.Add(list(list("name" = chem.name, "volume" = chem.volume))) + data["loadedreagents"] = loadedreagents; + else + data["hasreagents"] = 0 + + if (A.airsupply) + data["hasair"] = 1 + var/air[0] + air["internalpressure"] = round(A.airsupply.air_contents.return_pressure()) + air["releasepressure"] = round(A.airsupply.distribute_pressure) + data["air"] = air; + else + data["hasair"] = 0 + + if (A.bloodbag) + data["hasblood"] = 1 + var/blood[0] + blood["volume"] = A.bloodbag.reagents.total_volume + if (A.bloodbag.reagents.reagent_list.len) + for (var/datum/reagent/blood/Blood in A.bloodbag.reagents.reagent_list) + blood["type"] = Blood.data["blood_type"] + else + blood["type"] = "N/A" + data["blood"] = blood; + else + data["hasblood"] = 0 + + var/program[0] + program["autotransfuse"] = A.checkprogram("AUTO_TRANSFUSE") + program["transfuseactive"] = A.checkprogram("TRANSFUSE_ACTIVE") + program["autoair"] = A.checkprogram("AUTO_AIR") + program["airactive"] = A.checkprogram("AIR_ACTIVE") + data["program"] = program; + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "operating_computer.tmpl", "Operating Computer", 540, 680) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) /obj/machinery/computer/operating/Topic(href, href_list) if(..()) return - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - return - -/obj/machinery/computer/operating/process() - if(..()) - src.updateDialog() + if (istype(table, /obj/machinery/optable/lifesupport)) + var/obj/machinery/optable/lifesupport/A = table + if (href_list["toggle_lifesupport"]) + A.toggleactive() + return 1 + if (href_list["eject_advanced"]) + A.eject(href_list["eject_advanced"]) + return 1 + if (href_list["toggle_program"]) + A.toggleprogram(null, href_list["toggle_program"]) + return 1 + return 1 diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index d8032de4..12053964 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -408,6 +408,28 @@ obj/item/weapon/circuitboard/rdserver "/obj/item/weapon/stock_parts/subspace/crystal" = 1, "/obj/item/weapon/stock_parts/micro_laser/high" = 2) +/obj/item/weapon/circuitboard/optable + name = "Circuit Board (Operating Table)" + build_path = "/obj/machinery/optable" + board_type = "machine" + origin_tech = "biotech=2;programming=1" + frame_desc = "Requires 1 Cable Coil, 1 Health Analyzer, 1 Console Screen and 1 capacitor." + req_components = list( + "/obj/item/weapon/cable_coil" = 1, + "/obj/item/weapon/stock_parts/console_screen" = 1, + "/obj/item/weapon/stock_parts/capacitor" = 1, + "/obj/item/device/healthanalyzer" = 1) - - +/obj/item/weapon/circuitboard/optable_lifesupport + name = "Circuit Board (Life Support Enable Operating Table)" + build_path = "/obj/machinery/optable/lifesupport" + board_type = "machine" + origin_tech = "biotech=4;programming=3" + frame_desc = "Requires 1 Cable Coil, 1 Health Analyzer, 1 Console Screen, 1 Advanced Capacitor, 1 Beaker, 1 Advanced Sensor Module." + req_components = list( + "/obj/item/weapon/cable_coil" = 1, + "/obj/item/weapon/stock_parts/console_screen" = 1, + "/obj/item/weapon/stock_parts/capacitor/adv" = 1, + "/obj/item/device/healthanalyzer" = 1, + "/obj/item/weapon/reagent_containers/glass/beaker" = 1, + "/obj/item/weapon/stock_parts/scanning_module/adv" = 1) diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 7c010844..a6ef98d0 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -67,14 +67,21 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 if(species && species.has_organ["heart"]) var/datum/organ/internal/heart/heart = internal_organs_by_name["heart"] - if(!heart) - blood_volume = 0 - else if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) - blood_volume *= 0.8 - else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage) - blood_volume *= 0.6 - else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY) - blood_volume *= 0.3 + // Before we do that, we check for lifesupport. + var/onlifesupport = 0 + if (buckled && istype(buckled, /obj/machinery/optable/lifesupport)) + var/obj/machinery/optable/lifesupport/A = buckled + onlifesupport = A.onlifesupport() + + if (!onlifesupport) + if(!heart) + blood_volume = 0 + else if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) + blood_volume *= 0.8 + else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage) + blood_volume *= 0.6 + else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY) + blood_volume *= 0.3 //Effects of bloodloss switch(blood_volume) diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 53f28e83..2694caeb 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -41,11 +41,16 @@ E.internal_organs |= src /datum/organ/internal/process() + //Check if we're on lifesupport, and whether or not organs should be processing. + if (owner.buckled && istype(owner.buckled, /obj/machinery/optable/lifesupport)) + var/obj/machinery/optable/lifesupport/A = owner.buckled + if (A.onlifesupport()) + return 1 //Process infections if (robotic >= 2 || (owner.species && owner.species.flags & IS_PLANT)) //TODO make robotic internal and external organs separate types of organ instead of a flag germ_level = 0 - return + return 0 if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //** Handle antibiotics and curing infections @@ -92,6 +97,8 @@ take_damage(4) owner.reagents.add_reagent("toxin", rand(3,5)) + return 0 + /datum/organ/internal/proc/take_damage(amount, var/silent=0) if(src.robotic == 2) src.damage += (amount * 0.8) @@ -152,7 +159,10 @@ removed_type = /obj/item/organ/lungs process() - ..() + . = ..() + if (.) + return + if (germ_level > INFECTION_LEVEL_ONE) if(prob(5)) owner.emote("cough") //respitory tract infection @@ -174,7 +184,9 @@ process() - ..() + . = ..() + if (.) + return if (germ_level > INFECTION_LEVEL_ONE) if(prob(1)) @@ -232,7 +244,9 @@ process() - ..() + . = ..() + if (.) + return // Coffee is really bad for you with busted kidneys. // This should probably be expanded in some way, but fucked if I know diff --git a/nano/templates/operating_computer.tmpl b/nano/templates/operating_computer.tmpl new file mode 100644 index 00000000..22b929f8 --- /dev/null +++ b/nano/templates/operating_computer.tmpl @@ -0,0 +1,224 @@ + +{{if !data.table}} +
+






No connected table detected! +
+{{else}} +
+

Patient Information:

+ + {{if data.patientgeneral && data.patienthealth}} + +
+
+ Name: +
+
+ {{:data.patientgeneral.Name}} +
+
+
+
+ Age: +
+
+ {{:data.patientgeneral.Age}} +
+
+
+
+ Blood Type: +
+
+ {{:data.patientgeneral.BloodType}} +
+
+ +
+
+ Health: +
+
+ {{:data.patienthealth.Health}} +
+
+
+
+ Brute Damage: +
+
+ {{:data.patienthealth.Brute}} +
+
+
+
+ Toxins Damage: +
+
+ {{:data.patienthealth.Toxins}} +
+
+
+
+ Burn Damage: +
+
+ {{:data.patienthealth.Burn}} +
+
+
+
+ Suffocation Damage: +
+
+ {{:data.patienthealth.Suffocation}} +
+
+
+
+ Status: +
+
+ {{:data.patienthealth.Status}} +
+
+
+
+ Heartbeat Rate: +
+
+ {{:data.patienthealth.Heartrate}} +
+
+ {{else}} +
+ No Patient Detected! +
+ {{/if}} +
+ + {{if data.table == 2}} +
+

Life Support Systems Detected

+

Machine Information:

+ +
+
+ Restraints: +
+
+ {{:data.buckled ? 'Active' : 'Inactive'}} +
+
+ +
+
+ Life Support Systems: +
+
+ {{:data.lifesupport ? 'Enabled' : 'Disabled'}} +
+
+ {{:helper.link(data.lifesupport ? 'Disable Life Support' : 'Enable Life Support', data.lifesupport ? 'close-thick' : 'check', {'toggle_lifesupport' : 1}, null, 'floatRight')}} +
+
+ +
+
+ Stored Chemicals +
+
+ {{:helper.link('Flush Chemicals', 'eject', {'eject_advanced' : 'chems'}, data.hasreagents ? null : 'disabled', 'floatRight')}} +
+
+ + {{if data.hasreagents}} +
+
+
+ {{for data.loadedreagents}} + {{:value.volume}} units of {{:value.name}}
+ {{/for}} +
+
+
+ {{else}} +
+ No chemicals stored! +
+ {{/if}} + +
+
+ Internal Air Tank +
+
+ {{:helper.link('Eject Air Tank', 'eject', {'eject_advanced' : 'airsupply'}, data.hasair ? null : 'disabled', 'floatRight')}} +
+
+ + {{if data.hasair}} +
+
+
+ Tank Internal Pressure: {{:data.air.internalpressure}} kPa
+ Tank Release Pressure: {{:data.air.releasepressure}} kPa +
+
+
+ {{else}} +
+ No air tank detected! +
+ {{/if}} + +
+
+ Internal Blood Supply +
+
+ {{:helper.link('Eject Blood Bag', 'eject', {'eject_advanced' : 'bloodbag'}, data.hasblood ? null : 'disabled', 'floatRight')}} +
+
+ + {{if data.hasblood}} +
+
+
+ Stored Volume: {{:data.blood.volume}}
+ Blood Type: {{:data.blood.type}} +
+
+
+ {{else}} +
+ No blood bag detected! +
+ {{/if}} + +

Programming Information:

+ +
+
+
Transfusion Control:
+
{{:helper.link(data.program.autotransfuse ? 'Automated' : 'Manually Controlled', 'refresh', {'toggle_program' : 'AUTO_TRANSFUSE'}, null)}}
+
+
+
Transfusion:
+
{{:helper.link(data.program.transfuseactive ? 'Activated' : 'Deactivated', 'refresh', {'toggle_program' : 'TRANSFUSE_ACTIVE'}, data.program.autotransfuse ? 'disabled' : null)}}
+
+
+
Air Control:
+
{{:helper.link(data.program.autoair ? 'Automated' : 'Manually Controlled', 'refresh', {'toggle_program' : 'AUTO_AIR'}, null)}}
+
+
+
Air Status:
+
{{:helper.link(data.program.airactive ? 'Activated' : 'Deactivated', 'refresh', {'toggle_program' : 'AIR_ACTIVE'}, data.program.autoair ? 'disabled' : null)}}
+
+
+
+ {{/if}} +{{/if}}