From f3fd10a0a4cc6a7a46e9d24236226747da4912ce Mon Sep 17 00:00:00 2001 From: HelmCrab <90987989+Thera-Pissed@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:49:09 -0500 Subject: [PATCH] TGUI pipe dispenser (#3464) ## About The Pull Request Implements a tweaked UI from rapid pipe dispensers for normal (obj/machinery/pipedispenser) dispensers Pipe dispensers now have a 5ms delay on prints and can make disposals and transport tubes. Removes dispenser/disposals and dispenser/transport because they're redundant now. ![image](https://github.com/user-attachments/assets/73a9bd7a-7d5d-49d2-a8f2-3313350ee4c8) updates text2path regex to 115 from 117 updates non-bitwise << uses to 262 from 266 ## Why It's Good For The Game The old UI sucks and is laggy and bad. ## Changelog :cl: add: pipe dispenser UI is now similar to rapid pipe dispenser UI. /:cl: --------- Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> --- .../independent/independent_junker.dmm | 2 +- check_regex.yaml | 4 +- code/game/machinery/pipe/pipe_dispenser.dm | 338 +++++++++--------- .../packages/tgui/interfaces/PipeDispenser.js | 193 ++++++++++ 4 files changed, 362 insertions(+), 175 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/PipeDispenser.js diff --git a/_maps/shuttles/independent/independent_junker.dmm b/_maps/shuttles/independent/independent_junker.dmm index 7819d04ec1c2..0ae98ef37fe2 100644 --- a/_maps/shuttles/independent/independent_junker.dmm +++ b/_maps/shuttles/independent/independent_junker.dmm @@ -2284,7 +2284,6 @@ /turf/closed/wall/r_wall, /area/ship/maintenance/port) "Ro" = ( -/obj/machinery/pipedispenser/disposal, /obj/item/reagent_containers/food/drinks/mug/tea{ pixel_y = 8; pixel_x = -7 @@ -2305,6 +2304,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ dir = 1 }, +/obj/machinery/pipedispenser, /turf/open/floor/plating, /area/ship/maintenance/central) "RQ" = ( diff --git a/check_regex.yaml b/check_regex.yaml index eadd642f0676..41174bd9aa22 100644 --- a/check_regex.yaml +++ b/check_regex.yaml @@ -31,14 +31,14 @@ standards: - exactly: [4, "/mob text paths", '"/mob'] - exactly: [42, "/obj text paths", '"/obj'] - exactly: [0, "/turf text paths", '"/turf'] - - exactly: [117, "text2path uses", "text2path"] + - exactly: [115, "text2path uses", "text2path"] - exactly: [18, "world<< uses", 'world[ \t]*<<'] - exactly: [0, "world.log<< uses", 'world.log[ \t]*<<'] - exactly: [ - 266, + 262, "non-bitwise << uses", '(?--[piping_layer]++
" - - var/recipes = GLOB.atmos_pipe_recipes - - for(var/category in recipes) - var/list/cat_recipes = recipes[category] - dat += "[category]:" - - user << browse("[src][dat]", "window=pipedispenser") - onclose(user, "pipedispenser") - return - -/obj/machinery/pipedispenser/Topic(href, href_list) - if(..()) - return 1 - var/mob/living/L = usr - if(!anchored || (istype(L) && !(L.mobility_flags & MOBILITY_UI)) || usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED) || !in_range(loc, usr)) - usr << browse(null, "window=pipedispenser") - return 1 - usr.set_machine(src) - add_fingerprint(usr) - if(href_list["makepipe"]) - if(wait < world.time) - var/p_type = text2path(href_list["makepipe"]) - if (!verify_recipe(GLOB.atmos_pipe_recipes, p_type)) - return - var/p_dir = text2num(href_list["dir"]) - var/obj/item/pipe/P = new (loc, p_type, p_dir) - P.setPipingLayer(piping_layer) - P.add_fingerprint(usr) - wait = world.time + 10 - if(href_list["makemeter"]) - if(wait < world.time) - new /obj/item/pipe_meter(loc) - wait = world.time + 15 - if(href_list["layer_up"]) - piping_layer = clamp(++piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX) - if(href_list["layer_down"]) - piping_layer = clamp(--piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX) - return + if(.) + return + + if(!usr.canUseTopic(src, BE_CLOSE)) + return + switch(action) + if("color") + paint_color = params["paint_color"] + if("category") + category = text2num(params["category"]) + switch(category) + if(DISPOSALS_CATEGORY) + recipe = first_disposal + if(ATMOS_CATEGORY) + recipe = first_atmos + if(TRANSIT_CATEGORY) + recipe = first_transit + p_dir = NORTH + if("print") + make_pipe() + if("piping_layer") + piping_layer = text2num(params["piping_layer"]) + if("ducting_layer") + ducting_layer = text2num(params["ducting_layer"]) + if("pipe_type") + var/static/list/recipes + if(!recipes) + recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes + GLOB.transit_tube_recipes + recipe = recipes[params["category"]][text2num(params["pipe_type"])] + p_dir = NORTH + if("setdir") + p_dir = text2dir(params["dir"]) + p_flipped = text2num(params["flipped"]) + return TRUE /obj/machinery/pipedispenser/attackby(obj/item/W, mob/user, params) add_fingerprint(user) @@ -70,15 +125,6 @@ else return ..() -/obj/machinery/pipedispenser/proc/verify_recipe(recipes, path) - for(var/category in recipes) - var/list/cat_recipes = recipes[category] - for(var/i in cat_recipes) - var/datum/pipe_info/info = i - if (path == info.id) - return TRUE - return FALSE - /obj/machinery/pipedispenser/wrench_act(mob/living/user, obj/item/I) ..() if(default_unfasten_wrench(user, I, 40)) @@ -96,129 +142,77 @@ default_deconstruction_crowbar(I) return TRUE -/obj/machinery/pipedispenser/disposal - name = "disposal pipe dispenser" - icon = 'icons/obj/stationobjs.dmi' - icon_state = "pipe_d" - desc = "Dispenses pipes that will ultimately be used to move trash around." - density = TRUE - - //Allow you to drag-drop disposal pipes and transit tubes into it -/obj/machinery/pipedispenser/disposal/MouseDrop_T(obj/structure/pipe, mob/usr) - if(!usr.incapacitated()) +/obj/machinery/pipedispenser/MouseDrop_T(obj/structure/pipe, mob/usr) + if(usr.incapacitated()) return - if (!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod)) + if(!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod)) return - if (get_dist(usr, src) > 1 || get_dist(src,pipe) > 1) + if(get_dist(usr, src) > 1 || get_dist(src,pipe) > 1) return - if (pipe.anchored) + if(pipe.anchored) return qdel(pipe) -/obj/machinery/pipedispenser/disposal/interact(mob/user) - - var/dat = "" - var/recipes = GLOB.disposal_pipe_recipes - - for(var/category in recipes) - var/list/cat_recipes = recipes[category] - dat += "[category]:" - - user << browse("[src][dat]", "window=pipedispenser") - return - - -/obj/machinery/pipedispenser/disposal/Topic(href, href_list) - if(..()) - return 1 - usr.set_machine(src) - add_fingerprint(usr) - if(href_list["dmake"]) - if(wait < world.time) - var/p_type = text2path(href_list["dmake"]) - if (!verify_recipe(GLOB.disposal_pipe_recipes, p_type)) - return - var/obj/structure/disposalconstruct/C = new (loc, p_type) - - if(!C.can_place()) - to_chat(usr, "There's not enough room to build that here!") - qdel(C) - return - if(href_list["dir"]) - C.setDir(text2num(href_list["dir"])) - C.add_fingerprint(usr) - C.update_appearance() - wait = world.time + 15 - return - -//transit tube dispenser -//inherit disposal for the dragging proc -/obj/machinery/pipedispenser/disposal/transit_tube - name = "transit tube dispenser" - icon = 'icons/obj/stationobjs.dmi' - icon_state = "pipe_d" - density = TRUE - desc = "Dispenses pipes that will move beings around." - -/obj/machinery/pipedispenser/disposal/transit_tube/interact(mob/user) - - var/dat = {"Transit Tubes:
-Straight Tube
-Straight Tube with Crossing
-Curved Tube
-Diagonal Tube
-Diagonal Tube with Crossing
-Junction
-Station Equipment:
-Through Tube Station
-Terminus Tube Station
-Transit Tube Pod
-"} - - user << browse("[src][dat]", "window=pipedispenser") - return - - -/obj/machinery/pipedispenser/disposal/transit_tube/Topic(href, href_list) - if(..()) - return 1 - usr.set_machine(src) - add_fingerprint(usr) - if(wait < world.time) - if(href_list["tube"]) - var/tube_type = text2num(href_list["tube"]) - var/obj/structure/C - switch(tube_type) - if(TRANSIT_TUBE_STRAIGHT) - C = new /obj/structure/c_transit_tube(loc) - if(TRANSIT_TUBE_STRAIGHT_CROSSING) - C = new /obj/structure/c_transit_tube/crossing(loc) - if(TRANSIT_TUBE_CURVED) - C = new /obj/structure/c_transit_tube/curved(loc) - if(TRANSIT_TUBE_DIAGONAL) - C = new /obj/structure/c_transit_tube/diagonal(loc) - if(TRANSIT_TUBE_DIAGONAL_CROSSING) - C = new /obj/structure/c_transit_tube/diagonal/crossing(loc) - if(TRANSIT_TUBE_JUNCTION) - C = new /obj/structure/c_transit_tube/junction(loc) - if(TRANSIT_TUBE_STATION) - C = new /obj/structure/c_transit_tube/station(loc) - if(TRANSIT_TUBE_TERMINUS) - C = new /obj/structure/c_transit_tube/station/reverse(loc) - if(TRANSIT_TUBE_POD) - C = new /obj/structure/c_transit_tube_pod(loc) - if(C) - C.add_fingerprint(usr) - wait = world.time + 15 - return +/obj/machinery/pipedispenser/proc/make_pipe(mob/user) + if(busy) + src.visible_message(span_warning("[src] is busy.")) + return + var/queued_p_type = recipe.id + var/queued_p_dir = p_dir + var/queued_p_flipped = p_flipped + switch(category) + if(ATMOS_CATEGORY) + if(recipe.type == /datum/pipe_info/meter) + new /obj/item/pipe_meter(loc) + on_make_pipe() + else + if(recipe.all_layers == FALSE && (piping_layer == 1 || piping_layer == 5)) + src.visible_message(span_warning("[src] can't print this object on the layer...")) + return + var/obj/machinery/atmospherics/path = queued_p_type + var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe + var/obj/item/pipe/P = new pipe_item_type(loc, queued_p_type, queued_p_dir) + on_make_pipe() + + if(queued_p_flipped && istype(P, /obj/item/pipe/trinary/flippable)) + var/obj/item/pipe/trinary/flippable/F = P + F.flipped = queued_p_flipped + + P.update() + P.setPipingLayer(piping_layer) + if(ispath(path, /obj/machinery/atmospherics/pipe) && !findtext("[queued_p_type]", "layer_manifold")) + P.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY) + + if(DISPOSALS_CATEGORY) //Making disposals pipes + new /obj/structure/disposalconstruct(loc, queued_p_type, queued_p_dir, queued_p_flipped) + on_make_pipe() + return + + if(TRANSIT_CATEGORY) //Making transit tubes + if(istype(queued_p_type, /obj/structure/c_transit_tube_pod)) + new /obj/structure/c_transit_tube_pod(loc) + on_make_pipe() + else + var/obj/structure/c_transit_tube/tube = new queued_p_type(loc) + on_make_pipe() + tube.setDir(queued_p_dir) + + if(queued_p_flipped) + tube.setDir(turn(queued_p_dir, 45)) + tube.simple_rotate_flip() + +/obj/machinery/pipedispenser/proc/on_make_pipe() + busy = TRUE + delay = addtimer(CALLBACK(src, PROC_REF(reset_busy)), 5) + +/obj/machinery/pipedispenser/proc/reset_busy() + busy = FALSE + +#undef ATMOS_CATEGORY +#undef DISPOSALS_CATEGORY +#undef TRANSIT_CATEGORY diff --git a/tgui/packages/tgui/interfaces/PipeDispenser.js b/tgui/packages/tgui/interfaces/PipeDispenser.js new file mode 100644 index 000000000000..61798b67306a --- /dev/null +++ b/tgui/packages/tgui/interfaces/PipeDispenser.js @@ -0,0 +1,193 @@ +import { classes } from 'common/react'; +import { useBackend, useLocalState } from '../backend'; +import { + Box, + Button, + ColorBox, + Flex, + LabeledList, + Section, + Tabs, +} from '../components'; +import { Window } from '../layouts'; + +const ROOT_CATEGORIES = ['Atmospherics', 'Disposals', 'Transit Tubes']; + +const ICON_BY_CATEGORY_NAME = { + 'Atmospherics': 'wrench', + 'Disposals': 'trash-alt', + 'Transit Tubes': 'bus', + 'Pipes': 'grip-lines', + 'Disposal Pipes': 'grip-lines', + 'Devices': 'microchip', + 'Heat Exchange': 'thermometer-half', + 'Station Equipment': 'microchip', +}; + +const PAINT_COLORS = { + grey: '#bbbbbb', + amethyst: '#a365ff', + blue: '#4466ff', + brown: '#b26438', + cyan: '#48eae8', + dark: '#808080', + green: '#1edd00', + orange: '#ffa030', + purple: '#b535ea', + red: '#ff3333', + violet: '#6e00f6', + yellow: '#ffce26', +}; + +export const PipeDispenser = (props, context) => { + const { act, data } = useBackend(context); + const { + category: rootCategoryIndex, + categories = [], + selected_color, + piping_layer, + mode, + } = data; + const previews = data.preview_rows.flatMap((row) => row.previews); + const [categoryName, setCategoryName] = useLocalState( + context, + 'categoryName' + ); + const shownCategory = + categories.find((category) => category.cat_name === categoryName) || + categories[0]; + return ( + + +
+ + + {ROOT_CATEGORIES.map((categoryName, i) => ( +
+ + +
+ {rootCategoryIndex === 0 && ( + + {[1, 2, 3, 4, 5].map((layer) => ( + + act('piping_layer', { + piping_layer: layer, + }) + } + /> + ))} + + )} + + {previews.map((preview) => ( + + ))} + +
+
+ +
+ + {categories.map((category, i) => ( + setCategoryName(category.cat_name)} + > + {category.cat_name} + + ))} + + {shownCategory?.recipes.map((recipe) => ( + + act('pipe_type', { + pipe_type: recipe.pipe_index, + category: shownCategory.cat_name, + }) + } + /> + ))} +
+
+
+
+
+ ); +};