From 9fb6c2f3a3607e26645b879bbd3508c18ac120d7 Mon Sep 17 00:00:00 2001 From: Fermi <> Date: Tue, 19 Nov 2019 12:22:53 +0000 Subject: [PATCH] Okay I gotta hop --- code/game/machinery/fersi.dm | 268 ++++++++++++++++++ .../reagent_containers/sleeper_buffer.dm | 10 + tgui/src/interfaces/fersi.ract | 57 ++++ 3 files changed, 335 insertions(+) create mode 100644 code/game/machinery/fersi.dm create mode 100644 code/modules/reagents/reagent_containers/sleeper_buffer.dm create mode 100644 tgui/src/interfaces/fersi.ract diff --git a/code/game/machinery/fersi.dm b/code/game/machinery/fersi.dm new file mode 100644 index 0000000000..938ad42cc7 --- /dev/null +++ b/code/game/machinery/fersi.dm @@ -0,0 +1,268 @@ +/obj/machinery/sleep_console + name = "sleeper console" + icon = 'icons/obj/machines/sleeper.dmi' + icon_state = "console" + density = FALSE + +/obj/machinery/sleeper + name = "sleeper" + desc = "An enclosed machine used to stabilize and heal patients." + icon = 'icons/obj/machines/sleeper.dmi' + icon_state = "sleeper" + density = FALSE + state_open = TRUE + circuit = /obj/item/circuitboard/machine/sleeper + var/efficiency = 1 + var/min_health = -25 + var/list/available_chems + var/controls_inside = FALSE + var/list/possible_chems = list( + list("epinephrine", "morphine", "salbutamol", "bicaridine", "kelotane"), + list("oculine","inacusiate"), + list("antitoxin", "mutadone", "mannitol", "pen_acid"), + list("omnizine") + ) + var/list/chem_buttons //Used when emagged to scramble which chem is used, eg: antitoxin -> morphine + var/scrambled_chems = FALSE //Are chem buttons scrambled? used as a warning + var/enter_message = "You feel cool air surround you. You go numb as your senses turn inward." + +/obj/machinery/sleeper/Initialize() + . = ..() + create_reagents(300) + occupant_typecache = GLOB.typecache_living + update_icon() + reset_chem_buttons() + add_inital_chems() + +/obj/machinery/sleeper/RefreshParts() + var/E + for(var/obj/item/stock_parts/matter_bin/B in component_parts) + E += B.rating + var/I + for(var/obj/item/stock_parts/manipulator/M in component_parts) + I += M.rating + + efficiency = initial(efficiency)* E + min_health = initial(min_health) - (10*(E-1)) // CIT CHANGE - changes min health equation to be min_health - (matterbin rating * 10) + available_chems = list() + for(var/i in 1 to I) + available_chems |= possible_chems[i] + reset_chem_buttons() + + //Total container size 300 - 1200u + reagents.maximum_volume = (300*E) + +/obj/machinery/sleeper/update_icon() + icon_state = initial(icon_state) + if(state_open) + icon_state += "-open" + +/obj/machinery/sleeper/container_resist(mob/living/user) + visible_message("[occupant] emerges from [src]!", + "You climb out of [src]!") + open_machine() + +/obj/machinery/sleeper/Exited(atom/movable/user) + if (!state_open && user == occupant) + container_resist(user) + +/obj/machinery/sleeper/relaymove(mob/user) + if (!state_open) + container_resist(user) + +/obj/machinery/sleeper/open_machine() + if(!state_open && !panel_open) + ..() + +/obj/machinery/sleeper/close_machine(mob/user) + if((isnull(user) || istype(user)) && state_open && !panel_open) + ..(user) + var/mob/living/mob_occupant = occupant + if(mob_occupant && mob_occupant.stat != DEAD) + to_chat(occupant, "[enter_message]") + +/obj/machinery/sleeper/emp_act(severity) + . = ..() + if (. & EMP_PROTECT_SELF) + return + if(is_operational() && occupant) + var/datum/reagent/R = pick(reagents.reagent_list) + inject_chem(R.id, occupant) + open_machine() + + +/obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) + return + close_machine(target) + +/obj/machinery/sleeper/screwdriver_act(mob/living/user, obj/item/I) + . = TRUE + if(..()) + return + if(occupant) + to_chat(user, "[src] is currently occupied!") + return + if(state_open) + to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!") + return + if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I)) + return + return FALSE + +/obj/machinery/sleeper/wrench_act(mob/living/user, obj/item/I) + . = ..() + if(default_change_direction_wrench(user, I)) + return TRUE + +/obj/machinery/sleeper/crowbar_act(mob/living/user, obj/item/I) + . = ..() + if(default_pry_open(I)) + return TRUE + if(default_deconstruction_crowbar(I)) + return TRUE + +/obj/machinery/sleeper/default_pry_open(obj/item/I) //wew + . = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR + if(.) + I.play_tool_sound(src, 50) + visible_message("[usr] pries open [src].", "You pry open [src].") + open_machine() + +/obj/machinery/sleeper/AltClick(mob/user) + if(!user.canUseTopic(src, !issilicon(user))) + return + if(state_open) + close_machine() + else + open_machine() + +/obj/machinery/sleeper/examine(mob/user) + ..() + to_chat(user, "Alt-click [src] to [state_open ? "close" : "open"] it.") + +/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) + + if(controls_inside && state == GLOB.notcontained_state) + state = GLOB.default_state // If it has a set of controls on the inside, make it actually controllable by the mob in it. + + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "fersi", name, 375, 650, master_ui, state) + ui.open() + +/obj/machinery/sleeper/ui_data() + var/list/data = list() + data["occupied"] = occupant ? 1 : 0 + data["open"] = state_open + + data["chems"] = list() + for(var/chem in reagents.reagent_list) + var/datum/reagent/R = GLOB.chemical_reagents_list[chem] + data["chems"] += list(list("name" = R.name, "id" = R.id, "allowed" = chem_allowed(chem))) + + data["occupant"] = list() + var/mob/living/mob_occupant = occupant + if(mob_occupant) + data["occupant"]["name"] = mob_occupant.name + switch(mob_occupant.stat) + if(CONSCIOUS) + data["occupant"]["stat"] = "Conscious" + data["occupant"]["statstate"] = "good" + if(SOFT_CRIT) + data["occupant"]["stat"] = "Conscious" + data["occupant"]["statstate"] = "average" + if(UNCONSCIOUS) + data["occupant"]["stat"] = "Unconscious" + data["occupant"]["statstate"] = "average" + if(DEAD) + data["occupant"]["stat"] = "Dead" + data["occupant"]["statstate"] = "bad" + data["occupant"]["health"] = mob_occupant.health + data["occupant"]["maxHealth"] = mob_occupant.maxHealth + data["occupant"]["minHealth"] = HEALTH_THRESHOLD_DEAD + data["occupant"]["bruteLoss"] = mob_occupant.getBruteLoss() + data["occupant"]["oxyLoss"] = mob_occupant.getOxyLoss() + data["occupant"]["toxLoss"] = mob_occupant.getToxLoss() + data["occupant"]["fireLoss"] = mob_occupant.getFireLoss() + data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss() + data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN) + data["occupant"]["reagents"] = list() + if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len) + for(var/datum/reagent/R in mob_occupant.reagents.reagent_list) + data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume)) + if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner. + var/mob/living/carbon/C = mob_occupant + var/blood_id = C.get_blood_id() + if(blood_id) + data["occupant"]["blood"] = list() // We can start populating this list. + var/blood_type = C.dna.blood_type + if(blood_id != "blood") // special blood substance + var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id] + if(R) + blood_type = R.name + else + blood_type = blood_id + data["occupant"]["blood"]["maxBloodVolume"] = (BLOOD_VOLUME_NORMAL*C.blood_ratio) + data["occupant"]["blood"]["currentBloodVolume"] = C.blood_volume + data["occupant"]["blood"]["dangerBloodVolume"] = BLOOD_VOLUME_SAFE + data["occupant"]["blood"]["bloodType"] = blood_type + return data + +/obj/machinery/sleeper/ui_act(action, params) + if(..()) + return + var/mob/living/mob_occupant = occupant + + switch(action) + if("door") + if(state_open) + close_machine() + else + open_machine() + . = TRUE + if("inject") + var/chem = params["chem"] + if(!is_operational() || !mob_occupant) + return + if(mob_occupant.health < min_health && chem != "epinephrine") + return + if(inject_chem(chem, usr)) + . = TRUE + if(scrambled_chems && prob(5)) + to_chat(usr, "Chemical system re-route detected, results may not be as expected!") + +/obj/machinery/sleeper/emag_act(mob/user) + . = ..() + scramble_chem_buttons() + to_chat(user, "You scramble the sleeper's user interface!") + return TRUE + +//trans to +/obj/machinery/sleeper/proc/inject_chem(chem, mob/user) + if((chem in available_chems) && chem_allowed(chem)) + occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU + if(user) + log_combat(user, occupant, "injected [chem] into", addition = "via [src]") + return TRUE + +/obj/machinery/sleeper/proc/chem_allowed(chem) + var/mob/living/mob_occupant = occupant + if(!mob_occupant || !mob_occupant.reagents) + return + var/amount = mob_occupant.reagents.get_reagent_amount(chem) + 10 <= 20 * efficiency + var/occ_health = mob_occupant.health > min_health || chem == "epinephrine" + return amount && occ_health + +/obj/machinery/sleeper/proc/reset_chem_buttons() + scrambled_chems = FALSE + LAZYINITLIST(chem_buttons) + for(var/chem in available_chems) + chem_buttons[chem] = chem + +/obj/machinery/sleeper/proc/scramble_chem_buttons() + scrambled_chems = TRUE + var/list/av_chem = available_chems.Copy() + for(var/chem in av_chem) + chem_buttons[chem] = pick_n_take(av_chem) //no dupes, allow for random buttons to still be correct diff --git a/code/modules/reagents/reagent_containers/sleeper_buffer.dm b/code/modules/reagents/reagent_containers/sleeper_buffer.dm new file mode 100644 index 0000000000..dfbb162aef --- /dev/null +++ b/code/modules/reagents/reagent_containers/sleeper_buffer.dm @@ -0,0 +1,10 @@ +//Created if a sleeper is deconstructed, to contain the reagents within it. +/obj/item/reagent_containers/sleeper_buffer + name = "Sleeper buffer container" + desc = "A closed container for insertion in the Medical Sleepers." + volume = 1200 + reagent_flags = OPENCONTAINER + spillable = TRUE + resistance_flags = ACID_PROOF + amount_per_transfer_from_this = 0 + possible_transfer_amounts = list(0) diff --git a/tgui/src/interfaces/fersi.ract b/tgui/src/interfaces/fersi.ract new file mode 100644 index 0000000000..3d50d7e364 --- /dev/null +++ b/tgui/src/interfaces/fersi.ract @@ -0,0 +1,57 @@ + + + {{data.occupant.name ? data.occupant.name : "No Occupant"}} + + {{#if data.occupied}} + + {{data.occupant.stat}} + + + {{Math.round(adata.occupant.health)}} + + {{#each [{label: "Brute", type: "bruteLoss"}, {label: "Respiratory", type: "oxyLoss"}, {label: "Toxin", type: "toxLoss"}, {label: "Burn", type: "fireLoss"}]}} + + {{Math.round(adata.occupant[type])}} + + {{/each}} + {{#if data.occupant.blood}} + + + {{& data.occupant.blood.currentBloodVolume <= data.occupant.blood.dangerBloodVolume ? "LOW" : "OK"}} - {{Math.round(data.occupant.blood.currentBloodVolume)}} cl + + + {{data.occupant.blood.bloodType}} + + + {{/if}} + + {{data.occupant.cloneLoss ? "Damaged" : "Healthy"}} + + + {{data.occupant.brainLoss ? "Abnormal" : "Healthy"}} + + + {{#each adata.occupant.reagents}} + {{Math.fixed(volume, 1)}} units of {{name}}
+ {{else}} + Pure + {{/each}} +
+ {{/if}} +
+ + + {{data.open ? "Open" : "Closed"}} + + + {{#each data.chems}} + {{name}} + {{if adata.partRating > 3}} + 1 + {{if adata.partRating > 2}} + 5 + 10
+ {{/each}} +
+