diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 21273ed2273..196a8cb1fd3 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -58,6 +58,7 @@ #define GAS_PIPE_VISIBLE_LAYER 2.47 //layer = initial(layer) + piping_layer / 1000 in atmospherics/update_icon() to determine order of pipe overlap #define GAS_FILTER_LAYER 2.48 #define GAS_PUMP_LAYER 2.49 +#define PLUMBING_PIPE_VISIBILE_LAYER 2.495//layer = initial(layer) + ducting_layer / 3333 in atmospherics/handle_layer() to determine order of duct overlap #define LOW_OBJ_LAYER 2.5 ///catwalk overlay of /turf/open/floor/catwalk_floor #define CATWALK_LAYER 2.51 diff --git a/code/__DEFINES/plumbing.dm b/code/__DEFINES/plumbing.dm index 9666a5be1e1..320bbe8258f 100644 --- a/code/__DEFINES/plumbing.dm +++ b/code/__DEFINES/plumbing.dm @@ -7,3 +7,29 @@ #define DUCT_LAYER_DEFAULT THIRD_DUCT_LAYER #define MACHINE_REAGENT_TRANSFER 10 //the default max plumbing machinery transfers + +/// List of plumbing layers as name => bitflag +GLOBAL_LIST_INIT(plumbing_layers, list( + "First Layer" = FIRST_DUCT_LAYER, + "Second Layer" = SECOND_DUCT_LAYER, + "Default Layer" = THIRD_DUCT_LAYER, + "Fourth Layer" = FOURTH_DUCT_LAYER, + "Fifth Layer" = FIFTH_DUCT_LAYER, +)) + +/// Reverse of plumbing_layers, as "[bitflag]" => name +GLOBAL_LIST_INIT(plumbing_layer_names, list( + "[FIRST_DUCT_LAYER]" = "First Layer", + "[SECOND_DUCT_LAYER]" = "Second Layer", + "[THIRD_DUCT_LAYER]" = "Default Layer", + "[FOURTH_DUCT_LAYER]" = "Fourth Layer", + "[FIFTH_DUCT_LAYER]" = "Fifth Layer", +)) + +/// Name of omni color +#define DUCT_COLOR_OMNI "omni" + +/// Cached radial menu options for plumbing RCD color picker +GLOBAL_LIST_EMPTY(plumbing_color_menu_options) +/// Cached radial menu options for plumbing RCD layer picker +GLOBAL_LIST_EMPTY(plumbing_layer_menu_options) diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 47e4f580732..c3c82775aa8 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -22,10 +22,10 @@ var/recipient_reagents_holder ///How do we apply the new reagents to the receiver? Generally doesn't matter, but some stuff, like people, does care if its injected or whatevs var/methods - ///What color is our demand connect? Also it's not auto-colored so you'll have to make new sprites if its anything other than red, blue, yellow or green - var/demand_color = "red" - ///What color is our supply connect? Also, refrain from pointlessly using non-standard colors unless it's really funny or something - var/supply_color = "blue" + ///What color is our demand connect? + var/demand_color = COLOR_RED + ///What color is our supply connect? + var/supply_color = COLOR_BLUE ///turn_connects is for wheter or not we spin with the object to change our pipes /datum/component/plumbing/Initialize(start=TRUE, _ducting_layer, _turn_connects=TRUE, datum/reagents/custom_receiver) @@ -35,14 +35,14 @@ if(_ducting_layer) ducting_layer = _ducting_layer - var/atom/movable/AM = parent - if(!AM.reagents && !custom_receiver) + var/atom/movable/parent_movable = parent + if(!parent_movable.reagents && !custom_receiver) return COMPONENT_INCOMPATIBLE - reagents = AM.reagents + reagents = parent_movable.reagents turn_connects = _turn_connects - set_recipient_reagents_holder(custom_receiver ? custom_receiver : AM.reagents) + set_recipient_reagents_holder(custom_receiver ? custom_receiver : parent_movable.reagents) if(start) //We're registering here because I need to check whether we start active or not, and this is just easier @@ -76,10 +76,10 @@ send_request(D) ///Can we be added to the ductnet? -/datum/component/plumbing/proc/can_add(datum/ductnet/D, dir) +/datum/component/plumbing/proc/can_add(datum/ductnet/ductnet, dir) if(!active) return - if(!dir || !D) + if(!dir || !ductnet) return FALSE if(num2text(dir) in ducts) return FALSE @@ -97,15 +97,13 @@ if(!ducts.Find(num2text(dir))) return net = ducts[num2text(dir)] - for(var/A in net.suppliers) - var/datum/component/plumbing/supplier = A + for(var/datum/component/plumbing/supplier as anything in net.suppliers) if(supplier.can_give(amount, reagent, net)) valid_suppliers += supplier // Need to ask for each in turn very carefully, making sure we get the total volume. This is to avoid a division that would always round down and become 0 var/targetVolume = reagents.total_volume + amount var/suppliersLeft = valid_suppliers.len - for(var/A in valid_suppliers) - var/datum/component/plumbing/give = A + for(var/datum/component/plumbing/give as anything in valid_suppliers) var/currentRequest = (targetVolume - reagents.total_volume) / suppliersLeft give.transfer_to(src, currentRequest, reagent, net) suppliersLeft-- @@ -116,9 +114,8 @@ return if(reagent) //only asked for one type of reagent - for(var/A in reagents.reagent_list) - var/datum/reagent/R = A - if(R.type == reagent) + for(var/datum/reagent/contained_reagent as anything in reagents.reagent_list) + if(contained_reagent.type == reagent) return TRUE else if(reagents.total_volume > 0) //take whatever return TRUE @@ -133,7 +130,7 @@ reagents.trans_to(target.recipient_reagents_holder, amount, round_robin = TRUE, methods = methods)//we deal with alot of precise calculations so we round_robin=TRUE. Otherwise we get floating point errors, 1 != 1 and 2.5 + 2.5 = 6 ///We create our luxurious piping overlays/underlays, to indicate where we do what. only called once if use_overlays = TRUE in Initialize() -/datum/component/plumbing/proc/create_overlays(atom/movable/AM, list/overlays) +/datum/component/plumbing/proc/create_overlays(atom/movable/parent_movable, list/overlays) SIGNAL_HANDLER if(tile_covered || !use_overlays) @@ -158,39 +155,30 @@ var/duct_y = offset - for(var/D in GLOB.cardinals) + for(var/direction in GLOB.cardinals) var/color - var/direction - if(D & initial(demand_connects)) + if(direction & initial(demand_connects)) color = demand_color - else if(D & initial(supply_connects)) + else if(direction & initial(supply_connects)) color = supply_color else continue - var/image/I - - switch(D) - if(NORTH) - direction = "north" - if(SOUTH) - direction = "south" - if(EAST) - direction = "east" - if(WEST) - direction = "west" + var/direction_text = dir2text(direction) + var/duct_layer = PLUMBING_PIPE_VISIBILE_LAYER + ducting_layer * 0.0003 + var/image/overlay if(turn_connects) - I = image('icons/obj/plumbing/connects.dmi', "[direction]-[color]", layer = AM.layer - 1) - + overlay = image('icons/obj/plumbing/connects.dmi', "[direction_text]-[ducting_layer]", layer = duct_layer) else - I = image('icons/obj/plumbing/connects.dmi', "[direction]-[color]-s", layer = AM.layer - 1) //color is not color as in the var, it's just the name of the icon_state - I.dir = D + overlay = image('icons/obj/plumbing/connects.dmi', "[direction_text]-[ducting_layer]-s", layer = duct_layer) + overlay.dir = direction - I.pixel_x = duct_x - I.pixel_y = duct_y + overlay.color = color + overlay.pixel_x = duct_x + overlay.pixel_y = duct_y - overlays += I + overlays += overlay ///we stop acting like a plumbing thing and disconnect if we are, so we can safely be moved and stuff /datum/component/plumbing/proc/disable() @@ -201,19 +189,21 @@ STOP_PROCESSING(SSplumbing, src) - for(var/A in ducts) - var/datum/ductnet/D = ducts[A] - D.remove_plumber(src) + for(var/duct_dir in ducts) + var/datum/ductnet/duct = ducts[duct_dir] + duct.remove_plumber(src) active = FALSE - for(var/D in GLOB.cardinals) - if(D & (demand_connects | supply_connects)) - for(var/obj/machinery/duct/duct in get_step(parent, D)) - if(duct.duct_layer == ducting_layer) - duct.remove_connects(turn(D, 180)) - duct.neighbours.Remove(parent) - duct.update_appearance() + for(var/direction in GLOB.cardinals) + if(!(direction & (demand_connects | supply_connects))) + continue + for(var/obj/machinery/duct/duct in get_step(parent, direction)) + if(!(duct.duct_layer & ducting_layer)) + continue + duct.remove_connects(turn(direction, 180)) + duct.neighbours.Remove(parent) + duct.update_appearance() ///settle wherever we are, and start behaving like a piece of plumbing /datum/component/plumbing/proc/enable(obj/object, datum/component/component) @@ -225,29 +215,32 @@ update_dir() active = TRUE - var/atom/movable/AM = parent - for(var/obj/machinery/duct/D in AM.loc) //Destroy any ducts under us. Ducts also self-destruct if placed under a plumbing machine. machines disable when they get moved - if(D.anchored) //that should cover everything - D.disconnect_duct() + var/atom/movable/parent_movable = parent + // Destroy any ducts under us on the same layer. + // Ducts also self-destruct if placed under a plumbing machine. + // Machines disable when they get moved + for(var/obj/machinery/duct/duct in parent_movable.loc) + if(duct.anchored && (duct.duct_layer & ducting_layer)) + duct.disconnect_duct() if(demand_connects) START_PROCESSING(SSplumbing, src) - for(var/D in GLOB.cardinals) + for(var/direction in GLOB.cardinals) + if(!(direction & (demand_connects | supply_connects))) + continue + for(var/atom/movable/found_atom in get_step(parent, direction)) + if(istype(found_atom, /obj/machinery/duct)) + var/obj/machinery/duct/duct = found_atom + duct.attempt_connect() + continue - if(D & (demand_connects | supply_connects)) - for(var/atom/movable/A in get_step(parent, D)) - - if(istype(A, /obj/machinery/duct)) - var/obj/machinery/duct/duct = A - duct.attempt_connect() - else - for(var/datum/component/plumbing/plumber as anything in A.GetComponents(/datum/component/plumbing)) - if(plumber.ducting_layer == ducting_layer) - direct_connect(plumber, D) + for(var/datum/component/plumbing/plumber as anything in found_atom.GetComponents(/datum/component/plumbing)) + if(plumber.ducting_layer & ducting_layer) + direct_connect(plumber, direction) /// Toggle our machinery on or off. This is called by a hook from default_unfasten_wrench with anchored as only param, so we dont have to copypaste this on every object that can move -/datum/component/plumbing/proc/toggle_active(obj/O, new_state) +/datum/component/plumbing/proc/toggle_active(obj/parent_obj, new_state) SIGNAL_HANDLER if(new_state) enable() @@ -271,45 +264,44 @@ demand_connects = initial(demand_connects) supply_connects = initial(supply_connects) else - for(var/D in GLOB.cardinals) - if(D & initial(demand_connects)) - new_demand_connects += turn(D, angle) - if(D & initial(supply_connects)) - new_supply_connects += turn(D, angle) + for(var/direction in GLOB.cardinals) + if(direction & initial(demand_connects)) + new_demand_connects += turn(direction, angle) + if(direction & initial(supply_connects)) + new_supply_connects += turn(direction, angle) demand_connects = new_demand_connects supply_connects = new_supply_connects ///Give the direction of a pipe, and it'll return wich direction it originally was when it's object pointed SOUTH /datum/component/plumbing/proc/get_original_direction(dir) - var/atom/movable/AM = parent - return turn(dir, dir2angle(AM.dir) - 180) + var/atom/movable/parent_movable = parent + return turn(dir, dir2angle(parent_movable.dir) - 180) //special case in-case we want to connect directly with another machine without a duct -/datum/component/plumbing/proc/direct_connect(datum/component/plumbing/P, dir) - if(!P.active) +/datum/component/plumbing/proc/direct_connect(datum/component/plumbing/plumbing, dir) + if(!plumbing.active) return var/opposite_dir = turn(dir, 180) - if(P.demand_connects & opposite_dir && supply_connects & dir || P.supply_connects & opposite_dir && demand_connects & dir) //make sure we arent connecting two supplies or demands + if(plumbing.demand_connects & opposite_dir && supply_connects & dir || plumbing.supply_connects & opposite_dir && demand_connects & dir) //make sure we arent connecting two supplies or demands var/datum/ductnet/net = new() net.add_plumber(src, dir) - net.add_plumber(P, opposite_dir) + net.add_plumber(plumbing, opposite_dir) -/datum/component/plumbing/proc/hide(atom/movable/AM, should_hide) +/datum/component/plumbing/proc/hide(atom/movable/parent_obj, should_hide) SIGNAL_HANDLER tile_covered = should_hide - AM.update_appearance() + parent_obj.update_appearance() -/datum/component/plumbing/proc/change_ducting_layer(obj/caller, obj/O, new_layer = DUCT_LAYER_DEFAULT) +/datum/component/plumbing/proc/change_ducting_layer(obj/caller, obj/changer, new_layer = DUCT_LAYER_DEFAULT) SIGNAL_HANDLER ducting_layer = new_layer - if(ismovable(parent)) - var/atom/movable/AM = parent - AM.update_appearance() + var/atom/movable/parent_movable = parent + parent_movable.update_appearance() - if(O) - playsound(O, 'sound/items/ratchet.ogg', 10, TRUE) //sound + if(changer) + playsound(changer, 'sound/items/ratchet.ogg', 10, TRUE) //sound //quickly disconnect and reconnect the network. if(active) @@ -348,7 +340,7 @@ demand_connects = NORTH supply_connects = SOUTH -/datum/component/plumbing/manifold/change_ducting_layer(obj/caller, obj/O, new_layer) +/datum/component/plumbing/manifold/change_ducting_layer(obj/caller, obj/changer, new_layer) return #define READY 2 diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm index fe6064cccc8..c750fda7142 100644 --- a/code/datums/components/plumbing/reaction_chamber.dm +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -40,7 +40,7 @@ ///Special connect that we currently use for reaction chambers. Being used so we can keep certain inputs separate, like into a special internal acid container /datum/component/plumbing/acidic_input demand_connects = WEST - demand_color = "yellow" + demand_color = COLOR_YELLOW ducting_layer = SECOND_DUCT_LAYER @@ -50,7 +50,7 @@ ///Special connect that we currently use for reaction chambers. Being used so we can keep certain inputs separate, like into a special internal base container /datum/component/plumbing/alkaline_input demand_connects = EAST - demand_color = "green" + demand_color = COLOR_VIBRANT_LIME ducting_layer = FOURTH_DUCT_LAYER diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 582feb952e8..6574224f645 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -87,7 +87,7 @@ RLD upgrade |= rcd_up.upgrade if((rcd_up.upgrade & RCD_UPGRADE_SILO_LINK) && !silo_mats) silo_mats = AddComponent(/datum/component/remote_materials, "RCD", FALSE, FALSE) - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) qdel(rcd_up) /// Inserts matter into the RCD allowing it to build @@ -105,7 +105,7 @@ RLD if(R.ammoamt <= 0) qdel(R) matter += load - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) loaded = TRUE else if(istype(O, /obj/item/stack)) loaded = loadwithsheets(O, user) @@ -124,17 +124,17 @@ RLD var/amount_to_use = min(S.amount, maxsheets) S.use(amount_to_use) matter += value*amount_to_use - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) to_chat(user, span_notice("You insert [amount_to_use] [S.name] sheets into [src]. ")) return TRUE to_chat(user, span_warning("You can't insert any more [S.name] sheets into [src]!")) return FALSE /obj/item/construction/proc/activate() - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) + playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) /obj/item/construction/attack_self(mob/user) - playsound(src.loc, 'sound/effects/pop.ogg', 50, FALSE) + playsound(loc, 'sound/effects/pop.ogg', 50, FALSE) if(prob(20)) spark_system.start() @@ -358,7 +358,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) T.rcd_act(user, src, RCD_FLOORWALL) useResource(16, user) activate() - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + playsound(loc, 'sound/machines/click.ogg', 50, 1) user.gib() return MANUAL_SUICIDE @@ -709,7 +709,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) if(rcd_results["mode"] == RCD_MACHINE || rcd_results["mode"] == RCD_COMPUTER || rcd_results["mode"] == RCD_FURNISHING) var/turf/target_turf = get_turf(A) if(target_turf.is_blocked_turf(exclude_mobs = TRUE)) - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) qdel(rcd_effect) return FALSE if(!do_after(user, delay, target = A)) @@ -724,7 +724,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) rcd_effect.end_animation() useResource(rcd_results["cost"], user) activate() - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) return TRUE /obj/item/construction/rcd/Initialize(mapload) @@ -1046,7 +1046,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) if(checkResource(deconcost, user)) to_chat(user, span_notice("You start deconstructing [A]...")) user.Beam(A,icon_state="light_beam", time = 15) - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) if(do_after(user, decondelay, target = A)) if(!useResource(deconcost, user)) return FALSE @@ -1060,8 +1060,8 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) if(checkResource(floorcost, user)) to_chat(user, span_notice("You start building a wall light...")) user.Beam(A,icon_state="light_beam", time = 15) - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) - playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, FALSE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/effects/light_flicker.ogg', 50, FALSE) if(do_after(user, floordelay, target = A)) if(!istype(W)) return FALSE @@ -1075,7 +1075,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) candidates += C if(!candidates.len) to_chat(user, span_warning("Valid target not found...")) - playsound(src.loc, 'sound/misc/compiler-failure.ogg', 30, TRUE) + playsound(loc, 'sound/misc/compiler-failure.ogg', 30, TRUE) return FALSE for(var/turf/open/O in candidates) if(istype(O)) @@ -1106,8 +1106,8 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) if(checkResource(floorcost, user)) to_chat(user, span_notice("You start building a floor light...")) user.Beam(A,icon_state="light_beam", time = 15) - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) - playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, TRUE) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) + playsound(loc, 'sound/effects/light_flicker.ogg', 50, TRUE) if(do_after(user, floordelay, target = A)) if(!istype(F)) return FALSE @@ -1170,44 +1170,69 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) var/list/machinery_data = list("cost" = list()) ///This list that holds all the plumbing design types the plumberer can construct. Its purpose is to make it easy to make new plumberer subtypes with a different selection of machines. var/list/plumbing_design_types - ///Possible layers to pick from - var/static/list/layers = list("Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT, "Fourth Layer" = FOURTH_DUCT_LAYER) ///Current selected layer var/current_layer = "Default Layer" + ///Current selected color, for ducts + var/current_color = "omni" /obj/item/construction/plumbing/Initialize(mapload) . = ..() set_plumbing_designs() +/obj/item/construction/plumbing/examine(mob/user) + . = ..() + . += span_notice("Alt-Click to change layer and duct color.") + +/obj/item/construction/plumbing/equipped(mob/user, slot, initial) + . = ..() + if(slot == ITEM_SLOT_HANDS) + RegisterSignal(user, COMSIG_MOUSE_SCROLL_ON, .proc/mouse_wheeled) + else + UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON) + +/obj/item/construction/plumbing/dropped(mob/user, silent) + UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON) + return ..() + +/obj/item/construction/plumbing/cyborg_unequip(mob/user) + UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON) + return ..() + /obj/item/construction/plumbing/attack_self(mob/user) ..() if(!choices.len) - for(var/A in plumbing_design_types) - var/obj/machinery/plumbing/M = A + for(var/obj/machinery/plumbing/plumbing_type as anything in plumbing_design_types) + choices += list(initial(plumbing_type.name) = image(initial(plumbing_type.icon), icon_state = initial(plumbing_type.icon_state))) + name_to_type[initial(plumbing_type.name)] = plumbing_type + machinery_data["cost"][plumbing_type] = plumbing_design_types[plumbing_type] - choices += list(initial(M.name) = image(icon = initial(M.icon), icon_state = initial(M.icon_state))) - name_to_type[initial(M.name)] = M - machinery_data["cost"][A] = plumbing_design_types[A] + // Update duct icon + var/image/duct_image = choices["fluid duct"] + duct_image.color = current_color var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) - if(!check_menu(user)) + if(!choice || !check_menu(user)) return blueprint = name_to_type[choice] playsound(src, 'sound/effects/pop.ogg', 50, FALSE) to_chat(user, span_notice("You change [name]s blueprint to '[choice]'.")) -///Set the list of designs this plumbing rcd can make +/** + * Set the list of designs this plumbing rcd can make + */ /obj/item/construction/plumbing/proc/set_plumbing_designs() plumbing_design_types = list( + // Note that the list MUST include fluid ducts. + /obj/machinery/duct = 1, /obj/machinery/plumbing/input = 5, /obj/machinery/plumbing/output = 5, /obj/machinery/plumbing/tank = 20, /obj/machinery/plumbing/synthesizer = 15, /obj/machinery/plumbing/reaction_chamber = 15, /obj/machinery/plumbing/buffer = 10, - /obj/machinery/plumbing/layer_manifold = 5, //Above are the most common machinery which is shown on the first cycle. Keep new additions below THIS line, unless they're probably gonna be needed alot + /obj/machinery/plumbing/layer_manifold = 5, /obj/machinery/plumbing/pill_press = 20, /obj/machinery/plumbing/acclimator = 10, /obj/machinery/plumbing/bottler = 50, @@ -1223,56 +1248,152 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) ) ///pretty much rcd_create, but named differently to make myself feel less bad for copypasting from a sibling-type -/obj/item/construction/plumbing/proc/create_machine(atom/A, mob/user) - if(!machinery_data || !isopenturf(A)) +/obj/item/construction/plumbing/proc/create_machine(atom/destination, mob/user) + if(!machinery_data || !isopenturf(destination)) return FALSE + if(!canPlace(destination)) + var/obj/blueprint_type = blueprint + to_chat(user, span_notice("There is something blocking you from placing a [initial(blueprint_type.name)] there.")) + return if(checkResource(machinery_data["cost"][blueprint], user) && blueprint) //"cost" is relative to delay at a rate of 10 matter/second (1matter/decisecond) rather than playing with 2 different variables since everyone set it to this rate anyways. - if(do_after(user, machinery_data["cost"][blueprint], target = A)) - if(checkResource(machinery_data["cost"][blueprint], user) && canPlace(A)) + if(do_after(user, machinery_data["cost"][blueprint], target = destination)) + if(checkResource(machinery_data["cost"][blueprint], user) && canPlace(destination)) useResource(machinery_data["cost"][blueprint], user) activate() - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) - new blueprint (A, FALSE, layers[current_layer]) + playsound(loc, 'sound/machines/click.ogg', 50, TRUE) + if(ispath(blueprint, /obj/machinery/duct)) + var/is_omni = current_color == DUCT_COLOR_OMNI + new blueprint(destination, FALSE, GLOB.pipe_paint_colors[current_color], GLOB.plumbing_layers[current_layer], null, is_omni) + else + new blueprint(destination, FALSE, GLOB.plumbing_layers[current_layer]) return TRUE -/obj/item/construction/plumbing/proc/canPlace(turf/T) - if(!isopenturf(T)) +/obj/item/construction/plumbing/proc/canPlace(turf/destination) + if(!isopenturf(destination)) return FALSE . = TRUE - for(var/obj/O in T.contents) - if(O.density) //let's not built ontop of dense stuff, like big machines and other obstacles, it kills my immershion + + var/obj/blueprint_template = blueprint + var/layer_id = GLOB.plumbing_layers[current_layer] + + for(var/obj/content_obj in destination.contents) + // Let's not built ontop of dense stuff, if this is also dense. + if(initial(blueprint_template.density) && content_obj.density) return FALSE -/obj/item/construction/plumbing/afterattack(atom/A, mob/user, proximity) + // Ducts can overlap other plumbing objects IF the layers are different + + // make sure plumbling isn't overlapping. + for(var/datum/component/plumbing/plumber as anything in content_obj.GetComponents(/datum/component/plumbing)) + if(plumber.ducting_layer & layer_id) + return FALSE + + if(istype(content_obj, /obj/machinery/duct)) + // Make sure ducts aren't overlapping. + var/obj/machinery/duct/duct_machine = content_obj + if(duct_machine.duct_layer & layer_id) + return FALSE + +/obj/item/construction/plumbing/afterattack(atom/target, mob/user, proximity) . = ..() if(!prox_check(proximity)) return - if(istype(A, /obj/machinery/plumbing)) - var/obj/machinery/plumbing/P = A - if(P.anchored) - to_chat(user, span_warning("The [P.name] needs to be unanchored!")) + if(istype(target, /obj/machinery/plumbing)) + var/obj/machinery/machine_target = target + if(machine_target.anchored) + to_chat(user, span_warning("The [target.name] needs to be unanchored!")) return - if(do_after(user, 20, target = P)) - P.deconstruct() //Let's not substract matter + if(do_after(user, 20, target = target)) + machine_target.deconstruct() //Let's not substract matter playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect else - create_machine(A, user) + create_machine(target, user) /obj/item/construction/plumbing/AltClick(mob/user) - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE)) + // give a menu to pick layers or colors + var/list/options_menu = list( + "Current Layer" = image('icons/hud/radial.dmi', icon_state = "plumbing_layer[GLOB.plumbing_layers[current_layer]]"), + "Current Color" = image('icons/hud/radial.dmi', icon_state = current_color), + ) + + playsound(loc, 'sound/effects/pop.ogg', 50, FALSE) + var/choice = show_radial_menu(user, src, options_menu, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!check_menu(user)) return - //this is just cycling options through a list - var/current_loc = layers.Find(current_layer) + 1 + switch(choice) + if("Current Layer") + choose_layer_menu(user) + if("Current Color") + choose_color_menu(user) - if(current_loc > layers.len) - current_loc = 1 +/** + * Choose the current layer via radial menu. + * + * Arguments: + * * user - current user. + */ +/obj/item/construction/plumbing/proc/choose_layer_menu(mob/user) + if(!GLOB.plumbing_layer_menu_options.len) + for(var/layer_name in GLOB.plumbing_layers) + GLOB.plumbing_layer_menu_options += list((layer_name) = image('icons/hud/radial.dmi', icon_state = "plumbing_layer[GLOB.plumbing_layers[layer_name]]")) - //We want the key (the define), not the index (the string) - current_layer = layers[current_loc] - to_chat(user, span_notice("You switch [src] to [current_layer].")) + playsound(loc, 'sound/effects/pop.ogg', 50, FALSE) + var/new_layer = show_radial_menu(user, src, GLOB.plumbing_layer_menu_options, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!new_layer || !check_menu(user)) + return + + current_layer = new_layer + to_chat(user, span_notice("You set the layer to [new_layer].")) + +/** + * Choose the current color via radial menu. + * + * Arguments: + * * user - current user. + */ +/obj/item/construction/plumbing/proc/choose_color_menu(mob/user) + if(!GLOB.plumbing_color_menu_options.len) + for(var/color_name in GLOB.pipe_paint_colors) + GLOB.plumbing_color_menu_options += list((color_name) = image('icons/hud/radial.dmi', icon_state = color_name)) + + playsound(loc, 'sound/effects/pop.ogg', 50, FALSE) + var/new_color = show_radial_menu(user, src, GLOB.plumbing_color_menu_options, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!new_color || !check_menu(user)) + return + + current_color = new_color + to_chat(user, span_notice("You set the color to [new_color].")) + +/** + * Choose layer via mouse wheel, like an RPD + * + * Arguments: + * * source - the user + * * A - the atom being selected, unused. + * * delta_x - X scroll delta + * * delta_y - Y scroll delta + */ +/obj/item/construction/plumbing/proc/mouse_wheeled(mob/source, atom/A, delta_x, delta_y, params) + SIGNAL_HANDLER + if(source.incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS)) + return + if(delta_y == 0) + return + + if(delta_y < 0) + var/current_loc = GLOB.plumbing_layers.Find(current_layer) + 1 + if(current_loc > GLOB.plumbing_layers.len) + current_loc = 1 + current_layer = GLOB.plumbing_layers[current_loc] + else + var/current_loc = GLOB.plumbing_layers.Find(current_layer) - 1 + if(current_loc < 1) + current_loc = GLOB.plumbing_layers.len + current_layer = GLOB.plumbing_layers[current_loc] + to_chat(source, span_notice("You set the layer to [current_layer].")) /obj/item/construction/plumbing/research name = "research plumbing constructor" @@ -1285,17 +1406,18 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) /obj/item/construction/plumbing/research/set_plumbing_designs() plumbing_design_types = list( - /obj/machinery/plumbing/input = 5, - /obj/machinery/plumbing/output = 5, - /obj/machinery/plumbing/tank = 20, - /obj/machinery/plumbing/acclimator = 10, - /obj/machinery/plumbing/filter = 5, - /obj/machinery/plumbing/grinder_chemical = 30, - /obj/machinery/plumbing/reaction_chamber = 15, - /obj/machinery/plumbing/splitter = 5, - /obj/machinery/plumbing/disposer = 10, - /obj/machinery/plumbing/growing_vat = 20 -) + /obj/machinery/duct = 1, + /obj/machinery/plumbing/input = 5, + /obj/machinery/plumbing/output = 5, + /obj/machinery/plumbing/tank = 20, + /obj/machinery/plumbing/acclimator = 10, + /obj/machinery/plumbing/filter = 5, + /obj/machinery/plumbing/reaction_chamber = 15, + /obj/machinery/plumbing/grinder_chemical = 30, + /obj/machinery/plumbing/splitter = 5, + /obj/machinery/plumbing/disposer = 10, + /obj/machinery/plumbing/growing_vat = 20 + ) /obj/item/rcd_upgrade diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index cba7f2b01b9..68d86eb44e5 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -139,9 +139,6 @@ ///What layer we set it to var/target_layer = DUCT_LAYER_DEFAULT - ///Assoc list for possible layers - var/list/layers = list("Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT, "Fourth Layer" = FOURTH_DUCT_LAYER) - /obj/item/plunger/attack_atom(obj/O, mob/living/user, params) if(layer_mode) SEND_SIGNAL(O, COMSIG_MOVABLE_CHANGE_DUCT_LAYER, O, target_layer) @@ -178,10 +175,10 @@ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE)) return - var/new_layer = tgui_input_list(user, "Select a layer", "Layer", layers) + var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers) if(isnull(new_layer)) return - target_layer = layers[new_layer] + target_layer = GLOB.plumbing_layers[new_layer] ///A faster reinforced plunger /obj/item/plunger/reinforced diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index 295cc7b790d..6faa86ab488 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -7,6 +7,7 @@ All the important duct code: name = "fluid duct" icon = 'icons/obj/plumbing/fluid_ducts.dmi' icon_state = "nduct" + layer = PLUMBING_PIPE_VISIBILE_LAYER use_power = NO_POWER_USE @@ -22,7 +23,7 @@ All the important duct code: var/capacity = 10 ///the color of our duct - var/duct_color = null + 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 @@ -35,122 +36,113 @@ All the important duct code: 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() - ///wheter we just unanchored or drop whatever is in the variable. either is safe + ///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 = "#ffffff", layer_of_duct = DUCT_LAYER_DEFAULT, force_connects) +/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()) - qdel(src) - CRASH("Overlapping ducts detected") - - 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) - duct_layer = layer_of_duct - if(!ignore_colors) - duct_color = color_of_duct - if(duct_color) - add_atom_colour(duct_color, FIXED_COLOUR_PRIORITY) + 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() - for(var/obj/machinery/duct/D in loc) - if(D == src) - continue - if(D.duct_layer & duct_layer) - return INITIALIZE_HINT_QDEL //If we have company, end it all - 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/atom/movable/AM in loc) - for(var/datum/component/plumbing/plumber as anything in AM.GetComponents(/datum/component/plumbing)) - if(plumber.active) - disconnect_duct() //let's not built under plumbing machinery - return - - for(var/D in GLOB.cardinals) - if(dumb && !(D & connects)) + for(var/direction in GLOB.cardinals) + if(dumb && !(direction & connects)) continue - for(var/atom/movable/AM in get_step(src, D)) - if(connect_network(AM, D)) - add_connects(D) + 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/AM, direction, ignore_color) - if(istype(AM, /obj/machinery/duct)) - return connect_duct(AM, direction, ignore_color) +/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 AM.GetComponents(/datum/component/plumbing)) + 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/D, direction, ignore_color) +/obj/machinery/duct/proc/connect_duct(obj/machinery/duct/other, direction) var/opposite_dir = turn(direction, 180) - if(!active || !D.active) + if(!active || !other.active) return - if(!dumb && D.dumb && !(opposite_dir & D.connects)) + if(!dumb && other.dumb && !(opposite_dir & other.connects)) return - if(dumb && D.dumb && !(connects & D.connects)) //we eliminated a few more scenarios in attempt connect + if(dumb && other.dumb && !(connects & other.connects)) //we eliminated a few more scenarios in attempt connect return - if((duct == D.duct) && duct)//check if we're not just comparing two null values - add_neighbour(D, direction) + if((duct == other.duct) && duct)//check if we're not just comparing two null values + add_neighbour(other, direction) - D.add_connects(opposite_dir) - D.update_appearance() + other.add_connects(opposite_dir) + other.update_appearance() return TRUE //tell the current pipe to also update it's sprite - if(!(D in neighbours)) //we cool - if((duct_color != D.duct_color) && !(ignore_colors || D.ignore_colors)) + if(!(other in neighbours)) //we cool + if((duct_color != other.duct_color) && !(ignore_colors || other.ignore_colors)) return - if(!(duct_layer & D.duct_layer)) + if(!(duct_layer & other.duct_layer)) return - if(D.duct) + if(other.duct) if(duct) - duct.assimilate(D.duct) + duct.assimilate(other.duct) else - D.duct.add_duct(src) + other.duct.add_duct(src) else if(duct) - duct.add_duct(D) + duct.add_duct(other) else create_duct() - duct.add_duct(D) + duct.add_duct(other) - add_neighbour(D, direction) + 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(D, .proc/attempt_connect)) + addtimer(CALLBACK(other, .proc/attempt_connect)) return TRUE ///connect to a plumbing object -/obj/machinery/duct/proc/connect_plumber(datum/component/plumbing/P, direction) +/obj/machinery/duct/proc/connect_plumber(datum/component/plumbing/plumbing, direction) var/opposite_dir = turn(direction, 180) - if(duct_layer != P.ducting_layer) + if(!(duct_layer & plumbing.ducting_layer)) return FALSE - if(!P.active) + if(!plumbing.active) return - var/comp_directions = P.supply_connects + P.demand_connects //they should never, ever have supply and demand connects overlap or catastrophic failure + 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(P, opposite_dir)) - neighbours[P.parent] = direction + 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 @@ -164,9 +156,12 @@ All the important duct code: reset_connects(0) update_appearance() if(ispath(drop_on_wrench)) - new drop_on_wrench(drop_location()) + 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(!QDELETED(src)) + 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 @@ -184,16 +179,17 @@ All the important duct code: 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/D, direction) - if(!(D in neighbours)) - neighbours[D] = direction - if(!(src in D.neighbours)) - D.neighbours[src] = turn(direction, 180) +/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/D in neighbours) - D.neighbours.Remove(src) + for(var/obj/machinery/duct/other in neighbours) + other.neighbours.Remove(src) + other.generate_connects() neighbours = list() ///add a connect direction @@ -214,24 +210,24 @@ All the important duct code: ///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/A in GLOB.cardinals) - if(A & connects) - for(var/obj/machinery/duct/D in get_step(src, A)) - if((turn(A, 180) & D.connects) && D.active) - adjacents += D + 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/D in GLOB.cardinals) - if(D & connects) - if(D == NORTH) + for(var/direction in GLOB.cardinals) + switch(direction & connects) + if(NORTH) temp_icon += "_n" - if(D == SOUTH) + if(SOUTH) temp_icon += "_s" - if(D == EAST) + if(EAST) temp_icon += "_e" - if(D == WEST) + if(WEST) temp_icon += "_w" icon_state = temp_icon return ..() @@ -239,7 +235,8 @@ All the important duct code: ///update the layer we are on /obj/machinery/duct/proc/handle_layer() var/offset - switch(duct_layer)//it's a bitfield, but it's fine because it only works when there's one layer, and multiple layers should be handled differently + //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) @@ -253,6 +250,7 @@ All the important duct code: pixel_x = offset pixel_y = offset + layer = initial(layer) + duct_layer * 0.0003 /obj/machinery/duct/set_anchored(anchorvalue) . = ..() @@ -264,10 +262,10 @@ All the important duct code: else disconnect_duct(TRUE) -/obj/machinery/duct/wrench_act(mob/living/user, obj/item/I) //I can also be the RPD +/obj/machinery/duct/wrench_act(mob/living/user, obj/item/wrench) //I can also be the RPD ..() add_fingerprint(user) - I.play_tool_sound(src) + wrench.play_tool_sound(src) if(anchored || can_anchor()) set_anchored(!anchored) user.visible_message( \ @@ -277,14 +275,15 @@ All the important duct code: 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/T) - if(!T) - T = get_turf(src) - for(var/obj/machinery/duct/D in T) - if(!anchored || D == src) - continue - for(var/A in GLOB.cardinals) - if(A & connects && A & D.connects) +/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 @@ -297,26 +296,29 @@ All the important duct code: disconnect_duct() return ..() -/obj/machinery/duct/MouseDrop_T(atom/A, mob/living/user) - if(!istype(A, /obj/machinery/duct)) +/obj/machinery/duct/MouseDrop_T(atom/drag_source, mob/living/user) + if(!istype(drag_source, /obj/machinery/duct)) return - var/obj/machinery/duct/D = A - var/obj/item/I = user.get_active_held_item() - if(I?.tool_behaviour != TOOL_WRENCH) - to_chat(user, span_warning("You need to be holding a wrench in your active hand to do that!")) + var/obj/machinery/duct/other = drag_source + if(get_dist(src, other) != 1) return - if(get_dist(src, D) != 1) - return - var/direction = get_dir(src, D) + var/direction = get_dir(src, other) if(!(direction in GLOB.cardinals)) return - if(duct_layer != D.duct_layer) + 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(D, direction) - connect_network(D, direction, TRUE) + 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" @@ -330,22 +332,21 @@ All the important duct code: 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" - ///Assoc index with all the available layers. yes five might be a bit much. Colors uses a global by the way - var/list/layers = list("Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT, "Fourth Layer" = FOURTH_DUCT_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", layers) + 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) + 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) @@ -355,16 +356,25 @@ All the important duct code: if(!proximity) return if(istype(target, /obj/machinery/duct)) - var/obj/machinery/duct/D = target - if(!D.anchored) - add(1) - qdel(D) + 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(istype(target, /turf/open) && use(1)) + if(isopenturf(target) && use(1)) var/turf/open/open_turf = target - new /obj/machinery/duct(open_turf, FALSE, GLOB.pipe_paint_colors[duct_color], layers[duct_layer]) + 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 diff --git a/code/modules/plumbing/plumbers/_plumb_machinery.dm b/code/modules/plumbing/plumbers/_plumb_machinery.dm index f9930bf5f6b..54cea5f5ca2 100644 --- a/code/modules/plumbing/plumbers/_plumb_machinery.dm +++ b/code/modules/plumbing/plumbers/_plumb_machinery.dm @@ -14,7 +14,6 @@ var/buffer = 50 ///Flags for reagents, like INJECTABLE, TRANSPARENT bla bla everything thats in DEFINES/reagents.dm var/reagent_flags = TRANSPARENT - ///wheter we partake in rcd construction or not /obj/machinery/plumbing/Initialize(mapload, bolt = TRUE) . = ..() @@ -98,6 +97,8 @@ /obj/machinery/plumbing/layer_manifold/Initialize(mapload, bolt, layer) . = ..() + AddComponent(/datum/component/plumbing/manifold, bolt, FIRST_DUCT_LAYER) AddComponent(/datum/component/plumbing/manifold, bolt, SECOND_DUCT_LAYER) AddComponent(/datum/component/plumbing/manifold, bolt, THIRD_DUCT_LAYER) AddComponent(/datum/component/plumbing/manifold, bolt, FOURTH_DUCT_LAYER) + AddComponent(/datum/component/plumbing/manifold, bolt, FIFTH_DUCT_LAYER) diff --git a/icons/hud/radial.dmi b/icons/hud/radial.dmi index 5e301600956..54b28e2f36f 100644 Binary files a/icons/hud/radial.dmi and b/icons/hud/radial.dmi differ diff --git a/icons/obj/plumbing/connects.dmi b/icons/obj/plumbing/connects.dmi index 32277ffac65..943b580a624 100644 Binary files a/icons/obj/plumbing/connects.dmi and b/icons/obj/plumbing/connects.dmi differ diff --git a/icons/obj/plumbing/fluid_ducts.dmi b/icons/obj/plumbing/fluid_ducts.dmi index d911e25b9c9..f28a4c35853 100644 Binary files a/icons/obj/plumbing/fluid_ducts.dmi and b/icons/obj/plumbing/fluid_ducts.dmi differ