diff --git a/code/__DEFINES/pipe_construction.dm b/code/__DEFINES/pipe_construction.dm
index a671b548ba..641187e964 100644
--- a/code/__DEFINES/pipe_construction.dm
+++ b/code/__DEFINES/pipe_construction.dm
@@ -1,23 +1,17 @@
//Construction Categories
-#define PIPE_BINARY 0 //2 directions: N/S, E/W
+#define PIPE_STRAIGHT 0 //2 directions: N/S, E/W
#define PIPE_BENDABLE 1 //6 directions: N/S, E/W, N/E, N/W, S/E, S/W
#define PIPE_TRINARY 2 //4 directions: N/E/S, E/S/W, S/W/N, W/N/E
#define PIPE_TRIN_M 3 //8 directions: N->S+E, S->N+E, N->S+W, S->N+W, E->W+S, W->E+S, E->W+N, W->E+N
#define PIPE_UNARY 4 //4 directions: N, S, E, W
-#define PIPE_QUAD 5 //1 directions: N/S/E/W
+#define PIPE_ONEDIR 5 //1 direction: N/S/E/W
-//Disposal piping numbers - do NOT hardcode these, use the defines
-#define DISP_PIPE_STRAIGHT 0
-#define DISP_PIPE_BENT 1
-#define DISP_JUNCTION 2
-#define DISP_JUNCTION_FLIP 3
-#define DISP_YJUNCTION 4
-#define DISP_END_TRUNK 5
-#define DISP_END_BIN 6
-#define DISP_END_OUTLET 7
-#define DISP_END_CHUTE 8
-#define DISP_SORTJUNCTION 9
-#define DISP_SORTJUNCTION_FLIP 10
+//Disposal pipe relative connection directions
+#define DISP_DIR_BASE 0
+#define DISP_DIR_LEFT 1
+#define DISP_DIR_RIGHT 2
+#define DISP_DIR_FLIP 4
+#define DISP_DIR_NONE 8
//Transit tubes
#define TRANSIT_TUBE_STRAIGHT 0
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index 28c4b8c0aa..80181b656b 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -25,7 +25,7 @@ Buildable meters
/obj/item/pipe/directional
RPD_type = PIPE_UNARY
/obj/item/pipe/binary
- RPD_type = PIPE_BINARY
+ RPD_type = PIPE_STRAIGHT
/obj/item/pipe/binary/bendable
RPD_type = PIPE_BENDABLE
/obj/item/pipe/trinary
@@ -34,7 +34,7 @@ Buildable meters
RPD_type = PIPE_TRIN_M
var/flipped = FALSE
/obj/item/pipe/quaternary
- RPD_type = PIPE_QUAD
+ RPD_type = PIPE_ONEDIR
/obj/item/pipe/examine(mob/user)
..()
diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index 52aa82f82a..38ead73631 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -14,35 +14,19 @@
/obj/machinery/pipedispenser/attack_hand(mob/user)
if(..())
return 1
- var/dat = {"
-PIPING LAYER: --[piping_layer]++
-Pipes:
-Pipe
-Bent Pipe
-Manifold
-Layer Manifold
-4-Way Manifold
-Manual Valve
-Digital Valve
-Devices:
-Connector
-Vent
-Gas Pump
-Passive Gate
-Volume Pump
-Scrubber
-Meter
-Gas Filter
-Gas Mixer
-Heat exchange:
-Pipe
-Bent Pipe
-Manifold
-4-Way Manifold
-Junction
-Heat Exchanger
-"}
+ var/dat = "PIPING LAYER: --[piping_layer]++
"
+ var/recipes = GLOB.atmos_pipe_recipes
+
+ for(var/category in recipes)
+ var/list/cat_recipes = recipes[category]
+ dat += "[category]:
" - dirsel += render_dir_img(1,"vertical.png","Vertical") - dirsel += render_dir_img(4,"horizontal.png","Horizontal") + dirsel += render_dir_img(NORTH,"vertical.png","Vertical") + dirsel += render_dir_img(EAST,"horizontal.png","Horizontal") dirsel += "
" else dirsel+={" "} @@ -291,26 +302,26 @@ GLOBAL_LIST_INIT(RPD_recipes, list( user << browse_rsc(new /icon(preview, dir=SOUTHEAST), "se.png") dirsel += ""
- dirsel += render_dir_img(1,"vertical.png","Vertical")
- dirsel += render_dir_img(4,"horizontal.png","Horizontal")
+ dirsel += render_dir_img(NORTH,"vertical.png","Vertical")
+ dirsel += render_dir_img(EAST,"horizontal.png","Horizontal")
dirsel += "
"
- dirsel += render_dir_img(9,"nw.png","West to North")
- dirsel += render_dir_img(5,"ne.png","North to East")
+ dirsel += render_dir_img(NORTHWEST,"nw.png","West to North")
+ dirsel += render_dir_img(NORTHEAST,"ne.png","North to East")
dirsel += "
"
- dirsel += render_dir_img(10,"sw.png","South to West")
- dirsel += render_dir_img(6,"se.png","East to South")
+ dirsel += render_dir_img(SOUTHWEST,"sw.png","South to West")
+ dirsel += render_dir_img(SOUTHEAST,"se.png","East to South")
dirsel += "
- ↕
- ↔
+ ↕
+ ↔
- ╝
- ╚
+ ╝
+ ╚
- ╗
- ╔
+ ╗
+ ╔
"
- dirsel += render_dir_img(1,"s.png","West South East")
- dirsel += render_dir_img(4,"w.png","North West South")
+ dirsel += render_dir_img(NORTH,"s.png","West South East")
+ dirsel += render_dir_img(EAST,"w.png","North West South")
dirsel += "
"
- dirsel += render_dir_img(2,"n.png","East North West")
- dirsel += render_dir_img(8,"e.png","South East North")
+ dirsel += render_dir_img(SOUTH,"n.png","East North West")
+ dirsel += render_dir_img(WEST,"e.png","South East North")
dirsel += "
- ╦
- ╣
+ ╦
+ ╣
- ╩
- ╠
+ ╩
+ ╠
"
- dirsel += render_dir_img(1,"s.png","West South East")
- dirsel += render_dir_img(4,"w.png","North West South")
+ dirsel += render_dir_img(NORTH,"s.png","West South East")
+ dirsel += render_dir_img(EAST,"w.png","North West South")
dirsel += "
"
- dirsel += render_dir_img(2,"n.png","East North West")
- dirsel += render_dir_img(8,"e.png","South East North")
+ dirsel += render_dir_img(SOUTH,"n.png","East North West")
+ dirsel += render_dir_img(WEST,"e.png","South East North")
dirsel += "
"
- dirsel += render_dir_img(6,"sm.png","West South East", 1)
- dirsel += render_dir_img(5,"wm.png","North West South", 1)
+ dirsel += render_dir_img(SOUTHEAST,"sm.png","West South East", 1)
+ dirsel += render_dir_img(NORTHEAST,"wm.png","North West South", 1)
dirsel += "
"
- dirsel += render_dir_img(9,"nm.png","East North West", 1)
- dirsel += render_dir_img(10,"em.png","South East North", 1)
+ dirsel += render_dir_img(NORTHWEST,"nm.png","East North West", 1)
+ dirsel += render_dir_img(SOUTHWEST,"em.png","South East North", 1)
dirsel += "
- ╦
- ╣
+ ╦
+ ╣
- ╩
- ╠
+ ╩
+ ╠
- ╦
- ╣
+ ╦
+ ╣
- ╩
- ╠
+ ╩
+ ╠
- ↑ - → - ↓ - ← + ↑ + → + ↓ + ←
"} - if(PIPE_QUAD) // Single icon_state (eg 4-way manifolds) + if(PIPE_ONEDIR) // Single icon_state (eg 4-way manifolds) if(preview) user << browse_rsc(new /icon(preview), "pipe.png") dirsel += "" - dirsel += render_dir_img(1,"pipe.png","Pipe") + dirsel += render_dir_img(SOUTH,"pipe.png","Pipe") dirsel += "
" else dirsel+={" "} @@ -472,8 +483,11 @@ GLOBAL_LIST_INIT(RPD_recipes, list( show_menu(usr) if(href_list["setdir"]) - p_dir= text2num(href_list["setdir"]) - p_flipped = text2num(href_list["flipped"]) + p_dir = text2num(href_list["setdir"]) + if(href_list["flipped"]) + p_flipped = text2num(href_list["flipped"]) + else + p_flipped = FALSE show_menu(usr) if(href_list["setlayer"]) @@ -507,9 +521,9 @@ GLOBAL_LIST_INIT(RPD_recipes, list( if(href_list["makepipe"]) p_type = text2path(href_list["makepipe"]) - p_dir = text2num(href_list["dir"]) var/obj/item/pipe/path = text2path(href_list["type"]) p_conntype = initial(path.RPD_type) + p_dir = NORTH p_class = ATMOS_MODE spark_system.start() playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) @@ -518,15 +532,15 @@ GLOBAL_LIST_INIT(RPD_recipes, list( if(href_list["makemeter"]) p_class = METER_MODE p_conntype = -1 - p_dir = 1 + p_dir = NORTH spark_system.start() playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) show_menu(usr) if(href_list["dmake"]) - p_type = text2num(href_list["dmake"]) + p_type = text2path(href_list["dmake"]) p_conntype = text2num(href_list["type"]) - p_dir = 1 + p_dir = NORTH p_class = DISPOSALS_MODE spark_system.start() playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) @@ -614,12 +628,12 @@ GLOBAL_LIST_INIT(RPD_recipes, list( if(!can_make_pipe) return ..() if(isclosedturf(A)) - to_chat(user, "\the [src]'s error light flickers; there's something in the way!") + to_chat(user, "[src]'s error light flickers; there's something in the way!") return to_chat(user, "You start building a disposals pipe...") playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) if(do_after(user, 4, target = A)) - var/obj/structure/disposalconstruct/C = new (A, queued_p_type ,queued_p_dir) + var/obj/structure/disposalconstruct/C = new (A, queued_p_type, queued_p_dir, queued_p_flipped) if(!C.can_place()) to_chat(user, "There's not enough room to build that here!") diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 9865f0bfb3..cbe1161422 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -35,7 +35,10 @@ MASS SPECTROMETER var/image/I = new(loc = get_turf(pipe)) var/mutable_appearance/MA = new(pipe) MA.alpha = 128 + MA.dir = pipe.dir I.appearance = MA + I.dir = pipe.dir + // Workaround for a weird bug with icon direction on T-Ray scan not matching the actual disposal pipe dir. if(M.client) flick_overlay(I, list(M.client), 8) diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm deleted file mode 100644 index f6fc0bc582..0000000000 --- a/code/modules/recycling/disposal-construction.dm +++ /dev/null @@ -1,284 +0,0 @@ -// Disposal pipe construction -// This is the pipe that you drag around, not the attached ones. - -/obj/structure/disposalconstruct - - name = "disposal pipe segment" - desc = "A huge pipe segment used for constructing disposal systems." - icon = 'icons/obj/atmospherics/pipes/disposal.dmi' - icon_state = "conpipe-s" - anchored = FALSE - density = FALSE - pressure_resistance = 5*ONE_ATMOSPHERE - level = 2 - max_integrity = 200 - var/ptype = 0 - - var/dpdir = 0 // directions as disposalpipe - var/base_state = "pipe-s" - -/obj/structure/disposalconstruct/examine(mob/user) - ..() - to_chat(user, "Alt-click to rotate it clockwise.") - -/obj/structure/disposalconstruct/New(var/loc, var/pipe_type, var/direction = 1) - ..(loc) - if(pipe_type) - ptype = pipe_type - setDir(direction) - -// update iconstate and dpdir due to dir and type -/obj/structure/disposalconstruct/update_icon() - var/flip = turn(dir, 180) - var/left = turn(dir, 90) - var/right = turn(dir, -90) - - switch(ptype) - if(DISP_PIPE_STRAIGHT) - base_state = "pipe-s" - dpdir = dir | flip - if(DISP_PIPE_BENT) - base_state = "pipe-c" - dpdir = dir | right - if(DISP_JUNCTION) - base_state = "pipe-j1" - dpdir = dir | right | flip - if(DISP_JUNCTION_FLIP) - base_state = "pipe-j2" - dpdir = dir | left | flip - if(DISP_YJUNCTION) - base_state = "pipe-y" - dpdir = dir | left | right - if(DISP_END_TRUNK) - base_state = "pipe-t" - dpdir = dir - // disposal bin has only one dir, thus we don't need to care about setting it - if(DISP_END_BIN) - if(anchored) - base_state = "disposal" - else - base_state = "condisposal" - - if(DISP_END_OUTLET) - base_state = "outlet" - dpdir = dir - - if(DISP_END_CHUTE) - base_state = "intake" - dpdir = dir - - if(DISP_SORTJUNCTION) - base_state = "pipe-j1s" - dpdir = dir | right | flip - - if(DISP_SORTJUNCTION_FLIP) - base_state = "pipe-j2s" - dpdir = dir | left | flip - - - if(is_pipe()) - icon_state = "con[base_state]" - else - icon_state = base_state - - // if invisible, fade icon - alpha = (invisibility ? 0 : 255) - -// hide called by levelupdate if turf intact status changes -// change visibility status and force update of icon -/obj/structure/disposalconstruct/hide(var/intact) - invisibility = (intact && level==1) ? INVISIBILITY_MAXIMUM: 0 // hide if floor is intact - update_icon() - - -// flip and rotate verbs -/obj/structure/disposalconstruct/verb/rotate() - set name = "Rotate Pipe" - set category = "Object" - set src in view(1) - - if(usr.stat || !usr.canmove || usr.restrained()) - return - - if(anchored) - to_chat(usr, "You must unfasten the pipe before rotating it!") - return - - setDir(turn(dir, -90)) - update_icon() - -/obj/structure/disposalconstruct/AltClick(mob/user) - ..() - if(user.incapacitated()) - to_chat(user, "You can't do that right now!") - return - if(!in_range(src, user)) - return - else - rotate() - -/obj/structure/disposalconstruct/verb/flip() - set name = "Flip Pipe" - set category = "Object" - set src in view(1) - if(usr.stat || !usr.canmove || usr.restrained()) - return - - if(anchored) - to_chat(usr, "You must unfasten the pipe before flipping it!") - return - - setDir(turn(dir, 180)) - switch(ptype) - if(DISP_JUNCTION) - ptype = DISP_JUNCTION_FLIP - if(DISP_JUNCTION_FLIP) - ptype = DISP_JUNCTION - if(DISP_SORTJUNCTION) - ptype = DISP_SORTJUNCTION_FLIP - if(DISP_SORTJUNCTION_FLIP) - ptype = DISP_SORTJUNCTION - - update_icon() - -// returns the type path of disposalpipe corresponding to this item dtype -/obj/structure/disposalconstruct/proc/dpipetype() - switch(ptype) - if(DISP_PIPE_STRAIGHT,DISP_PIPE_BENT) - return /obj/structure/disposalpipe/segment - if(DISP_JUNCTION, DISP_JUNCTION_FLIP, DISP_YJUNCTION) - return /obj/structure/disposalpipe/junction - if(DISP_END_TRUNK) - return /obj/structure/disposalpipe/trunk - if(DISP_END_BIN) - return /obj/machinery/disposal/bin - if(DISP_END_OUTLET) - return /obj/structure/disposaloutlet - if(DISP_END_CHUTE) - return /obj/machinery/disposal/deliveryChute - if(DISP_SORTJUNCTION, DISP_SORTJUNCTION_FLIP) - return /obj/structure/disposalpipe/sortjunction - return - - - -// attackby item -// wrench: (un)anchor -// weldingtool: convert to real pipe - -/obj/structure/disposalconstruct/attackby(obj/item/I, mob/user, params) - var/nicetype = "pipe" - var/ispipe = is_pipe() // Indicates if we should change the level of this pipe - add_fingerprint(user) - switch(ptype) - if(DISP_END_BIN) - nicetype = "disposal bin" - if(DISP_END_OUTLET) - nicetype = "disposal outlet" - if(DISP_END_CHUTE) - nicetype = "delivery chute" - if(DISP_SORTJUNCTION, DISP_SORTJUNCTION_FLIP) - nicetype = "sorting pipe" - else - nicetype = "pipe" - - var/turf/T = loc - if(T.intact && isfloorturf(T)) - to_chat(user, "You can only attach the [nicetype] if the floor plating is removed!") - return - - if(!ispipe && iswallturf(T)) - to_chat(user, "You can't build [nicetype]s on walls, only disposal pipes!") - return - - var/obj/structure/disposalpipe/CP = locate() in T - - if(istype(I, /obj/item/wrench)) - if(anchored) - anchored = FALSE - if(ispipe) - level = 2 - density = FALSE - to_chat(user, "You detach the [nicetype] from the underfloor.") - else - if(!is_pipe()) // Disposal or outlet - if(CP) // There's something there - if(!istype(CP, /obj/structure/disposalpipe/trunk)) - to_chat(user, "The [nicetype] requires a trunk underneath it in order to work!") - return - else // Nothing under, fuck. - to_chat(user, "The [nicetype] requires a trunk underneath it in order to work!") - return - else - if(CP) - update_icon() - var/pdir = CP.dpdir - if(istype(CP, /obj/structure/disposalpipe/broken)) - pdir = CP.dir - if(pdir & dpdir) - to_chat(user, "There is already a [nicetype] at that location!") - return - anchored = TRUE - if(ispipe) - level = 1 // We don't want disposal bins to disappear under the floors - density = FALSE - to_chat(user, "You attach the [nicetype] to the underfloor.") - playsound(loc, I.usesound, 100, 1) - update_icon() - - else if(istype(I, /obj/item/weldingtool)) - if(anchored) - var/obj/item/weldingtool/W = I - if(W.remove_fuel(0,user)) - playsound(loc, 'sound/items/welder2.ogg', 100, 1) - to_chat(user, "You start welding the [nicetype] in place...") - if(do_after(user, 8*I.toolspeed, target = src)) - if(!loc || !W.isOn()) - return - to_chat(user, "The [nicetype] has been welded in place.") - update_icon() // TODO: Make this neat - - if(ispipe) - var/pipetype = dpipetype() - var/obj/structure/disposalpipe/P = new pipetype(loc, src) - P.updateicon() - transfer_fingerprints_to(P) - - if(ptype == DISP_SORTJUNCTION || ptype == DISP_SORTJUNCTION_FLIP) - var/obj/structure/disposalpipe/sortjunction/SortP = P - SortP.updatedir() - - else if(ptype == DISP_END_BIN) - var/obj/machinery/disposal/bin/B = new /obj/machinery/disposal/bin(loc,src) - B.pressure_charging = FALSE // start with pump off - transfer_fingerprints_to(B) - - else if(ptype == DISP_END_OUTLET) - var/obj/structure/disposaloutlet/P = new /obj/structure/disposaloutlet(loc,src) - transfer_fingerprints_to(P) - - else if(ptype == DISP_END_CHUTE) - var/obj/machinery/disposal/deliveryChute/P = new /obj/machinery/disposal/deliveryChute(loc,src) - transfer_fingerprints_to(P) - - return - else - to_chat(user, "You need to attach it to the plating first!") - return - -/obj/structure/disposalconstruct/proc/is_pipe() - return !(ptype >=DISP_END_BIN && ptype <= DISP_END_CHUTE) - -//helper proc that makes sure you can place the construct (i.e no dense objects stacking) -/obj/structure/disposalconstruct/proc/can_place() - if(is_pipe()) - return 1 - - for(var/obj/structure/disposalconstruct/DC in get_turf(src)) - if(DC == src) - continue - - if(!DC.is_pipe()) //there's already a chute/outlet/bin there - return 0 - - return 1 diff --git a/code/modules/recycling/disposal-structures.dm b/code/modules/recycling/disposal-structures.dm deleted file mode 100644 index 5a7428d1d1..0000000000 --- a/code/modules/recycling/disposal-structures.dm +++ /dev/null @@ -1,749 +0,0 @@ - -// virtual disposal object -// travels through pipes in lieu of actual items -// contents will be items flushed by the disposal -// this allows the gas flushed to be tracked - -/obj/structure/disposalholder - invisibility = INVISIBILITY_MAXIMUM - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point - var/active = 0 // true if the holder is moving, otherwise inactive - dir = 0 - var/count = 1000 //*** can travel 1000 steps before going inactive (in case of loops) - var/destinationTag = 0 // changes if contains a delivery container - var/tomail = 0 //changes if contains wrapped package - var/hasmob = 0 //If it contains a mob - -/obj/structure/disposalholder/ComponentInitialize() - . = ..() - AddComponent(/datum/component/rad_insulation, RAD_NO_INSULATION) - -/obj/structure/disposalholder/Destroy() - qdel(gas) - active = 0 - return ..() - - // initialize a holder from the contents of a disposal unit -/obj/structure/disposalholder/proc/init(obj/machinery/disposal/D) - gas = D.air_contents// transfer gas resv. into holder object - - //Check for any living mobs trigger hasmob. - //hasmob effects whether the package goes to cargo or its tagged destination. - for(var/mob/living/M in D) - if(M.client) - M.reset_perspective(src) - hasmob = 1 - - //Checks 1 contents level deep. This means that players can be sent through disposals... - //...but it should require a second person to open the package. (i.e. person inside a wrapped locker) - for(var/obj/O in D) - if(O.contents) - for(var/mob/living/M in O.contents) - hasmob = 1 - - // now everything inside the disposal gets put into the holder - // note AM since can contain mobs or objs - for(var/atom/movable/AM in D) - AM.loc = src - if(istype(AM, /obj/structure/bigDelivery) && !hasmob) - var/obj/structure/bigDelivery/T = AM - src.destinationTag = T.sortTag - if(istype(AM, /obj/item/smallDelivery) && !hasmob) - var/obj/item/smallDelivery/T = AM - src.destinationTag = T.sortTag - - -// start the movement process -// argument is the disposal unit the holder started in -/obj/structure/disposalholder/proc/start(obj/machinery/disposal/D) - if(!D.trunk) - D.expel(src) // no trunk connected, so expel immediately - return - loc = D.trunk - active = 1 - setDir(DOWN) - move() - - return - -// movement process, persists while holder is moving through pipes -/obj/structure/disposalholder/proc/move() - set waitfor = 0 - var/obj/structure/disposalpipe/last - while(active) - var/obj/structure/disposalpipe/curr = loc - last = curr - curr = curr.transfer(src) - if(!curr && active) - last.expel(src, loc, dir) - - stoplag() - if(!(count--)) - active = 0 - return - -// find the turf which should contain the next pipe -/obj/structure/disposalholder/proc/nextloc() - return get_step(loc,dir) - -// find a matching pipe on a turf -/obj/structure/disposalholder/proc/findpipe(turf/T) - - if(!T) - return null - - var/fdir = turn(dir, 180) // flip the movement direction - for(var/obj/structure/disposalpipe/P in T) - if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir - return P - // if no matching pipe, return null - return null - -// merge two holder objects -// used when a holder meets a stuck holder -/obj/structure/disposalholder/proc/merge(obj/structure/disposalholder/other) - for(var/atom/movable/AM in other) - AM.loc = src // move everything in other holder to this one - if(ismob(AM)) - var/mob/M = AM - M.reset_perspective(src) // if a client mob, update eye to follow this holder - qdel(other) - - -// called when player tries to move while in a pipe -/obj/structure/disposalholder/relaymove(mob/user) - if (user.stat) - return - if (src.loc) - for (var/mob/M in get_hearers_in_view(src.loc.loc)) - M.show_message("CLONG, clong!", 2) - playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0) - -// called to vent all gas in holder to a location -/obj/structure/disposalholder/proc/vent_gas(turf/T) - T.assume_air(gas) - T.air_update_turf() - -/obj/structure/disposalholder/AllowDrop() - return TRUE - -/obj/structure/disposalholder/ex_act(severity, target) - return - -// Disposal pipes - -/obj/structure/disposalpipe - icon = 'icons/obj/atmospherics/pipes/disposal.dmi' - name = "disposal pipe" - desc = "An underfloor disposal pipe." - anchored = TRUE - density = FALSE - on_blueprints = TRUE - level = 1 // underfloor only - var/dpdir = 0 // bitmask of pipe directions - dir = 0// dir will contain dominant direction for junction pipes - max_integrity = 200 - armor = list(melee = 25, bullet = 10, laser = 10, energy = 100, bomb = 0, bio = 100, rad = 100, fire = 90, acid = 30) - layer = DISPOSAL_PIPE_LAYER // slightly lower than wires and other pipes - var/base_icon_state // initial icon state on map - var/obj/structure/disposalconstruct/stored - - // new pipe, set the icon_state as on map -/obj/structure/disposalpipe/Initialize(mapload, obj/structure/disposalconstruct/make_from) - . = ..() - - if(make_from && !QDELETED(make_from)) - base_icon_state = make_from.base_state - setDir(make_from.dir) - dpdir = make_from.dpdir - make_from.loc = src - stored = make_from - else - base_icon_state = icon_state - stored = new /obj/structure/disposalconstruct(src,direction=dir) - switch(base_icon_state) - if("pipe-s") - stored.ptype = DISP_PIPE_STRAIGHT - if("pipe-c") - stored.ptype = DISP_PIPE_BENT - if("pipe-j1") - stored.ptype = DISP_JUNCTION - if("pipe-j2") - stored.ptype = DISP_JUNCTION_FLIP - if("pipe-y") - stored.ptype = DISP_YJUNCTION - if("pipe-t") - stored.ptype = DISP_END_TRUNK - if("pipe-j1s") - stored.ptype = DISP_SORTJUNCTION - if("pipe-j2s") - stored.ptype = DISP_SORTJUNCTION_FLIP - -/obj/structure/disposalpipe/ComponentInitialize() - . = ..() - AddComponent(/datum/component/rad_insulation, RAD_NO_INSULATION) - - // pipe is deleted - // ensure if holder is present, it is expelled -/obj/structure/disposalpipe/Destroy() - var/obj/structure/disposalholder/H = locate() in src - if(H) - H.active = 0 - var/turf/T = src.loc - expel(H, T, 0) - return ..() - -// returns the direction of the next pipe object, given the entrance dir -// by default, returns the bitmask of remaining directions -/obj/structure/disposalpipe/proc/nextdir(fromdir) - return dpdir & (~turn(fromdir, 180)) - -// transfer the holder through this pipe segment -// overriden for special behaviour -// -/obj/structure/disposalpipe/proc/transfer(obj/structure/disposalholder/H) - var/nextdir = nextdir(H.dir) - return transfer_to_dir(H, nextdir) - -/obj/structure/disposalpipe/proc/transfer_to_dir(obj/structure/disposalholder/H, nextdir) - H.setDir(nextdir) - var/turf/T = H.nextloc() - var/obj/structure/disposalpipe/P = H.findpipe(T) - - if(P) - // find other holder in next loc, if inactive merge it with current - var/obj/structure/disposalholder/H2 = locate() in P - if(H2 && !H2.active) - H.merge(H2) - - H.loc = P - return P - else // if wasn't a pipe, then they're now in our turf - H.loc = get_turf(src) - return null - -// update the icon_state to reflect hidden status -/obj/structure/disposalpipe/proc/update() - var/turf/T = src.loc - hide(T.intact && !isspaceturf(T)) // space never hides pipes - -// hide called by levelupdate if turf intact status changes -// change visibility status and force update of icon -/obj/structure/disposalpipe/hide(var/intact) - invisibility = intact ? INVISIBILITY_MAXIMUM: 0 // hide if floor is intact - updateicon() - -// update actual icon_state depending on visibility -// if invisible, append "f" to icon_state to show faded version -// this will be revealed if a T-scanner is used -// if visible, use regular icon_state -/obj/structure/disposalpipe/proc/updateicon() - if(invisibility) - icon_state = "[base_icon_state]f" - else - icon_state = base_icon_state - return - - -// expel the held objects into a turf -// called when there is a break in the pipe -// - -/obj/structure/disposalpipe/proc/expel(obj/structure/disposalholder/H, turf/T, direction) - - var/turf/target - var/eject_range = 5 - var/turf/open/floor/floorturf - - if(isfloorturf(T)) //intact floor, pop the tile - floorturf = T - if(floorturf.floor_tile) - new floorturf.floor_tile(T) - floorturf.make_plating() - - if(direction) // direction is specified - if(isspaceturf(T)) // if ended in space, then range is unlimited - target = get_edge_target_turf(T, direction) - else // otherwise limit to 10 tiles - target = get_ranged_target_turf(T, direction, 10) - - eject_range = 10 - - else if(floorturf) - target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5)) - - playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) - for(var/atom/movable/AM in H) - AM.forceMove(src.loc) - AM.pipe_eject(direction) - if(target) - AM.throw_at(target, eject_range, 1) - H.vent_gas(T) - qdel(H) - - -// pipe affected by explosion -/obj/structure/disposalpipe/contents_explosion(severity, target) - var/obj/structure/disposalholder/H = locate() in src - if(H) - H.contents_explosion(severity, target) - - -/obj/structure/disposalpipe/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) - if(damage_flag == "melee" && damage_amount < 10) - return 0 - . = ..() - -//attack by item -//weldingtool: unfasten and convert to obj/disposalconstruct - -/obj/structure/disposalpipe/attackby(obj/item/I, mob/user, params) - var/turf/T = src.loc - if(T.intact) - return // prevent interaction with T-scanner revealed pipes - add_fingerprint(user) - if(istype(I, /obj/item/weldingtool)) - var/obj/item/weldingtool/W = I - if(can_be_deconstructed(user)) - if(W.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/welder2.ogg', 100, 1) - to_chat(user, "You start slicing the disposal pipe...") - // check if anything changed over 2 seconds - if(do_after(user,30, target = src)) - if(!src || !W.isOn()) - return - deconstruct() - to_chat(user, "You slice the disposal pipe.") - else - return ..() - -//checks if something is blocking the deconstruction (e.g. trunk with a bin still linked to it) -/obj/structure/disposalpipe/proc/can_be_deconstructed() - . = 1 - -// called when pipe is cut with welder -/obj/structure/disposalpipe/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - if(disassembled) - if(stored) - var/turf/T = loc - stored.loc = T - transfer_fingerprints_to(stored) - stored.setDir(dir) - stored.density = FALSE - stored.anchored = TRUE - stored.update_icon() - else - for(var/D in GLOB.cardinals) - if(D & dpdir) - var/obj/structure/disposalpipe/broken/P = new(src.loc) - P.setDir(D) - qdel(src) - - -/obj/structure/disposalpipe/singularity_pull(S, current_size) - ..() - if(current_size >= STAGE_FIVE) - deconstruct() - -// *** TEST verb -//client/verb/dispstop() -// for(var/obj/structure/disposalholder/H in world) -// H.active = 0 - -// a straight or bent segment -/obj/structure/disposalpipe/segment - icon_state = "pipe-s" - -/obj/structure/disposalpipe/segment/Initialize() - . = ..() - if(stored.ptype == DISP_PIPE_STRAIGHT) - dpdir = dir | turn(dir, 180) - else - dpdir = dir | turn(dir, -90) - - update() - - - - -//a three-way junction with dir being the dominant direction -/obj/structure/disposalpipe/junction - icon_state = "pipe-j1" - -/obj/structure/disposalpipe/junction/Initialize() - . = ..() - switch(stored.ptype) - if(DISP_JUNCTION) - dpdir = dir | turn(dir, -90) | turn(dir,180) - if(DISP_JUNCTION_FLIP) - dpdir = dir | turn(dir, 90) | turn(dir,180) - if(DISP_YJUNCTION) - dpdir = dir | turn(dir,90) | turn(dir, -90) - update() - - -// next direction to move -// if coming in from secondary dirs, then next is primary dir -// if coming in from primary dir, then next is equal chance of other dirs - -/obj/structure/disposalpipe/junction/nextdir(fromdir) - var/flipdir = turn(fromdir, 180) - if(flipdir != dir) // came from secondary dir - return dir // so exit through primary - else // came from primary - // so need to choose either secondary exit - var/mask = ..(fromdir) - - // find a bit which is set - var/setbit = 0 - if(mask & NORTH) - setbit = NORTH - else if(mask & SOUTH) - setbit = SOUTH - else if(mask & EAST) - setbit = EAST - else - setbit = WEST - - if(prob(50)) // 50% chance to choose the found bit or the other one - return setbit - else - return mask & (~setbit) - -//a three-way junction that sorts objects -/obj/structure/disposalpipe/sortjunction - desc = "An underfloor disposal pipe with a package sorting mechanism." - icon_state = "pipe-j1s" - var/sortType = 0 - // To be set in map editor. - // Supports both singular numbers and strings of numbers similar to access level strings. - // Look at the list called TAGGERLOCATIONS in /_globalvars/lists/flavor_misc.dm - var/list/sortTypes = list() - var/posdir = 0 - var/negdir = 0 - var/sortdir = 0 - -/obj/structure/disposalpipe/sortjunction/examine(mob/user) - ..() - if(sortTypes.len>0) - to_chat(user, "It is tagged with the following tags:") - for(var/t in sortTypes) - to_chat(user, "\t[GLOB.TAGGERLOCATIONS[t]].") - else - to_chat(user, "It has no sorting tags set.") - - -/obj/structure/disposalpipe/sortjunction/proc/updatedir() - posdir = dir - negdir = turn(posdir, 180) - - if(stored.ptype == DISP_SORTJUNCTION) - sortdir = turn(posdir, -90) - else - icon_state = "pipe-j2s" - sortdir = turn(posdir, 90) - - dpdir = sortdir | posdir | negdir - -/obj/structure/disposalpipe/sortjunction/Initialize() - . = ..() - - // Generate a list of soring tags. - if(sortType) - if(isnum(sortType)) - sortTypes |= sortType - else if(istext(sortType)) - var/list/sorts = splittext(sortType,";") - for(var/x in sorts) - var/n = text2num(x) - if(n) - sortTypes |= n - - updatedir() - update() - -/obj/structure/disposalpipe/sortjunction/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/device/destTagger)) - var/obj/item/device/destTagger/O = I - - if(O.currTag > 0)// Tag set - if(O.currTag in sortTypes) - sortTypes -= O.currTag - to_chat(user, "Removed \"[GLOB.TAGGERLOCATIONS[O.currTag]]\" filter.") - else - sortTypes |= O.currTag - to_chat(user, "Added \"[GLOB.TAGGERLOCATIONS[O.currTag]]\" filter.") - playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) - else - return ..() - - -// next direction to move -// if coming in from negdir, then next is primary dir or sortdir -// if coming in from posdir, then flip around and go back to posdir -// if coming in from sortdir, go to posdir - -/obj/structure/disposalpipe/sortjunction/nextdir(fromdir, sortTag) - //var/flipdir = turn(fromdir, 180) - if(fromdir != sortdir) // probably came from the negdir - - if(sortTag in sortTypes) //if destination matches filtered type... - return sortdir // exit through sortdirection - else - return posdir - else // came from sortdir - // so go with the flow to positive direction - return posdir - -/obj/structure/disposalpipe/sortjunction/transfer(obj/structure/disposalholder/H) - var/nextdir = nextdir(H.dir, H.destinationTag) - return transfer_to_dir(H, nextdir) - -//a three-way junction that sorts objects destined for the mail office mail table (tomail = 1) -/obj/structure/disposalpipe/wrapsortjunction - - desc = "An underfloor disposal pipe which sorts wrapped and unwrapped objects." - icon_state = "pipe-j1s" - var/posdir = 0 - var/negdir = 0 - var/sortdir = 0 - -/obj/structure/disposalpipe/wrapsortjunction/Initialize() - . = ..() - posdir = dir - if(stored.ptype == DISP_SORTJUNCTION) - sortdir = turn(posdir, -90) - negdir = turn(posdir, 180) - else - icon_state = "pipe-j2s" - sortdir = turn(posdir, 90) - negdir = turn(posdir, 180) - dpdir = sortdir | posdir | negdir - - update() - -// next direction to move -// if coming in from negdir, then next is primary dir or sortdir -// if coming in from posdir, then flip around and go back to posdir -// if coming in from sortdir, go to posdir - -/obj/structure/disposalpipe/wrapsortjunction/nextdir(fromdir, istomail) - //var/flipdir = turn(fromdir, 180) - if(fromdir != sortdir) // probably came from the negdir - - if(istomail) //if destination matches filtered type... - return sortdir // exit through sortdirection - else - return posdir - else // came from sortdir - // so go with the flow to positive direction - return posdir - -/obj/structure/disposalpipe/wrapsortjunction/transfer(obj/structure/disposalholder/H) - var/nextdir = nextdir(H.dir, H.tomail) - return transfer_to_dir(H, nextdir) - -//a trunk joining to a disposal bin or outlet on the same turf -/obj/structure/disposalpipe/trunk - icon_state = "pipe-t" - var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet - -/obj/structure/disposalpipe/trunk/Initialize() - . = ..() - dpdir = dir - getlinked() - update() - -/obj/structure/disposalpipe/trunk/Destroy() - if(linked) - if(istype(linked, /obj/structure/disposaloutlet)) - var/obj/structure/disposaloutlet/D = linked - D.trunk = null - else if(istype(linked, /obj/machinery/disposal)) - var/obj/machinery/disposal/D = linked - D.trunk = null - return ..() - -/obj/structure/disposalpipe/trunk/proc/getlinked() - linked = null - var/obj/machinery/disposal/D = locate() in src.loc - if(D) - linked = D - if (!D.trunk) - D.trunk = src - - var/obj/structure/disposaloutlet/O = locate() in src.loc - if(O) - linked = O - - update() - return - -/obj/structure/disposalpipe/trunk/can_be_deconstructed(mob/user) - if(linked) - to_chat(user, "You need to deconstruct disposal machinery above this pipe!") - else - . = 1 - - // would transfer to next pipe segment, but we are in a trunk - // if not entering from disposal bin, - // transfer to linked object (outlet or bin) - -/obj/structure/disposalpipe/trunk/transfer(obj/structure/disposalholder/H) - if(H.dir == DOWN) // we just entered from a disposer - return ..() // so do base transfer proc - // otherwise, go to the linked object - if(linked) - var/obj/structure/disposaloutlet/O = linked - if(istype(O) && (H)) - O.expel(H) // expel at outlet - else - var/obj/machinery/disposal/D = linked - if(H) - D.expel(H) // expel at disposal - else - if(H) - src.expel(H, get_turf(src), 0) // expel at turf - return null - -/obj/structure/disposalpipe/trunk/nextdir(fromdir) - if(fromdir == DOWN) - return dir - else - return 0 - -// a broken pipe -/obj/structure/disposalpipe/broken - icon_state = "pipe-b" - dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes - // i.e. will be treated as an empty turf - desc = "A broken piece of disposal pipe." - -/obj/structure/disposalpipe/broken/Initialize() - . = ..() - update() - -// the disposal outlet machine - -/obj/structure/disposalpipe/broken/deconstruct() - qdel(src) - -/obj/structure/disposaloutlet - name = "disposal outlet" - desc = "An outlet for the pneumatic disposal system." - icon = 'icons/obj/atmospherics/pipes/disposal.dmi' - icon_state = "outlet" - density = TRUE - anchored = TRUE - var/active = 0 - var/turf/target // this will be where the output objects are 'thrown' to. - var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk - var/obj/structure/disposalconstruct/stored - var/mode = 0 - var/start_eject = 0 - var/eject_range = 2 - -/obj/structure/disposaloutlet/Initialize(mapload, obj/structure/disposalconstruct/make_from) - . = ..() - - if(make_from) - setDir(make_from.dir) - make_from.loc = src - stored = make_from - else - stored = new (src, DISP_END_OUTLET,dir) - - target = get_ranged_target_turf(src, dir, 10) - - trunk = locate() in loc - if(trunk) - trunk.linked = src // link the pipe trunk to self - -/obj/structure/disposaloutlet/ComponentInitialize() - . = ..() - AddComponent(/datum/component/rad_insulation, RAD_NO_INSULATION) - -/obj/structure/disposaloutlet/Destroy() - if(trunk) - trunk.linked = null - return ..() - -// expel the contents of the holder object, then delete it -// called when the holder exits the outlet -/obj/structure/disposaloutlet/proc/expel(obj/structure/disposalholder/H) - var/turf/T = get_turf(src) - flick("outlet-open", src) - if((start_eject + 30) < world.time) - start_eject = world.time - playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0) - sleep(20) - playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) - else - sleep(20) - if(H) - for(var/atom/movable/AM in H) - AM.forceMove(T) - AM.pipe_eject(dir) - AM.throw_at(target, eject_range, 1) - - H.vent_gas(T) - qdel(H) - return - -/obj/structure/disposaloutlet/attackby(obj/item/I, mob/user, params) - add_fingerprint(user) - if(istype(I, /obj/item/screwdriver)) - if(mode==0) - mode=1 - playsound(src.loc, I.usesound, 50, 1) - to_chat(user, "You remove the screws around the power connection.") - else if(mode==1) - mode=0 - playsound(src.loc, I.usesound, 50, 1) - to_chat(user, "You attach the screws around the power connection.") - - else if(istype(I, /obj/item/weldingtool) && mode==1) - var/obj/item/weldingtool/W = I - if(W.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/welder2.ogg', 100, 1) - to_chat(user, "You start slicing the floorweld off \the [src]...") - if(do_after(user,20*I.toolspeed, target = src)) - if(!src || !W.isOn()) - return - to_chat(user, "You slice the floorweld off \the [src].") - stored.loc = loc - src.transfer_fingerprints_to(stored) - stored.update_icon() - stored.anchored = FALSE - stored.density = TRUE - qdel(src) - else - return ..() - - - -// called when movable is expelled from a disposal pipe or outlet -// by default does nothing, override for special behaviour - -/atom/movable/proc/pipe_eject(direction) - return - -/obj/effect/decal/cleanable/blood/gibs/pipe_eject(direction) - var/list/dirs - if(direction) - dirs = list( direction, turn(direction, -45), turn(direction, 45)) - else - dirs = GLOB.alldirs.Copy() - - src.streak(dirs) - -/obj/effect/decal/cleanable/robot_debris/gib/pipe_eject(direction) - var/list/dirs - if(direction) - dirs = list( direction, turn(direction, -45), turn(direction, 45)) - else - dirs = GLOB.alldirs.Copy() - - src.streak(dirs) diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal/bin.dm similarity index 92% rename from code/modules/recycling/disposal-unit.dm rename to code/modules/recycling/disposal/bin.dm index 926e6326ad..67aada1c2a 100644 --- a/code/modules/recycling/disposal-unit.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -1,5 +1,4 @@ - -//disposal bin and Delivery chute. +// Disposal bin and Delivery chute. #define SEND_PRESSURE 0.05*ONE_ATMOSPHERE @@ -30,14 +29,15 @@ if(make_from) setDir(make_from.dir) - make_from.loc = 0 + make_from.loc = null stored = make_from + pressure_charging = FALSE // newly built disposal bins start with pump off else - stored = new /obj/structure/disposalconstruct(0,DISP_END_BIN,dir) + stored = new /obj/structure/disposalconstruct(null, make_from = src) trunk_check() - air_contents = new/datum/gas_mixture() + air_contents = new /datum/gas_mixture() //gas.volume = 1.05 * CELLSTANDARD update_icon() @@ -167,16 +167,6 @@ flush = !flush update_icon() -// ai as human but can't flush -/obj/machinery/disposal/attack_ai(mob/user) - interact(user, 1) - -// human interact with machine -/obj/machinery/disposal/attack_hand(mob/user) - if(user && user.loc == src) - to_chat(usr, "You cannot reach the controls from inside!") - return - interact(user, 0) // eject the contents of the disposal unit /obj/machinery/disposal/proc/eject() @@ -210,7 +200,7 @@ /obj/machinery/disposal/proc/newHolderDestination(obj/structure/disposalholder/H) for(var/obj/item/smallDelivery/O in src) - H.tomail = 1 + H.tomail = TRUE return /obj/machinery/disposal/proc/flushAnimation() @@ -222,21 +212,22 @@ update_icon() // update icon // called when holder is expelled from a disposal -// should usually only occur if the pipe network is modified /obj/machinery/disposal/proc/expel(obj/structure/disposalholder/H) var/turf/T = get_turf(src) var/turf/target playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) - if(H) // Somehow, someone managed to flush a window which broke mid-transit and caused the disposal to go in an infinite loop trying to expel null, hopefully this fixes it - for(var/atom/movable/AM in H) - target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5)) - AM.forceMove(T) - AM.pipe_eject(0) - AM.throw_at(target, 5, 1) + for(var/A in H) + var/atom/movable/AM = A - H.vent_gas(loc) - qdel(H) + target = get_offset_target_turf(loc, rand(5)-rand(5), rand(5)-rand(5)) + + AM.forceMove(T) + AM.pipe_eject(0) + AM.throw_at(target, 5, 1) + + H.vent_gas(loc) + qdel(H) /obj/machinery/disposal/deconstruct(disassembled = TRUE) var/turf/T = loc @@ -290,12 +281,9 @@ // handle machine interaction /obj/machinery/disposal/bin/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) if(stat & BROKEN) return - if(user.loc == src) - to_chat(user, "You cannot reach the controls from inside!") - return ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) ui = new(user, src, ui_key, "disposal_unit", name, 300, 200, master_ui, state) @@ -315,6 +303,7 @@ /obj/machinery/disposal/bin/ui_act(action, params) if(..()) return + switch(action) if("handle-0") flush = FALSE @@ -453,7 +442,6 @@ /obj/machinery/disposal/deliveryChute/Initialize(mapload, obj/structure/disposalconstruct/make_from) . = ..() - stored.ptype = DISP_END_CHUTE trunk = locate() in loc if(trunk) trunk.linked = src // link the pipe trunk to self @@ -492,7 +480,7 @@ flush() /atom/movable/proc/CanEnterDisposals() - return 1 + return TRUE /obj/item/projectile/CanEnterDisposals() return diff --git a/code/modules/recycling/disposal/construction.dm b/code/modules/recycling/disposal/construction.dm new file mode 100644 index 0000000000..db8f258dc7 --- /dev/null +++ b/code/modules/recycling/disposal/construction.dm @@ -0,0 +1,231 @@ +// Disposal pipe construction +// This is the pipe that you drag around, not the attached ones. + +/obj/structure/disposalconstruct + name = "disposal pipe segment" + desc = "A huge pipe segment used for constructing disposal systems." + icon = 'icons/obj/atmospherics/pipes/disposal.dmi' + icon_state = "conpipe" + anchored = FALSE + density = FALSE + pressure_resistance = 5*ONE_ATMOSPHERE + level = 2 + max_integrity = 200 + var/obj/pipe_type = /obj/structure/disposalpipe/segment + var/pipename + + +/obj/structure/disposalconstruct/examine(mob/user) + ..() + to_chat(user, "Alt-click to rotate it clockwise.") + +/obj/structure/disposalconstruct/New(loc, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from) + ..() + if(make_from) + pipe_type = make_from.type + setDir(make_from.dir) + anchored = TRUE + + if(istype(make_from, /obj/structure/disposalpipe)) + var/obj/structure/disposalpipe/D = make_from + if(D.construct_type) + pipe_type = D.construct_type + + else + if(_pipe_type) + pipe_type = _pipe_type + setDir(_dir) + + pipename = initial(pipe_type.name) + + if(flip) + flip() + + update_icon() + +/obj/structure/disposalconstruct/Move() + var/old_dir = dir + ..() + setDir(old_dir) //pipes changing direction when moved is just annoying and buggy + +// update iconstate and dpdir due to dir and type +/obj/structure/disposalconstruct/update_icon() + icon_state = initial(pipe_type.icon_state) + if(is_pipe()) + icon_state = "con[icon_state]" + if(anchored) + level = initial(pipe_type.level) + layer = initial(pipe_type.layer) + else + level = initial(level) + layer = initial(layer) + + else if(ispath(pipe_type, /obj/machinery/disposal/bin)) + // Disposal bins recieve special icon treating + if(anchored) + icon_state = "disposal" + else + icon_state = "condisposal" + + +// hide called by levelupdate if turf intact status changes +// change visibility status and force update of icon +/obj/structure/disposalconstruct/hide(var/intact) + invisibility = (intact && level==1) ? INVISIBILITY_MAXIMUM: 0 // hide if floor is intact + update_icon() + +/obj/structure/disposalconstruct/proc/get_disposal_dir() + if(!is_pipe()) + return NONE + + var/obj/structure/disposalpipe/temp = pipe_type + var/initialize_dirs = initial(temp.initialize_dirs) + var/dpdir = NONE + + if(dir in GLOB.diagonals) // Bent pipes + return dir + + if(initialize_dirs != DISP_DIR_NONE) + dpdir = dir + + if(initialize_dirs & DISP_DIR_LEFT) + dpdir |= turn(dir, 90) + if(initialize_dirs & DISP_DIR_RIGHT) + dpdir |= turn(dir, -90) + if(initialize_dirs & DISP_DIR_FLIP) + dpdir |= turn(dir, 180) + return dpdir + +// flip and rotate verbs +/obj/structure/disposalconstruct/verb/rotate() + set name = "Rotate Pipe" + set category = "Object" + set src in view(1) + + if(usr.incapacitated()) + return + + if(anchored) + to_chat(usr, "You must unfasten the pipe before rotating it!") + return + + setDir(turn(dir, -90)) + update_icon() + +/obj/structure/disposalconstruct/AltClick(mob/user) + ..() + if(!in_range(src, user)) + return + else + rotate() + +/obj/structure/disposalconstruct/verb/flip() + set name = "Flip Pipe" + set category = "Object" + set src in view(1) + + if(usr.incapacitated()) + return + + if(anchored) + to_chat(usr, "You must unfasten the pipe before flipping it!") + return + + setDir(turn(dir, 180)) + + var/obj/structure/disposalpipe/temp = pipe_type + if(initial(temp.flip_type)) + if(dir in GLOB.diagonals) // Fix RPD-induced diagonal turning + setDir(turn(dir, 45)) + pipe_type = initial(temp.flip_type) + + update_icon() + + +// attackby item +// wrench: (un)anchor +// weldingtool: convert to real pipe + +/obj/structure/disposalconstruct/attackby(obj/item/I, mob/user, params) + var/ispipe = is_pipe() // Indicates if we should change the level of this pipe + + add_fingerprint(user) + + var/turf/T = get_turf(src) + if(T.intact && isfloorturf(T)) + to_chat(user, "You can only attach the [pipename] if the floor plating is removed!") + return + + if(!ispipe && iswallturf(T)) + to_chat(user, "You can't build [pipename]s on walls, only disposal pipes!") + return + + if(istype(I, /obj/item/wrench)) + if(anchored) + anchored = FALSE + density = FALSE + to_chat(user, "You detach the [pipename] from the underfloor.") + else + if(ispipe) + var/dpdir = get_disposal_dir() + for(var/obj/structure/disposalpipe/CP in T) + var/pdir = CP.dpdir + if(istype(CP, /obj/structure/disposalpipe/broken)) + pdir = CP.dir + if(pdir & dpdir) + to_chat(user, "There is already a disposal pipe at that location!") + return + level = 1 // Pipes only, don't want disposal bins to disappear under the floors + + else // Disposal or outlet + var/found_trunk = FALSE + for(var/obj/structure/disposalpipe/CP in T) + if(istype(CP, /obj/structure/disposalpipe/trunk)) + found_trunk = TRUE + break + + if(!found_trunk) + to_chat(user, "The [pipename] requires a trunk underneath it in order to work!") + return + + anchored = TRUE + density = initial(pipe_type.density) + to_chat(user, "You attach the [pipename] to the underfloor.") + playsound(src, I.usesound, 100, 1) + update_icon() + + else if(istype(I, /obj/item/weldingtool)) + if(anchored) + var/obj/item/weldingtool/W = I + if(W.remove_fuel(0,user)) + playsound(src, I.usesound, 50, 1) + to_chat(user, "You start welding the [pipename] in place...") + if(do_after(user, 8*I.toolspeed, target = src)) + if(!loc || !W.isOn()) + return + to_chat(user, "The [pipename] has been welded in place.") + + var/obj/O = new pipe_type(loc, src) + transfer_fingerprints_to(O) + + return + else + to_chat(user, "You need to attach it to the plating first!") + return + +/obj/structure/disposalconstruct/proc/is_pipe() + return ispath(pipe_type, /obj/structure/disposalpipe) + +//helper proc that makes sure you can place the construct (i.e no dense objects stacking) +/obj/structure/disposalconstruct/proc/can_place() + if(is_pipe()) + return TRUE + + for(var/obj/structure/disposalconstruct/DC in get_turf(src)) + if(DC == src) + continue + + if(!DC.is_pipe()) //there's already a chute/outlet/bin there + return FALSE + + return TRUE diff --git a/code/modules/recycling/disposal/eject.dm b/code/modules/recycling/disposal/eject.dm new file mode 100644 index 0000000000..48162f3745 --- /dev/null +++ b/code/modules/recycling/disposal/eject.dm @@ -0,0 +1,23 @@ +// called when movable is expelled from a disposal pipe or outlet +// by default does nothing, override for special behaviour + +/atom/movable/proc/pipe_eject(direction) + return + +/obj/effect/decal/cleanable/blood/gibs/pipe_eject(direction) + var/list/dirs + if(direction) + dirs = list(direction, turn(direction, -45), turn(direction, 45)) + else + dirs = GLOB.alldirs.Copy() + + streak(dirs) + +/obj/effect/decal/cleanable/robot_debris/gib/pipe_eject(direction) + var/list/dirs + if(direction) + dirs = list(direction, turn(direction, -45), turn(direction, 45)) + else + dirs = GLOB.alldirs.Copy() + + streak(dirs) diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm new file mode 100644 index 0000000000..cf9b5a2b58 --- /dev/null +++ b/code/modules/recycling/disposal/holder.dm @@ -0,0 +1,128 @@ +// virtual disposal object +// travels through pipes in lieu of actual items +// contents will be items flushed by the disposal +// this allows the gas flushed to be tracked + +/obj/structure/disposalholder + invisibility = INVISIBILITY_MAXIMUM + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + dir = NONE + var/datum/gas_mixture/gas // gas used to flush, will appear at exit point + var/active = FALSE // true if the holder is moving, otherwise inactive + var/count = 1000 // can travel 1000 steps before going inactive (in case of loops) + var/destinationTag = NONE // changes if contains a delivery container + var/tomail = FALSE // contains wrapped package + var/hasmob = FALSE // contains a mob + +/obj/structure/disposalholder/ComponentInitialize() + . = ..() + AddComponent(/datum/component/rad_insulation, RAD_NO_INSULATION) + +/obj/structure/disposalholder/Destroy() + QDEL_NULL(gas) + active = FALSE + return ..() + +// initialize a holder from the contents of a disposal unit +/obj/structure/disposalholder/proc/init(obj/machinery/disposal/D) + gas = D.air_contents// transfer gas resv. into holder object + + //Check for any living mobs trigger hasmob. + //hasmob effects whether the package goes to cargo or its tagged destination. + for(var/mob/living/M in D) + if(M.client) + M.reset_perspective(src) + hasmob = TRUE + + //Checks 1 contents level deep. This means that players can be sent through disposals mail... + //...but it should require a second person to open the package. (i.e. person inside a wrapped locker) + for(var/obj/O in D) + if(locate(/mob/living) in O) + hasmob = TRUE + break + + // now everything inside the disposal gets put into the holder + // note AM since can contain mobs or objs + for(var/A in D) + var/atom/movable/AM = A + AM.forceMove(src) + if(istype(AM, /obj/structure/bigDelivery) && !hasmob) + var/obj/structure/bigDelivery/T = AM + src.destinationTag = T.sortTag + if(istype(AM, /obj/item/smallDelivery) && !hasmob) + var/obj/item/smallDelivery/T = AM + src.destinationTag = T.sortTag + + +// start the movement process +// argument is the disposal unit the holder started in +/obj/structure/disposalholder/proc/start(obj/machinery/disposal/D) + if(!D.trunk) + D.expel(src) // no trunk connected, so expel immediately + return + forceMove(D.trunk) + active = TRUE + setDir(DOWN) + move() + +// movement process, persists while holder is moving through pipes +/obj/structure/disposalholder/proc/move() + set waitfor = FALSE + var/obj/structure/disposalpipe/last + while(active) + var/obj/structure/disposalpipe/curr = loc + last = curr + curr = curr.transfer(src) + if(!curr && active) + last.expel(src, loc, dir) + + stoplag() + if(!(count--)) + active = FALSE + +// find the turf which should contain the next pipe +/obj/structure/disposalholder/proc/nextloc() + return get_step(src, dir) + +// find a matching pipe on a turf +/obj/structure/disposalholder/proc/findpipe(turf/T) + if(!T) + return null + + var/fdir = turn(dir, 180) // flip the movement direction + for(var/obj/structure/disposalpipe/P in T) + if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir + return P + // if no matching pipe, return null + return null + +// merge two holder objects +// used when a holder meets a stuck holder +/obj/structure/disposalholder/proc/merge(obj/structure/disposalholder/other) + for(var/A in other) + var/atom/movable/AM = A + AM.forceMove(src) // move everything in other holder to this one + if(ismob(AM)) + var/mob/M = AM + M.reset_perspective(src) // if a client mob, update eye to follow this holder + qdel(other) + + +// called when player tries to move while in a pipe +/obj/structure/disposalholder/relaymove(mob/user) + if(user.incapacitated()) + return + for(var/mob/M in range(5, get_turf(src))) + M.show_message("CLONG, clong!", 2) + playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0) + +// called to vent all gas in holder to a location +/obj/structure/disposalholder/proc/vent_gas(turf/T) + T.assume_air(gas) + T.air_update_turf() + +/obj/structure/disposalholder/AllowDrop() + return TRUE + +/obj/structure/disposalholder/ex_act(severity, target) + return diff --git a/code/modules/recycling/disposal/outlet.dm b/code/modules/recycling/disposal/outlet.dm new file mode 100644 index 0000000000..9351494cd5 --- /dev/null +++ b/code/modules/recycling/disposal/outlet.dm @@ -0,0 +1,88 @@ +// the disposal outlet machine +/obj/structure/disposaloutlet + name = "disposal outlet" + desc = "An outlet for the pneumatic disposal system." + icon = 'icons/obj/atmospherics/pipes/disposal.dmi' + icon_state = "outlet" + density = TRUE + anchored = TRUE + var/active = FALSE + var/turf/target // this will be where the output objects are 'thrown' to. + var/obj/structure/disposalpipe/trunk/trunk // the attached pipe trunk + var/obj/structure/disposalconstruct/stored + var/start_eject = 0 + var/eject_range = 3 + +/obj/structure/disposaloutlet/Initialize(mapload, obj/structure/disposalconstruct/make_from) + . = ..() + if(make_from) + setDir(make_from.dir) + make_from.forceMove(src) + stored = make_from + else + stored = new /obj/structure/disposalconstruct(src, make_from = src) + + target = get_ranged_target_turf(src, dir, 10) + + trunk = locate() in loc + if(trunk) + trunk.linked = src // link the pipe trunk to self + +/obj/structure/disposaloutlet/ComponentInitialize() + . = ..() + AddComponent(/datum/component/rad_insulation, RAD_NO_INSULATION) + +/obj/structure/disposaloutlet/Destroy() + if(trunk) + trunk.linked = null + trunk = null + QDEL_NULL(stored) + return ..() + +// expel the contents of the holder object, then delete it +// called when the holder exits the outlet +/obj/structure/disposaloutlet/proc/expel(obj/structure/disposalholder/H) + flick("outlet-open", src) + if((start_eject + 30) < world.time) + start_eject = world.time + playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0) + addtimer(CALLBACK(src, .proc/expel_holder, H, TRUE), 20) + else + addtimer(CALLBACK(src, .proc/expel_holder, H), 20) + +/obj/structure/disposaloutlet/proc/expel_holder(obj/structure/disposalholder/H, playsound=FALSE) + if(playsound) + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + + if(!H) + return + + var/turf/T = get_turf(src) + + for(var/A in H) + var/atom/movable/AM = A + AM.forceMove(T) + AM.pipe_eject(dir) + AM.throw_at(target, eject_range, 1) + + H.vent_gas(T) + qdel(H) + + +/obj/structure/disposaloutlet/attackby(obj/item/I, mob/user, params) + add_fingerprint(user) + if(istype(I, /obj/item/weldingtool)) + var/obj/item/weldingtool/W = I + if(W.remove_fuel(0,user)) + playsound(src, 'sound/items/welder2.ogg', 100, 1) + to_chat(user, "You start slicing the floorweld off [src]...") + if(do_after(user, 20*I.toolspeed, target = src)) + if(!W.isOn()) + return + to_chat(user, "You slice the floorweld off [src].") + stored.forceMove(loc) + transfer_fingerprints_to(stored) + stored = null + qdel(src) + else + return ..() diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm new file mode 100644 index 0000000000..238e72185d --- /dev/null +++ b/code/modules/recycling/disposal/pipe.dm @@ -0,0 +1,345 @@ +// Disposal pipes + +/obj/structure/disposalpipe + name = "disposal pipe" + desc = "An underfloor disposal pipe." + icon = 'icons/obj/atmospherics/pipes/disposal.dmi' + anchored = TRUE + density = FALSE + on_blueprints = TRUE + level = 1 // underfloor only + dir = NONE // dir will contain dominant direction for junction pipes + max_integrity = 200 + armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30) + layer = DISPOSAL_PIPE_LAYER // slightly lower than wires and other pipes + var/dpdir = NONE // bitmask of pipe directions + var/initialize_dirs = NONE // bitflags of pipe directions added on init, see \code\_DEFINES\pipe_construction.dm + var/construct_type // If set, used as type for pipe constructs. If not set, src.type is used. + var/flip_type // If set, the pipe is flippable and becomes this type when flipped + var/obj/structure/disposalconstruct/stored + + +/obj/structure/disposalpipe/Initialize(mapload, obj/structure/disposalconstruct/make_from) + . = ..() + + if(!QDELETED(make_from)) + setDir(make_from.dir) + make_from.forceMove(src) + stored = make_from + else + stored = new /obj/structure/disposalconstruct(src, make_from=src) + + // Hack for old map pipes to work, remove after all maps are updated + if(flip_type) + var/obj/structure/disposalpipe/flip = flip_type + if(icon_state == initial(flip.icon_state)) + initialize_dirs = initial(flip.initialize_dirs) + construct_type = flip_type + + + if(dir in GLOB.diagonals) // Bent pipes already have all the dirs set + initialize_dirs = NONE + + if(initialize_dirs != DISP_DIR_NONE) + dpdir = dir + + if(initialize_dirs & DISP_DIR_LEFT) + dpdir |= turn(dir, 90) + if(initialize_dirs & DISP_DIR_RIGHT) + dpdir |= turn(dir, -90) + if(initialize_dirs & DISP_DIR_FLIP) + dpdir |= turn(dir, 180) + update() + +/obj/structure/disposalpipe/ComponentInitialize() + . = ..() + AddComponent(/datum/component/rad_insulation, RAD_NO_INSULATION) + +// pipe is deleted +// ensure if holder is present, it is expelled +/obj/structure/disposalpipe/Destroy() + var/obj/structure/disposalholder/H = locate() in src + if(H) + H.active = FALSE + expel(H, get_turf(src), 0) + QDEL_NULL(stored) + return ..() + +// returns the direction of the next pipe object, given the entrance dir +// by default, returns the bitmask of remaining directions +/obj/structure/disposalpipe/proc/nextdir(obj/structure/disposalholder/H) + return dpdir & (~turn(H.dir, 180)) + +// transfer the holder through this pipe segment +// overriden for special behaviour +/obj/structure/disposalpipe/proc/transfer(obj/structure/disposalholder/H) + return transfer_to_dir(H, nextdir(H)) + +/obj/structure/disposalpipe/proc/transfer_to_dir(obj/structure/disposalholder/H, nextdir) + H.setDir(nextdir) + var/turf/T = H.nextloc() + var/obj/structure/disposalpipe/P = H.findpipe(T) + + if(P) + // find other holder in next loc, if inactive merge it with current + var/obj/structure/disposalholder/H2 = locate() in P + if(H2 && !H2.active) + H.merge(H2) + + H.forceMove(P) + return P + else // if wasn't a pipe, then they're now in our turf + H.forceMove(get_turf(src)) + return null + +// update the icon_state to reflect hidden status +/obj/structure/disposalpipe/proc/update() + var/turf/T = get_turf(src) + hide(T.intact && !isspaceturf(T)) // space never hides pipes + +// hide called by levelupdate if turf intact status changes +// change visibility status and force update of icon +/obj/structure/disposalpipe/hide(var/intact) + invisibility = intact ? INVISIBILITY_MAXIMUM: 0 // hide if floor is intact + +// expel the held objects into a turf +// called when there is a break in the pipe +/obj/structure/disposalpipe/proc/expel(obj/structure/disposalholder/H, turf/T, direction) + var/turf/target + var/eject_range = 5 + var/turf/open/floor/floorturf + + if(isfloorturf(T)) //intact floor, pop the tile + floorturf = T + if(floorturf.floor_tile) + new floorturf.floor_tile(T) + floorturf.make_plating() + + if(direction) // direction is specified + if(isspaceturf(T)) // if ended in space, then range is unlimited + target = get_edge_target_turf(T, direction) + else // otherwise limit to 10 tiles + target = get_ranged_target_turf(T, direction, 10) + + eject_range = 10 + + else if(floorturf) + target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5)) + + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + for(var/A in H) + var/atom/movable/AM = A + AM.forceMove(get_turf(src)) + AM.pipe_eject(direction) + if(target) + AM.throw_at(target, eject_range, 1) + H.vent_gas(T) + qdel(H) + + +// pipe affected by explosion +/obj/structure/disposalpipe/contents_explosion(severity, target) + var/obj/structure/disposalholder/H = locate() in src + if(H) + H.contents_explosion(severity, target) + + +/obj/structure/disposalpipe/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) + if(damage_flag == "melee" && damage_amount < 10) + return 0 + return ..() + + +//attack by item +//weldingtool: unfasten and convert to obj/disposalconstruct +/obj/structure/disposalpipe/attackby(obj/item/I, mob/user, params) + add_fingerprint(user) + if(istype(I, /obj/item/weldingtool)) + if(!can_be_deconstructed(user)) + return + + var/obj/item/weldingtool/W = I + if(W.remove_fuel(0, user)) + playsound(src, I.usesound, 50, 1) + to_chat(user, "You start slicing [src]...") + // check if anything changed over 2 seconds + if(do_after(user, 30*I.toolspeed, target = src)) + if(!W.isOn()) + return + deconstruct() + to_chat(user, "You slice [src].") + else + return ..() + +//checks if something is blocking the deconstruction (e.g. trunk with a bin still linked to it) +/obj/structure/disposalpipe/proc/can_be_deconstructed() + return TRUE + +// called when pipe is cut with welder +/obj/structure/disposalpipe/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + if(disassembled) + if(stored) + stored.forceMove(loc) + transfer_fingerprints_to(stored) + stored.setDir(dir) + stored = null + else + var/turf/T = get_turf(src) + for(var/D in GLOB.cardinals) + if(D & dpdir) + var/obj/structure/disposalpipe/broken/P = new(T) + P.setDir(D) + qdel(src) + + +/obj/structure/disposalpipe/singularity_pull(S, current_size) + ..() + if(current_size >= STAGE_FIVE) + deconstruct() + + +// Straight pipe segment +/obj/structure/disposalpipe/segment + icon_state = "pipe" + initialize_dirs = DISP_DIR_FLIP + +/obj/structure/disposalpipe/segment/Initialize() + // Hacks for old map pipes to work, remove after all maps are updated + if(icon_state == "pipe-c") + switch(dir) + if(NORTH) + dir = NORTHEAST + if(SOUTH) + dir = SOUTHWEST + if(EAST) + dir = SOUTHEAST + if(WEST) + dir = NORTHWEST + + if(icon_state != "pipe") + icon_state = "pipe" + . = ..() + + +// A three-way junction with dir being the dominant direction +/obj/structure/disposalpipe/junction + icon_state = "pipe-j1" + initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP + flip_type = /obj/structure/disposalpipe/junction/flip + +/obj/structure/disposalpipe/junction/Initialize() + if(icon_state == "pipe-y") // Hack for old map pipes to work, remove after all maps are updated + initialize_dirs = DISP_DIR_LEFT | DISP_DIR_RIGHT + flip_type = null + construct_type = /obj/structure/disposalpipe/junction/yjunction + . = ..() + + +// next direction to move +// if coming in from secondary dirs, then next is primary dir +// if coming in from primary dir, then next is equal chance of other dirs +/obj/structure/disposalpipe/junction/nextdir(obj/structure/disposalholder/H) + var/flipdir = turn(H.dir, 180) + if(flipdir != dir) // came from secondary dir, so exit through primary + return dir + + else // came from primary, so need to choose a secondary exit + var/mask = dpdir & (~dir) // get a mask of secondary dirs + + // find one secondary dir in mask + var/secdir = NONE + for(var/D in GLOB.cardinals) + if(D & mask) + secdir = D + break + + if(prob(50)) // 50% chance to choose the found secondary dir + return secdir + else // or the other one + return mask & (~secdir) + +/obj/structure/disposalpipe/junction/flip + icon_state = "pipe-j2" + initialize_dirs = DISP_DIR_LEFT | DISP_DIR_FLIP + flip_type = /obj/structure/disposalpipe/junction + +/obj/structure/disposalpipe/junction/yjunction + icon_state = "pipe-y" + initialize_dirs = DISP_DIR_LEFT | DISP_DIR_RIGHT + flip_type = null + + +//a trunk joining to a disposal bin or outlet on the same turf +/obj/structure/disposalpipe/trunk + icon_state = "pipe-t" + var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet + +/obj/structure/disposalpipe/trunk/Initialize() + . = ..() + getlinked() + +/obj/structure/disposalpipe/trunk/Destroy() + if(linked) + if(istype(linked, /obj/structure/disposaloutlet)) + var/obj/structure/disposaloutlet/D = linked + D.trunk = null + else if(istype(linked, /obj/machinery/disposal)) + var/obj/machinery/disposal/D = linked + D.trunk = null + return ..() + +/obj/structure/disposalpipe/trunk/proc/getlinked() + linked = null + var/turf/T = get_turf(src) + var/obj/machinery/disposal/D = locate() in T + if(D) + linked = D + if (!D.trunk) + D.trunk = src + + var/obj/structure/disposaloutlet/O = locate() in T + if(O) + linked = O + + +/obj/structure/disposalpipe/trunk/can_be_deconstructed(mob/user) + if(linked) + to_chat(user, "You need to deconstruct disposal machinery above this pipe!") + return FALSE + return TRUE + +// would transfer to next pipe segment, but we are in a trunk +// if not entering from disposal bin, +// transfer to linked object (outlet or bin) +/obj/structure/disposalpipe/trunk/transfer(obj/structure/disposalholder/H) + if(H.dir == DOWN) // we just entered from a disposer + return ..() // so do base transfer proc + // otherwise, go to the linked object + if(linked) + var/obj/structure/disposaloutlet/O = linked + if(istype(O)) + O.expel(H) // expel at outlet + else + var/obj/machinery/disposal/D = linked + D.expel(H) // expel at disposal + else + expel(H, get_turf(src), 0) // expel at turf + return null + +/obj/structure/disposalpipe/trunk/nextdir(obj/structure/disposalholder/H) + if(H.dir == DOWN) + return dir + else + return NONE + +// a broken pipe +/obj/structure/disposalpipe/broken + desc = "A broken piece of disposal pipe." + icon_state = "pipe-b" + initialize_dirs = DISP_DIR_NONE + // broken pipes always have dpdir=0 so they're not found as 'real' pipes + // i.e. will be treated as an empty turf + +/obj/structure/disposalpipe/broken/deconstruct() + qdel(src) diff --git a/code/modules/recycling/disposal/pipe_sorting.dm b/code/modules/recycling/disposal/pipe_sorting.dm new file mode 100644 index 0000000000..7b2d1aff0f --- /dev/null +++ b/code/modules/recycling/disposal/pipe_sorting.dm @@ -0,0 +1,102 @@ +// A three-way junction that sorts objects based on check_sorting(H) proc +// This is a base type, use subtypes on the map. +/obj/structure/disposalpipe/sorting + name = "sorting disposal pipe" + desc = "An underfloor disposal pipe with a sorting mechanism." + icon_state = "pipe-j1s" + initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP + +/obj/structure/disposalpipe/sorting/nextdir(obj/structure/disposalholder/H) + var/sortdir = dpdir & ~(dir | turn(dir, 180)) + if(H.dir != sortdir) // probably came from the negdir + if(check_sorting(H)) // if destination matches filtered type... + return sortdir // exit through sortdirection + + // go with the flow to positive direction + return dir + +// Sorting check, to be overridden in subtypes +/obj/structure/disposalpipe/sorting/proc/check_sorting(obj/structure/disposalholder/H) + return FALSE + + + +// Mail sorting junction, uses package tags to sort objects. +/obj/structure/disposalpipe/sorting/mail + flip_type = /obj/structure/disposalpipe/sorting/mail/flip + var/sortType = 0 + // sortType is to be set in map editor. + // Supports both singular numbers and strings of numbers similar to access level strings. + // Look at the list called TAGGERLOCATIONS in /_globalvars/lists/flavor_misc.dm + var/list/sortTypes = list() + +/obj/structure/disposalpipe/sorting/mail/flip + flip_type = /obj/structure/disposalpipe/sorting/mail + icon_state = "pipe-j2s" + initialize_dirs = DISP_DIR_LEFT | DISP_DIR_FLIP + +/obj/structure/disposalpipe/sorting/mail/Initialize() + . = ..() + // Generate a list of soring tags. + if(sortType) + if(isnum(sortType)) + sortTypes |= sortType + else if(istext(sortType)) + var/list/sorts = splittext(sortType,";") + for(var/x in sorts) + var/n = text2num(x) + if(n) + sortTypes |= n + +/obj/structure/disposalpipe/sorting/mail/examine(mob/user) + ..() + if(sortTypes.len) + to_chat(user, "It is tagged with the following tags:") + for(var/t in sortTypes) + to_chat(user, "\t[GLOB.TAGGERLOCATIONS[t]].") + else + to_chat(user, "It has no sorting tags set.") + + +/obj/structure/disposalpipe/sorting/mail/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/device/destTagger)) + var/obj/item/device/destTagger/O = I + + if(O.currTag)// Tagger has a tag set + if(O.currTag in sortTypes) + sortTypes -= O.currTag + to_chat(user, "Removed \"[GLOB.TAGGERLOCATIONS[O.currTag]]\" filter.") + else + sortTypes |= O.currTag + to_chat(user, "Added \"[GLOB.TAGGERLOCATIONS[O.currTag]]\" filter.") + playsound(src, 'sound/machines/twobeep.ogg', 100, 1) + else + return ..() + +/obj/structure/disposalpipe/sorting/mail/check_sorting(obj/structure/disposalholder/H) + return (H.destinationTag in sortTypes) + + + + +// Wrap sorting junction, sorts objects destined for the mail office mail table (tomail = 1) +/obj/structure/disposalpipe/sorting/wrap + desc = "An underfloor disposal pipe which sorts wrapped and unwrapped objects." + flip_type = /obj/structure/disposalpipe/sorting/wrap/flip + initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP + +/obj/structure/disposalpipe/sorting/wrap/check_sorting(obj/structure/disposalholder/H) + return H.tomail + +/obj/structure/disposalpipe/sorting/wrap/flip + icon_state = "pipe-j2s" + flip_type = /obj/structure/disposalpipe/sorting/wrap + initialize_dirs = DISP_DIR_LEFT | DISP_DIR_FLIP + + +// Hacks for old map pipes to work, remove after all maps are updated +/obj/structure/disposalpipe/wrapsortjunction + parent_type = /obj/structure/disposalpipe/sorting/wrap + +/obj/structure/disposalpipe/sortjunction + parent_type = /obj/structure/disposalpipe/sorting/mail diff --git a/icons/obj/atmospherics/pipes/disposal.dmi b/icons/obj/atmospherics/pipes/disposal.dmi index 15bb0e521a..a705b35c5a 100644 Binary files a/icons/obj/atmospherics/pipes/disposal.dmi and b/icons/obj/atmospherics/pipes/disposal.dmi differ diff --git a/tgstation.dme b/tgstation.dme index a23a8a0c36..96ea688a6a 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2145,10 +2145,14 @@ #include "code\modules\reagents\reagent_containers\spray.dm" #include "code\modules\reagents\reagent_containers\syringes.dm" #include "code\modules\recycling\conveyor2.dm" -#include "code\modules\recycling\disposal-construction.dm" -#include "code\modules\recycling\disposal-structures.dm" -#include "code\modules\recycling\disposal-unit.dm" #include "code\modules\recycling\sortingmachinery.dm" +#include "code\modules\recycling\disposal\bin.dm" +#include "code\modules\recycling\disposal\construction.dm" +#include "code\modules\recycling\disposal\eject.dm" +#include "code\modules\recycling\disposal\holder.dm" +#include "code\modules\recycling\disposal\outlet.dm" +#include "code\modules\recycling\disposal\pipe.dm" +#include "code\modules\recycling\disposal\pipe_sorting.dm" #include "code\modules\research\circuitprinter.dm" #include "code\modules\research\designs.dm" #include "code\modules\research\destructive_analyzer.dm"