diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 6e63e537952..433bfc66de3 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -7,6 +7,7 @@
* angle2dir
* angle2text
* worldtime2text
+ * text2dir_extended & dir2text_short
*/
//Returns an integer given a hex input, supports negative values "-ff"
@@ -405,3 +406,51 @@ for(var/t in test_times)
/proc/isLeap(y)
return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
+
+// A copy of text2dir, extended to accept one and two letter
+// directions, and to clearly return 0 otherwise.
+/proc/text2dir_extended(direction)
+ switch(uppertext(direction))
+ if("NORTH", "N")
+ return 1
+ if("SOUTH", "S")
+ return 2
+ if("EAST", "E")
+ return 4
+ if("WEST", "W")
+ return 8
+ if("NORTHEAST", "NE")
+ return 5
+ if("NORTHWEST", "NW")
+ return 9
+ if("SOUTHEAST", "SE")
+ return 6
+ if("SOUTHWEST", "SW")
+ return 10
+ else
+ return 0
+
+
+
+// A copy of dir2text, which returns the short one or two letter
+// directions used in tube icon states.
+/proc/dir2text_short(direction)
+ switch(direction)
+ if(1)
+ return "N"
+ if(2)
+ return "S"
+ if(4)
+ return "E"
+ if(8)
+ return "W"
+ if(5)
+ return "NE"
+ if(6)
+ return "SE"
+ if(9)
+ return "NW"
+ if(10)
+ return "SW"
+ else
+ return
diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index a1aeefc9618..2a1edbfa870 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -123,12 +123,15 @@
Nah
*/
-//Allow you to drag-drop disposal pipes into it
-/obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe as obj, mob/usr as mob)
+//Allow you to drag-drop disposal pipes and transit tubes into it
+/obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/pipe as obj, mob/usr as mob)
if(!usr.canmove || usr.stat || usr.restrained())
return
- if (!istype(pipe) || get_dist(usr, src) > 1 || get_dist(src,pipe) > 1 )
+ if (!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/transit_tube_pod))
+ return
+
+ if (get_dist(usr, src) > 1 || get_dist(src,pipe) > 1 )
return
if (pipe.anchored)
@@ -196,3 +199,79 @@ Nah
wait = 0
return
+//transit tube dispenser
+//inherit disposal for the dragging proc
+/obj/machinery/pipedispenser/disposal/transit_tube
+ name = "transit tube dispenser"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "pipe_d"
+ density = 1
+ anchored = 1.0
+
+/obj/machinery/pipedispenser/disposal/transit_tube/attack_hand(user as mob)
+ if(..())
+ return
+
+ var/dat = {"Transit Tubes:
+Straight Tube
+Straight Tube with Crossing
+Clockwise Curved Tube
+Counterclockwise Curved Tube
+Diagonal Tube
+Clockwise Junction
+Counterclockwise Junction
+Station Equipment:
+Through Tube Station
+Terminus Tube Station
+Tube Blocker
+Transit Tube Pod
+"}
+
+ user << browse("
[src][dat]", "window=pipedispenser")
+ return
+
+
+/obj/machinery/pipedispenser/disposal/Topic(href, href_list)
+ if(..())
+ return
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+ if(!wait)
+ if(href_list["tube"])
+ var/tube_type = text2num(href_list["tube"])
+ if(tube_type <= 6)
+ var/obj/structure/c_transit_tube/C = new/obj/structure/c_transit_tube(src.loc)
+ switch(tube_type)
+ if(0)
+ C.icon_state = "E-W"
+ if(1)
+ C.icon_state = "E-W-Pass"
+ if(2)
+ C.icon_state = "S-NE"
+ if(3)
+ C.icon_state = "S-NW"
+ if(4)
+ C.icon_state = "NE-SW"
+ if(5)
+ C.icon_state = "W-NE-SE"
+ if(6)
+ C.icon_state = "S-NE-NW"
+ C.add_fingerprint(usr)
+ else
+ switch(tube_type)
+ if(7)
+ var/obj/structure/c_transit_tube/station/C = new/obj/structure/c_transit_tube/station(src.loc)
+ C.add_fingerprint(usr)
+ if(8)
+ var/obj/structure/c_transit_tube/station/reverse/C = new/obj/structure/c_transit_tube/station/reverse(src.loc)
+ C.add_fingerprint(usr)
+ if(9)
+ var/obj/structure/c_transit_tube/station/block/C = new/obj/structure/c_transit_tube/station/block(src.loc)
+ C.add_fingerprint(usr)
+ if(10)
+ var/obj/structure/c_transit_tube_pod/C = new/obj/structure/c_transit_tube_pod(src.loc)
+ C.add_fingerprint(usr)
+ wait = 1
+ spawn(15)
+ wait = 0
+ return
diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm
index 327b1aa5906..ce38f66f96a 100644
--- a/code/game/objects/structures/transit_tubes/station.dm
+++ b/code/game/objects/structures/transit_tubes/station.dm
@@ -40,6 +40,20 @@
return
+//pod insertion
+/obj/structure/transit_tube/station/MouseDrop_T(obj/structure/c_transit_tube_pod/R as obj, mob/user as mob)
+ if(!usr.canmove || usr.stat || usr.restrained())
+ return
+ if (!istype(R) || get_dist(user, src) > 1 || get_dist(src,R) > 1)
+ return
+ var/obj/structure/transit_tube_pod/T = new/obj/structure/transit_tube_pod(src)
+ R.transfer_fingerprints_to(T)
+ T.add_fingerprint(usr)
+ T.loc = src.loc
+ T.dir = turn(src.dir, -90)
+ user.visible_message("[user] inserts the [R].", "You insert the [R].")
+ qdel(R)
+
/obj/structure/transit_tube/station/attack_hand(mob/user as mob)
if(!pod_moving)
@@ -76,6 +90,17 @@
src.Bumped(GM)
qdel(G)
break
+ if(istype(W, /obj/item/weapon/crowbar))
+ for(var/obj/structure/transit_tube_pod/pod in loc)
+ if(pod.contents)
+ user << "Empty the pod first."
+ return
+ user.visible_message("[user] removes the [pod].", "You remove the [pod].")
+ var/obj/structure/c_transit_tube_pod/R = new/obj/structure/c_transit_tube_pod(src.loc)
+ pod.transfer_fingerprints_to(R)
+ R.add_fingerprint(user)
+ qdel(pod)
+ ..(W, user)
/obj/structure/transit_tube/station/proc/open_animation()
if(icon_state == "closed")
diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm
index 707dbb015df..162aea555a2 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube.dm
@@ -1,4 +1,3 @@
-
// Basic transit tubes. Straight pieces, curved sections,
// and basic splits/joins (no routing logic).
// Mappers: you can use "Generate Instances from Icon-states"
@@ -48,6 +47,30 @@ obj/structure/transit_tube/ex_act(severity)
if(tube_dirs == null)
init_dirs()
+/obj/structure/transit_tube/attackby(obj/item/W, mob/user)
+ if(istype(W, /obj/item/weapon/wrench))
+ for(var/obj/structure/transit_tube_pod/pod in loc)
+ user << "Remove the pod first."
+ return
+ user.visible_message("[user] starts to deattach the [src]!", "You start deattaching the [name]...")
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
+ if(do_after(user, 80))
+ user << "You deattach the [name]!"
+ if(copytext(icon_state, 1, 3) != "D-")
+ if(istype(src, /obj/structure/transit_tube/station/reverse))
+ var/obj/structure/R = new/obj/structure/c_transit_tube/station/reverse(src.loc)
+ src.transfer_fingerprints_to(R)
+ R.add_fingerprint(user)
+ else if(istype(src, /obj/structure/transit_tube/station))
+ var/obj/structure/R = new/obj/structure/c_transit_tube/station(src.loc)
+ src.transfer_fingerprints_to(R)
+ R.add_fingerprint(user)
+ else
+ var/obj/structure/R = new/obj/structure/c_transit_tube(src.loc)
+ R.icon_state = src.icon_state
+ src.transfer_fingerprints_to(R)
+ R.add_fingerprint(user)
+ qdel(src)
// Called to check if a pod should stop upon entering this tube.
/obj/structure/transit_tube/proc/should_stop_pod(pod, from_dir)
@@ -258,53 +281,3 @@ obj/structure/transit_tube/ex_act(severity)
direction_table[text] = directions
return directions
-
-
-
-// A copy of text2dir, extended to accept one and two letter
-// directions, and to clearly return 0 otherwise.
-/obj/structure/transit_tube/proc/text2dir_extended(direction)
- switch(uppertext(direction))
- if("NORTH", "N")
- return 1
- if("SOUTH", "S")
- return 2
- if("EAST", "E")
- return 4
- if("WEST", "W")
- return 8
- if("NORTHEAST", "NE")
- return 5
- if("NORTHWEST", "NW")
- return 9
- if("SOUTHEAST", "SE")
- return 6
- if("SOUTHWEST", "SW")
- return 10
- else
- return 0
-
-
-
-// A copy of dir2text, which returns the short one or two letter
-// directions used in tube icon states.
-/obj/structure/transit_tube/proc/dir2text_short(direction)
- switch(direction)
- if(1)
- return "N"
- if(2)
- return "S"
- if(4)
- return "E"
- if(8)
- return "W"
- if(5)
- return "NE"
- if(6)
- return "SE"
- if(9)
- return "NW"
- if(10)
- return "SW"
- else
- return
diff --git a/code/game/objects/structures/transit_tubes/transit_tube_construction.dm b/code/game/objects/structures/transit_tubes/transit_tube_construction.dm
new file mode 100644
index 00000000000..72daccb3969
--- /dev/null
+++ b/code/game/objects/structures/transit_tubes/transit_tube_construction.dm
@@ -0,0 +1,132 @@
+// transit tube construction
+//TODO: dispenser, restrict flip/rotate, testing
+
+// normal transit tubes
+/obj/structure/c_transit_tube
+ name = "unattached transit tube"
+ icon = 'icons/obj/pipes/transit_tube.dmi'
+ icon_state = "E-W" //icon_state decides which tube will be built
+ density = 0
+ layer = 3.1 //same as the built tube
+ anchored = 0.0
+
+//wrapper for turn that changes the transit tube formatted icon_state instead of the dir
+/obj/structure/c_transit_tube/proc/tube_turn(var/angle)
+ var/list/badtubes = list("W-E", "W-E-Pass", "S-N", "S-N-Pass", "SW-NE", "SE-NW")
+ var/list/split_text = text2list(icon_state, "-")
+ for(var/i=1; i<=split_text.len; i++)
+ var/curdir = text2dir_extended(split_text[i]) //0 if not a valid direction (e.g. Pass, Block)
+ if(curdir)
+ split_text[i] = dir2text_short(turn(curdir, angle))
+ var/newdir = list2text(split_text, "-")
+ if(badtubes.Find(newdir))
+ split_text.Swap(1,2)
+ newdir = list2text(split_text, "-")
+ icon_state = newdir
+
+// disposals-style "flip" and rotate verbs
+/obj/structure/c_transit_tube/verb/rotate()
+ set name = "Rotate Tube"
+ set category = "Object"
+ set src in view(1)
+
+ if(usr.stat)
+ return
+
+ tube_turn(-90)
+
+//not a real flip because it won't mirror junction pipe exits
+//yes i am autistic
+/obj/structure/c_transit_tube/verb/flip()
+ set name = "Rotate Tube Twice"
+ set category = "Object"
+ set src in view(1)
+
+ if(usr.stat)
+ return
+
+ tube_turn(180)
+
+/obj/structure/c_transit_tube/proc/buildtube()
+ var/obj/structure/transit_tube/R = new/obj/structure/transit_tube(src.loc)
+ R.icon_state = src.icon_state
+ R.init_dirs()
+ R.generate_automatic_corners(R.tube_dirs)
+ return R
+
+/obj/structure/c_transit_tube/attackby(var/obj/item/I, var/mob/user)
+ if(istype(I, /obj/item/weapon/wrench))
+ user << "You start attaching the [name]..."
+ src.add_fingerprint(user)
+ if(do_after(user, 40))
+ if(!src) return
+ user << "You attach the [name]!"
+ var/obj/structure/transit_tube/R = src.buildtube()
+ src.transfer_fingerprints_to(R)
+ qdel(src)
+ return
+
+// transit tube station
+/obj/structure/c_transit_tube/station
+ name = "unattached through station"
+ icon = 'icons/obj/pipes/transit_tube_station.dmi'
+ icon_state = "closed"
+
+/obj/structure/c_transit_tube/station/rotate()
+ set name = "Rotate Tube"
+ set category = "Object"
+ set src in view(1)
+
+ if(usr.stat)
+ return
+
+ src.dir = turn(src.dir, -90)
+
+/obj/structure/c_transit_tube/station/flip()
+ set name = "Rotate Tube Twice"
+ set category = "Object"
+ set src in view(1)
+
+ if(usr.stat)
+ return
+
+ src.dir = turn(src.dir, 180)
+
+/obj/structure/c_transit_tube/station/buildtube()
+ var/obj/structure/transit_tube/station/R = new/obj/structure/transit_tube/station(src.loc)
+ R.dir = src.dir
+ R.init_dirs()
+ return R
+
+// reverser station, used for the terminus
+/obj/structure/c_transit_tube/station/reverse
+ name = "unattached terminus station"
+
+/obj/structure/c_transit_tube/station/reverse/buildtube()
+ var/obj/structure/transit_tube/station/reverse/R = new/obj/structure/transit_tube/station/reverse(src.loc)
+ R.dir = src.dir
+ return R
+
+// block, used after the terminus of a transit tube station, decorative only
+// code-wise they're normal tubes but they're ~speshul~ because they care about the dir instead of the icon_state
+// in that sense they're the same as stations and can reuse their flip and rotate verbs
+/obj/structure/c_transit_tube/station/block
+ name = "unattached tube blocker"
+ icon = 'icons/obj/pipes/transit_tube.dmi'
+ icon_state = "Block"
+
+/obj/structure/c_transit_tube/station/block/buildtube()
+ var/obj/structure/transit_tube/R = new/obj/structure/transit_tube(src.loc)
+ R.icon_state = src.icon_state
+ R.dir = src.dir
+ R.init_dirs()
+ return R
+
+//transit tube pod
+//see station.dm for the logic
+/obj/structure/c_transit_tube_pod
+ name = "unattached transit tube pod"
+ icon = 'icons/obj/pipes/transit_tube_pod.dmi'
+ icon_state = "pod"
+ anchored = 0.0
+ density = 0
diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
index 1eb1910a7fc..a787db9a347 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
@@ -25,6 +25,23 @@
..()
+/obj/structure/transit_tube_pod/attackby(var/obj/item/I, var/mob/user)
+ if(istype(I, /obj/item/weapon/crowbar))
+ if(!moving)
+ for(var/obj/structure/transit_tube/station/T in loc)
+ return
+ if(src.contents)
+ user.visible_message("[user] empties the [src].", "You empty the [src].")
+ for(var/atom/movable/M in src.contents)
+ M.loc = src.loc
+ return
+ else
+ user << "You free the [src]."
+ var/obj/structure/c_transit_tube_pod/R = new/obj/structure/c_transit_tube_pod(src.loc)
+ src.transfer_fingerprints_to(R)
+ R.add_fingerprint(user)
+ qdel(src)
+
/obj/structure/transit_tube_pod/proc/follow_tube(var/reverse_launch)
if(moving)
return
diff --git a/tgstation.dme b/tgstation.dme
index 3918643a73c..1aa51b82d88 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -672,6 +672,7 @@
#include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\stools.dm"
#include "code\game\objects\structures\transit_tubes\station.dm"
+#include "code\game\objects\structures\transit_tubes\transit_tube_construction.dm"
#include "code\game\objects\structures\transit_tubes\transit_tube.dm"
#include "code\game\objects\structures\transit_tubes\transit_tube_pod.dm"
#include "code\game\pooling\atom_pool.dm"