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]:
"
-
- for(var/i in cat_recipes)
- var/datum/pipe_info/I = i
- dat += I.Render(src)
-
- dat += "
"
-
- 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]:"
-
- for(var/i in cat_recipes)
- var/datum/pipe_info/I = i
- dat += I.Render(src)
-
- dat += "
"
-
- 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) => (
+
+
+
+
+
+ {selected_color}
+
+ {Object.keys(PAINT_COLORS).map((colorName) => (
+
+ act('color', {
+ paint_color: colorName,
+ })
+ }
+ />
+ ))}
+
+
+
+
+
+
+ {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,
+ })
+ }
+ />
+ ))}
+
+
+
+
+
+ );
+};