'lolman? did you test your code?'

no i did not ms. kevinz
This commit is contained in:
lolman360
2020-07-22 10:49:56 +10:00
parent 4ac4d94c31
commit 0f1aa3c0ca
36 changed files with 2171 additions and 7 deletions
+1 -2
View File
@@ -266,7 +266,7 @@
name = "pipes"
/datum/asset/spritesheet/pipes/register()
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi'))
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi', 'icons/obj/plumbing/fluid_ducts.dmi'))
InsertAll("", each, GLOB.alldirs)
..()
@@ -378,4 +378,3 @@
assets = list(
"ghost.png" = 'html/ghost.png'
)
+371
View File
@@ -0,0 +1,371 @@
/*
All the important duct code:
/code/datums/components/plumbing/plumbing.dm
/code/datums/ductnet.dm
*/
/obj/machinery/duct
name = "fluid duct"
icon = 'icons/obj/plumbing/fluid_ducts.dmi'
icon_state = "nduct"
level = 1
///bitfield with the directions we're connected in
var/connects
///set to TRUE to disable smart cable behaviour
var/dumb = FALSE
///wheter we allow our connects to be changed after initialization or not
var/lock_connects = FALSE
///our ductnet, wich tracks what we're connected to
var/datum/ductnet/duct
///amount we can transfer per process. note that the ductnet can carry as much as the lowest capacity duct
var/capacity = 10
///the color of our duct
var/duct_color = null
///TRUE to ignore colors, so yeah we also connect with other colors without issue
var/ignore_colors = FALSE
///1,2,4,8,16
var/duct_layer = DUCT_LAYER_DEFAULT
///whether we allow our layers to be altered
var/lock_layers = FALSE
///TRUE to let colors connect when forced with a wrench, false to just not do that at all
var/color_to_color_support = TRUE
///wheter to even bother with plumbing code or not
var/active = TRUE
///track ducts we're connected to. Mainly for ducts we connect to that we normally wouldn't, like different layers and colors, for when we regenerate the ducts
var/list/neighbours = list()
///wheter we just unanchored or drop whatever is in the variable. either is safe
var/drop_on_wrench = /obj/item/stack/ducts
/obj/machinery/duct/Initialize(mapload, no_anchor, color_of_duct, layer_of_duct = DUCT_LAYER_DEFAULT, force_connects)
. = ..()
if(no_anchor)
active = FALSE
anchored = FALSE
else if(!can_anchor())
CRASH("Overlapping ducts detected")
qdel(src)
if(force_connects)
connects = force_connects //skip change_connects() because we're still initializing and we need to set our connects at one point
if(!lock_layers)
duct_layer = layer_of_duct
if(!ignore_colors)
duct_color = color_of_duct
if(duct_color)
add_atom_colour(duct_color, FIXED_COLOUR_PRIORITY)
handle_layer()
for(var/obj/machinery/duct/D in loc)
if(D == src)
continue
if(D.duct_layer & duct_layer)
disconnect_duct()
if(active)
attempt_connect()
///start looking around us for stuff to connect to
/obj/machinery/duct/proc/attempt_connect()
reset_connects() //All connects are gathered here again eitherway, we might aswell reset it so they properly update when reconnecting
for(var/atom/movable/AM in loc)
var/datum/component/plumbing/P = AM.GetComponent(/datum/component/plumbing)
if(P?.active)
disconnect_duct() //let's not built under plumbing machinery
return
for(var/D in GLOB.cardinals)
if(dumb && !(D & connects))
continue
for(var/atom/movable/AM in get_step(src, D))
if(connect_network(AM, D))
add_connects(D)
update_icon()
///see if whatever we found can be connected to
/obj/machinery/duct/proc/connect_network(atom/movable/AM, direction, ignore_color)
if(istype(AM, /obj/machinery/duct))
return connect_duct(AM, direction, ignore_color)
var/plumber = AM.GetComponent(/datum/component/plumbing)
if(!plumber)
return
return connect_plumber(plumber, direction)
///connect to a duct
/obj/machinery/duct/proc/connect_duct(obj/machinery/duct/D, direction, ignore_color)
var/opposite_dir = turn(direction, 180)
if(!active || !D.active)
return
if(!dumb && D.dumb && !(opposite_dir & D.connects))
return
if(dumb && D.dumb && !(connects & D.connects)) //we eliminated a few more scenario in attempt connect
return
if((duct == D.duct) && duct)//check if we're not just comparing two null values
add_neighbour(D)
D.add_connects(opposite_dir)
D.update_icon()
return TRUE //tell the current pipe to also update it's sprite
if(!(D in neighbours)) //we cool
if((duct_color != D.duct_color) && !(ignore_colors || D.ignore_colors))
return
if(!(duct_layer & D.duct_layer))
return
if(D.duct)
if(duct)
duct.assimilate(D.duct)
else
D.duct.add_duct(src)
else
if(duct)
duct.add_duct(D)
else
create_duct()
duct.add_duct(D)
add_neighbour(D)
D.attempt_connect()//tell our buddy its time to pass on the torch of connecting to pipes. This shouldn't ever infinitely loop since it only works on pipes that havent been inductrinated
return TRUE
///connect to a plumbing object
/obj/machinery/duct/proc/connect_plumber(datum/component/plumbing/P, direction)
var/opposite_dir = turn(direction, 180)
if(duct_layer != DUCT_LAYER_DEFAULT) //plumbing devices don't support multilayering. 3 is the default layer so we only use that. We can change this later
return FALSE
if(!P.active)
return
var/comp_directions = P.supply_connects + P.demand_connects //they should never, ever have supply and demand connects overlap or catastrophic failure
if(opposite_dir & comp_directions)
if(!duct)
create_duct()
duct.add_plumber(P, opposite_dir)
return TRUE
///we disconnect ourself from our neighbours. we also destroy our ductnet and tell our neighbours to make a new one
/obj/machinery/duct/proc/disconnect_duct()
anchored = FALSE
active = FALSE
if(duct)
duct.remove_duct(src)
lose_neighbours()
reset_connects(0)
update_icon()
if(ispath(drop_on_wrench) && !QDELING(src))
new drop_on_wrench(drop_location())
qdel(src)
///create a new duct datum
/obj/machinery/duct/proc/create_duct()
duct = new()
duct.add_duct(src)
///add a duct as neighbour. this means we're connected and will connect again if we ever regenerate
/obj/machinery/duct/proc/add_neighbour(obj/machinery/duct/D)
if(!(D in neighbours))
neighbours += D
if(!(src in D.neighbours))
D.neighbours += src
///remove all our neighbours, and remove us from our neighbours aswell
/obj/machinery/duct/proc/lose_neighbours()
for(var/A in neighbours)
var/obj/machinery/duct/D = A
D.neighbours.Remove(src)
neighbours = list()
///add a connect direction
/obj/machinery/duct/proc/add_connects(new_connects) //make this a define to cut proc calls?
if(!lock_connects)
connects |= new_connects
///remove our connects
/obj/machinery/duct/proc/reset_connects()
if(!lock_connects)
connects = 0
///get a list of the ducts we can connect to if we are dumb
/obj/machinery/duct/proc/get_adjacent_ducts()
var/list/adjacents = list()
for(var/A in GLOB.cardinals)
if(A & connects)
for(var/obj/machinery/duct/D in get_step(src, A))
if((turn(A, 180) & D.connects) && D.active)
adjacents += D
return adjacents
/obj/machinery/duct/update_icon() //setting connects isnt a parameter because sometimes we make more than one change, overwrite it completely or just add it to the bitfield
var/temp_icon = initial(icon_state)
for(var/D in GLOB.cardinals)
if(D & connects)
if(D == NORTH)
temp_icon += "_n"
if(D == SOUTH)
temp_icon += "_s"
if(D == EAST)
temp_icon += "_e"
if(D == WEST)
temp_icon += "_w"
icon_state = temp_icon
///update the layer we are on
/obj/machinery/duct/proc/handle_layer()
var/offset
switch(duct_layer)//it's a bitfield, but it's fine because it only works when there's one layer, and multiple layers should be handled differently
if(FIRST_DUCT_LAYER)
offset = -10
if(SECOND_DUCT_LAYER)
offset = -5
if(THIRD_DUCT_LAYER)
offset = 0
if(FOURTH_DUCT_LAYER)
offset = 5
if(FIFTH_DUCT_LAYER)
offset = 10
pixel_x = offset
pixel_y = offset
/obj/machinery/duct/wrench_act(mob/living/user, obj/item/I) //I can also be the RPD
..()
add_fingerprint(user)
I.play_tool_sound(src)
if(anchored)
user.visible_message( \
"[user] unfastens \the [src].", \
"<span class='notice'>You unfasten \the [src].</span>", \
"<span class='hear'>You hear ratcheting.</span>")
disconnect_duct()
else if(can_anchor())
anchored = TRUE
active = TRUE
user.visible_message( \
"[user] fastens \the [src].", \
"<span class='notice'>You fasten \the [src].</span>", \
"<span class='hear'>You hear ratcheting.</span>")
attempt_connect()
return TRUE
///collection of all the sanity checks to prevent us from stacking ducts that shouldnt be stacked
/obj/machinery/duct/proc/can_anchor(turf/T)
if(!T)
T = get_turf(src)
for(var/obj/machinery/duct/D in T)
if(!anchored)
continue
for(var/A in GLOB.cardinals)
if(A & connects && A & D.connects)
return FALSE
return TRUE
/obj/machinery/duct/doMove(destination)
. = ..()
disconnect_duct()
anchored = FALSE
/obj/machinery/duct/Destroy()
disconnect_duct()
return ..()
/obj/machinery/duct/MouseDrop_T(atom/A, mob/living/user)
if(!istype(A, /obj/machinery/duct))
return
var/obj/machinery/duct/D = A
var/obj/item/I = user.get_active_held_item()
if(I?.tool_behaviour != TOOL_WRENCH)
to_chat(user, "<span class='warning'>You need to be holding a wrench in your active hand to do that!</span>")
return
if(get_dist(src, D) != 1)
return
var/direction = get_dir(src, D)
if(!(direction in GLOB.cardinals))
return
if(duct_layer != D.duct_layer)
return
add_connects(direction) //the connect of the other duct is handled in connect_network, but do this here for the parent duct because it's not necessary in normal cases
add_neighbour(D)
connect_network(D, direction, TRUE)
update_icon()
///has a total of 5 layers and doesnt give a shit about color. its also dumb so doesnt autoconnect.
/obj/machinery/duct/multilayered
name = "duct layer-manifold"
icon = 'icons/obj/2x2.dmi'
icon_state = "multiduct"
pixel_x = -15
pixel_y = -15
color_to_color_support = FALSE
duct_layer = FIRST_DUCT_LAYER | SECOND_DUCT_LAYER | THIRD_DUCT_LAYER | FOURTH_DUCT_LAYER | FIFTH_DUCT_LAYER
drop_on_wrench = null
lock_connects = TRUE
lock_layers = TRUE
ignore_colors = TRUE
dumb = TRUE
active = FALSE
anchored = FALSE
/obj/machinery/duct/multilayered/Initialize(mapload, no_anchor, color_of_duct, layer_of_duct = DUCT_LAYER_DEFAULT, force_connects)
. = ..()
update_connects()
/obj/machinery/duct/multilayered/update_icon()
return
/obj/machinery/duct/multilayered/wrench_act(mob/living/user, obj/item/I)
. = ..()
update_connects()
/obj/machinery/duct/multilayered/proc/update_connects()
if(dir & NORTH || dir & SOUTH)
connects = NORTH | SOUTH
else
connects = EAST | WEST
///don't connect to other multilayered stuff because honestly it shouldnt be done and I dont wanna deal with it
/obj/machinery/duct/multilayered/connect_duct(obj/machinery/duct/D, direction, ignore_color)
if(istype(D, /obj/machinery/duct/multilayered))
return
return ..()
/obj/machinery/duct/multilayered/handle_layer()
return
/obj/item/stack/ducts
name = "stack of duct"
desc = "A stack of fluid ducts."
singular_name = "duct"
icon = 'icons/obj/plumbing/fluid_ducts.dmi'
icon_state = "ducts"
w_class = WEIGHT_CLASS_TINY
novariants = FALSE
max_amount = 50
item_flags = NOBLUDGEON
merge_type = /obj/item/stack/ducts
///Color of our duct
var/duct_color = "grey"
///Default layer of our duct
var/duct_layer = "Default Layer"
///Assoc index with all the available layers. yes five might be a bit much. Colors uses a global by the way
var/list/layers = list("First Layer" = FIRST_DUCT_LAYER, "Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT,
"Fourth Layer" = FOURTH_DUCT_LAYER, "Fifth Layer" = FIFTH_DUCT_LAYER)
/obj/item/stack/ducts/examine(mob/user)
. = ..()
. += "<span class='notice'>It's current color and layer are [duct_color] and [duct_layer]. Use in-hand to change.</span>"
/obj/item/stack/ducts/attack_self(mob/user)
var/new_layer = input("Select a layer", "Layer") as null|anything in layers
if(new_layer)
duct_layer = new_layer
var/new_color = input("Select a color", "Color") as null|anything in GLOB.pipe_paint_colors
if(new_color)
duct_color = new_color
add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY)
/obj/item/stack/ducts/afterattack(atom/A, user, proximity)
. = ..()
if(!proximity)
return
if(istype(A, /obj/machinery/duct))
var/obj/machinery/duct/D = A
if(!D.anchored)
add(1)
qdel(D)
if(istype(A, /turf/open) && use(1))
var/turf/open/OT = A
new /obj/machinery/duct(OT, FALSE, GLOB.pipe_paint_colors[duct_color], layers[duct_layer])
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE)
/obj/item/stack/ducts/fifty
amount = 50
@@ -0,0 +1,97 @@
/**Basic plumbing object.
* It doesn't really hold anything special, YET.
* Objects that are plumbing but not a subtype are as of writing liquid pumps and the reagent_dispenser tank
* Also please note that the plumbing component is toggled on and off by the component using a signal from default_unfasten_wrench, so dont worry about it
*/
/obj/machinery/plumbing
name = "pipe thing"
icon = 'icons/obj/plumbing/plumbers.dmi'
icon_state = "pump"
density = TRUE
active_power_usage = 30
use_power = ACTIVE_POWER_USE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
///Plumbing machinery is always gonna need reagents, so we might aswell put it here
var/buffer = 50
///Flags for reagents, like INJECTABLE, TRANSPARENT bla bla everything thats in DEFINES/reagents.dm
var/reagent_flags = TRANSPARENT
///wheter we partake in rcd construction or not
var/rcd_constructable = TRUE
///cost of the plumbing rcd construction
var/rcd_cost = 15
///delay of constructing it throught the plumbing rcd
var/rcd_delay = 10
/obj/machinery/plumbing/Initialize(mapload, bolt = TRUE)
. = ..()
anchored = bolt
create_reagents(buffer, reagent_flags)
AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS )
/obj/machinery/plumbing/proc/can_be_rotated(mob/user,rotation_type)
return TRUE
/obj/machinery/plumbing/examine(mob/user)
. = ..()
. += "<span class='notice'>The maximum volume display reads: <b>[reagents.maximum_volume] units</b>.</span>"
/obj/machinery/plumbing/wrench_act(mob/living/user, obj/item/I)
..()
default_unfasten_wrench(user, I)
return TRUE
/obj/machinery/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced)
to_chat(user, "<span class='notice'>You start furiously plunging [name].")
if(do_after(user, 30, target = src))
to_chat(user, "<span class='notice'>You finish plunging the [name].")
reagents.reaction(get_turf(src), TOUCH) //splash on the floor
reagents.clear_reagents()
/obj/machinery/plumbing/welder_act(mob/living/user, obj/item/I)
. = ..()
if(anchored)
to_chat(user, "<span class='warning'>The [name] needs to be unbolted to do that!</span")
if(I.tool_start_check(user, amount=0))
to_chat(user, "<span class='notice'>You start slicing the [name] apart.</span")
if(I.use_tool(src, user, rcd_delay * 2, volume=50))
deconstruct(TRUE)
to_chat(user, "<span class='notice'>You slice the [name] apart.</span")
return TRUE
///We can empty beakers in here and everything
/obj/machinery/plumbing/input
name = "input gate"
desc = "Can be manually filled with reagents from containers."
icon_state = "pipe_input"
reagent_flags = TRANSPARENT | REFILLABLE
rcd_cost = 5
rcd_delay = 5
/obj/machinery/plumbing/input/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt)
///We can fill beakers in here and everything. we dont inheret from input because it has nothing that we need
/obj/machinery/plumbing/output
name = "output gate"
desc = "A manual output for plumbing systems, for taking reagents directly into containers."
icon_state = "pipe_output"
reagent_flags = TRANSPARENT | DRAINABLE
rcd_cost = 5
rcd_delay = 5
/obj/machinery/plumbing/output/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_demand, bolt)
/obj/machinery/plumbing/tank
name = "chemical tank"
desc = "A massive chemical holding tank."
icon_state = "tank"
buffer = 400
rcd_cost = 25
rcd_delay = 20
/obj/machinery/plumbing/tank/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/tank, bolt)
@@ -0,0 +1,105 @@
//we cant use defines in tgui, so use a string instead of magic numbers
#define COOLING "Cooling"
#define HEATING "Heating"
#define NEUTRAL "Neutral"
///this the plumbing version of a heater/freezer.
/obj/machinery/plumbing/acclimator
name = "chemical acclimator"
desc = "An efficient cooler and heater for the perfect showering temperature or illicit chemical factory."
icon_state = "acclimator"
buffer = 200
///towards wich temperature do we build?
var/target_temperature = 300
///I cant find a good name for this. Basically if target is 300, and this is 10, it will still target 300 but will start emptying itself at 290 and 310.
var/allowed_temperature_difference = 1
///cool/heat power
var/heater_coefficient = 0.1
///Are we turned on or off? this is from the on and off button
var/enabled = TRUE
///COOLING, HEATING or NEUTRAL. We track this for change, so we dont needlessly update our icon
var/acclimate_state
/**We can't take anything in, at least till we're emptied. Down side of the round robin chem transfer, otherwise while emptying 5u of an unreacted chem gets added,
and you get nasty leftovers
*/
var/emptying = FALSE
var/ui_x = 320
var/ui_y = 310
/obj/machinery/plumbing/acclimator/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/acclimator, bolt)
/obj/machinery/plumbing/acclimator/process()
if(stat & NOPOWER || !enabled || !reagents.total_volume || reagents.chem_temp == target_temperature)
if(acclimate_state != NEUTRAL)
acclimate_state = NEUTRAL
update_icon()
if(!reagents.total_volume)
emptying = FALSE
return
if(reagents.chem_temp < target_temperature && acclimate_state != HEATING) //note that we check if the temperature is the same at the start
acclimate_state = HEATING
update_icon()
else if(reagents.chem_temp > target_temperature && acclimate_state != COOLING)
acclimate_state = COOLING
update_icon()
if(!emptying)
if(reagents.chem_temp >= target_temperature && target_temperature + allowed_temperature_difference >= reagents.chem_temp) //cooling here
emptying = TRUE
if(reagents.chem_temp <= target_temperature && target_temperature - allowed_temperature_difference <= reagents.chem_temp) //heating here
emptying = TRUE
reagents.adjust_thermal_energy((target_temperature - reagents.chem_temp) * heater_coefficient * SPECIFIC_HEAT_DEFAULT * reagents.total_volume) //keep constant with chem heater
reagents.handle_reactions()
/obj/machinery/plumbing/acclimator/update_icon()
icon_state = initial(icon_state)
switch(acclimate_state)
if(COOLING)
icon_state += "_cold"
if(HEATING)
icon_state += "_hot"
/obj/machinery/plumbing/acclimator/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemAcclimator", name)
ui.open()
/obj/machinery/plumbing/acclimator/ui_data(mob/user)
var/list/data = list()
data["enabled"] = enabled
data["chem_temp"] = reagents.chem_temp
data["target_temperature"] = target_temperature
data["allowed_temperature_difference"] = allowed_temperature_difference
data["acclimate_state"] = acclimate_state
data["max_volume"] = reagents.maximum_volume
data["reagent_volume"] = reagents.total_volume
data["emptying"] = emptying
return data
/obj/machinery/plumbing/acclimator/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("set_target_temperature")
var/target = text2num(params["temperature"])
target_temperature = clamp(target, 0, 1000)
if("set_allowed_temperature_difference")
var/target = text2num(params["temperature"])
allowed_temperature_difference = clamp(target, 0, 1000)
if("toggle_power")
enabled = !enabled
if("change_volume")
var/target = text2num(params["volume"])
reagents.maximum_volume = clamp(round(target), 1, buffer)
#undef COOLING
#undef HEATING
#undef NEUTRAL
+79
View File
@@ -0,0 +1,79 @@
/obj/machinery/plumbing/bottler
name = "chemical bottler"
desc = "Puts reagents into containers, like bottles and beakers."
icon_state = "bottler"
layer = ABOVE_ALL_MOB_LAYER
reagent_flags = TRANSPARENT | DRAINABLE
rcd_cost = 50
rcd_delay = 50
buffer = 100
///how much do we fill
var/wanted_amount = 10
///where things are sent
var/turf/goodspot = null
///where things are taken
var/turf/inputspot = null
///where beakers that are already full will be sent
var/turf/badspot = null
/obj/machinery/plumbing/bottler/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_demand, bolt)
setDir(dir)
/obj/machinery/plumbing/bottler/can_be_rotated(mob/user, rotation_type)
if(anchored)
to_chat(user, "<span class='warning'>It is fastened to the floor!</span>")
return FALSE
return TRUE
///changes the tile array
/obj/machinery/plumbing/bottler/setDir(newdir)
. = ..()
switch(dir)
if(NORTH)
goodspot = get_step(get_turf(src), NORTH)
inputspot = get_step(get_turf(src), SOUTH)
badspot = get_step(get_turf(src), EAST)
if(SOUTH)
goodspot = get_step(get_turf(src), SOUTH)
inputspot = get_step(get_turf(src), NORTH)
badspot = get_step(get_turf(src), WEST)
if(WEST)
goodspot = get_step(get_turf(src), WEST)
inputspot = get_step(get_turf(src), EAST)
badspot = get_step(get_turf(src), NORTH)
if(EAST)
goodspot = get_step(get_turf(src), EAST)
inputspot = get_step(get_turf(src), WEST)
badspot = get_step(get_turf(src), SOUTH)
///changing input ammount with a window
/obj/machinery/plumbing/bottler/interact(mob/user)
. = ..()
wanted_amount = clamp(round(input(user,"maximum is 100u","set ammount to fill with") as num|null, 1), 1, 100)
reagents.clear_reagents()
to_chat(user, "<span class='notice'> The [src] will now fill for [wanted_amount]u.</span>")
/obj/machinery/plumbing/bottler/process()
if(machine_stat & NOPOWER)
return
///see if machine has enough to fill
if(reagents.total_volume >= wanted_amount && anchored)
var/obj/AM = pick(inputspot.contents)///pick a reagent_container that could be used
if(istype(AM, /obj/item/reagent_containers) && (!istype(AM, /obj/item/reagent_containers/hypospray/medipen)))
var/obj/item/reagent_containers/B = AM
///see if it would overflow else inject
if((B.reagents.total_volume + wanted_amount) <= B.reagents.maximum_volume)
reagents.trans_to(B, wanted_amount, transfered_by = src)
B.forceMove(goodspot)
return
///glass was full so we move it away
AM.forceMove(badspot)
if(istype(AM, /obj/item/slime_extract)) ///slime extracts need inject
AM.forceMove(goodspot)
reagents.trans_to(AM, wanted_amount, transfered_by = src, method = INJECT)
return
if(istype(AM, /obj/item/slimecross/industrial)) ///no need to move slimecross industrial things
reagents.trans_to(AM, wanted_amount, transfered_by = src, method = INJECT)
return
@@ -0,0 +1,21 @@
/obj/machinery/plumbing/disposer
name = "chemical disposer"
desc = "Breaks down chemicals and annihilates them."
icon_state = "disposal"
///we remove 10 reagents per second
var/disposal_rate = 10
/obj/machinery/plumbing/disposer/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_demand, bolt)
/obj/machinery/plumbing/disposer/process()
if(stat & NOPOWER)
return
if(reagents.total_volume)
if(icon_state != initial(icon_state) + "_working") //threw it here instead of update icon since it only has two states
icon_state = initial(icon_state) + "_working"
reagents.remove_any(disposal_rate)
else
if(icon_state != initial(icon_state))
icon_state = initial(icon_state)
@@ -0,0 +1,52 @@
/obj/machinery/plumbing/fermenter //FULLY AUTOMATIC BEER BREWING. TRULY, THE FUTURE.
name = "chemical fermenter"
desc = "Turns plants into various types of booze."
icon_state = "fermenter"
layer = ABOVE_ALL_MOB_LAYER
reagent_flags = TRANSPARENT | DRAINABLE
rcd_cost = 30
rcd_delay = 30
buffer = 400
///input dir
var/eat_dir = SOUTH
/obj/machinery/plumbing/fermenter/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt)
/obj/machinery/plumbing/grinder_chemical/can_be_rotated(mob/user, rotation_type)
if(anchored)
to_chat(user, "<span class='warning'>It is fastened to the floor!</span>")
return FALSE
return TRUE
/obj/machinery/plumbing/fermenter/setDir(newdir)
. = ..()
eat_dir = newdir
/obj/machinery/plumbing/fermenter/CanAllowThrough(atom/movable/AM)
. = ..()
if(!anchored)
return
var/move_dir = get_dir(loc, AM.loc)
if(move_dir == eat_dir)
return TRUE
/obj/machinery/plumbing/fermenter/Crossed(atom/movable/AM)
. = ..()
ferment(AM)
/// uses fermentation proc similar to fermentation barrels
/obj/machinery/plumbing/fermenter/proc/ferment(atom/AM)
if(machine_stat & NOPOWER)
return
if(reagents.holder_full())
return
if(!isitem(AM))
return
if(istype(AM, /obj/item/reagent_containers/food/snacks/grown))
var/obj/item/reagent_containers/food/snacks/grown/G = AM
if(G.distill_reagent)
var/amount = G.seed.potency * 0.25
reagents.add_reagent(G.distill_reagent, amount)
qdel(G)
+74
View File
@@ -0,0 +1,74 @@
///chemical plumbing filter. If it's not filtered by left and right, it goes straight.
/obj/machinery/plumbing/filter
name = "chemical filter"
desc = "A chemical filter for filtering chemicals. The left and right outputs appear to be from the perspective of the input port."
icon_state = "filter"
density = FALSE
///whitelist of chems id's that go to the left side. Empty to disable port
var/list/left = list()
///whitelist of chem id's that go to the right side. Empty to disable port
var/list/right = list()
///whitelist of chems but their name instead of path
var/list/english_left = list()
///whitelist of chems but their name instead of path
var/list/english_right = list()
var/ui_x = 320
var/ui_y = 310
/obj/machinery/plumbing/filter/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/filter, bolt)
/obj/machinery/plumbing/filter/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "chemical_filter", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/plumbing/filter/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemFilter", name)
ui.open()
/obj/machinery/plumbing/filter/ui_data(mob/user)
var/list/data = list()
data["left"] = english_left
data["right"] = english_right
return data
/obj/machinery/plumbing/filter/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("add")
var/new_chem_name = params["name"]
var/chem_id = get_chem_id(new_chem_name)
if(chem_id)
switch(params["which"])
if("left")
if(!left.Find(chem_id))
english_left += new_chem_name
left += chem_id
if("right")
if(!right.Find(chem_id))
english_right += new_chem_name
right += chem_id
else
to_chat(usr, "<span class='warning'>No such known reagent exists!</span>")
if("remove")
var/chem_name = params["reagent"]
var/chem_id = get_chem_id(chem_name)
switch(params["which"])
if("left")
if(english_left.Find(chem_name))
english_left -= chem_name
left -= chem_id
if("right")
if(english_right.Find(chem_name))
english_right -= chem_name
right -= chem_id
@@ -0,0 +1,58 @@
/obj/machinery/plumbing/grinder_chemical
name = "chemical grinder"
desc = "chemical grinder."
icon_state = "grinder_chemical"
layer = ABOVE_ALL_MOB_LAYER
reagent_flags = TRANSPARENT | DRAINABLE
rcd_cost = 30
rcd_delay = 30
buffer = 400
var/eat_dir = SOUTH
/obj/machinery/plumbing/grinder_chemical/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt)
/obj/machinery/plumbing/grinder_chemical/can_be_rotated(mob/user, rotation_type)
if(anchored)
to_chat(user, "<span class='warning'>It is fastened to the floor!</span>")
return FALSE
return TRUE
/obj/machinery/plumbing/grinder_chemical/setDir(newdir)
. = ..()
eat_dir = newdir
/obj/machinery/plumbing/grinder_chemical/CanAllowThrough(atom/movable/AM)
. = ..()
if(!anchored)
return
var/move_dir = get_dir(loc, AM.loc)
if(move_dir == eat_dir)
return TRUE
/obj/machinery/plumbing/grinder_chemical/Crossed(atom/movable/AM)
. = ..()
grind(AM)
/obj/machinery/plumbing/grinder_chemical/proc/grind(atom/AM)
if(machine_stat & NOPOWER)
return
if(reagents.holder_full())
return
if(!isitem(AM))
return
var/obj/item/I = AM
if(I.juice_results || I.grind_results)
if(I.juice_results)
I.on_juice()
reagents.add_reagent_list(I.juice_results)
if(I.reagents)
I.reagents.trans_to(src, I.reagents.total_volume, transfered_by = src)
qdel(I)
return
I.on_grind()
reagents.add_reagent_list(I.grind_results)
if(I.reagents)
I.reagents.trans_to(src, I.reagents.total_volume, transfered_by = src)
qdel(I)
@@ -0,0 +1,107 @@
///We take a constant input of reagents, and produce a pill once a set volume is reached
/obj/machinery/plumbing/pill_press
name = "pill press"
desc = "A press that presses pills."
icon_state = "pill_press"
///the minimum size a pill can be
var/minimum_pill = 5
///the maximum size a pill can be
var/maximum_pill = 50
///the size of the pill
var/pill_size = 10
///pill name
var/pill_name = "factory pill"
///the icon_state number for the pill.
var/pill_number = RANDOM_PILL_STYLE
///list of id's and icons for the pill selection of the ui
var/list/pill_styles
///list of pills stored in the machine, so we dont have 610 pills on one tile
var/list/stored_pills = list()
///max amount of pills allowed on our tile before we start storing them instead
var/max_floor_pills = 10
/obj/machinery/plumbing/pill_press/examine(mob/user)
. = ..()
. += "<span class='notice'>The [name] currently has [stored_pills.len] stored. There needs to be less than [max_floor_pills] on the floor to continue dispensing.</span>"
/obj/machinery/plumbing/pill_press/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_demand, bolt)
//expertly copypasted from chemmasters
var/datum/asset/spritesheet/simple/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills)
pill_styles = list()
for (var/x in 1 to PILL_STYLE_COUNT)
var/list/SL = list()
SL["id"] = x
SL["htmltag"] = assets.icon_tag("pill[x]")
pill_styles += list(SL)
/obj/machinery/plumbing/pill_press/process()
if(stat & NOPOWER)
return
if(reagents.total_volume >= pill_size)
var/obj/item/reagent_containers/pill/P = new(src)
reagents.trans_to(P, pill_size)
P.name = pill_name
stored_pills += P
if(pill_number == RANDOM_PILL_STYLE)
P.icon_state = "pill[rand(1,21)]"
else
P.icon_state = "pill[pill_number]"
if(P.icon_state == "pill4") //mirrored from chem masters
P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
if(stored_pills.len)
var/pill_amount = 0
for(var/obj/item/reagent_containers/pill/P in loc)
pill_amount++
if(pill_amount >= max_floor_pills) //too much so just stop
break
if(pill_amount < max_floor_pills)
var/atom/movable/AM = stored_pills[1] //AM because forceMove is all we need
stored_pills -= AM
AM.forceMove(drop_location())
/obj/machinery/plumbing/pill_press/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/simple/pills),
)
/obj/machinery/plumbing/pill_press/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemPress", name)
ui.open()
/obj/machinery/plumbing/pill_press/ui_data(mob/user)
var/list/data = list()
data["pill_style"] = pill_number
data["current_volume"] = current_volume
data["product_name"] = product_name
data["pill_styles"] = pill_styles
data["product"] = product
data["min_volume"] = min_volume
data["max_volume"] = max_volume
return data
/obj/machinery/plumbing/pill_press/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("change_pill_style")
pill_number = clamp(text2num(params["id"]), 1 , PILL_STYLE_COUNT)
if("change_current_volume")
current_volume = clamp(text2num(params["volume"]), min_volume, max_volume)
if("change_product_name")
product_name = html_encode(params["name"])
if("change_product")
product = params["product"]
if (product == "pill")
max_volume = max_pill_volume
else if (product == "patch")
max_volume = max_patch_volume
else if (product == "bottle")
max_volume = max_bottle_volume
current_volume = clamp(current_volume, min_volume, max_volume)
+83
View File
@@ -0,0 +1,83 @@
///We pump liquids from activated(plungerated) geysers to a plumbing outlet. We need to be wired.
/obj/machinery/power/liquid_pump
name = "liquid pump"
desc = "Pump up those sweet liquids from under the surface."
icon = 'icons/obj/plumbing/plumbers.dmi'
icon_state = "pump"
anchored = FALSE
density = TRUE
idle_power_usage = 10
active_power_usage = 1000
///Are we powered?
var/powered = FALSE
///units we pump per process (2 seconds)
var/pump_power = 2
///set to true if the loop couldnt find a geyser in process, so it remembers and stops checking every loop until moved. more accurate name would be absolutely_no_geyser_under_me_so_dont_try
var/geyserless = FALSE
///The geyser object
var/obj/structure/geyser/geyser
///volume of our internal buffer
var/volume = 200
/obj/machinery/power/liquid_pump/Initialize()
. = ..()
create_reagents(volume)
AddComponent(/datum/component/plumbing/simple_supply, TRUE)
/obj/machinery/power/liquid_pump/attackby(obj/item/W, mob/user, params)
if(!powered)
if(!anchored)
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]_open", "[initial(icon_state)]",W))
return
if(default_deconstruction_crowbar(W))
return
return ..()
/obj/machinery/power/liquid_pump/wrench_act(mob/living/user, obj/item/I)
..()
default_unfasten_wrench(user, I)
return TRUE
///please note that the component has a hook in the parent call, wich handles activating and deactivating
/obj/machinery/power/liquid_pump/default_unfasten_wrench(mob/user, obj/item/I, time = 20)
. = ..()
if(. == SUCCESSFUL_UNFASTEN)
geyser = null
update_icon()
powered = FALSE
geyserless = FALSE //we switched state, so lets just set this back aswell
/obj/machinery/power/liquid_pump/process()
if(!anchored || panel_open)
return
if(!geyser && !geyserless)
for(var/obj/structure/geyser/G in loc.contents)
geyser = G
if(!geyser) //we didnt find one, abort
anchored = FALSE
geyserless = TRUE
visible_message("<span class='warning'>The [name] makes a sad beep!</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50)
return
if(avail(active_power_usage))
if(!powered) //we werent powered before this tick so update our sprite
powered = TRUE
update_icon()
add_load(active_power_usage)
pump()
else if(powered) //we were powered, but now we arent
powered = FALSE
update_icon()
///pump up that sweet geyser nectar
/obj/machinery/power/liquid_pump/proc/pump()
if(!geyser || !geyser.reagents)
return
geyser.reagents.trans_to(src, pump_power)
/obj/machinery/power/liquid_pump/update_icon()
if(powered)
icon_state = initial(icon_state) + "-on"
else if(panel_open)
icon_state = initial(icon_state) + "-open"
else
icon_state = initial(icon_state)
@@ -0,0 +1,63 @@
///a reaction chamber for plumbing. pretty much everything can react, but this one keeps the reagents seperated and only reacts under your given terms
/obj/machinery/plumbing/reaction_chamber
name = "reaction chamber"
desc = "Keeps chemicals seperated until given conditions are met."
icon_state = "reaction_chamber"
buffer = 200
reagent_flags = TRANSPARENT | NO_REACT
/**list of set reagents that the reaction_chamber allows in, and must all be present before mixing is enabled.
* example: list(/datum/reagent/water = 20, /datum/reagent/fuel/oil = 50)
*/
var/list/required_reagents = list()
///our reagent goal has been reached, so now we lock our inputs and start emptying
var/emptying = FALSE
/obj/machinery/plumbing/reaction_chamber/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/reaction_chamber, bolt)
/obj/machinery/plumbing/reaction_chamber/on_reagent_change()
if(reagents.total_volume == 0 && emptying) //we were emptying, but now we aren't
emptying = FALSE
reagent_flags |= NO_REACT
/obj/machinery/plumbing/reaction_chamber/power_change()
. = ..()
if(use_power != NO_POWER_USE)
icon_state = initial(icon_state) + "_on"
else
icon_state = initial(icon_state)
/obj/machinery/plumbing/reaction_chamber/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemReactionChamber", name)
ui.open()
/obj/machinery/plumbing/reaction_chamber/ui_data(mob/user)
var/list/data = list()
var/list/text_reagents = list()
for(var/A in required_reagents) //make a list where the key is text, because that looks alot better in the ui than a typepath
var/datum/reagent/R = A
text_reagents[initial(R.name)] = required_reagents[R]
data["reagents"] = text_reagents
data["emptying"] = emptying
return data
/obj/machinery/plumbing/reaction_chamber/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("remove")
var/reagent = get_chem_id(params["chem"])
if(reagent)
required_reagents.Remove(reagent)
if("add")
var/input_reagent = get_chem_id(params["chem"])
if(input_reagent && !required_reagents.Find(input_reagent))
var/input_amount = text2num(params["amount"])
if(input_amount)
required_reagents[input_reagent] = input_amount
@@ -0,0 +1,50 @@
///it splits the reagents however you want. So you can "every 60 units, 45 goes left and 15 goes straight". The side direction is EAST, you can change this in the component
/obj/machinery/plumbing/splitter
name = "Chemical Splitter"
desc = "A chemical splitter for smart chemical factorization. Waits till a set of conditions is met and then stops all input and splits the buffer evenly or other in two ducts."
icon_state = "splitter"
buffer = 100
density = FALSE
///constantly switches between TRUE and FALSE. TRUE means the batch tick goes straight, FALSE means the next batch goes in the side duct.
var/turn_straight = TRUE
///how much we must transfer straight. note input can be as high as 10 reagents per process, usually
var/transfer_straight = 5
///how much we must transfer to the side
var/transfer_side = 5
//the maximum you can set the transfer to
var/max_transfer = 9
/obj/machinery/plumbing/splitter/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/splitter, bolt)
/obj/machinery/plumbing/splitter/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemSplitter", name)
ui.open()
/obj/machinery/plumbing/splitter/ui_data(mob/user)
var/list/data = list()
data["straight"] = transfer_straight
data["side"] = transfer_side
data["max_transfer"] = max_transfer
return data
/obj/machinery/plumbing/splitter/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("set_amount")
var/direction = params["target"]
var/value = clamp(text2num(params["amount"]), 1, max_transfer)
switch(direction)
if("straight")
transfer_straight = value
if("side")
transfer_side = value
else
return FALSE
@@ -0,0 +1,111 @@
///A single machine that produces a single chem. Can be placed in unison with others through plumbing to create chemical factories
/obj/machinery/plumbing/synthesizer
name = "chemical synthesizer"
desc = "Produces a single chemical at a given volume. Must be plumbed. Most effective when working in unison with other chemical synthesizers, heaters and filters."
icon_state = "synthesizer"
icon = 'icons/obj/plumbing/plumbers.dmi'
rcd_cost = 25
rcd_delay = 15
///Amount we produce for every process. Ideally keep under 5 since thats currently the standard duct capacity
var/amount = 1
///The maximum we can produce for every process
buffer = 5
///I track them here because I have no idea how I'd make tgui loop like that
var/static/list/possible_amounts = list(0,1,2,3,4,5)
///The reagent we are producing. We are a typepath, but are also typecast because there's several occations where we need to use initial.
var/datum/reagent/reagent_id = null
///straight up copied from chem dispenser. Being a subtype would be extremely tedious and making it global would restrict potential subtypes using different dispensable_reagents
var/list/dispensable_reagents = list(
/datum/reagent/aluminium,
/datum/reagent/bromine,
/datum/reagent/carbon,
/datum/reagent/chlorine,
/datum/reagent/copper,
/datum/reagent/consumable/ethanol,
/datum/reagent/fluorine,
/datum/reagent/hydrogen,
/datum/reagent/iodine,
/datum/reagent/iron,
/datum/reagent/lithium,
/datum/reagent/mercury,
/datum/reagent/nitrogen,
/datum/reagent/oxygen,
/datum/reagent/phosphorus,
/datum/reagent/potassium,
/datum/reagent/uranium/radium,
/datum/reagent/silicon,
/datum/reagent/silver,
/datum/reagent/sodium,
/datum/reagent/stable_plasma,
/datum/reagent/consumable/sugar,
/datum/reagent/sulfur,
/datum/reagent/toxin/acid,
/datum/reagent/water,
/datum/reagent/fuel,
)
/obj/machinery/plumbing/synthesizer/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt)
/obj/machinery/plumbing/synthesizer/process()
if(machine_stat & NOPOWER || !reagent_id || !amount)
return
if(reagents.total_volume >= amount) //otherwise we get leftovers, and we need this to be precise
return
reagents.add_reagent(reagent_id, amount)
/obj/machinery/plumbing/synthesizer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemSynthesizer", name)
ui.open()
/obj/machinery/plumbing/synthesizer/ui_data(mob/user)
var/list/data = list()
var/is_hallucinating = user.hallucinating()
var/list/chemicals = list()
for(var/A in dispensable_reagents)
var/datum/reagent/R = GLOB.chemical_reagents_list[A]
if(R)
var/chemname = R.name
if(is_hallucinating && prob(5))
chemname = "[pick_list_replacements("hallucination.json", "chemicals")]"
chemicals.Add(list(list("title" = chemname, "id" = ckey(R.name))))
data["chemicals"] = chemicals
data["amount"] = amount
data["possible_amounts"] = possible_amounts
data["current_reagent"] = ckey(initial(reagent_id.name))
return data
/obj/machinery/plumbing/synthesizer/ui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("amount")
var/new_amount = text2num(params["target"])
if(new_amount in possible_amounts)
amount = new_amount
. = TRUE
if("select")
var/new_reagent = GLOB.name2reagent[params["reagent"]]
if(new_reagent in dispensable_reagents)
reagent_id = new_reagent
. = TRUE
update_icon()
reagents.clear_reagents()
/obj/machinery/plumbing/synthesizer/update_overlays()
. = ..()
var/mutable_appearance/r_overlay = mutable_appearance(icon, "[icon_state]_overlay")
if(reagent_id)
r_overlay.color = initial(reagent_id.color)
else
r_overlay.color = "#FFFFFF"
. += r_overlay
@@ -1165,3 +1165,9 @@
random_reagents += R
var/picked_reagent = pick(random_reagents)
return picked_reagent
/proc/get_chem_id(chem_name)
for(var/X in GLOB.chemical_reagents_list)
var/datum/reagent/R = GLOB.chemical_reagents_list[X]
if(ckey(chem_name) == ckey(lowertext(R.name)))
return X
+1 -1
View File
@@ -8,6 +8,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
if (length(initial(R.name)))
.[ckey(initial(R.name))] = t
//Various reagents
//Toxin & acid reagents
//Hydroponics stuff
@@ -220,4 +221,3 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
bloodsuckerdatum.handle_eat_human_food(disgust, blood_puke, force)
if(blood_change)
bloodsuckerdatum.AddBloodVolume(blood_change)
+34 -3
View File
@@ -24,7 +24,8 @@
/obj/structure/reagent_dispensers/Initialize()
create_reagents(tank_volume, DRAINABLE | AMOUNT_VISIBLE)
reagents.add_reagent(reagent_id, tank_volume)
if(reagent_id)
reagents.add_reagent(reagent_id, tank_volume)
. = ..()
/obj/structure/reagent_dispensers/proc/boom()
@@ -91,6 +92,38 @@
user.put_in_hands(S)
paper_cups--
/obj/structure/reagent_dispensers/plumbed
name = "stationairy water tank"
anchored = TRUE
icon_state = "water_stationairy"
desc = "A stationairy, plumbed, water tank."
/obj/structure/reagent_dispensers/plumbed/wrench_act(mob/living/user, obj/item/I)
default_unfasten_wrench(user, I)
return TRUE
/obj/structure/reagent_dispensers/plumbed/default_unfasten_wrench(mob/user, obj/item/I, time = 20)
. = ..()
if(. == SUCCESSFUL_UNFASTEN)
user.visible_message("<span class='notice'>[user.name] [anchored ? "fasten" : "unfasten"] [src]</span>", \
"<span class='notice'>You [anchored ? "fasten" : "unfasten"] [src]</span>")
var/datum/component/plumbing/CP = GetComponent(/datum/component/plumbing)
if(anchored)
CP.enable()
else
CP.disable()
/obj/structure/reagent_dispensers/plumbed/ComponentInitialize()
AddComponent(/datum/component/plumbing/simple_supply)
/obj/structure/reagent_dispensers/plumbed/storage
name = "stationairy storage tank"
icon_state = "tank_stationairy"
reagent_id = null //start empty
/obj/structure/reagent_dispensers/plumbed/storage/ComponentInitialize()
AddComponent(/datum/component/plumbing/tank)
//////////////
//Fuel Tanks//
//////////////
@@ -284,5 +317,3 @@
icon_state = "bluekeg"
reagent_id = /datum/reagent/consumable/ethanol/neurotoxin
tank_volume = 100 //2.5x less than the other kegs because it's harder to get
@@ -961,3 +961,158 @@
build_path = /obj/item/bodypart/r_arm/robot/surplus_upgraded
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/acclimator
name = "Plumbing Acclimator"
desc = "A heating and cooling device for pipes!"
id = "acclimator"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 500)
construction_time = 75
build_path = /obj/machinery/plumbing/acclimator
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/disposer
name = "Plumbing Disposer"
desc = "Using the power of SCIENCE, dissolves reagents into nothing (almost)."
id = "disposer"
build_type = PROTOLATHE
materials = list(MAT_METAL = 500, MAT_GLASS = 100)
construction_time = 75
build_path = /obj/machinery/plumbing/disposer
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_filter
name = "Plumbing Filter"
desc = "Filters out chemicals by their NTDB ID."
id = "plumb_filter"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 500)
construction_time = 75
build_path = /obj/machinery/plumbing/filter
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_synth
name = "Plumbing Synthesizer"
desc = "Using standard mass-energy dynamic autoconverters, generates reagents from power and puts them in a pipe."
id = "plumb_synth"
build_type = PROTOLATHE
materials = list(MAT_METAL = 5000, MAT_GLASS = 1000, MAT_PLASTIC = 1000)
construction_time = 75
build_path = /obj/machinery/plumbing/synthesizer
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_grinder
name = "Plumbing-Linked Autogrinder"
desc = "Automatically extracts reagents from an item by grinding it. Think of the possibilities! Note: does not grind people."
id = "plumb_grinder"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1500)
construction_time = 75
build_path = /obj/machinery/plumbing/grinder_chemical
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/reaction_chamber
name = "Plumbing Reaction Chamber"
desc = "You can set a list of allowed reagents and amounts. Once the chamber has these reagents, will let the products through."
id = "reaction_chamber"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 500)
construction_time = 75
build_path = /obj/machinery/plumbing/reaction_chamber
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/duct_print
name = "Plumbing Ducts"
desc = "Ducts for plumbing! Now lathed for efficiency."
id = "duct_print"
build_type = PROTOLATHE
materials = list(MAT_PLASTIC = 400)
construction_time = 5
build_path = /obj/item/stack/ducts
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_splitter
name = "Plumbing Chemical Splitter"
desc = "A splitter. Has 2 outputs. Can be configured to allow a certain amount through each side."
id = "plumb_splitter"
build_type = PROTOLATHE
materials = list(MAT_METAL = 750, MAT_GLASS = 250)
construction_time = 75
build_path = /obj/machinery/plumbing/splitter
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/pill_press
name = "Plumbing Automatic Pill Former"
desc = "Automatically forms pills to the required parameters with piped reagents! A good replacement for those lazy, useless chemists."
id = "pill_press"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 500)
construction_time = 75
build_path = /obj/machinery/plumbing/pill_press
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_pump
name = "Liquid Extraction Pump"
desc = "Use it for extracting liquids from lavaland's geysers!"
id = "plumb_pump"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 500)
construction_time = 75
build_path = /obj/machinery/power/liquid_pump
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_in
name = "Plumbing Input Device"
desc = "A big piped funnel for putting stuff in the pipe network."
id = "plumb_in"
build_type = PROTOLATHE
materials = list(MAT_METAL = 400, MAT_GLASS = 400)
construction_time = 75
build_path = /obj/machinery/plumbing/input
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_out
name = "Plumbing Output Device"
desc = "A big piped funnel for taking stuff out of the pipe network."
id = "plumb_out"
build_type = PROTOLATHE
materials = list(MAT_METAL = 400, MAT_GLASS = 400)
construction_time = 75
build_path = /obj/machinery/plumbing/output
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_tank
name = "Plumbed Storage Tank"
desc = "A tank for storing plumbed reagents."
id = "plumb_tank"
build_type = PROTOLATHE
materials = list(MAT_METAL = 10000, MAT_GLASS = 10000, MAT_PLASTIC = 4000)
construction_time = 75
build_path = /obj/machinery/plumbing/tank
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/plumb_rcd
name = "Plumbed Autoconstruction Device"
desc = "A RCD for plumbing machines! Cannot make ducts."
id = "plumb_rcd"
build_type = PROTOLATHE
materials = list(MAT_METAL = 20000, MAT_GLASS = 10000, MAT_PLASTIC = 20000, MAT_PLASMA = 6000, MAT_DIAMOND = 5000, MAT_BLUESPACE = 5000, MAT_GOLD = 5000, MAT_SILVER = 5000)
construction_time = 150
build_path = /obj/item/construction/plumbing
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCEs
@@ -24,6 +24,23 @@
design_ids = list("defib_decay", "defib_shock", "defib_heal", "defib_speed")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/plumbing
id = "plumbing"
display_name = "Reagent Plumbing Technology"
description = "Plastic tubes, and machinery used for manipulating things in them."
prereq_ids = list("base")
design_ids = list("acclimator", "disposer", "plumb_filter", "plumb_synth", "plumb_grinder", "reaction_chamber", "duct_print", "plumb_splitter", "pill_press", "plumb_pump", "plumb_in", "plumb_out", "plumb_tank")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/advplumbing
id = "advplumbing"
display_name = "Advanced Plumbing Technology"
description = "Plumbing RCD."
prereq_ids = list("plumbing", "adv_engi", "adv_biotech")
design_ids = list("plumb_rcd")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
//////////////////////Cybernetics/////////////////////
/datum/techweb_node/surplus_limbs