diff --git a/.vscode/settings.json b/.vscode/settings.json index c1c58bc3287..a5f5ccd084c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,10 +3,7 @@ "./tgui-next" ], - "workbench.editorAssociations": [ - { - "filenamePattern": "*.dmi", - "viewType": "imagePreview.previewEditor" - } - ] + "workbench.editorAssociations": { + "*.dmi": "imagePreview.previewEditor" + } } diff --git a/_maps/map_files/debug/multiz.dmm b/_maps/map_files/debug/multiz.dmm index fa55c2a08e6..2f24af453e6 100644 --- a/_maps/map_files/debug/multiz.dmm +++ b/_maps/map_files/debug/multiz.dmm @@ -106,9 +106,7 @@ /turf/open/openspace, /area/space) "av" = ( -/obj/structure/stairs{ - dir = 1 - }, +/obj/structure/stairs/north, /turf/open/floor/plating, /area/hallway/secondary/service) "aw" = ( @@ -910,7 +908,7 @@ "dO" = ( /obj/structure/table, /obj/machinery/light, -/obj/item/twohanded/fireaxe, +/obj/item/fireaxe, /obj/item/extinguisher, /turf/open/floor/plasteel, /area/storage/primary) @@ -1185,8 +1183,7 @@ /turf/open/floor/plating, /area/space) "iq" = ( -/obj/machinery/power/deck_relay, -/obj/structure/cable, +/obj/structure/cable/multilayer/multiz, /turf/open/floor/plating, /area/construction) "iu" = ( @@ -1275,8 +1272,7 @@ /turf/open/floor/plasteel, /area/engine/storage) "nF" = ( -/obj/structure/cable, -/obj/machinery/power/deck_relay, +/obj/structure/cable/multilayer/multiz, /turf/open/floor/plating, /area/hallway/secondary/service) "od" = ( @@ -1349,7 +1345,7 @@ }, /area/hallway/secondary/service) "sm" = ( -/obj/structure/stairs, +/obj/structure/stairs/south, /turf/open/floor/plating, /area/construction) "su" = ( @@ -1775,8 +1771,7 @@ /turf/open/floor/plating, /area/engine/storage) "Vm" = ( -/obj/machinery/power/deck_relay, -/obj/structure/cable, +/obj/structure/cable/multilayer/multiz, /turf/open/floor/plating, /area/engine/storage) "Vn" = ( diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm new file mode 100644 index 00000000000..8e84149de35 --- /dev/null +++ b/code/__DEFINES/dcs/signals.dm @@ -0,0 +1,7 @@ + + /// If returned from [COMSIG_ATOM_UPDATE_ICON] it prevents the atom from updating its icon state. + #define COMSIG_ATOM_NO_UPDATE_ICON_STATE UPDATE_ICON_STATE + /// If returned from [COMSIG_ATOM_UPDATE_ICON] it prevents the atom from updating its overlays. + #define COMSIG_ATOM_NO_UPDATE_OVERLAYS UPDATE_OVERLAYS + ///from base of [atom/update_icon_state]: () + #define COMSIG_ATOM_UPDATE_ICON_STATE "atom_update_icon_state" diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 80850905630..c5e4610f1b6 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -48,6 +48,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff. /// Is this object currently processing in the atmos object list? #define ATMOS_IS_PROCESSING_1 (1<<16) +/// Update the atom's icon state //turf-only flags #define NOJAUNT_1 (1<<0) @@ -60,6 +61,25 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 These defines are used specifically with the atom/pass_flags bitmask the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example) */ + +/// Update the atom's icon state +#define UPDATE_ICON_STATE (1<<2) +/// Update the atom's name +#define UPDATE_NAME (1<<0) +/// Update the atom's desc +#define UPDATE_DESC (1<<1) +/// Update the atom's icon state +#define UPDATE_ICON_STATE (1<<2) +/// Update the atom's overlays +#define UPDATE_OVERLAYS (1<<3) +/// Update the atom's greyscaling +#define UPDATE_GREYSCALE (1<<4) +/// Update the atom's smoothing. (More accurately, queue it for an update) +#define UPDATE_SMOOTHING (1<<5) +/// Update the atom's icon +#define UPDATE_ICON (UPDATE_ICON_STATE|UPDATE_OVERLAYS) + + //flags for pass_flags #define PASSTABLE (1<<0) #define PASSGLASS (1<<1) diff --git a/code/__DEFINES/power.dm b/code/__DEFINES/power.dm index 1892220dbda..9262eb36ea9 100644 --- a/code/__DEFINES/power.dm +++ b/code/__DEFINES/power.dm @@ -2,6 +2,8 @@ #define CABLE_LAYER_2 "l2" #define CABLE_LAYER_3 "l3" +#define MACHINERY_LAYER_1 1 + #define SOLAR_TRACK_OFF 0 #define SOLAR_TRACK_TIMED 1 #define SOLAR_TRACK_AUTO 2 diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm new file mode 100644 index 00000000000..17b8d501f4b --- /dev/null +++ b/code/__DEFINES/span.dm @@ -0,0 +1 @@ +#define span_notice(str) ("" + str + "") diff --git a/code/datums/elements/undertile.dm b/code/datums/elements/undertile.dm new file mode 100644 index 00000000000..a6a1dddc85b --- /dev/null +++ b/code/datums/elements/undertile.dm @@ -0,0 +1,61 @@ +///Add to an object if you want to be able to be hidden under tiles +/datum/element/undertile + element_flags = ELEMENT_BESPOKE | COMPONENT_DUPE_HIGHLANDER + id_arg_index = 2 + + ///the invisiblity trait applied, like TRAIT_T_RAY_VISIBLE + var/invisibility_trait + ///level of invisibility applied when under a tile. Could be INVISIBILITY_OBSERVER if you still want it to be visible to ghosts + var/invisibility_level + ///an overlay for the tile if we wish to apply that + var/tile_overlay + ///whether we use alpha or not. TRUE uses ALPHA_UNDERTILE because otherwise we have 200 different instances of this element for different alphas + var/use_alpha + ///We will switch between anchored and unanchored. for stuff like satchels that shouldn't be pullable under tiles but are otherwise unanchored + var/use_anchor + +/datum/element/undertile/Attach(datum/target, invisibility_trait, invisibility_level = INVISIBILITY_MAXIMUM, tile_overlay, use_alpha = TRUE, use_anchor = FALSE) + . = ..() + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_OBJ_HIDE, .proc/hide) + + src.invisibility_trait = invisibility_trait + src.invisibility_level = invisibility_level + src.tile_overlay = tile_overlay + src.use_alpha = use_alpha + src.use_anchor = use_anchor + +///called when a tile has been covered or uncovered +/datum/element/undertile/proc/hide(atom/movable/source, covered) + SIGNAL_HANDLER + + source.invisibility = covered ? invisibility_level : 0 + + var/turf/T = get_turf(source) + + if(covered) + if(invisibility_trait) + ADD_TRAIT(source, invisibility_trait, TRAIT_GENERIC) + if(tile_overlay) + T.add_overlay(tile_overlay) + if(use_alpha) + source.alpha = ALPHA_UNDERTILE + if(use_anchor) + source.set_anchored(TRUE) + + else + if(invisibility_trait) + REMOVE_TRAIT(source, invisibility_trait, TRAIT_GENERIC) + if(tile_overlay) + T.overlays -= tile_overlay + if(use_alpha) + source.alpha = 255 + if(use_anchor) + source.set_anchored(FALSE) + +/datum/element/undertile/Detach(atom/movable/AM, visibility_trait, invisibility_level = INVISIBILITY_MAXIMUM) + . = ..() + + hide(AM, FALSE) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 31eb9aad15e..b68101d1efd 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -40,6 +40,12 @@ var/rad_flags = NONE // Will move to flags_1 when i can be arsed to var/rad_insulation = RAD_NO_INSULATION + + ///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.) + ///The list referenced by this var can be shared by multiple objects and should not be directly modified. Instead, use [set_custom_materials][/atom/proc/set_custom_materials]. + var/list/datum/material/custom_materials + ///Bitfield for how the atom handles materials. + /atom/New(loc, ...) //atom creation method that preloads variables at creation if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() @@ -770,6 +776,13 @@ var/suffix = forced_by ? " FORCED by [forced_by]" : "" log_message("[prefix]\"[message]\"[suffix]", message_type, log_globally=log_globally) + +/// Updates the icon state of the atom +/atom/proc/update_icon_state() + SHOULD_CALL_PARENT(TRUE) + return SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON_STATE) + + // Helper for logging of messages with only one sender and receiver /proc/log_directed_talk(atom/source, atom/target, message, message_type, tag) if(!tag) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 17f29b35443..40d78f07e14 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -1,6 +1,6 @@ //Use this only for things that aren't a subtype of obj/machinery/power //For things that are, override "should_have_node()" on them -GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/grille, /obj/structure/cable_bridge))) +GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/grille))) #define UNDER_SMES -1 #define UNDER_TERMINAL 1 @@ -17,37 +17,39 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri icon = 'icons/obj/power_cond/layer_cable.dmi' icon_state = "l2-1-2-4-8-node" color = "yellow" - level = 1 //is underfloor layer = WIRE_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER anchored = TRUE obj_flags = CAN_BE_HIT | ON_BLUEPRINTS var/linked_dirs = 0 //bitflag var/node = FALSE //used for sprites display - var/cable_layer = CABLE_LAYER_2 + var/cable_layer = CABLE_LAYER_2 //bitflag + var/machinery_layer = MACHINERY_LAYER_1 //bitflag var/datum/powernet/powernet /obj/structure/cable/layer1 color = "red" cable_layer = CABLE_LAYER_1 + machinery_layer = null layer = WIRE_LAYER - 0.01 icon_state = "l1-1-2-4-8-node" /obj/structure/cable/layer3 color = "blue" cable_layer = CABLE_LAYER_3 + machinery_layer = null layer = WIRE_LAYER + 0.01 icon_state = "l3-1-2-4-8-node" /obj/structure/cable/Initialize(mapload) . = ..() - var/turf/T = get_turf(src) // hide if turf is not intact - if(level==1) - hide(T.intact) GLOB.cable_list += src //add it to the global cable list - connect_wire() + Connect_cable() + AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) -/obj/structure/cable/proc/connect_wire(clear_before_updating = FALSE) + +///Set the linked indicator bitflags +/obj/structure/cable/proc/Connect_cable(clear_before_updating = FALSE) var/under_thing = NONE if(clear_before_updating) linked_dirs = 0 @@ -82,24 +84,27 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri continue var/inverse = turn(check_dir, 180) for(var/obj/structure/cable/C in TB) - if(C.cable_layer == cable_layer) + if(C.cable_layer & cable_layer) linked_dirs |= check_dir C.linked_dirs |= inverse C.update_icon() update_icon() -/obj/structure/cable/Destroy() // called when a cable is deleted - //Clear the linked indicator bitflags +///Clear the linked indicator bitflags +/obj/structure/cable/proc/Disconnect_cable() for(var/check_dir in GLOB.cardinals) var/inverse = turn(check_dir, 180) if(linked_dirs & check_dir) var/TB = get_step(loc, check_dir) for(var/obj/structure/cable/C in TB) - if(cable_layer == C.cable_layer) + if(cable_layer & C.cable_layer) C.linked_dirs &= ~inverse C.update_icon() +/obj/structure/cable/Destroy() // called when a cable is deleted + Disconnect_cable() + if(powernet) cut_cable_from_powernet() // update the powernets GLOB.cable_list -= src //remove it from global cable list @@ -108,40 +113,36 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri /obj/structure/cable/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) - new /obj/item/stack/cable_coil(get_turf(loc), 1) + new /obj/item/stack/cable_coil(drop_location(), 1) qdel(src) /////////////////////////////////// // General procedures /////////////////////////////////// -//If underfloor, hide the cable -/obj/structure/cable/hide(i) - if(level == 1 && isturf(loc)) - invisibility = i ? INVISIBILITY_MAXIMUM : 0 - update_icon() - -/obj/structure/cable/update_icon() +/obj/structure/cable/update_icon_state() if(!linked_dirs) - icon_state = "[cable_layer]-noconnection" - else - var/list/dir_icon_list = list() - for(var/check_dir in GLOB.cardinals) - if(linked_dirs & check_dir) - dir_icon_list += "[check_dir]" - var/dir_string = dir_icon_list.Join("-") - if(dir_icon_list.len > 1) - for(var/obj/O in loc) - if(GLOB.wire_node_generating_types[O.type]) + icon_state = "l[cable_layer]-noconnection" + return ..() + + var/list/dir_icon_list = list() + for(var/check_dir in GLOB.cardinals) + if(linked_dirs & check_dir) + dir_icon_list += "[check_dir]" + var/dir_string = dir_icon_list.Join("-") + if(dir_icon_list.len > 1) + for(var/obj/O in loc) + if(GLOB.wire_node_generating_types[O.type]) + dir_string = "[dir_string]-node" + break + else if(istype(O, /obj/machinery/power)) + var/obj/machinery/power/P = O + if(P.should_have_node()) dir_string = "[dir_string]-node" break - else if(istype(O, /obj/machinery/power)) - var/obj/machinery/power/P = O - if(P.should_have_node()) - dir_string = "[dir_string]-node" - break - dir_string = "[cable_layer]-[dir_string]" - icon_state = dir_string + dir_string = "l[cable_layer]-[dir_string]" + icon_state = dir_string + return ..() /obj/structure/cable/proc/handlecable(obj/item/W, mob/user, params) @@ -250,7 +251,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(src == C) continue - if(cable_layer != C.cable_layer) + if(!(cable_layer & C.cable_layer)) continue if(C.linked_dirs & inverse_dir) //we've got a matching cable in the neighbor turf @@ -306,17 +307,21 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri /obj/structure/cable/proc/get_cable_connections(powernetless_only) . = list() var/turf/T = get_turf(src) - if(locate(/obj/structure/cable_bridge) in T) - for(var/obj/structure/cable/C in T) - if(C != src) - . += C for(var/check_dir in GLOB.cardinals) if(linked_dirs & check_dir) T = get_step(src, check_dir) for(var/obj/structure/cable/C in T) - if(cable_layer == C.cable_layer) + if(cable_layer & C.cable_layer) . += C +/obj/structure/cable/proc/get_all_cable_connections(powernetless_only) + . = list() + var/turf/T + for(var/check_dir in GLOB.cardinals) + T = get_step(src, check_dir) + for(var/obj/structure/cable/C in T.contents - src) + . += C + /obj/structure/cable/proc/get_machine_connections(powernetless_only) . = list() for(var/obj/machinery/power/P in get_turf(src)) @@ -324,14 +329,14 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(P.anchored) . += P -/obj/structure/cable/proc/auto_propogate_cut_cable(obj/O) +/obj/structure/cable/proc/auto_propagate_cut_cable(obj/O) if(O && !QDELETED(O)) var/datum/powernet/newPN = new()// creates a new powernet... propagate_network(O, newPN)//... and propagates it to the other side of the cable //Makes a new network for the cable and propgates it. -//If it finds another network in the process, aborts and uses that one and propogates off of it instead -/obj/structure/cable/proc/propogate_if_no_network() +//If it finds another network in the process, aborts and uses that one and propagates off of it instead +/obj/structure/cable/proc/propagate_if_no_network() if(powernet) return var/datum/powernet/newPN = new() @@ -366,7 +371,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(first) first = FALSE continue - addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables + addtimer(CALLBACK(O, .proc/auto_propagate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables /////////////////////////////////////////////// // The cable coil object, used for laying cable @@ -376,12 +381,11 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri // Definitions //////////////////////////////// -GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15), - new/datum/stack_recipe("cable bridge", /obj/structure/cable_bridge, 15))) +GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15), new/datum/stack_recipe("multilayer cable", /obj/structure/cable/multilayer, 1), new/datum/stack_recipe("multiZ cable", /obj/structure/cable/multilayer/multiz, 1))) /obj/item/stack/cable_coil name = "cable coil" - custom_price = 30 + custom_price = 75 gender = NEUTER //That's a cable coil sounds better than that's some cable coils icon = 'icons/obj/power.dmi' icon_state = "coil" @@ -398,7 +402,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain w_class = WEIGHT_CLASS_SMALL throw_speed = 3 throw_range = 5 - materials = list(MAT_METAL=10, MAT_GLASS=5) + custom_materials = list(/datum/material/iron=10, /datum/material/glass=5) flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BELT attack_verb = list("whipped", "lashed", "disciplined", "flogged") @@ -407,6 +411,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil usesound = 'sound/items/deconstruct.ogg' var/obj/structure/cable/target_type = /obj/structure/cable + var/target_layer = CABLE_LAYER_2 /obj/item/stack/cable_coil/Initialize(mapload, new_amount = null) . = ..() @@ -433,27 +438,56 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain return FALSE return TRUE +GLOBAL_LIST(cable_radial_layer_list) + /obj/item/stack/cable_coil/CtrlClick(mob/living/user) + if(loc!=user) + return ..() if(!user) return - var/list/layer_list = list( + if(!GLOB.cable_radial_layer_list) + GLOB.cable_radial_layer_list = list( "Layer 1" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-red"), "Layer 2" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-yellow"), - "Layer 3" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-blue") + "Layer 3" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-blue"), + "Multilayer cable hub" = image(icon = 'icons/obj/power.dmi', icon_state = "cable_bridge"), + "Multi Z layer cable hub" = image(icon = 'icons/obj/power.dmi', icon_state = "cablerelay-broken-cable") ) - var/layer_result = show_radial_menu(user, src, layer_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + var/layer_result = show_radial_menu(user, src, GLOB.cable_radial_layer_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) if(!check_menu(user)) return switch(layer_result) if("Layer 1") + name = "cable coil" + icon_state = "coil" color = "red" target_type = /obj/structure/cable/layer1 + target_layer = CABLE_LAYER_1 if("Layer 2") + name = "cable coil" + icon_state = "coil" color = "yellow" target_type = /obj/structure/cable + target_layer = CABLE_LAYER_2 if("Layer 3") + name = "cable coil" + icon_state = "coil" color = "blue" target_type = /obj/structure/cable/layer3 + target_layer = CABLE_LAYER_3 + if("Multilayer cable hub") + name = "multilayer cable hub" + icon_state = "cable_bridge" + color = "white" + target_type = /obj/structure/cable/multilayer + target_layer = CABLE_LAYER_2 + if("Multi Z layer cable hub") + name = "multi z layer cable hub" + icon_state = "cablerelay-broken-cable" + color = "white" + target_type = /obj/structure/cable/multilayer/multiz + target_layer = CABLE_LAYER_2 + update_icon() /////////////////////////////////// @@ -476,11 +510,6 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain else return ..() - -/obj/item/stack/cable_coil/update_icon() - icon_state = "[initial(item_state)][amount < 3 ? amount : ""]" - name = "cable [amount < 3 ? "piece" : "coil"]" - //add cables to the stack /obj/item/stack/cable_coil/proc/give(extra) if(amount + extra > max_amount) @@ -512,7 +541,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain return for(var/obj/structure/cable/C in T) - if(target_type == C.type) + if(C.cable_layer & target_layer) to_chat(user, "There's already a cable at that position!") return @@ -552,45 +581,164 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain /obj/item/stack/cable_coil/cyborg is_cyborg = 1 - materials = list() + custom_materials = list() cost = 1 -/obj/structure/cable_bridge - name = "cable bridge" - desc = "A bridge to connect different cable layers, or link terminals to incompatible cable layers" +#undef UNDER_SMES +#undef UNDER_TERMINAL + +///multilayer cable to connect different layers +/obj/structure/cable/multilayer + name = "multilayer cable hub" + desc = "A flexible, superconducting insulated multilayer hub for heavy-duty multilayer power transfer." icon = 'icons/obj/power.dmi' icon_state = "cable_bridge" - level = 1 //is underfloor - layer = WIRE_LAYER + 0.02 //Above all the cables but below terminals - anchored = TRUE - obj_flags = CAN_BE_HIT | ON_BLUEPRINTS + cable_layer = CABLE_LAYER_2 + machinery_layer = MACHINERY_LAYER_1 + layer = WIRE_LAYER - 0.02 //Below all cables Disabled layers can lay over hub + color = "white" + var/obj/effect/node/machinery_node + var/obj/effect/node/layer1/cable_node_1 + var/obj/effect/node/layer2/cable_node_2 + var/obj/effect/node/layer3/cable_node_3 + +/obj/effect/node + icon = 'icons/obj/power_cond/layer_cable.dmi' + icon_state = "l2-noconnection" + vis_flags = VIS_INHERIT_ID|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER + color = "black" + +/obj/effect/node/layer1 + color = "red" + icon_state = "l1-1-2-4-8-node" + vis_flags = VIS_INHERIT_ID|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER|VIS_UNDERLAY + +/obj/effect/node/layer2 + color = "yellow" + icon_state = "l2-1-2-4-8-node" + vis_flags = VIS_INHERIT_ID|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER|VIS_UNDERLAY + +/obj/effect/node/layer3 + color = "blue" + icon_state = "l4-1-2-4-8-node" + vis_flags = VIS_INHERIT_ID|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER|VIS_UNDERLAY + +/obj/structure/cable/multilayer/update_icon_state() + return + +/obj/structure/cable/multilayer/update_icon() + var/R = 50 + var/G = 50 + var/B = 50 + + R += cable_layer & CABLE_LAYER_1 ? 150 : 0 + G += cable_layer & CABLE_LAYER_2 ? 150 : 0 + B += cable_layer & CABLE_LAYER_3 ? 150 : 0 + + color = rgb(R, G, B) -/obj/structure/cable_bridge/Initialize(mapload) + machinery_node?.alpha = machinery_layer & MACHINERY_LAYER_1 ? 255 : 0 + + cable_node_1?.alpha = cable_layer & CABLE_LAYER_1 ? 255 : 0 + + cable_node_2?.alpha = cable_layer & CABLE_LAYER_2 ? 255 : 0 + + cable_node_3?.alpha = cable_layer & CABLE_LAYER_3 ? 255 : 0 + + return ..() + +/obj/structure/cable/multilayer/Initialize(mapload) . = ..() - if (!mapload) - var/turf/T = get_turf(src) // hide if turf is not intact - if(level==1) - hide(T.intact) - var/first = TRUE - var/datum/powernet/PN - for(var/obj/structure/cable/C in get_turf(src)) - C.update_icon() - if(first == TRUE) - first = FALSE - PN = C.powernet - continue - propagate_network(C, PN) -//If underfloor, hide the cable -/obj/structure/cable_bridge/hide(i) - if(level == 1 && isturf(loc)) - invisibility = i ? INVISIBILITY_MAXIMUM : 0 + var/turf/T = get_turf(src) + for(var/obj/structure/cable/C in T.contents - src) + if(C.cable_layer & cable_layer) + C.deconstruct() // remove adversary cable + if(!mapload) + auto_propagate_cut_cable(src) + + machinery_node = new /obj/effect/node() + vis_contents += machinery_node + cable_node_1 = new /obj/effect/node/layer1() + vis_contents += cable_node_1 + cable_node_2 = new /obj/effect/node/layer2() + vis_contents += cable_node_2 + cable_node_3 = new /obj/effect/node/layer3() + vis_contents += cable_node_3 update_icon() -/obj/structure/cable_bridge/wirecutter_act(mob/living/user, obj/item/I) - . = ..() - qdel(src) +/obj/structure/cable/multilayer/Destroy() // called when a cable is deleted + QDEL_NULL(machinery_node) + QDEL_NULL(cable_node_1) + QDEL_NULL(cable_node_2) + QDEL_NULL(cable_node_3) + return ..() // then go ahead and delete the cable + +/obj/structure/cable/multilayer/examine(mob/user) + . += ..() + . += "L1:[cable_layer & CABLE_LAYER_1 ? "Connect" : "Disconnect"]." + . += "L2:[cable_layer & CABLE_LAYER_2 ? "Connect" : "Disconnect"]." + . += "L3:[cable_layer & CABLE_LAYER_3 ? "Connect" : "Disconnect"]." + . += "M:[machinery_layer & MACHINERY_LAYER_1 ? "Connect" : "Disconnect"]." + +GLOBAL_LIST(hub_radial_layer_list) + +/obj/structure/cable/multilayer/attack_hand(mob/living/user) + if(!user) + return + if(!GLOB.hub_radial_layer_list) + GLOB.hub_radial_layer_list = list( + "Layer 1" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-red"), + "Layer 2" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-yellow"), + "Layer 3" = image(icon = 'icons/mob/radial.dmi', icon_state = "coil-blue"), + "Machinery" = image(icon = 'icons/obj/power.dmi', icon_state = "smes") + ) + + var/layer_result = show_radial_menu(user, src, GLOB.hub_radial_layer_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) + if(!check_menu(user)) + return + var/CL + switch(layer_result) + if("Layer 1") + CL = CABLE_LAYER_1 + to_chat(user, "You toggle L1 connection.") + if("Layer 2") + CL = CABLE_LAYER_2 + to_chat(user, "You toggle L2 connection.") + if("Layer 3") + CL = CABLE_LAYER_3 + to_chat(user, "You toggle L3 connection.") + if("Machinery") + machinery_layer ^= MACHINERY_LAYER_1 + to_chat(user, "You toggle machinery connection.") + + cut_cable_from_powernet(FALSE) + + Disconnect_cable() + + cable_layer ^= CL + + Connect_cable(TRUE) + + Reload() + +/obj/structure/cable/multilayer/proc/check_menu(mob/living/user) + if(!istype(user)) + return FALSE + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE return TRUE -#undef UNDER_SMES -#undef UNDER_TERMINAL +///Reset powernet in this hub. +/obj/structure/cable/multilayer/proc/Reload() + var/turf/T = get_turf(src) + for(var/obj/structure/cable/C in T.contents - src) + if(C.cable_layer & cable_layer) + C.deconstruct() // remove adversary cable + auto_propagate_cut_cable(src) // update the powernets + +/obj/structure/cable/multilayer/CtrlClick(mob/living/user) + to_chat(user, "You pust reset button.") + addtimer(CALLBACK(src, .proc/Reload), 10, TIMER_UNIQUE) //spam protect + + diff --git a/code/modules/power/multiz.dm b/code/modules/power/multiz.dm index 4d83646f112..2641818d69c 100644 --- a/code/modules/power/multiz.dm +++ b/code/modules/power/multiz.dm @@ -1,144 +1,19 @@ -#define RELAY_OK 1 -#define RELAY_ADD_CABLE 2 -#define RELAY_ADD_METAL 3 - -/obj/machinery/power/deck_relay //This bridges powernets - name = "Multi-deck power adapter" - desc = "A huge bundle of double insulated cabling which seems to run up into the ceiling." +/obj/structure/cable/multilayer/multiz //This bridges powernets betwen Z levels + name = "multi z layer cable hub" + desc = "A flexible, superconducting insulated multi Z layer hub for heavy-duty multi Z power transfer." icon = 'icons/obj/power.dmi' - icon_state = "cablerelay-off" - max_integrity = 350 - integrity_failure = 0.25 - var/broken_status = RELAY_OK - var/obj/machinery/power/deck_relay/below ///The relay that's below us (for bridging powernets) - var/obj/machinery/power/deck_relay/above ///The relay that's above us (for bridging powernets) - anchored = TRUE - density = FALSE - -/obj/machinery/power/deck_relay/examine(mob/user) - . += ..() - if(!anchored) - . += "The securing bolts are undone." - if(broken_status == RELAY_ADD_CABLE) - . += "The cable insulation is torn apart and the wires are frayed beyond use." - if(broken_status == RELAY_ADD_METAL) - . += "The cable insulation is torn apart and the wiring is exposed." - -/obj/machinery/power/deck_relay/attackby(obj/item/I, mob/user, params) - if(default_unfasten_wrench(user, I)) - if(!anchored && broken_status == RELAY_OK) - break_connections() - return FALSE - - else if(istype(I, /obj/item/stack/cable_coil) && broken_status == RELAY_ADD_CABLE) - var/obj/item/stack/C = I - if(C.use(15)) - to_chat(user, "You fix the frayed wires inside [src].") - icon_state = "cablerelay-broken-cable" - broken_status = RELAY_ADD_METAL - else - to_chat(user, "You need 15 cables to rewire [src].") - - else if(istype(I, /obj/item/stack/sheet/metal) && broken_status == RELAY_ADD_METAL) - var/obj/item/stack/S = I - if(S.use(10)) - to_chat(user, "You reseal the insulation for [src].") - icon_state = "cablerelay" - broken_status = RELAY_OK - obj_integrity = max_integrity - else - to_chat(user, "You need 10 metal to mend [src].") - - else - return ..() - -/obj/machinery/power/deck_relay/obj_break() - ..() - if(broken_status == RELAY_OK) - break_connections() - visible_message("[src]'s insulation breaks, fraying and severing the cable bundle!") - playsound(loc, 'sound/effects/glassbr3.ogg', 100, TRUE) - icon_state = "cablerelay-broken" - broken_status = RELAY_ADD_CABLE + icon_state = "cablerelay-on" + cable_layer = CABLE_LAYER_1|CABLE_LAYER_2|CABLE_LAYER_3 + machinery_layer = null -/obj/machinery/power/deck_relay/obj_destruction() - return //this shouldn't break under usual means - -/obj/machinery/power/deck_relay/Destroy() - break_connections() - return ..() - -///Lose connections and reset the merged powernet so it makes 2 new seperated ones -/obj/machinery/power/deck_relay/proc/break_connections() - if(above) - var/turf/above_deck_relay = get_turf(above) - var/obj/structure/cable/above_cable = above_deck_relay.get_cable_node() - if(above_cable) - var/datum/powernet/above_powernet = new() - propagate_network(above_cable, above_powernet) - above.below = null - above = null - if(below) - var/turf/below_deck_relay = get_turf(below) - var/obj/structure/cable/below_cable = below_deck_relay.get_cable_node() - if(below_cable) - var/datum/powernet/below_powernet = new() - propagate_network(below_cable, below_powernet) - below.above = null - below = null - -///Allows you to scan the relay with a multitool to see stats/reconnect relays -/obj/machinery/power/deck_relay/multitool_act(mob/user, obj/item/I) - if(!anchored) - to_chat(user, "You need to wrench this into place before getting a reading!") - return TRUE - if(broken_status == RELAY_ADD_CABLE || broken_status == RELAY_ADD_METAL) - to_chat(user, "The [src] isn't in proper shape to get a reading!") - return TRUE - if(powernet && (above || below))//we have a powernet and at least one connected relay - to_chat(user, "Total power: [DisplayPower(powernet.avail)]\nLoad: [DisplayPower(powernet.load)]\nExcess power: [DisplayPower(surplus())]") - if(!above && !below) - to_chat(user, "Cannot access valid powernet. Attempting to re-establish. Ensure any relays above and below are aligned properly and on cable nodes.") - find_relays() - addtimer(CALLBACK(src, .proc/refresh), 20) //Wait a bit so we can find the one below, then get powering - return TRUE - -/obj/machinery/power/deck_relay/Initialize() +/obj/structure/cable/multilayer/multiz/get_cable_connections(powernetless_only) . = ..() - addtimer(CALLBACK(src, .proc/find_relays), 30) - addtimer(CALLBACK(src, .proc/refresh), 50) //Wait a bit so we can find the one below, then get powering - -///Handles re-acquiring + merging powernets found by find_relays() -/obj/machinery/power/deck_relay/proc/refresh() - if(above) - above.merge(src) - if(below) - below.merge(src) - -///Merges the two powernets connected to the deck relays -/obj/machinery/power/deck_relay/proc/merge(var/obj/machinery/power/deck_relay/DR) - if(!DR) - return - var/turf/merge_from = get_turf(DR) - var/turf/merge_to = get_turf(src) - var/obj/structure/cable/C = merge_from.get_cable_node() - var/obj/structure/cable/XR = merge_to.get_cable_node() - if(C && XR) - merge_powernets(XR.powernet,C.powernet)//Bridge the powernets. + var/turf/T = get_turf(src) + . += locate(/obj/structure/cable/multilayer/multiz) in (SSmapping.get_turf_below(T)) + . += locate(/obj/structure/cable/multilayer/multiz) in (SSmapping.get_turf_above(T)) -///Locates relays that are above and below this object -/obj/machinery/power/deck_relay/proc/find_relays() +/obj/structure/cable/multilayer/examine(mob/user) + . += ..() var/turf/T = get_turf(src) - if(!T || !istype(T)) - return FALSE - below = null //in case we're re-establishing - above = null - var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked - if(C && C.powernet) - C.powernet.add_machine(src) //Nice we're in. - powernet = C.powernet - below = locate(/obj/machinery/power/deck_relay) in(SSmapping.get_turf_below(T)) - above = locate(/obj/machinery/power/deck_relay) in(SSmapping.get_turf_above(T)) - if(below || above) - icon_state = "cablerelay-on" - return TRUE \ No newline at end of file + . += span_notice("[locate(/obj/structure/cable/multilayer/multiz) in (SSmapping.get_turf_below(T)) ? "Detected" : "Undetected"] hub UP.") + . += span_notice("[locate(/obj/structure/cable/multilayer/multiz) in (SSmapping.get_turf_above(T)) ? "Detected" : "Undetected"] hub DOWN.") diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index e60a37e661a..b97899575c4 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -15,6 +15,7 @@ use_power = NO_POWER_USE idle_power_usage = 0 active_power_usage = 0 + var/machinery_layer = MACHINERY_LAYER_1 //cable layer to which the machine is connected /obj/machinery/power/Destroy() disconnect_from_network() @@ -138,7 +139,7 @@ if(!T || !istype(T)) return FALSE - var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked + var/obj/structure/cable/C = T.get_cable_node(machinery_layer) //check if we have a node cable on the machine turf, the first found is picked if(!C || !C.powernet) var/obj/machinery/power/terminal/term = locate(/obj/machinery/power/terminal) in T if(!term || !term.powernet) @@ -352,13 +353,12 @@ // Misc. /////////////////////////////////////////////// -// return a cable if there's one on the turf, null if there isn't one -/turf/proc/get_cable_node() +// return a cable able connect to machinery on layer if there's one on the turf, null if there isn't one +/turf/proc/get_cable_node(machinery_layer = MACHINERY_LAYER_1) if(!can_have_cabling()) return null - var/obj/structure/cable_bridge/B = locate() in src for(var/obj/structure/cable/C in src) - if(C.cable_layer == CABLE_LAYER_2 || B) + if(C.machinery_layer & machinery_layer) C.update_icon() return C return null diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 261d983bf47..1501b156024 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -346,11 +346,8 @@ All ShuttleMove procs go here /obj/structure/cable/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) . = ..() - var/turf/T = loc - if(level==1) - hide(T.intact) - connect_wire(TRUE) - propogate_if_no_network() + Connect_cable(TRUE) + propagate_if_no_network() /obj/structure/shuttle/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock) . = ..() diff --git a/hippiestation.dme b/hippiestation.dme index 3f434174fd1..82902deda56 100644 --- a/hippiestation.dme +++ b/hippiestation.dme @@ -113,6 +113,8 @@ #include "code\__DEFINES\vv.dm" #include "code\__DEFINES\wall_dents.dm" #include "code\__DEFINES\wires.dm" +#include "code\__DEFINES\span.dm" +#include "code\__DEFINES\dcs\signals.dm" #include "code\__DEFINES\~hippie_defines\admin.dm" #include "code\__DEFINES\~hippie_defines\antagonists.dm" #include "code\__DEFINES\~hippie_defines\atmospherics.dm" @@ -523,6 +525,7 @@ #include "code\datums\elements\atmos_sensitive.dm" #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\earhealing.dm" +#include "code\datums\elements\undertile.dm #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\getrev.dm" #include "code\datums\helper_datums\icon_snapshot.dm" diff --git a/hippiestation/code/modules/power/cable.dm b/hippiestation/code/modules/power/cable.dm index 2f1bb0a9b1a..0474aea6b8d 100644 --- a/hippiestation/code/modules/power/cable.dm +++ b/hippiestation/code/modules/power/cable.dm @@ -4,7 +4,7 @@ /obj/item/stack/cable_coil/Initialize(mapload, new_amount = null, param_color = null) . = ..() - recipes = list(new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15), new/datum/stack_recipe("noose", /obj/structure/chair/noose, 30, time = 80, one_per_turf = 1, on_floor = 1), new/datum/stack_recipe("cable bridge", /obj/structure/cable_bridge, 15)) + recipes = list(new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15), new/datum/stack_recipe("noose", /obj/structure/chair/noose, 30, time = 80, one_per_turf = 1, on_floor = 1), new/datum/stack_recipe("multilayer cable", /obj/structure/cable/multilayer, 1)) /obj/item/stack/cable_coil/attack(mob/living/carbon/human/H, mob/user)