// Disposal pipes /obj/structure/disposalpipe icon = 'icons/obj/pipes/disposal.dmi' name = "disposal pipe" desc = "An underfloor disposal pipe." anchored = TRUE density = FALSE unacidable = TRUE level = 1 // underfloor only var/dpdir = 0 // bitmask of pipe directions dir = 0 // dir will contain dominant direction for junction pipes var/health = 10 // health points 0-10 plane = PLATING_PLANE layer = DISPOSAL_LAYER // slightly lower than wires and other pipes var/base_icon_state // initial icon state on map var/sortType = "" var/subtype = 0 // new pipe, set the icon_state as on map /obj/structure/disposalpipe/Initialize(mapload) . = ..() base_icon_state = icon_state // 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) // holder was present H.active = FALSE var/turf/T = get_turf(src) if(T.density) // deleting pipe is inside a dense turf (wall) // this is unlikely, but just dump out everything into the turf in case for(var/atom/movable/AM in H) AM.forceMove(T) AM.pipe_eject(0) qdel(H) ..() return // otherwise, do normal expel from turf if(H) pipe_expel(H, T, 0) . = ..() // 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(var/fromdir) return dpdir & (~turn(fromdir, 180)) // transfer the holder through this pipe segment // overriden for special behaviour /obj/structure/disposalpipe/proc/transfer(var/obj/structure/disposalholder/H) var/nextdir = nextdir(H.dir) H.set_dir(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) else // if wasn't a pipe, then set loc to turf H.forceMove(T) return null return P // update the icon_state to reflect hidden status /obj/structure/disposalpipe/proc/update() var/turf/T = get_turf(src) hide(!T.is_plating() && !istype(T,/turf/space)) // 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_ABSTRACT : INVISIBILITY_NONE // hide if floor is intact update_icon() // 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/update_icon() if(!(flags & ATOM_INITIALIZED)) // Do not call update_icon before init. E.g. hide might be called before return /* if(invisibility) //we hide things with alpha now, no need for transparent icons icon_state = "[base_icon_state]f" else icon_state = base_icon_state*/ 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/pipe_expel(obj/structure/disposalholder/H, turf/T, direction) if(!istype(H)) return // Empty the holder if it is expelled into a dense turf. // Leaving it intact and sitting in a wall is stupid. if(T.density) for(var/atom/movable/AM in H) AM.loc = T AM.pipe_eject(0) qdel(H) return if(!T.is_plating() && istype(T,/turf/simulated/floor)) //intact floor, pop the tile var/turf/simulated/floor/F = T F.make_plating(TRUE) var/turf/target if(direction) // direction is specified if(istype(T, /turf/space)) // 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) playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) if(H) for(var/atom/movable/AM in H) if(QDELETED(AM)) continue AM.forceMove(T) AM.pipe_eject(direction) AM.throw_at(target, 100, 1) H.vent_gas(T) qdel(H) else // no specified direction, so throw in random direction playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) if(H) for(var/atom/movable/AM in H) if(QDELETED(AM)) continue target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5)) AM.forceMove(T) AM.pipe_eject(0) AM.throw_at(target, 5, 1) H.vent_gas(T) // all gas vent to turf qdel(H) return // call to break the pipe // will expel any holder inside at the time // then delete the pipe // remains : set to leave broken pipe pieces in place /obj/structure/disposalpipe/proc/broken(remains = 0) if(remains) for(var/D in GLOB.cardinal) if(D & dpdir) var/obj/structure/disposalpipe/broken/P = new(get_turf(src)) P.set_dir(D) invisibility = INVISIBILITY_ABSTRACT // make invisible (since we won't delete the pipe immediately) var/obj/structure/disposalholder/H = locate() in src if(H) // holder was present H.active = FALSE var/turf/T = get_turf(src) if(T.density) // broken pipe is inside a dense turf (wall) // this is unlikely, but just dump out everything into the turf in case for(var/atom/movable/AM in H) AM.forceMove(T) AM.pipe_eject(0) qdel(H) return // otherwise, do normal expel from turf if(H) pipe_expel(H, T, 0) spawn(2) // delete pipe after 2 ticks to ensure expel proc finished qdel(src) // pipe affected by explosion /obj/structure/disposalpipe/ex_act(severity) switch(severity) if(1.0) broken(0) return if(2.0) health -= rand(5,15) healthcheck() return if(3.0) health -= rand(0,15) healthcheck() return // test health for brokenness /obj/structure/disposalpipe/proc/healthcheck() if(health < -2) broken(0) else if(health<1) broken(1) return //attack by item //weldingtool: unfasten and convert to obj/disposalconstruct /obj/structure/disposalpipe/attackby(obj/item/I, mob/user) var/turf/T = get_turf(src) if(!T.is_plating()) return // prevent interaction with T-scanner revealed pipes add_fingerprint(user) if(I.has_tool_quality(TOOL_WELDER)) var/obj/item/weldingtool/W = I.get_welder() if(W.remove_fuel(0,user)) playsound(src, W.usesound, 100, 1) to_chat(user, "You start slicing [src]....") if(do_after(user, 2 SECONDS * W.toolspeed, target = src)) if(!src || !W.isOn()) return to_chat(user, "You slice [src]") welded() else to_chat(user, "You must stay still while welding the pipe.") else to_chat(user, "You need more welding fuel to cut the pipe.") return // called when pipe is cut with welder /obj/structure/disposalpipe/proc/welded() var/obj/structure/disposalconstruct/C = new (get_turf(src)) switch(base_icon_state) if("pipe-s") C.ptype = 0 if("pipe-c") C.ptype = 1 if("pipe-j1") C.ptype = 2 if("pipe-j2") C.ptype = 3 if("pipe-y") C.ptype = 4 if("pipe-t") C.ptype = 5 if("pipe-j1s") C.ptype = 9 C.sortType = sortType if("pipe-j2s") C.ptype = 10 C.sortType = sortType ///// Z-Level stuff if("pipe-u") C.ptype = 11 if("pipe-d") C.ptype = 12 ///// Z-Level stuff if("pipe-tagger") C.ptype = 13 if("pipe-tagger-partial") C.ptype = 14 C.subtype = subtype transfer_fingerprints_to(C) C.set_dir(dir) C.density = FALSE C.anchored = TRUE C.update() qdel(src) // 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) // holder was present H.active = FALSE var/turf/T = get_turf(src) if(T.density) // deleting pipe is inside a dense turf (wall) // this is unlikely, but just dump out everything into the turf in case for(var/atom/movable/AM in H) AM.forceMove(T) AM.pipe_eject(0) qdel(H) ..() return // otherwise, do normal expel from turf if(H) pipe_expel(H, T, 0) . = ..() /obj/structure/disposalpipe/hides_under_flooring() return 1 // *** 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(mapload) . = ..() if(icon_state == "pipe-s") dpdir = dir | turn(dir, 180) else dpdir = dir | turn(dir, -90) update() ///// Z-Level stuff /obj/structure/disposalpipe/up icon_state = "pipe-u" /obj/structure/disposalpipe/up/Initialize(mapload) . = ..() dpdir = dir update() /obj/structure/disposalpipe/up/nextdir(fromdir) var/nextdir if(fromdir == 11) nextdir = dir else nextdir = 12 return nextdir /obj/structure/disposalpipe/up/transfer(obj/structure/disposalholder/H) var/nextdir = nextdir(H.dir) H.set_dir(nextdir) var/turf/T var/obj/structure/disposalpipe/P if(nextdir == 12) T = GetAbove(src) if(!T) H.forceMove(loc) return else for(var/obj/structure/disposalpipe/down/F in T) P = F else T = get_step(get_turf(src), H.dir) 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) else // if wasn't a pipe, then set loc to turf H.forceMove(T) return null return P /obj/structure/disposalpipe/down icon_state = "pipe-d" /obj/structure/disposalpipe/down/Initialize(mapload) . = ..() dpdir = dir update() /obj/structure/disposalpipe/down/nextdir(fromdir) var/nextdir if(fromdir == 12) nextdir = dir else nextdir = 11 return nextdir /obj/structure/disposalpipe/down/transfer(obj/structure/disposalholder/H) var/nextdir = nextdir(H.dir) H.dir = nextdir var/turf/T var/obj/structure/disposalpipe/P if(nextdir == 11) T = GetBelow(src) if(!T) H.forceMove(get_turf(src)) return else for(var/obj/structure/disposalpipe/up/F in T) P = F else T = get_step(get_turf(src), H.dir) 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) else // if wasn't a pipe, then set loc to turf H.forceMove(T) return null return P // 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(mapload) . = ..() update() // called when welded /obj/structure/disposalpipe/broken/welded() qdel(src) // 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 // check if mob has client, if so restore client view on eject /mob/pipe_eject(var/direction) reset_perspective() /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/blood/gibs/robot/pipe_eject(direction) var/list/dirs if(direction) dirs = list( direction, turn(direction, -45), turn(direction, 45)) else dirs = GLOB.alldirs.Copy() streak(dirs)