mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-14 19:03:21 +00:00
* TGUI replaces Radial menu for Plumbing RCD (#71569) **About the pull request** Radial menu's replaced with TGUI window for all plumbing RCD's https://user-images.githubusercontent.com/110812394/204481973-8f6d62c0-9288-4165-bce7-ee8bfec95bee.mp4 **Why it's good for the game** **1. Faster Navigation** - Old System: It had 3 radial menus' ->To select type of device to build ->To select the colour of fluid ducts ->To select the layer of devices 3 menus for one system makes navigation between them annoying for e.g.: to create a red fluid duct of layer 5 you have to open all these 3 menus & cycling through the radial menu by clicking the next button is time consuming when you have a large number of items - New System: with just one window open it's as simple as 3 clicks and your done just like the RPD **2. Always available** - Old System: When you select an option inside a radial menu the menu closes so you have to reopen it again to change a setting - New System: open the window drag it to the side and it will always be there for you **3. Just easier for our eyes** - Old System: Moving my eyes in a circle across the menu only to find out i have to click Next and circle my eyes again honestly makes my head spin - New System: The menu options are small enough to be viewed all at once & helps me see what I need more easily **4. Consistency** Both the RPD & plumbing all have similar concepts i.e., pipes, devices, layers & colours it only makes sense they should have similar interfaces. Also categorizing the items into tabs can help with explaining what each item does **Conclusion** Just because the radial menu looks attractive shouldn't mean it must be used everywhere, it only makes sense to use it when the number of options of an item is small enough to be displayed on the screen all at once for e.g., modules in a Mod suit. If the user has to click the next button to cycle through the item's, it defeats the purpose of the radial menu and makes the user work more to find his settings **Side Note :** removed unused code in RapidPipeDispenser.js **ChangeLog** 🆑 add: plumbing constructor TGUI, just like Rapid Pipe Dispensers del: plumbing constructor radials code: categories for each item /🆑 Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@ users.noreply.github.com> Co-authored-by: Time-Green <timkoster1@ hotmail.com> * TGUI replaces Radial menu for Plumbing RCD Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@ users.noreply.github.com> Co-authored-by: Time-Green <timkoster1@ hotmail.com>
381 lines
12 KiB
Plaintext
381 lines
12 KiB
Plaintext
/*
|
|
All the important duct code:
|
|
/code/datums/components/plumbing/plumbing.dm
|
|
/code/datums/ductnet.dm
|
|
*/
|
|
/obj/machinery/duct
|
|
name = "fluid duct"
|
|
icon = 'icons/obj/plumbing/fluid_ducts.dmi'
|
|
icon_state = "nduct"
|
|
layer = PLUMBING_PIPE_VISIBILE_LAYER
|
|
use_power = NO_POWER_USE
|
|
|
|
///bitfield with the directions we're connected in
|
|
var/connects
|
|
///set to TRUE to disable smart duct behaviour
|
|
var/dumb = FALSE
|
|
///wheter we allow our connects to be changed after initialization or not
|
|
var/lock_connects = FALSE
|
|
///our ductnet, wich tracks what we're connected to
|
|
var/datum/ductnet/duct
|
|
///amount we can transfer per process. note that the ductnet can carry as much as the lowest capacity duct
|
|
var/capacity = 10
|
|
|
|
///the color of our duct
|
|
var/duct_color = COLOR_VERY_LIGHT_GRAY
|
|
///TRUE to ignore colors, so yeah we also connect with other colors without issue
|
|
var/ignore_colors = FALSE
|
|
///1,2,4,8,16
|
|
var/duct_layer = DUCT_LAYER_DEFAULT
|
|
///whether we allow our layers to be altered
|
|
var/lock_layers = FALSE
|
|
///TRUE to let colors connect when forced with a wrench, false to just not do that at all
|
|
var/color_to_color_support = TRUE
|
|
///wheter to even bother with plumbing code or not
|
|
var/active = TRUE
|
|
///track ducts we're connected to. Mainly for ducts we connect to that we normally wouldn't, like different layers and colors, for when we regenerate the ducts
|
|
var/list/neighbours = list()
|
|
///what stack to drop when disconnected. Must be /obj/item/stack/ducts or a subtype
|
|
var/drop_on_wrench = /obj/item/stack/ducts
|
|
|
|
/obj/machinery/duct/Initialize(mapload, no_anchor, color_of_duct = null, layer_of_duct = null, force_connects, force_ignore_colors)
|
|
. = ..()
|
|
|
|
if(force_connects)
|
|
connects = force_connects //skip change_connects() because we're still initializing and we need to set our connects at one point
|
|
if(!lock_layers && layer_of_duct)
|
|
duct_layer = layer_of_duct
|
|
if(force_ignore_colors)
|
|
ignore_colors = force_ignore_colors
|
|
if(!ignore_colors && color_of_duct)
|
|
duct_color = color_of_duct
|
|
if(duct_color)
|
|
add_atom_colour(duct_color, FIXED_COLOUR_PRIORITY)
|
|
|
|
if(no_anchor)
|
|
active = FALSE
|
|
set_anchored(FALSE)
|
|
else if(!can_anchor())
|
|
if(mapload)
|
|
log_mapping("Overlapping ducts detected at [AREACOORD(src)], unanchoring one.")
|
|
// Note that qdeling automatically drops a duct stack
|
|
return INITIALIZE_HINT_QDEL
|
|
|
|
handle_layer()
|
|
|
|
attempt_connect()
|
|
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE)
|
|
|
|
///start looking around us for stuff to connect to
|
|
/obj/machinery/duct/proc/attempt_connect()
|
|
for(var/direction in GLOB.cardinals)
|
|
if(dumb && !(direction & connects))
|
|
continue
|
|
for(var/atom/movable/duct_candidate in get_step(src, direction))
|
|
if(connect_network(duct_candidate, direction))
|
|
add_connects(direction)
|
|
update_appearance()
|
|
|
|
///see if whatever we found can be connected to
|
|
/obj/machinery/duct/proc/connect_network(atom/movable/plumbable, direction)
|
|
if(istype(plumbable, /obj/machinery/duct))
|
|
return connect_duct(plumbable, direction)
|
|
|
|
for(var/datum/component/plumbing/plumber as anything in plumbable.GetComponents(/datum/component/plumbing))
|
|
. += connect_plumber(plumber, direction) //so that if one is true, all is true. beautiful.
|
|
|
|
///connect to a duct
|
|
/obj/machinery/duct/proc/connect_duct(obj/machinery/duct/other, direction)
|
|
var/opposite_dir = turn(direction, 180)
|
|
if(!active || !other.active)
|
|
return
|
|
|
|
if(!dumb && other.dumb && !(opposite_dir & other.connects))
|
|
return
|
|
if(dumb && other.dumb && !(connects & other.connects)) //we eliminated a few more scenarios in attempt connect
|
|
return
|
|
|
|
if((duct == other.duct) && duct)//check if we're not just comparing two null values
|
|
add_neighbour(other, direction)
|
|
|
|
other.add_connects(opposite_dir)
|
|
other.update_appearance()
|
|
return TRUE //tell the current pipe to also update it's sprite
|
|
if(!(other in neighbours)) //we cool
|
|
if((duct_color != other.duct_color) && !(ignore_colors || other.ignore_colors))
|
|
return
|
|
if(!(duct_layer & other.duct_layer))
|
|
return
|
|
|
|
if(other.duct)
|
|
if(duct)
|
|
duct.assimilate(other.duct)
|
|
else
|
|
other.duct.add_duct(src)
|
|
else
|
|
if(duct)
|
|
duct.add_duct(other)
|
|
else
|
|
create_duct()
|
|
duct.add_duct(other)
|
|
|
|
add_neighbour(other, direction)
|
|
|
|
//Delegate to timer subsystem so its handled the next tick and doesnt cause byond to mistake it for an infinite loop and kill the game
|
|
addtimer(CALLBACK(other, PROC_REF(attempt_connect)))
|
|
|
|
return TRUE
|
|
|
|
///connect to a plumbing object
|
|
/obj/machinery/duct/proc/connect_plumber(datum/component/plumbing/plumbing, direction)
|
|
var/opposite_dir = turn(direction, 180)
|
|
|
|
if(!(duct_layer & plumbing.ducting_layer))
|
|
return FALSE
|
|
|
|
if(!plumbing.active)
|
|
return
|
|
|
|
var/comp_directions = plumbing.supply_connects + plumbing.demand_connects //they should never, ever have supply and demand connects overlap or catastrophic failure
|
|
if(opposite_dir & comp_directions)
|
|
if(!duct)
|
|
create_duct()
|
|
if(duct.add_plumber(plumbing, opposite_dir))
|
|
neighbours[plumbing.parent] = direction
|
|
return TRUE
|
|
|
|
///we disconnect ourself from our neighbours. we also destroy our ductnet and tell our neighbours to make a new one
|
|
/obj/machinery/duct/proc/disconnect_duct(skipanchor)
|
|
if(!skipanchor) //since set_anchored calls us too.
|
|
set_anchored(FALSE)
|
|
active = FALSE
|
|
if(duct)
|
|
duct.remove_duct(src)
|
|
lose_neighbours()
|
|
reset_connects(0)
|
|
update_appearance()
|
|
if(ispath(drop_on_wrench))
|
|
var/obj/item/stack/ducts/duct_stack = new drop_on_wrench(drop_location())
|
|
duct_stack.duct_color = GLOB.pipe_color_name[duct_color] || DUCT_COLOR_OMNI
|
|
duct_stack.duct_layer = GLOB.plumbing_layer_names["[duct_layer]"] || GLOB.plumbing_layer_names["[DUCT_LAYER_DEFAULT]"]
|
|
duct_stack.add_atom_colour(duct_color, FIXED_COLOUR_PRIORITY)
|
|
drop_on_wrench = null
|
|
if(!QDELING(src))
|
|
qdel(src)
|
|
|
|
///Special proc to draw a new connect frame based on neighbours. not the norm so we can support multiple duct kinds
|
|
/obj/machinery/duct/proc/generate_connects()
|
|
if(lock_connects)
|
|
return
|
|
connects = 0
|
|
for(var/A in neighbours)
|
|
connects |= neighbours[A]
|
|
update_appearance()
|
|
|
|
///create a new duct datum
|
|
/obj/machinery/duct/proc/create_duct()
|
|
duct = new()
|
|
duct.add_duct(src)
|
|
|
|
///add a duct as neighbour. this means we're connected and will connect again if we ever regenerate
|
|
/obj/machinery/duct/proc/add_neighbour(obj/machinery/duct/other, direction)
|
|
if(!(other in neighbours))
|
|
neighbours[other] = direction
|
|
if(!(src in other.neighbours))
|
|
other.neighbours[src] = turn(direction, 180)
|
|
|
|
///remove all our neighbours, and remove us from our neighbours aswell
|
|
/obj/machinery/duct/proc/lose_neighbours()
|
|
for(var/obj/machinery/duct/other in neighbours)
|
|
other.neighbours.Remove(src)
|
|
other.generate_connects()
|
|
neighbours = list()
|
|
|
|
///add a connect direction
|
|
/obj/machinery/duct/proc/add_connects(new_connects) //make this a define to cut proc calls?
|
|
if(!lock_connects)
|
|
connects |= new_connects
|
|
|
|
///remove a connect direction
|
|
/obj/machinery/duct/proc/remove_connects(dead_connects)
|
|
if(!lock_connects)
|
|
connects &= ~dead_connects
|
|
|
|
///remove our connects
|
|
/obj/machinery/duct/proc/reset_connects()
|
|
if(!lock_connects)
|
|
connects = 0
|
|
|
|
///get a list of the ducts we can connect to if we are dumb
|
|
/obj/machinery/duct/proc/get_adjacent_ducts()
|
|
var/list/adjacents = list()
|
|
for(var/direction in GLOB.cardinals)
|
|
if(direction & connects)
|
|
for(var/obj/machinery/duct/other in get_step(src, direction))
|
|
if((turn(direction, 180) & other.connects) && other.active)
|
|
adjacents += other
|
|
return adjacents
|
|
|
|
/obj/machinery/duct/update_icon_state()
|
|
var/temp_icon = initial(icon_state)
|
|
for(var/direction in GLOB.cardinals)
|
|
switch(direction & connects)
|
|
if(NORTH)
|
|
temp_icon += "_n"
|
|
if(SOUTH)
|
|
temp_icon += "_s"
|
|
if(EAST)
|
|
temp_icon += "_e"
|
|
if(WEST)
|
|
temp_icon += "_w"
|
|
icon_state = temp_icon
|
|
return ..()
|
|
|
|
///update the layer we are on
|
|
/obj/machinery/duct/proc/handle_layer()
|
|
var/offset
|
|
//it's a bitfield, but it's fine because ducts themselves are only on one layer
|
|
switch(duct_layer)
|
|
if(FIRST_DUCT_LAYER)
|
|
offset = -10
|
|
if(SECOND_DUCT_LAYER)
|
|
offset = -5
|
|
if(THIRD_DUCT_LAYER)
|
|
offset = 0
|
|
if(FOURTH_DUCT_LAYER)
|
|
offset = 5
|
|
if(FIFTH_DUCT_LAYER)
|
|
offset = 10
|
|
pixel_x = offset
|
|
pixel_y = offset
|
|
|
|
layer = initial(layer) + duct_layer * 0.0003
|
|
|
|
/obj/machinery/duct/set_anchored(anchorvalue)
|
|
. = ..()
|
|
if(isnull(.))
|
|
return
|
|
if(anchorvalue)
|
|
active = TRUE
|
|
attempt_connect()
|
|
else
|
|
disconnect_duct(TRUE)
|
|
|
|
/obj/machinery/duct/wrench_act(mob/living/user, obj/item/wrench) //I can also be the RPD
|
|
..()
|
|
add_fingerprint(user)
|
|
wrench.play_tool_sound(src)
|
|
if(anchored || can_anchor())
|
|
set_anchored(!anchored)
|
|
user.visible_message( \
|
|
"[user] [anchored ? null : "un"]fastens \the [src].", \
|
|
span_notice("You [anchored ? null : "un"]fasten \the [src]."), \
|
|
span_hear("You hear ratcheting."))
|
|
return TRUE
|
|
|
|
///collection of all the sanity checks to prevent us from stacking ducts that shouldn't be stacked
|
|
/obj/machinery/duct/proc/can_anchor(turf/destination)
|
|
if(!destination)
|
|
destination = get_turf(src)
|
|
for(var/obj/machinery/duct/other in destination)
|
|
if(other.anchored && other != src && (duct_layer & other.duct_layer))
|
|
return FALSE
|
|
for(var/obj/machinery/machine in destination)
|
|
for(var/datum/component/plumbing/plumber as anything in machine.GetComponents(/datum/component/plumbing))
|
|
if(plumber.ducting_layer & duct_layer)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/machinery/duct/doMove(destination)
|
|
. = ..()
|
|
disconnect_duct()
|
|
set_anchored(FALSE)
|
|
|
|
/obj/machinery/duct/Destroy()
|
|
disconnect_duct()
|
|
return ..()
|
|
|
|
/obj/machinery/duct/MouseDrop_T(atom/drag_source, mob/living/user)
|
|
if(!istype(drag_source, /obj/machinery/duct))
|
|
return
|
|
var/obj/machinery/duct/other = drag_source
|
|
if(get_dist(src, other) != 1)
|
|
return
|
|
var/direction = get_dir(src, other)
|
|
if(!(direction in GLOB.cardinals))
|
|
return
|
|
if(!(duct_layer & other.duct_layer))
|
|
to_chat(user, span_warning("The ducts must be on the same layer to connect them!"))
|
|
return
|
|
var/obj/item/held_item = user.get_active_held_item()
|
|
if(held_item?.tool_behaviour != TOOL_WRENCH)
|
|
to_chat(user, span_warning("You need to be holding a wrench in your active hand to do that!"))
|
|
return
|
|
|
|
add_connects(direction) //the connect of the other duct is handled in connect_network, but do this here for the parent duct because it's not necessary in normal cases
|
|
add_neighbour(other, direction)
|
|
connect_network(other, direction)
|
|
update_appearance()
|
|
held_item.play_tool_sound(src)
|
|
to_chat(user, span_notice("You connect the two plumbing ducts."))
|
|
|
|
/obj/item/stack/ducts
|
|
name = "stack of duct"
|
|
desc = "A stack of fluid ducts."
|
|
singular_name = "duct"
|
|
icon = 'icons/obj/plumbing/fluid_ducts.dmi'
|
|
icon_state = "ducts"
|
|
mats_per_unit = list(/datum/material/iron=500)
|
|
w_class = WEIGHT_CLASS_TINY
|
|
novariants = FALSE
|
|
max_amount = 50
|
|
item_flags = NOBLUDGEON
|
|
merge_type = /obj/item/stack/ducts
|
|
matter_amount = 1
|
|
///Color of our duct
|
|
var/duct_color = "omni"
|
|
///Default layer of our duct
|
|
var/duct_layer = "Default Layer"
|
|
|
|
/obj/item/stack/ducts/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("It's current color and layer are [duct_color] and [duct_layer]. Use in-hand to change.")
|
|
|
|
/obj/item/stack/ducts/attack_self(mob/user)
|
|
var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers, duct_layer)
|
|
if(new_layer)
|
|
duct_layer = new_layer
|
|
var/new_color = tgui_input_list(user, "Select a color", "Color", GLOB.pipe_paint_colors, duct_color)
|
|
if(new_color)
|
|
duct_color = new_color
|
|
add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY)
|
|
|
|
/obj/item/stack/ducts/afterattack(atom/target, user, proximity)
|
|
. = ..()
|
|
if(!proximity)
|
|
return
|
|
if(istype(target, /obj/machinery/duct))
|
|
var/obj/machinery/duct/duct = target
|
|
if(duct.anchored)
|
|
to_chat(user, span_warning("The duct must be unanchored before it can be picked up."))
|
|
return
|
|
|
|
// Turn into a duct stack and then merge to the in-hand stack.
|
|
var/obj/item/stack/ducts/stack = new(duct.loc, 1, FALSE)
|
|
qdel(duct)
|
|
if(stack.can_merge(src))
|
|
stack.merge(src)
|
|
return
|
|
|
|
check_attach_turf(target)
|
|
|
|
/obj/item/stack/ducts/proc/check_attach_turf(atom/target)
|
|
if(isopenturf(target) && use(1))
|
|
var/turf/open/open_turf = target
|
|
var/is_omni = duct_color == DUCT_COLOR_OMNI
|
|
new /obj/machinery/duct(open_turf, FALSE, GLOB.pipe_paint_colors[duct_color], GLOB.plumbing_layers[duct_layer], null, is_omni)
|
|
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
|
|
|
|
/obj/item/stack/ducts/fifty
|
|
amount = 50
|