// Disposal pipes #define IFFY 2 /obj/structure/disposalpipe name = "disposal pipe" desc = "An underfloor disposal pipe." icon = 'icons/obj/atmospherics/pipes/disposal.dmi' anchored = TRUE density = FALSE obj_flags = CAN_BE_HIT | ON_BLUEPRINTS 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 rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE 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/flip_type // If set, the pipe is flippable and becomes this type when flipped var/canclank = FALSE // Determines if the pipe will cause a clank sound when holders pass by it. use the IFFY define for weird-ass edge cases like the segment subtype 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, null , SOUTH , FALSE , src) 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() // 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 // overridden 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) if(P.canclank == TRUE || (P.canclank == IFFY && P.dpdir != 3 && P.dpdir != 12)) playsound(P, H.hasmob ? "clang" : "clangsmall", H.hasmob ? 50 : 25, 1) 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 ..() //welding tool: unfasten and convert to obj/disposalconstruct /obj/structure/disposalpipe/welder_act(mob/living/user, obj/item/I) if(!can_be_deconstructed(user)) return TRUE if(!I.tool_start_check(user, amount=0)) return TRUE to_chat(user, "You start slicing [src]...") if(I.use_tool(src, user, 30, volume=50)) deconstruct() to_chat(user, "You slice [src].") return TRUE //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/bent pipe segment /obj/structure/disposalpipe/segment icon_state = "pipe" initialize_dirs = DISP_DIR_FLIP canclank = IFFY // 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 canclank = TRUE // 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" canclank = TRUE 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 // Returning null without expelling holder makes the holder expell itself 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) #undef IFFY