mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-28 06:28:01 +01:00
- Moved pipe construction defines into __defines/construction.dm
- Unified pipe *unwrenching* by creating a standard proc along with the `construction_type` var.
- Eliminated the pipe fitting name & icon_state lookup tables by adding `pipe_state` var on atmos machinery and referencing that.
- Each pipe which can be made from a fitting object should override `pipe_state` with the icon state to be used on the pipe fitting object.
- Eliminated the giant switch statement of doom in pipe construction by delegating that work to `on_construction` proc.
- To make this work, every pipe must implement `get_neighbor_nodes_for_init` which returns a list of nodes which should be re-initialized on that pipe's construction.
- Combined the SCRUBBERS, SUPPLY and REGULAR pipe fitting classes together by storing the `piping_layer` variable and using the `setPipingLayer` procs
- Standardized the code for searching for node neighbors into the `can_be_node` proc.
- This proc is also improved in that is a mutual check, `check_connectable` is called on BOTH objects, so they have to mutually agree to connect as nodes. Eliminates lots of special edge case logic.
- Updated all the `amos_init` procs to use `can_be_node`. In the most common cases, even that boilerplate code is consolidated into the `STANDARD_ATMOS_CHOOSE_NODE` macro.
- Implemented `pipe_flags` which lets pipes declare (or override) certain requirements.
- Adds a "pipe_recipe" datum to help out things that construct pipes. By taking it out of the dispenser, we open the road for multiple dispenser types. No, no RPD yet. Soon.
- Enhances the pipe dispenser to operate on pipe recipe datums instead of hard coded lists of pipes it can construct. These datums are also (partially) initialized from the pipe machine types themselves, reducing having to define stuff in multiple places.
- Switched pipe dispenser UI to use browse(). Not a NanoUI, but makes it a bit prettier with low effort.
- Changed pipe dispenser to use a button selector to switch between Regular/Scrubbers/Supply instead of having separate list items.
- Added icon states to HE pipes to support the "connected on neither side" state.
275 lines
8.2 KiB
Plaintext
275 lines
8.2 KiB
Plaintext
/*CONTENTS
|
|
Buildable pipes
|
|
Buildable meters
|
|
*/
|
|
|
|
/obj/item/pipe
|
|
name = "pipe"
|
|
desc = "A pipe."
|
|
var/pipe_type
|
|
var/pipename
|
|
force = 7
|
|
throwforce = 7
|
|
icon = 'icons/obj/pipe-item.dmi'
|
|
icon_state = "simple"
|
|
item_state = "buildpipe"
|
|
w_class = ITEMSIZE_NORMAL
|
|
level = 2
|
|
var/piping_layer = PIPING_LAYER_DEFAULT
|
|
var/dispenser_class // Tells the dispenser what orientations we support, so RPD can show previews.
|
|
|
|
// One subtype for each way components connect to neighbors
|
|
/obj/item/pipe/directional
|
|
dispenser_class = PIPE_DIRECTIONAL
|
|
/obj/item/pipe/binary
|
|
dispenser_class = PIPE_STRAIGHT
|
|
/obj/item/pipe/binary/bendable
|
|
dispenser_class = PIPE_BENDABLE
|
|
/obj/item/pipe/trinary
|
|
dispenser_class = PIPE_TRINARY
|
|
/obj/item/pipe/trinary/flippable
|
|
dispenser_class = PIPE_TRIN_M
|
|
var/mirrored = FALSE
|
|
/obj/item/pipe/quaternary
|
|
dispenser_class = PIPE_ONEDIR
|
|
|
|
/**
|
|
* Call constructor with:
|
|
* @param loc Location
|
|
* @pipe_type
|
|
*/
|
|
/obj/item/pipe/initialize(var/mapload, var/_pipe_type, var/_dir, var/obj/machinery/atmospherics/make_from)
|
|
if(make_from)
|
|
make_from_existing(make_from)
|
|
else
|
|
pipe_type = _pipe_type
|
|
set_dir(_dir)
|
|
|
|
update()
|
|
pixel_x += rand(-5, 5)
|
|
pixel_y += rand(-5, 5)
|
|
return ..()
|
|
|
|
/obj/item/pipe/proc/make_from_existing(obj/machinery/atmospherics/make_from)
|
|
set_dir(make_from.dir)
|
|
pipename = make_from.name
|
|
if(make_from.req_access)
|
|
src.req_access = make_from.req_access
|
|
if(make_from.req_one_access)
|
|
src.req_one_access = make_from.req_one_access
|
|
color = make_from.pipe_color
|
|
pipe_type = make_from.type
|
|
|
|
/obj/item/pipe/trinary/flippable/make_from_existing(obj/machinery/atmospherics/trinary/make_from)
|
|
..()
|
|
if(make_from.mirrored)
|
|
do_a_flip()
|
|
|
|
/obj/item/pipe/dropped()
|
|
if(loc)
|
|
setPipingLayer(piping_layer)
|
|
return ..()
|
|
|
|
/obj/item/pipe/proc/setPipingLayer(new_layer = PIPING_LAYER_DEFAULT)
|
|
var/obj/machinery/atmospherics/fakeA = pipe_type
|
|
if(initial(fakeA.pipe_flags) & (PIPING_ALL_LAYER|PIPING_DEFAULT_LAYER_ONLY))
|
|
new_layer = PIPING_LAYER_DEFAULT
|
|
piping_layer = new_layer
|
|
// Do it the Polaris way
|
|
switch(piping_layer)
|
|
if(PIPING_LAYER_SCRUBBER)
|
|
color = PIPE_COLOR_RED
|
|
name = "[initial(fakeA.name)] scrubber fitting"
|
|
if(PIPING_LAYER_SUPPLY)
|
|
color = PIPE_COLOR_BLUE
|
|
name = "[initial(fakeA.name)] supply fitting"
|
|
// Or if we were to do it the TG way...
|
|
// pixel_x = PIPE_PIXEL_OFFSET_X(piping_layer)
|
|
// pixel_y = PIPE_PIXEL_OFFSET_Y(piping_layer)
|
|
// layer = initial(layer) + PIPE_LAYER_OFFSET(piping_layer)
|
|
|
|
/obj/item/pipe/proc/update()
|
|
var/obj/machinery/atmospherics/fakeA = pipe_type
|
|
name = "[initial(fakeA.name)] fitting"
|
|
icon_state = initial(fakeA.pipe_state)
|
|
|
|
/obj/item/pipe/verb/flip()
|
|
set category = "Object"
|
|
set name = "Flip Pipe"
|
|
set src in view(1)
|
|
|
|
if ( usr.stat || usr.restrained() || !usr.canmove )
|
|
return
|
|
|
|
do_a_flip()
|
|
|
|
/obj/item/pipe/proc/do_a_flip()
|
|
set_dir(turn(dir, -180))
|
|
fixdir()
|
|
|
|
/obj/item/pipe/trinary/flippable/do_a_flip()
|
|
// set_dir(turn(dir, flipped ? 45 : -45))
|
|
// TG has a magic icon set with the flipped versions in the diagonals.
|
|
// We may switch to this later, but for now gotta do some magic.
|
|
mirrored = !mirrored
|
|
var/obj/machinery/atmospherics/fakeA = pipe_type
|
|
icon_state = "[initial(fakeA.pipe_state)][mirrored ? "m" : ""]"
|
|
|
|
/obj/item/pipe/verb/rotate()
|
|
set category = "Object"
|
|
set name = "Rotate Pipe"
|
|
set src in view(1)
|
|
|
|
if ( usr.stat || usr.restrained() || !usr.canmove )
|
|
return
|
|
|
|
set_dir(turn(src.dir, -90)) // Rotate clockwise
|
|
fixdir()
|
|
|
|
/obj/item/pipe/Move()
|
|
var/old_dir = dir
|
|
. = ..()
|
|
set_dir(old_dir) //pipes changing direction when moved is just annoying and buggy
|
|
|
|
//Helper to clean up dir
|
|
/obj/item/pipe/proc/fixdir()
|
|
return
|
|
|
|
/obj/item/pipe/binary/fixdir()
|
|
if(dir == SOUTH)
|
|
set_dir(NORTH)
|
|
else if(dir == WEST)
|
|
set_dir(EAST)
|
|
|
|
/obj/item/pipe/trinary/flippable/fixdir()
|
|
if(dir in cornerdirs)
|
|
set_dir(turn(dir, 45))
|
|
|
|
/obj/item/pipe/attack_self(mob/user)
|
|
set_dir(turn(dir,-90))
|
|
fixdir()
|
|
|
|
//called when a turf is attacked with a pipe item
|
|
/obj/item/pipe/afterattack(turf/simulated/floor/target, mob/user, proximity)
|
|
if(!proximity) return
|
|
if(istype(target) && user.canUnEquip(src))
|
|
user.drop_from_inventory(src, target)
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
|
if(iswrench(W))
|
|
return wrench_act(user, W)
|
|
return ..()
|
|
|
|
/obj/item/pipe/proc/wrench_act(var/mob/living/user, var/obj/item/weapon/wrench/W)
|
|
if(!isturf(loc))
|
|
return TRUE
|
|
|
|
add_fingerprint(user)
|
|
fixdir()
|
|
|
|
var/obj/machinery/atmospherics/fakeA = pipe_type
|
|
var/flags = initial(fakeA.pipe_flags)
|
|
for(var/obj/machinery/atmospherics/M in loc)
|
|
if((M.pipe_flags & flags & PIPING_ONE_PER_TURF)) //Only one dense/requires density object per tile, eg connectors/cryo/heater/coolers.
|
|
to_chat(user, "<span class='warning'>Something is hogging the tile!</span>")
|
|
return TRUE
|
|
if((M.piping_layer != piping_layer) && !((M.pipe_flags | flags) & PIPING_ALL_LAYER)) // Pipes on different layers can't block each other unless they are ALL_LAYER
|
|
continue
|
|
if(M.get_init_dirs() & SSmachines.get_init_dirs(pipe_type, dir)) // matches at least one direction on either type of pipe
|
|
to_chat(user, "<span class='warning'>There is already a pipe at that location!</span>")
|
|
return TRUE
|
|
// no conflicts found
|
|
|
|
var/obj/machinery/atmospherics/A = new pipe_type(loc)
|
|
build_pipe(A)
|
|
// TODO - Evaluate and remove the "need at least one thing to connect to" thing ~Leshana
|
|
// With how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment.
|
|
if (QDELETED(A))
|
|
to_chat(user, "<span class='warning'>There's nothing to connect this pipe section to!</span>")
|
|
return TRUE
|
|
transfer_fingerprints_to(A)
|
|
|
|
playsound(src, W.usesound, 50, 1)
|
|
user.visible_message( \
|
|
"[user] fastens \the [src].", \
|
|
"<span class='notice'>You fasten \the [src].</span>", \
|
|
"<span class='italics'>You hear ratcheting.</span>")
|
|
|
|
qdel(src)
|
|
|
|
/obj/item/pipe/proc/build_pipe(obj/machinery/atmospherics/A)
|
|
A.set_dir(dir)
|
|
A.init_dir()
|
|
if(pipename)
|
|
A.name = pipename
|
|
if(req_access)
|
|
A.req_access = req_access
|
|
if(req_one_access)
|
|
A.req_one_access = req_one_access
|
|
A.on_construction(color, piping_layer)
|
|
|
|
/obj/item/pipe/trinary/flippable/build_pipe(obj/machinery/atmospherics/trinary/T)
|
|
T.mirrored = mirrored
|
|
. = ..()
|
|
|
|
// Lookup the initialize_directions for a given atmos machinery instance facing dir.
|
|
// TODO - Right now this determines the answer by instantiating an instance and checking!
|
|
// There has to be a better way... ~Leshana
|
|
/datum/controller/subsystem/machines/proc/get_init_dirs(type, dir)
|
|
var/static/list/pipe_init_dirs_cache = list()
|
|
if(!pipe_init_dirs_cache[type])
|
|
pipe_init_dirs_cache[type] = list()
|
|
|
|
if(!pipe_init_dirs_cache[type]["[dir]"])
|
|
var/obj/machinery/atmospherics/temp = new type(null, FALSE, dir)
|
|
pipe_init_dirs_cache[type]["[dir]"] = temp.get_init_dirs()
|
|
qdel(temp)
|
|
|
|
return pipe_init_dirs_cache[type]["[dir]"]
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Meters are special - not like any other pipes or components
|
|
//
|
|
|
|
/obj/item/pipe_meter
|
|
name = "meter"
|
|
desc = "A meter that can be laid on pipes."
|
|
icon = 'icons/obj/pipe-item.dmi'
|
|
icon_state = "meter"
|
|
item_state = "buildpipe"
|
|
w_class = ITEMSIZE_LARGE
|
|
var/piping_layer = PIPING_LAYER_DEFAULT
|
|
|
|
/obj/item/pipe_meter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
|
if(iswrench(W))
|
|
return wrench_act(user, W)
|
|
return ..()
|
|
|
|
/obj/item/pipe_meter/proc/wrench_act(var/mob/living/user, var/obj/item/weapon/wrench/W)
|
|
var/obj/machinery/atmospherics/pipe/pipe
|
|
for(var/obj/machinery/atmospherics/pipe/P in loc)
|
|
if(P.piping_layer == piping_layer)
|
|
pipe = P
|
|
break
|
|
if(!pipe)
|
|
to_chat(user, "<span class='warning'>You need to fasten it to a pipe!</span>")
|
|
return TRUE
|
|
new /obj/machinery/meter(loc, piping_layer)
|
|
playsound(src, W.usesound, 50, 1)
|
|
to_chat(user, "<span class='notice'>You fasten the meter to the pipe.</span>")
|
|
qdel(src)
|
|
|
|
/obj/item/pipe_meter/dropped()
|
|
. = ..()
|
|
if(loc)
|
|
setAttachLayer(piping_layer)
|
|
|
|
/obj/item/pipe_meter/proc/setAttachLayer(new_layer = PIPING_LAYER_DEFAULT)
|
|
piping_layer = new_layer
|