diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index a4c9164ccd4..fb69e500e4b 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -1,9 +1,13 @@ #define IV_TAKING 0 #define IV_INJECTING 1 + +#define MIN_IV_TRANSFER_RATE 0.1 +#define MAX_IV_TRANSFER_RATE 5 + ///Universal IV that can drain blood or feed reagents over a period of time from or to a replaceable container /obj/machinery/iv_drip name = "\improper IV drip" - desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. Right-Click to change the transfer rate." + desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are injected at twice the displayed rate. Right-Click to detach the IV or the attached container. Alt-Click to change the transfer rate to the maximum possible." icon = 'icons/obj/iv_drip.dmi' icon_state = "iv_drip" base_icon_state = "iv_drip" @@ -14,7 +18,7 @@ ///Are we donating or injecting? var/mode = IV_INJECTING ///whether we feed slower - var/dripfeed = FALSE + var/transfer_rate = MAX_IV_TRANSFER_RATE ///Internal beaker var/obj/item/reagent_container ///Set false to block beaker use and instead use an internal reagent holder @@ -24,6 +28,8 @@ /obj/item/reagent_containers/food, /obj/item/reagent_containers/glass, /obj/item/reagent_containers/chem_pack)) + // If the blood draining tab should be greyed out + var/inject_only = FALSE /obj/machinery/iv_drip/Initialize(mapload) . = ..() @@ -36,6 +42,43 @@ QDEL_NULL(reagent_container) return ..() +/obj/machinery/iv_drip/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "IVDrip") + ui.open() + +/obj/machinery/iv_drip/ui_data(mob/user) + var/list/data = list() + data["transferRate"] = transfer_rate + data["injectOnly"] = inject_only ? TRUE : FALSE + data["maxInjectRate"] = MAX_IV_TRANSFER_RATE + data["minInjectRate"] = MIN_IV_TRANSFER_RATE + data["mode"] = mode == IV_INJECTING ? TRUE : FALSE + data["connected"] = attached ? TRUE : FALSE + data["beakerAttached"] = reagent_container ? TRUE : FALSE + data["useInternalStorage"] = use_internal_storage + return data + +/obj/machinery/iv_drip/ui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("changeMode") + toggle_mode() + . = TRUE + if("eject") + eject_beaker() + . = TRUE + if("changeRate") + var/target_rate = params["rate"] + if(text2num(target_rate) != null) + target_rate = text2num(target_rate) + transfer_rate = round(clamp(target_rate, MIN_IV_TRANSFER_RATE, MAX_IV_TRANSFER_RATE), 0.1) + . = TRUE + update_appearance() + /obj/machinery/iv_drip/update_icon_state() if(attached) icon_state = "[base_icon_state]_[mode ? "injecting" : "donating"]" @@ -139,13 +182,11 @@ // Give blood if(mode) if(target_reagents.total_volume) - var/transfer_amount = 5 - if (dripfeed) - transfer_amount = 1 + var/real_transfer_amount = transfer_rate if(istype(reagent_container, /obj/item/reagent_containers/blood)) // speed up transfer on blood packs - transfer_amount *= 2 - target_reagents.trans_to(attached, transfer_amount * delta_time * 0.5, methods = INJECT, show_message = FALSE) //make reagents reacts, but don't spam messages + real_transfer_amount *= 2 + target_reagents.trans_to(attached, real_transfer_amount * delta_time * 0.5, methods = INJECT, show_message = FALSE) //make reagents reacts, but don't spam messages update_appearance() // Take blood @@ -166,9 +207,9 @@ attached.transfer_blood_to(target, amount) update_appearance() -/obj/machinery/iv_drip/attack_hand(mob/user, list/modifiers) +/obj/machinery/iv_drip/attack_hand_secondary(mob/user, list/modifiers) . = ..() - if(.) + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return if(!ishuman(user)) return @@ -180,20 +221,14 @@ eject_beaker(user) else toggle_mode() - -/obj/machinery/iv_drip/attack_hand_secondary(mob/user, modifiers) - . = ..() - if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) - return - - if(dripfeed) - dripfeed = FALSE - to_chat(usr, span_notice("You loosen the valve to speed up the [src].")) - else - dripfeed = TRUE - to_chat(usr, span_notice("You tighten the valve to slowly drip-feed the contents of [src].")) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN +/obj/machinery/iv_drip/AltClick(mob/user) + if(can_interact(user)) + transfer_rate = MAX_IV_TRANSFER_RATE + to_chat(usr, span_notice("You set the transfer rate to [transfer_rate] units per metabolism cycle to speed up the [src].")) + return ..() + ///called when an IV is attached /obj/machinery/iv_drip/proc/attach_iv(mob/living/target, mob/user) user.visible_message(span_warning("[usr] begins attaching [src] to [target]..."), span_warning("You begin attaching [src] to [target].")) @@ -232,6 +267,9 @@ if(usr.incapacitated()) return if(reagent_container) + if(attached) + visible_message(span_warning("[attached] is detached from [src].")) + detach_iv() reagent_container.forceMove(drop_location()) reagent_container = null update_appearance() @@ -278,6 +316,7 @@ icon_state = "saline" base_icon_state = "saline" density = TRUE + inject_only = TRUE /obj/machinery/iv_drip/saline/Initialize(mapload) . = ..() @@ -320,3 +359,6 @@ #undef IV_TAKING #undef IV_INJECTING + +#undef MIN_IV_TRANSFER_RATE +#undef MAX_IV_TRANSFER_RATE diff --git a/tgui/packages/tgui/interfaces/IVDrip.js b/tgui/packages/tgui/interfaces/IVDrip.js new file mode 100644 index 00000000000..c8bcfacdaf5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/IVDrip.js @@ -0,0 +1,63 @@ +import { useBackend } from '../backend'; +import { Box, Button, NumberInput, LabeledList, Section } from '../components'; +import { Window } from '../layouts'; + +export const IVDrip = (props, context) => { + const { act, data } = useBackend(context); + const { + transferRate, + injectOnly, + maxInjectRate, + minInjectRate, + mode, + connected, + beakerAttached, + useInternalStorage, + } = data; + return ( + + +
+ + + {connected ? "Connected" : "Not Connected"} + + +
+
+ + + act('changeRate', { + rate: value, + })} + /> + + +
+
+
+ ); +};