313 lines
9.7 KiB
Plaintext
313 lines
9.7 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
|
|
plane = ABOVE_WALL_PLANE
|
|
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)
|
|
stored = null //The qdel is handled in expel()
|
|
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, origin)
|
|
var/obj/structure/disposalholder/H = locate() in src
|
|
if(H)
|
|
H.contents_explosion(severity, target, origin)
|
|
|
|
|
|
/obj/structure/disposalpipe/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
|
|
if(damage_flag == MELEE && damage_amount < 10)
|
|
return FALSE
|
|
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(mapload)
|
|
. = ..()
|
|
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 && O.anchored) //GS Edit: Added anchored check to fix an edgecase where the trunk could get erroneously linked to an unanchored industrial feeding tube if the trunk was welded solid while the loose tube was above the trunk. Whew...
|
|
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
|