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)