Files
GS13/code/modules/recycling/disposal/pipe.dm
ReoDaProtovali 4f8aad26ce Finished.
Scrubbed out a few last bugs
2024-09-29 22:50:47 -05:00

315 lines
9.6 KiB
Plaintext

// 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, "<span class='notice'>You start slicing [src]...</span>")
if(I.use_tool(src, user, 30, volume=50))
deconstruct()
to_chat(user, "<span class='notice'>You slice [src].</span>")
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)
//GS add: Fixes a minor issue where the trunk gets linked to feeding tube improperly
if(O.type = /obj/structure/disposaloutlet/industrial_feeding_tube)
return
linked = O
/obj/structure/disposalpipe/trunk/can_be_deconstructed(mob/user)
if(linked)
to_chat(user, "<span class='warning'>You need to deconstruct disposal machinery above this pipe!</span>")
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