From 309da5fd7686bb29eeeb5b090c4ce67e5cdd14b3 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Fri, 26 Jan 2024 05:06:47 +0100 Subject: [PATCH] [MIRROR] makes air lock controllers use tgui (#26246) * makes air lock controllers use tgui (#81050) ## About The Pull Request makes air lock controllers use tgui ![image](https://github.com/tgstation/tgstation/assets/138636438/a5bba240-d0a2-4bef-b72b-3717e1a13f09) ## Why It's Good For The Game they will now use tgui instead of html ## Changelog :cl: refactor: airlock controllers now use tgui /:cl: * makes air lock controllers use tgui --------- Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> --- code/game/machinery/doors/airlock.dm | 3 - .../embedded_controller/access_controller.dm | 346 ++++++++---------- .../interfaces/AirlockButtonController.tsx | 95 +++++ 3 files changed, 248 insertions(+), 196 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/AirlockButtonController.tsx diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 1e9a363e70a..bf67684f0e1 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -308,9 +308,6 @@ for(var/obj/machinery/door/airlock/otherlock as anything in close_others) otherlock.close_others -= src close_others.Cut() - if(id_tag) - for(var/obj/machinery/door_buttons/D as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door_buttons)) - D.removeMe(src) QDEL_NULL(note) QDEL_NULL(seal) for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index 1e2287a0492..98d0ac1a02f 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -1,9 +1,3 @@ -#define CLOSING 1 -#define OPENING 2 -#define CYCLE 3 -#define CYCLE_EXTERIOR 4 -#define CYCLE_INTERIOR 5 - /obj/machinery/door_buttons power_channel = AREA_USAGE_ENVIRON use_power = IDLE_POWER_USE @@ -15,7 +9,7 @@ /obj/machinery/door_buttons/attackby(obj/O, mob/user) return attack_hand(user) -/obj/machinery/door_buttons/proc/findObjsByTag() +/obj/machinery/door_buttons/proc/find_objects_by_tag() return /obj/machinery/door_buttons/Initialize(mapload) @@ -23,7 +17,7 @@ return INITIALIZE_HINT_LATELOAD /obj/machinery/door_buttons/LateInitialize() - findObjsByTag() + find_objects_by_tag() /obj/machinery/door_buttons/emag_act(mob/user, obj/item/card/emag/emag_card) if(obj_flags & EMAGGED) @@ -35,9 +29,6 @@ balloon_alert(user, "access controller shorted") return TRUE -/obj/machinery/door_buttons/proc/removeMe() - - /obj/machinery/door_buttons/access_button icon = 'icons/obj/machines/wallmounts.dmi' // SKYRAT EDIT CHANGE - ICON OVERRIDEN BY AESTHETICS - SEE MODULE icon_state = "access_button_standby" @@ -49,14 +40,16 @@ var/obj/machinery/door_buttons/airlock_controller/controller var/busy -/obj/machinery/door_buttons/access_button/findObjsByTag() +/obj/machinery/door_buttons/access_button/find_objects_by_tag() for(var/obj/machinery/door_buttons/airlock_controller/A as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door_buttons/airlock_controller)) if(A.idSelf == idSelf) controller = A + RegisterSignal(controller, COMSIG_PREQDELETED, PROC_REF(remove_object)) break for(var/obj/machinery/door/airlock/I as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/airlock)) if(I.id_tag == idDoor) door = I + RegisterSignal(door, COMSIG_PREQDELETED, PROC_REF(remove_object)) break /obj/machinery/door_buttons/access_button/interact(mob/user) @@ -71,15 +64,15 @@ busy = TRUE update_appearance() if(door.density) - if(!controller.exteriorAirlock || !controller.interiorAirlock) - controller.onlyOpen(door) + if(!controller.exterior_airlock || !controller.interior_airlock) + controller.only_open(door) else - if(controller.exteriorAirlock.density && controller.interiorAirlock.density) - controller.onlyOpen(door) + if(controller.exterior_airlock.density && controller.interior_airlock.density) + controller.only_open(door) else - controller.cycleClose(door) + controller.cycle_close(door) else - controller.onlyClose(door) + controller.only_close(door) use_power(active_power_usage) addtimer(CALLBACK(src, PROC_REF(not_busy)), 2 SECONDS) @@ -94,218 +87,185 @@ icon_state = "[base_icon_state]_[busy ? "cycle" : "standby"]" return ..() -/obj/machinery/door_buttons/access_button/removeMe(obj/O) - if(O == door) +/obj/machinery/door_buttons/access_button/proc/remove_object(datum/source) + SIGNAL_HANDLER + + if(source == door) door = null + return + if(source == controller) + controller = null - +/obj/machinery/door_buttons/access_button/Destroy() + door = null + controller = null + return ..() /obj/machinery/door_buttons/airlock_controller + name = "access console" + desc = "A small console that can cycle opening between two airlocks." icon = 'icons/obj/machines/wallmounts.dmi' icon_state = "access_control_standby" base_icon_state = "access_control" - name = "access console" - desc = "A small console that can cycle opening between two airlocks." - interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE - var/obj/machinery/door/airlock/interiorAirlock - var/obj/machinery/door/airlock/exteriorAirlock + interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON + ///the id of the interior airlock var/idInterior + ///the id of the exterior airlock var/idExterior + ///are we currently in use? var/busy - var/lostPower + ///our interior airlock + var/obj/machinery/door/airlock/interior_airlock + ///our exterior airlock + var/obj/machinery/door/airlock/exterior_airlock -/obj/machinery/door_buttons/airlock_controller/removeMe(obj/O) - if(O == interiorAirlock) - interiorAirlock = null - else if(O == exteriorAirlock) - exteriorAirlock = null +///set our doors to null upon deletion +/obj/machinery/door_buttons/airlock_controller/proc/remove_door(datum/source) + SIGNAL_HANDLER -/obj/machinery/door_buttons/airlock_controller/Destroy() - for(var/obj/machinery/door_buttons/access_button/A as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door_buttons/access_button)) - if(A.controller == src) - A.controller = null - return ..() - -/obj/machinery/door_buttons/airlock_controller/Topic(href, href_list) - if(..()) + if(source == interior_airlock) + interior_airlock = null return - if(busy) + + if(source == exterior_airlock) + exterior_airlock = null + +///proc called when we want to open doors without any cycling involved +/obj/machinery/door_buttons/airlock_controller/proc/only_open(obj/machinery/door/airlock/target_door) + if(isnull(target_door)) return - if(!allowed(usr)) - to_chat(usr, span_warning("Access denied.")) + busy = TRUE + update_appearance() + open_door(target_door) + +///proc called when we want to close doors without any cycling involved +/obj/machinery/door_buttons/airlock_controller/proc/only_close(obj/machinery/door/airlock/target_door) + if(isnull(target_door)) return - switch(href_list["command"]) - if("close_exterior") - onlyClose(exteriorAirlock) - if("close_interior") - onlyClose(interiorAirlock) - if("cycle_exterior") - cycleClose(exteriorAirlock) - if("cycle_interior") - cycleClose(interiorAirlock) - if("open_exterior") - onlyOpen(exteriorAirlock) - if("open_interior") - onlyOpen(interiorAirlock) + busy = TRUE + close_door(target_door) -/obj/machinery/door_buttons/airlock_controller/proc/onlyOpen(obj/machinery/door/airlock/A) - if(A) - busy = CLOSING - update_appearance() - openDoor(A) - -/obj/machinery/door_buttons/airlock_controller/proc/onlyClose(obj/machinery/door/airlock/A) - if(A) - busy = CLOSING - closeDoor(A) - -/obj/machinery/door_buttons/airlock_controller/proc/closeDoor(obj/machinery/door/airlock/A) - if(A.density) - goIdle() +///proc that handles closing doors +/obj/machinery/door_buttons/airlock_controller/proc/close_door(obj/machinery/door/airlock/target_door, turn_idle_on_terminate = TRUE) + busy = TRUE + if(isnull(target_door) || target_door.density) + go_idle() return FALSE update_appearance() - A.safe = FALSE //Door crushies, manual door after all. Set every time in case someone changed it, safe doors can end up waiting forever. - A.unbolt() - if(A.close()) - if(machine_stat & NOPOWER || lostPower || !A || QDELETED(A)) - goIdle(TRUE) - return FALSE - A.bolt() - goIdle(TRUE) - return TRUE - goIdle(TRUE) - return FALSE + target_door.safe = FALSE //Door crushies, manual door after all. Set every time in case someone changed it, safe doors can end up waiting forever. + target_door.unbolt() + if(!target_door.close() || (machine_stat & NOPOWER)) + go_idle() + return FALSE + target_door?.bolt() -/obj/machinery/door_buttons/airlock_controller/proc/cycleClose(obj/machinery/door/airlock/A) - if(!A || !exteriorAirlock || !interiorAirlock) + if(turn_idle_on_terminate) + go_idle() + + return TRUE + +///proc called when we want to close doors with cycling +/obj/machinery/door_buttons/airlock_controller/proc/cycle_close(obj/machinery/door/airlock/target_door) + if(isnull(exterior_airlock) || isnull(interior_airlock)) return - if(exteriorAirlock.density == interiorAirlock.density || !A.density) + if(exterior_airlock.density == interior_airlock.density || !target_door.density) return - busy = CYCLE + busy = TRUE update_appearance() - if(A == interiorAirlock) - if(closeDoor(exteriorAirlock)) - busy = CYCLE_INTERIOR - else - if(closeDoor(interiorAirlock)) - busy = CYCLE_EXTERIOR + var/obj/machinery/door/airlock/opposite_airlock = (target_door == exterior_airlock ? interior_airlock : exterior_airlock) -/obj/machinery/door_buttons/airlock_controller/proc/cycleOpen(obj/machinery/door/airlock/A) - if(!A) - goIdle(TRUE) - if(A == exteriorAirlock) - if(interiorAirlock) - if(!interiorAirlock.density || !interiorAirlock.locked) - return - else - if(exteriorAirlock) - if(!exteriorAirlock.density || !exteriorAirlock.locked) - return - if(busy != OPENING) - busy = OPENING - openDoor(A) + if(!close_door(opposite_airlock, turn_idle_on_terminate = FALSE)) + return go_idle() -/obj/machinery/door_buttons/airlock_controller/proc/openDoor(obj/machinery/door/airlock/A) - if(exteriorAirlock && interiorAirlock && (!exteriorAirlock.density || !interiorAirlock.density)) - goIdle(TRUE) - return - A.unbolt() - INVOKE_ASYNC(src, PROC_REF(do_openDoor), A) + addtimer(CALLBACK(src, PROC_REF(cycle_open), target_door), 2 SECONDS) -/obj/machinery/door_buttons/airlock_controller/proc/do_openDoor(obj/machinery/door/airlock/A) - if(A?.open()) - if(machine_stat | (NOPOWER) && !lostPower && A && !QDELETED(A)) - A.bolt() - goIdle(TRUE) +///proc called when we want to open doors with cycling +/obj/machinery/door_buttons/airlock_controller/proc/cycle_open(obj/machinery/door/airlock/target_door) + if(isnull(target_door)) + return go_idle() + var/obj/machinery/door/airlock/opposite_airlock = (target_door == exterior_airlock ? interior_airlock : exterior_airlock) + if(isnull(opposite_airlock) || !opposite_airlock.density || !opposite_airlock.locked) + return go_idle() + busy = TRUE + open_door(target_door) -/obj/machinery/door_buttons/airlock_controller/proc/goIdle(update) - lostPower = FALSE +///proc that handles opening and unbolting the door +/obj/machinery/door_buttons/airlock_controller/proc/open_door(obj/machinery/door/airlock/target_door) + if(!target_door.density) + return go_idle() + + target_door.unbolt() + if(!target_door.open() || (machine_stat & NOPOWER)) + return go_idle() + + target_door?.bolt() + return go_idle() + + +///unsets our busy state and update our appearance +/obj/machinery/door_buttons/airlock_controller/proc/go_idle() busy = FALSE - if(update) - update_appearance() - updateUsrDialog() + update_appearance() -/obj/machinery/door_buttons/airlock_controller/process() - if(machine_stat & NOPOWER) - return - if(busy == CYCLE_EXTERIOR) - cycleOpen(exteriorAirlock) - else if(busy == CYCLE_INTERIOR) - cycleOpen(interiorAirlock) - -/obj/machinery/door_buttons/airlock_controller/power_change() - . = ..() - if(machine_stat & NOPOWER) - lostPower = TRUE - else - if(!busy) - lostPower = FALSE - -/obj/machinery/door_buttons/airlock_controller/findObjsByTag() +/obj/machinery/door_buttons/airlock_controller/find_objects_by_tag() for(var/obj/machinery/door/door as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door)) + if(isnull(idInterior) || isnull(idExterior)) + break if(door.id_tag == idInterior) - interiorAirlock = door - else if(door.id_tag == idExterior) - exteriorAirlock = door + interior_airlock = door + RegisterSignal(interior_airlock, COMSIG_PREQDELETED, PROC_REF(remove_door)) + if(door.id_tag == idExterior) + exterior_airlock = door + RegisterSignal(exterior_airlock, COMSIG_PREQDELETED, PROC_REF(remove_door)) /obj/machinery/door_buttons/airlock_controller/update_icon_state() if(machine_stat & NOPOWER) - icon_state = "access_control_off" + icon_state = "[base_icon_state]_off" return ..() - icon_state = "[base_icon_state]_[(busy || lostPower) ? "process" : "standby"]" + icon_state = "[base_icon_state]_[(busy) ? "process" : "standby"]" return ..() -/obj/machinery/door_buttons/airlock_controller/ui_interact(mob/user) - var/datum/browser/popup = new(user, "computer", name) - popup.set_content(returnText()) - popup.open() +/obj/machinery/door_buttons/airlock_controller/ui_interact(mob/user, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AirlockButtonController", name) + ui.open() -/obj/machinery/door_buttons/airlock_controller/proc/returnText() - var/output - if(!exteriorAirlock && !interiorAirlock) - return "ERROR ERROR ERROR ERROR" - if(lostPower) - output = "Initializing..." +/obj/machinery/door_buttons/airlock_controller/ui_data(mob/user) + var/list/data = list() + data["interior_door"] = interior_airlock ? REF(interior_airlock) : null + data["exterior_door"] = exterior_airlock ? REF(exterior_airlock) : null + data["busy"] = busy + data["interior_door_closed"] = interior_airlock?.density + data["exterior_door_closed"] = exterior_airlock?.density + return data + +/obj/machinery/door_buttons/airlock_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(. || busy) + return TRUE + + if(isnull(params["requested_door"])) + return TRUE + + var/atom/requested_door + var/atom/opposite_door + + if(REF(interior_airlock) == params["requested_door"]) + requested_door = interior_airlock + opposite_door = exterior_airlock else - if(!exteriorAirlock || !interiorAirlock) - if(!exteriorAirlock) - if(interiorAirlock.density) - output = "Open Interior Airlock
" - else - output = "Close Interior Airlock
" + requested_door = exterior_airlock + opposite_door = interior_airlock + + switch(action) + if("open") + if(opposite_door && !opposite_door.density) + cycle_close(requested_door) else - if(exteriorAirlock.density) - output = "Open Exterior Airlock
" - else - output = "Close Exterior Airlock
" - else - if(exteriorAirlock.density) - if(interiorAirlock.density) - output = {"Open Exterior Airlock
- Open Interior Airlock
"} - else - output = {"Cycle to Exterior Airlock
- Close Interior Airlock
"} - else - if(interiorAirlock.density) - output = {"Close Exterior Airlock
- Cycle to Interior Airlock
"} - else - output = {"Close Exterior Airlock
- Close Interior Airlock
"} + only_open(requested_door) + if("close") + only_close(requested_door) - - output = {"Access Control Console
- [output]
"} - if(exteriorAirlock) - output += "Exterior Door: [exteriorAirlock.density ? "closed" : "open"]
" - if(interiorAirlock) - output += "Interior Door: [interiorAirlock.density ? "closed" : "open"]
" - - return output - -#undef CLOSING -#undef OPENING -#undef CYCLE -#undef CYCLE_EXTERIOR -#undef CYCLE_INTERIOR + return TRUE diff --git a/tgui/packages/tgui/interfaces/AirlockButtonController.tsx b/tgui/packages/tgui/interfaces/AirlockButtonController.tsx new file mode 100644 index 00000000000..98a3f7c9113 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AirlockButtonController.tsx @@ -0,0 +1,95 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../backend'; +import { Button, NoticeBox, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + interior_door: string; + exterior_door: string; + interior_door_closed: BooleanLike; + exterior_door_closed: BooleanLike; + busy: BooleanLike; +}; + +export const AirlockButtonController = (props) => { + const { data } = useBackend(); + const { interior_door, exterior_door } = data; + return ( + + +
+ {!interior_door && !exterior_door ? ( + No doors detected + ) : ( + + {interior_door && ( + + + + )} + {exterior_door && ( + + + + )} + + )} +
+
+
+ ); +}; + +const RetrieveButton = (props) => { + const { act, data } = useBackend(); + const { + interior_door, + exterior_door, + interior_door_closed, + exterior_door_closed, + busy, + } = data; + const { airlockType } = props; + const our_door_closed = + airlockType === interior_door ? interior_door_closed : exterior_door_closed; + const opposite_door_closed = + airlockType === interior_door ? exterior_door_closed : interior_door_closed; + const opposite_door = + airlockType === interior_door ? exterior_door : interior_door; + + return ( + + ); +};