Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into thefunnytemporalkatanas

This commit is contained in:
zerothebigboy
2020-08-21 02:10:03 -04:00
62 changed files with 2633 additions and 41 deletions
+1
View File
@@ -312,6 +312,7 @@
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
#define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag)
#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench" //called exclusively in plumbing, for now
#define COMSIG_OBJ_ATTACK_GENERIC "obj_attack_generic" //from base of atom/animal_attack(): (/mob/user)
#define COMPONENT_STOP_GENERIC_ATTACK 1
+9
View File
@@ -0,0 +1,9 @@
#define FIRST_DUCT_LAYER 1
#define SECOND_DUCT_LAYER 2
#define THIRD_DUCT_LAYER 4
#define FOURTH_DUCT_LAYER 8
#define FIFTH_DUCT_LAYER 16
#define DUCT_LAYER_DEFAULT THIRD_DUCT_LAYER
#define MACHINE_REAGENT_TRANSFER 10
+4
View File
@@ -57,6 +57,10 @@
#define ADD_REAGENT 2 // reagent added
#define REM_REAGENT 3 // reagent removed (may still exist)
#define PILL_STYLE_COUNT 22 //Update this if you add more pill icons or you die (literally, we'll toss a nuke at whever your ip turns up)
#define RANDOM_PILL_STYLE 22 //Dont change this one though
#define THRESHOLD_UNHUSK 50 // health threshold for synthflesh/rezadone to unhusk someone
//reagent bitflags, used for altering how they works
+5
View File
@@ -0,0 +1,5 @@
PROCESSING_SUBSYSTEM_DEF(fluids)
name = "Fluids"
wait = 20
stat_tag = "FD" //its actually Fluid Ducts
flags = SS_NO_INIT | SS_TICKER
@@ -2,6 +2,15 @@
//Large Objects//
/////////////////
/datum/crafting_recipe/plunger
name = "Plunger"
result = /obj/item/plunger
time = 1
reqs = list(/obj/item/stack/sheet/plastic = 1,
/obj/item/stack/sheet/mineral/wood = 1)
category = CAT_MISC
subcategory = CAT_TOOL
/datum/crafting_recipe/showercurtain
name = "Shower Curtains"
reqs = list(/obj/item/stack/sheet/cloth = 2,
@@ -337,7 +346,7 @@
result = /obj/item/toy/sword/cx
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
/datum/crafting_recipe/catgirlplushie
name = "Catgirl Plushie"
reqs = list(/obj/item/toy/plush/hairball = 3)
@@ -0,0 +1,215 @@
/datum/component/plumbing
///Index with "1" = /datum/ductnet/theductpointingnorth etc. "1" being the num2text from NORTH define
var/list/datum/ductnet/ducts = list()
///shortcut to our parents' reagent holder
var/datum/reagents/reagents
///TRUE if we wanna add proper pipe outless under our parent object. this is pretty good if i may so so myself
var/use_overlays = TRUE
///We can't just cut all of the parents' overlays, so we'll track them here
var/list/image/ducterlays
///directions in wich we act as a supplier
var/supply_connects
///direction in wich we act as a demander
var/demand_connects
///FALSE to pretty much just not exist in the plumbing world so we can be moved, TRUE to go plumbo mode
var/active = FALSE
///if TRUE connects will spin with the parent object visually and codually, so you can have it work in any direction. FALSE if you want it to be static
var/turn_connects = TRUE
/datum/component/plumbing/Initialize(start=TRUE, _turn_connects=TRUE) //turn_connects for wheter or not we spin with the object to change our pipes
if(parent && !istype(parent, /atom/movable))
return COMPONENT_INCOMPATIBLE
var/atom/movable/AM = parent
if(!AM.reagents)
return COMPONENT_INCOMPATIBLE
reagents = AM.reagents
turn_connects = _turn_connects
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED,COMSIG_PARENT_PREQDELETED), .proc/disable)
RegisterSignal(parent, list(COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH), .proc/toggle_active)
if(start)
enable()
if(use_overlays)
create_overlays()
/datum/component/plumbing/process()
if(!demand_connects || !reagents)
STOP_PROCESSING(SSfluids, src)
return
if(reagents.total_volume < reagents.maximum_volume)
for(var/D in GLOB.cardinals)
if(D & demand_connects)
send_request(D)
///Can we be added to the ductnet?
/datum/component/plumbing/proc/can_add(datum/ductnet/D, dir)
if(!active)
return
if(!dir || !D)
return FALSE
if(num2text(dir) in ducts)
return FALSE
return TRUE
///called from in process(). only calls process_request(), but can be overwritten for children with special behaviour
/datum/component/plumbing/proc/send_request(dir)
process_request(amount = MACHINE_REAGENT_TRANSFER, reagent = null, dir = dir)
///check who can give us what we want, and how many each of them will give us
/datum/component/plumbing/proc/process_request(amount, reagent, dir)
var/list/valid_suppliers = list()
var/datum/ductnet/net
if(!ducts.Find(num2text(dir)))
return
net = ducts[num2text(dir)]
for(var/A in net.suppliers)
var/datum/component/plumbing/supplier = A
if(supplier.can_give(amount, reagent, net))
valid_suppliers += supplier
for(var/A in valid_suppliers)
var/datum/component/plumbing/give = A
give.transfer_to(src, amount / valid_suppliers.len, reagent, net)
///returns TRUE when they can give the specified amount and reagent. called by process request
/datum/component/plumbing/proc/can_give(amount, reagent, datum/ductnet/net)
if(amount <= 0)
return
if(reagent) //only asked for one type of reagent
for(var/A in reagents.reagent_list)
var/datum/reagent/R = A
if(R.type == reagent)
return TRUE
else if(reagents.total_volume > 0) //take whatever
return TRUE
///this is where the reagent is actually transferred and is thus the finish point of our process()
/datum/component/plumbing/proc/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net)
if(!reagents || !target || !target.reagents)
return FALSE
if(reagent)
reagents.trans_id_to(target.parent, reagent, amount)
else
reagents.trans_to(target.parent, amount)
///We create our luxurious piping overlays/underlays, to indicate where we do what. only called once if use_overlays = TRUE in Initialize()
/datum/component/plumbing/proc/create_overlays()
var/atom/movable/AM = parent
for(var/image/I in ducterlays)
AM.overlays.Remove(I)
qdel(I)
ducterlays = list()
for(var/D in GLOB.cardinals)
var/color
var/direction
if(D & demand_connects)
color = "red" //red because red is mean and it takes
else if(D & supply_connects)
color = "blue" //blue is nice and gives
else
continue
var/image/I
if(turn_connects)
switch(D)
if(NORTH)
direction = "north"
if(SOUTH)
direction = "south"
if(EAST)
direction = "east"
if(WEST)
direction = "west"
I = image('icons/obj/plumbing/plumbers.dmi', "[direction]-[color]", layer = AM.layer - 1)
else
I = image('icons/obj/plumbing/plumbers.dmi', color, layer = AM.layer - 1) //color is not color as in the var, it's just the name
I.dir = D
AM.add_overlay(I)
ducterlays += I
///we stop acting like a plumbing thing and disconnect if we are, so we can safely be moved and stuff
/datum/component/plumbing/proc/disable()
if(!active)
return
STOP_PROCESSING(SSfluids, src)
for(var/A in ducts)
var/datum/ductnet/D = ducts[A]
D.remove_plumber(src)
active = FALSE
for(var/D in GLOB.cardinals)
if(D & (demand_connects | supply_connects))
for(var/obj/machinery/duct/duct in get_step(parent, D))
duct.attempt_connect()
///settle wherever we are, and start behaving like a piece of plumbing
/datum/component/plumbing/proc/enable()
if(active)
return
update_dir()
active = TRUE
var/atom/movable/AM = parent
for(var/obj/machinery/duct/D in AM.loc) //Destroy any ducts under us. Ducts also self destruct if placed under a plumbing machine. machines disable when they get moved
if(D.anchored) //that should cover everything
D.disconnect_duct()
if(demand_connects)
START_PROCESSING(SSfluids, src)
for(var/D in GLOB.cardinals)
if(D & (demand_connects | supply_connects))
for(var/atom/movable/A in get_step(parent, D))
if(istype(A, /obj/machinery/duct))
var/obj/machinery/duct/duct = A
duct.attempt_connect()
else
var/datum/component/plumbing/P = A.GetComponent(/datum/component/plumbing)
if(P)
direct_connect(P, D)
/// Toggle our machinery on or off. This is called by a hook from default_unfasten_wrench with anchored as only param, so we dont have to copypaste this on every object that can move
/datum/component/plumbing/proc/toggle_active(obj/O, new_state)
if(new_state)
enable()
else
disable()
/** We update our connects only when we settle down by taking our current and original direction to find our new connects
* If someone wants it to fucking spin while connected to something go actually knock yourself out
*/
/datum/component/plumbing/proc/update_dir()
if(!turn_connects)
return
var/atom/movable/AM = parent
var/new_demand_connects
var/new_supply_connects
var/new_dir = AM.dir
var/angle = 180 - dir2angle(new_dir)
if(new_dir == SOUTH)
demand_connects = initial(demand_connects)
supply_connects = initial(supply_connects)
else
for(var/D in GLOB.cardinals)
if(D & initial(demand_connects))
new_demand_connects += turn(D, angle)
if(D & initial(supply_connects))
new_supply_connects += turn(D, angle)
demand_connects = new_demand_connects
supply_connects = new_supply_connects
///Give the direction of a pipe, and it'll return wich direction it originally was when it's object pointed SOUTH
/datum/component/plumbing/proc/get_original_direction(dir)
var/atom/movable/AM = parent
return turn(dir, dir2angle(AM.dir) - 180)
//special case in-case we want to connect directly with another machine without a duct
/datum/component/plumbing/proc/direct_connect(datum/component/plumbing/P, dir)
if(!P.active)
return
var/opposite_dir = turn(dir, 180)
if(P.demand_connects & opposite_dir && supply_connects & dir || P.supply_connects & opposite_dir && demand_connects & dir) //make sure we arent connecting two supplies or demands
var/datum/ductnet/net = new()
net.add_plumber(src, dir)
net.add_plumber(P, opposite_dir)
///has one pipe input that only takes, example is manual output pipe
/datum/component/plumbing/simple_demand
demand_connects = NORTH
///has one pipe output that only supplies. example is liquid pump and manual input pipe
/datum/component/plumbing/simple_supply
supply_connects = NORTH
///input and output, like a holding tank
/datum/component/plumbing/tank
demand_connects = WEST
supply_connects = EAST
@@ -0,0 +1,21 @@
/datum/component/plumbing/acclimator
demand_connects = WEST
supply_connects = EAST
var/obj/machinery/plumbing/acclimator/AC
/datum/component/plumbing/acclimator/Initialize(start=TRUE, _turn_connects=TRUE)
. = ..()
if(!istype(parent, /obj/machinery/plumbing/acclimator))
return COMPONENT_INCOMPATIBLE
AC = parent
/datum/component/plumbing/acclimator/can_give(amount, reagent)
. = ..()
if(. && AC.emptying)
return TRUE
return FALSE
///We're overriding process and not send_request, because all process does is do the requests, so we might aswell cut out the middle man and save some code from running
/datum/component/plumbing/acclimator/process()
if(AC.emptying)
return
. = ..()
+59
View File
@@ -0,0 +1,59 @@
///The magical plumbing component used by the chemical filters. The different supply connects behave differently depending on the filters set on the chemical filter
/datum/component/plumbing/filter
demand_connects = NORTH
supply_connects = SOUTH | EAST | WEST //SOUTH is straight, EAST is left and WEST is right. We look from the perspective of the insert
/datum/component/plumbing/filter/Initialize()
. = ..()
if(!istype(parent, /obj/machinery/plumbing/filter))
return COMPONENT_INCOMPATIBLE
/datum/component/plumbing/filter/can_give(amount, reagent, datum/ductnet/net)
. = ..()
if(.)
var/direction
for(var/A in ducts)
if(ducts[A] == net)
direction = get_original_direction(text2num(A)) //we need it relative to the direction, so filters don't change when we turn the filter
break
if(!direction)
return FALSE
if(reagent)
if(!can_give_in_direction(direction, reagent))
return FALSE
/datum/component/plumbing/filter/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net)
if(!reagents || !target || !target.reagents)
return FALSE
var/direction
for(var/A in ducts)
if(ducts[A] == net)
direction = get_original_direction(text2num(A))
break
if(reagent)
reagents.trans_id_to(target.parent, reagent, amount)
else
for(var/A in reagents.reagent_list)
var/datum/reagent/R = A
if(!can_give_in_direction(direction, R.type))
continue
var/new_amount
if(R.volume < amount)
new_amount = amount - R.volume
reagents.trans_id_to(target.parent, R.type, amount)
amount = new_amount
if(amount <= 0)
break
///We check if the direction and reagent are valid to give. Needed for filters since different outputs have different behaviours
/datum/component/plumbing/filter/proc/can_give_in_direction(dir, reagent)
var/obj/machinery/plumbing/filter/F = parent
switch(dir)
if(SOUTH) //straight
if(!F.left.Find(reagent) && !F.right.Find(reagent))
return TRUE
if(WEST) //right
if(F.right.Find(reagent))
return TRUE
if(EAST) //left
if(F.left.Find(reagent))
return TRUE
@@ -0,0 +1,38 @@
/datum/component/plumbing/reaction_chamber
demand_connects = WEST
supply_connects = EAST
/datum/component/plumbing/reaction_chamber/Initialize(start=TRUE, _turn_connects=TRUE)
. = ..()
if(!istype(parent, /obj/machinery/plumbing/reaction_chamber))
return COMPONENT_INCOMPATIBLE
/datum/component/plumbing/reaction_chamber/can_give(amount, reagent, datum/ductnet/net)
. = ..()
var/obj/machinery/plumbing/reaction_chamber/RC = parent
if(!. || !RC.emptying)
return FALSE
/datum/component/plumbing/reaction_chamber/send_request(dir)
var/obj/machinery/plumbing/reaction_chamber/RC = parent
if(RC.emptying || !LAZYLEN(RC.required_reagents))
return
for(var/RT in RC.required_reagents)
var/has_reagent = FALSE
for(var/A in reagents.reagent_list)
var/datum/reagent/RD = A
if(RT == RD.type)
has_reagent = TRUE
if(RD.volume < RC.required_reagents[RT])
process_request(min(RC.required_reagents[RT] - RD.volume, MACHINE_REAGENT_TRANSFER) , RT, dir)
return
if(!has_reagent)
process_request(min(RC.required_reagents[RT], MACHINE_REAGENT_TRANSFER), RT, dir)
return
RC.reagent_flags &= ~NO_REACT
reagents.handle_reactions()
RC.emptying = TRUE //If we move this up, it'll instantly get turned off since any reaction always sets the reagent_total to zero. Other option is make the reaction update
//everything for every chemical removed, wich isn't a good option either.
RC.on_reagent_change() //We need to check it now, because some reactions leave nothing left.
@@ -0,0 +1,45 @@
/datum/component/plumbing/splitter
demand_connects = NORTH
supply_connects = SOUTH | EAST
/datum/component/plumbing/splitter/Initialize()
. = ..()
if(. && !istype(parent, /obj/machinery/plumbing/splitter))
return FALSE
/datum/component/plumbing/splitter/can_give(amount, reagent, datum/ductnet/net)
. = ..()
if(!.)
return
. = FALSE
var/direction
for(var/A in ducts)
if(ducts[A] == net)
direction = get_original_direction(text2num(A))
break
var/obj/machinery/plumbing/splitter/S = parent
switch(direction)
if(SOUTH)
if(S.turn_straight && S.transfer_straight <= amount)
S.turn_straight = FALSE
return TRUE
if(EAST)
if(!S.turn_straight && S.transfer_side <= amount)
S.turn_straight = TRUE
return TRUE
/datum/component/plumbing/splitter/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net)
var/direction
for(var/A in ducts)
if(ducts[A] == net)
direction = get_original_direction(text2num(A))
break
var/obj/machinery/plumbing/splitter/S = parent
switch(direction)
if(SOUTH)
if(amount >= S.transfer_straight)
amount = S.transfer_straight
if(EAST)
if(amount >= S.transfer_side)
amount = S.transfer_side
. = ..()
+65
View File
@@ -0,0 +1,65 @@
///We handle the unity part of plumbing. We track who is connected to who.
/datum/ductnet
var/list/suppliers = list()
var/list/demanders = list()
var/list/obj/machinery/duct/ducts = list()
var/capacity
///Add a duct to our network
/datum/ductnet/proc/add_duct(obj/machinery/duct/D)
if(!D || (D in ducts))
return
ducts += D
D.duct = src
///Remove a duct from our network and commit suicide, because this is probably easier than to check who that duct was connected to and what part of us was lost
/datum/ductnet/proc/remove_duct(obj/machinery/duct/ducting)
destroy_network(FALSE)
for(var/obj/machinery/duct/D in ducting.neighbours)
addtimer(CALLBACK(D, /obj/machinery/duct/proc/reconnect), 0) //all needs to happen after the original duct that was destroyed finishes destroying itself
addtimer(CALLBACK(D, /obj/machinery/duct/proc/generate_connects), 0)
qdel(src)
///add a plumbing object to either demanders or suppliers
/datum/ductnet/proc/add_plumber(datum/component/plumbing/P, dir)
if(!P.can_add(src, dir))
return FALSE
P.ducts[num2text(dir)] = src
if(dir & P.supply_connects)
suppliers += P
else if(dir & P.demand_connects)
demanders += P
return TRUE
///remove a plumber. we dont delete ourselves because ductnets dont persist through plumbing objects
/datum/ductnet/proc/remove_plumber(datum/component/plumbing/P)
suppliers.Remove(P) //we're probably only in one of these, but Remove() is inherently sane so this is fine
demanders.Remove(P)
for(var/dir in P.ducts)
if(P.ducts[dir] == src)
P.ducts -= dir
if(!ducts.len) //there were no ducts, so it was a direct connection. we destroy ourselves since a ductnet with only one plumber and no ducts is worthless
destroy_network()
///we combine ductnets. this occurs when someone connects to seperate sets of fluid ducts
/datum/ductnet/proc/assimilate(datum/ductnet/D)
ducts.Add(D.ducts)
suppliers.Add(D.suppliers)
demanders.Add(D.demanders)
for(var/A in D.suppliers + D.demanders)
var/datum/component/plumbing/P = A
for(var/s in P.ducts)
if(P.ducts[s] != D)
continue
P.ducts[s] = src //all your ducts are belong to us
for(var/A in D.ducts)
var/obj/machinery/duct/M = A
M.duct = src //forget your old master
destroy_network()
///destroy the network and tell all our ducts and plumbers we are gone
/datum/ductnet/proc/destroy_network(delete=TRUE)
for(var/A in suppliers + demanders)
remove_plumber(A)
for(var/A in ducts)
var/obj/machinery/duct/D = A
D.duct = null
if(delete) //I don't want code to run with qdeleted objects because that can never be good, so keep this in-case the ductnet has some business left to attend to before commiting suicide
qdel(src)
+7
View File
@@ -646,3 +646,10 @@
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
sleep(1)
animate(I, alpha = 0, transform = matrix(), time = 1)
/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran
SHOULD_CALL_PARENT(TRUE)
if(anchored == anchorvalue)
return
. = anchored
anchored = anchorvalue
+2
View File
@@ -117,6 +117,7 @@ Class Procs:
var/new_occupant_dir = SOUTH //The direction the occupant will be set to look at when entering the machine.
var/speed_process = FALSE // Process as fast as possible?
var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created
var/wire_compatible = FALSE
// For storing and overriding ui id and dimensions
var/tgui_id // ID of TGUI interface
var/ui_style // ID of custom TGUI style (optional)
@@ -433,6 +434,7 @@ Class Procs:
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
setAnchored(!anchored)
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
SEND_SIGNAL(src, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, anchored)
return SUCCESSFUL_UNFASTEN
return FAILED_UNFASTEN
return CANT_UNFASTEN
+84 -7
View File
@@ -135,6 +135,14 @@ RLD
flick("[icon_state]_empty", src) //somewhat hacky thing to make RCDs with ammo counters actually have a blinking yellow light
return .
/obj/item/construction/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated() || !user.Adjacent(src))
return FALSE
return TRUE
/obj/item/construction/proc/range_check(atom/A, mob/user)
if(!(A in range(custom_range, get_turf(user))))
to_chat(user, "<span class='warning'>The \'Out of Range\' light on [src] blinks red.</span>")
@@ -276,13 +284,6 @@ RLD
//Not scaling these down to button size because they look horrible then, instead just bumping up radius.
return MA
/obj/item/construction/rcd/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated() || !user.Adjacent(src))
return FALSE
return TRUE
/obj/item/construction/rcd/proc/change_computer_dir(mob/user)
if(!user)
return
@@ -856,6 +857,82 @@ RLD
desc = "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells."
upgrade = RCD_UPGRADE_SIMPLE_CIRCUITS
/obj/item/construction/plumbing
name = "Plumbing Constructor"
desc = "An expertly modified RCD outfitted to construct plumbing machinery. Reload with compressed matter cartridges."
icon = 'icons/obj/tools.dmi'
icon_state = "arcd"
item_state = "oldrcd"
has_ammobar = FALSE
matter = 200
max_matter = 200
///type of the plumbing machine
var/blueprint = null
///index, used in the attack self to get the type. stored here since it doesnt change
var/list/choices = list()
///index, used in the attack self to get the type. stored here since it doesnt change
var/list/name_to_type = list()
///
var/list/machinery_data = list("cost" = list(), "delay" = list())
/obj/item/construction/plumbing/attack_self(mob/user)
..()
if(!choices.len)
for(var/A in subtypesof(/obj/machinery/plumbing))
var/obj/machinery/plumbing/M = A
if(initial(M.rcd_constructable))
choices += list(initial(M.name) = image(icon = initial(M.icon), icon_state = initial(M.icon_state)))
name_to_type[initial(M.name)] = M
machinery_data["cost"][A] = initial(M.rcd_cost)
machinery_data["delay"][A] = initial(M.rcd_delay)
var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
if(!check_menu(user))
return
blueprint = name_to_type[choice]
playsound(src, 'sound/effects/pop.ogg', 50, FALSE)
to_chat(user, "<span class='notice'>You change [name]s blueprint to '[choice]'.</span>")
///pretty much rcd_create, but named differently to make myself feel less bad for copypasting from a sibling-type
/obj/item/construction/plumbing/proc/create_machine(atom/A, mob/user)
if(!machinery_data || !isopenturf(A))
return FALSE
if(checkResource(machinery_data["cost"][blueprint], user) && blueprint)
if(do_after(user, machinery_data["delay"][blueprint], target = A))
if(checkResource(machinery_data["cost"][blueprint], user) && canPlace(A))
useResource(machinery_data["cost"][blueprint], user)
activate()
playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
new blueprint (A, FALSE, FALSE)
return TRUE
/obj/item/construction/plumbing/proc/canPlace(turf/T)
if(!isopenturf(T))
return FALSE
. = TRUE
for(var/obj/O in T.contents)
if(O.density) //let's not built ontop of dense stuff, like big machines and other obstacles, it kills my immershion
return FALSE
/obj/item/construction/plumbing/afterattack(atom/A, mob/user)
. = ..()
if(!range_check(A, user))
return
if(istype(A, /obj/machinery/plumbing))
var/obj/machinery/plumbing/P = A
if(P.anchored)
to_chat(user, "<span class='warning'>The [P.name] needs to be unanchored!</span>")
return
if(do_after(user, 20, target = P))
P.deconstruct() //Let's not substract matter
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect
else
create_machine(A, user)
#undef GLOW_MODE
#undef LIGHT_MODE
#undef REMOVE_MODE
+71 -3
View File
@@ -6,6 +6,7 @@ RPD
#define ATMOS_CATEGORY 0
#define DISPOSALS_CATEGORY 1
#define TRANSIT_CATEGORY 2
#define PLUMBING_CATEGORY 3
#define BUILD_MODE (1<<0)
#define WRENCH_MODE (1<<1)
@@ -75,6 +76,13 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
)
))
GLOBAL_LIST_INIT(fluid_duct_recipes, list(
"Fluid Ducts" = list(
new /datum/pipe_info/plumbing("Duct", /obj/machinery/duct, PIPE_ONEDIR),
new /datum/pipe_info/plumbing/multilayer("Duct Layer-Manifold",/obj/machinery/duct/multilayered, PIPE_STRAIGHT)
)
))
/datum/pipe_info
var/name
var/icon_state
@@ -175,6 +183,15 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
if(dt == PIPE_UNARY_FLIPPABLE)
icon_state = "[icon_state]_preview"
/datum/pipe_info/plumbing/New(label, obj/path, dt=PIPE_UNARY)
name = label
id = path
icon_state = initial(path.icon_state)
dirtype = dt
/datum/pipe_info/plumbing/multilayer //exists as identifier so we can see the difference between multi_layer and just ducts properly later on
/obj/item/pipe_dispenser
name = "Rapid Piping Device (RPD)"
desc = "A device used to rapidly pipe things."
@@ -200,15 +217,19 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
var/atmos_build_speed = 5 //deciseconds (500ms)
var/disposal_build_speed = 5
var/transit_build_speed = 5
var/plumbing_build_speed = 5
var/destroy_speed = 5
var/paint_speed = 5
var/category = ATMOS_CATEGORY
var/piping_layer = PIPING_LAYER_DEFAULT
var/ducting_layer = DUCT_LAYER_DEFAULT
var/datum/pipe_info/recipe
var/static/datum/pipe_info/first_atmos
var/static/datum/pipe_info/first_disposal
var/static/datum/pipe_info/first_transit
var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE
var/static/datum/pipe_info/first_plumbing
var/locked = FALSE //wheter we can change categories. Useful for the plumber
/obj/item/pipe_dispenser/New()
. = ..()
@@ -253,12 +274,15 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
var/list/data = list(
"category" = category,
"piping_layer" = piping_layer,
// "ducting_layer" = ducting_layer, //uhh is this for chem thing?
"ducting_layer" = ducting_layer,
"preview_rows" = recipe.get_preview(p_dir),
"categories" = list(),
"selected_color" = paint_color,
"paint_colors" = GLOB.pipe_paint_colors,
"mode" = mode
"mode" = mode,
"locked" = locked
)
var/list/recipes
@@ -269,6 +293,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
recipes = GLOB.disposal_pipe_recipes
if(TRANSIT_CATEGORY)
recipes = GLOB.transit_tube_recipes
if(PLUMBING_CATEGORY)
recipes = GLOB.fluid_duct_recipes
for(var/c in recipes)
var/list/cat = recipes[c]
var/list/r = list()
@@ -297,6 +323,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
recipe = first_atmos
if(TRANSIT_CATEGORY)
recipe = first_transit
if(PLUMBING_CATEGORY)
recipe = first_plumbing
p_dir = NORTH
playeffect = FALSE
if("piping_layer")
@@ -468,16 +496,56 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
if(mode & WRENCH_MODE)
tube.wrench_act(user, src)
return
if(PLUMBING_CATEGORY) //Plumbing.
if(!can_make_pipe)
return ..()
A = get_turf(A)
if(isclosedturf(A))
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
return
to_chat(user, "<span class='notice'>You start building a fluid duct...</span>")
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
if(do_after(user, plumbing_build_speed, target = A))
var/obj/machinery/duct/D
if(recipe.type == /datum/pipe_info/plumbing/multilayer)
var/temp_connects = NORTH + SOUTH
if(queued_p_dir == EAST)
temp_connects = EAST + WEST
D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer, temp_connects)
else
D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer)
D.add_fingerprint(usr)
if(mode & WRENCH_MODE)
D.wrench_act(user, src)
else
return ..()
/obj/item/pipe_dispenser/proc/activate()
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
/* unneeded, you can craft ducts from plastic
/obj/item/pipe_dispenser/plumbing
name = "Plumberinator"
desc = "A crude device to rapidly plumb things."
icon_state = "plumberer"
category = PLUMBING_CATEGORY
locked = TRUE
/obj/item/pipe_dispenser/plumbing/Initialize()
. = ..()
spark_system = new
spark_system.set_up(5, 0, src)
spark_system.attach(src)
if(!first_plumbing)
first_plumbing = GLOB.fluid_duct_recipes[GLOB.fluid_duct_recipes[1]][1]
recipe = first_plumbing
*/
#undef ATMOS_CATEGORY
#undef DISPOSALS_CATEGORY
#undef TRANSIT_CATEGORY
#undef PLUMBING_CATEGORY
#undef BUILD_MODE
#undef DESTROY_MODE
@@ -48,6 +48,13 @@
/obj/item/stack/cable_coil = 5,
/obj/item/stack/sheet/glass = 1)
/obj/item/circuitboard/machine/medipen_refiller
name = "Medipen Refiller (Machine Board)"
icon_state = "medical"
build_path = /obj/machinery/medipen_refiller
req_components = list(
/obj/item/stock_parts/matter_bin = 1)
/obj/item/circuitboard/machine/clonepod
name = "Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod
@@ -512,6 +519,10 @@
/obj/item/stack/sheet/glass = 1)
needs_anchored = FALSE
/obj/item/circuitboard/machine/hydroponics/automagic
name = "Automatic Hydroponics Tray (Machine Board)"
build_path = /obj/machinery/hydroponics/constructable/automagic
/obj/item/circuitboard/machine/seed_extractor
name = "Seed Extractor (Machine Board)"
build_path = /obj/machinery/seed_extractor
@@ -128,6 +128,7 @@
absorption_capacity = 5
splint_factor = 0.35
custom_price = PRICE_REALLY_CHEAP
grind_results = list(/datum/reagent/cellulose = 2)
// gauze is only relevant for wounds, which are handled in the wounds themselves
/obj/item/stack/medical/gauze/try_heal(mob/living/M, mob/user, silent)
@@ -412,6 +412,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
force = 0
throwforce = 0
merge_type = /obj/item/stack/sheet/cloth
grind_results = list(/datum/reagent/cellulose = 2)
/obj/item/stack/sheet/cloth/get_main_recipes()
. = ..()
@@ -773,6 +774,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/empty), \
new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/large/empty,3), \
new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 10, time = 10, one_per_turf = 1, on_floor = 1), \
new /datum/stack_recipe("duct", /obj/item/stack/ducts,1), \
new /datum/stack_recipe("laser pointer case", /obj/item/glasswork/glass_base/laserpointer_shell, 30), \
new /datum/stack_recipe("wet floor sign", /obj/item/caution, 2)))
@@ -841,6 +843,7 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
merge_type = /obj/item/stack/sheet/cotton
var/pull_effort = 30
var/loom_result = /obj/item/stack/sheet/cloth
grind_results = list(/datum/reagent/cellulose = 5)
/obj/item/stack/sheet/cotton/ten
amount = 10
@@ -856,6 +859,7 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
merge_type = /obj/item/stack/sheet/cotton/durathread
pull_effort = 70
loom_result = /obj/item/stack/sheet/durathread
grind_results = list(/datum/reagent/cellulose = 10)
/obj/item/stack/sheet/meat
name = "meat sheets"
+2 -2
View File
@@ -478,7 +478,7 @@
/obj/item/assembly/signaler,
/obj/item/lightreplacer,
/obj/item/rcd_ammo,
/obj/item/construction/rcd,
/obj/item/construction,
/obj/item/pipe_dispenser,
/obj/item/stack/rods,
/obj/item/stack/tile/plasteel,
@@ -492,7 +492,7 @@
icon_state = "grenadebeltnew"
item_state = "security"
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
/obj/item/storage/belt/grenade/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+3
View File
@@ -329,3 +329,6 @@
. = ..()
if(. && ricochet_damage_mod)
take_damage(P.damage * ricochet_damage_mod, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration) // pass along ricochet_damage_mod damage to the structure for the ricochet
/obj/proc/plunger_act(obj/item/plunger/P, mob/living/user, reinforced)
return
@@ -9,7 +9,7 @@
var/erupting_state = null //set to null to get it greyscaled from "[icon_state]_soup". Not very usable with the whole random thing, but more types can be added if you change the spawn prob
var/activated = FALSE //whether we are active and generating chems
var/reagent_id = /datum/reagent/fuel/oil
var/reagent_id = /datum/reagent/oil
var/potency = 2 //how much reagents we add every process (2 seconds)
var/max_volume = 500
var/start_volume = 50
@@ -77,10 +77,10 @@
/obj/item/plunger/reinforced
name = "reinforced plunger"
desc = "It's an M. 7 Reinforced Plunger© for heavy duty plunging."
desc = "It's an M. 7 Reinforced Plunger for heavy duty plunging."
icon_state = "reinforced_plunger"
reinforced = TRUE
plunge_mod = 0.8
custom_premium_price = 1200
custom_premium_price = 600
@@ -149,6 +149,8 @@
var/list/megafauna_spawn_list
/// Flora that can spawn in the tunnel, weighted list
var/list/flora_spawn_list
//terrain to spawn weighted list
var/list/terrain_spawn_list
/// Turf type to choose when spawning in tunnel at 1% chance, weighted list
var/list/choose_turf_type
/// if the tunnel should keep being created
@@ -230,7 +232,8 @@
megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/dragon = 4, /mob/living/simple_animal/hostile/megafauna/colossus = 2, /mob/living/simple_animal/hostile/megafauna/bubblegum = SPAWN_BUBBLEGUM)
if (!flora_spawn_list)
flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2)
if(!terrain_spawn_list)
terrain_spawn_list = list(/obj/structure/geyser/random = 1)
. = ..()
if(!has_data)
produce_tunnel_from_data()
@@ -334,8 +337,19 @@
spawned_flora = SpawnFlora(T)
if(!spawned_flora) // no rocks beneath mob spawners / mobs.
SpawnMonster(T)
SpawnTerrain(T)
T.ChangeTurf(turf_type, null, CHANGETURF_IGNORE_AIR)
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnTerrain(turf/T)
if(prob(1))
if(istype(loc, /area/mine/explored) || istype(loc, /area/lavaland/surface/outdoors/explored))
return
var/randumb = pickweight(terrain_spawn_list)
for(var/obj/structure/geyser/F in range(7, T))
if(istype(F, randumb))
return
new randumb(T)
/// Spawns a random mob or megafauna in the tunnel
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnMonster(turf/T)
if(!isarea(loc))
+3 -1
View File
@@ -264,7 +264,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)
..()
@@ -388,9 +388,11 @@
Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
..()
/datum/asset/spritesheet/mafia
name = "mafia"
/datum/asset/spritesheet/mafia/register()
InsertAll("", 'icons/obj/mafia.dmi')
..()
+14 -10
View File
@@ -30,7 +30,7 @@
var/self_sufficiency_req = 20 //Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood.
var/self_sufficiency_progress = 0
var/self_sustaining = FALSE //If the tray generates nutrients and water on its own
var/canirrigate = TRUE //tin
/obj/machinery/hydroponics/constructable
name = "hydroponics tray"
@@ -847,12 +847,13 @@
if (!anchored)
to_chat(user, "<span class='warning'>Anchor the tray first!</span>")
return
using_irrigation = !using_irrigation
O.play_tool_sound(src)
user.visible_message("<span class='notice'>[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.</span>", \
"<span class='notice'>You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.</span>")
for(var/obj/machinery/hydroponics/h in range(1,src))
h.update_icon()
if(canirrigate)
using_irrigation = !using_irrigation
O.play_tool_sound(src)
user.visible_message("<span class='notice'>[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.</span>", \
"<span class='notice'>You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.</span>")
for(var/obj/machinery/hydroponics/h in range(1,src))
h.update_icon()
else if(istype(O, /obj/item/shovel/spade))
if(!myseed && !weedlevel)
@@ -910,11 +911,14 @@
harvest = 0
lastproduce = age
if(istype(myseed, /obj/item/seeds/replicapod))
to_chat(user, "<span class='notice'>You harvest from the [myseed.plantname].</span>")
if(user)//runtimes
to_chat(user, "<span class='notice'>You harvest from the [myseed.plantname].</span>")
else if(myseed.getYield() <= 0)
to_chat(user, "<span class='warning'>You fail to harvest anything useful!</span>")
if(user)
to_chat(user, "<span class='warning'>You fail to harvest anything useful!</span>")
else
to_chat(user, "<span class='notice'>You harvest [myseed.getYield()] items from the [myseed.plantname].</span>")
if(user)
to_chat(user, "<span class='notice'>You harvest [myseed.getYield()] items from the [myseed.plantname].</span>")
if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest))
qdel(myseed)
myseed = null
+25
View File
@@ -190,6 +190,31 @@ obj/item/seeds/proc/is_gene_forbidden(typepath)
parent.update_tray(user)
return result
/obj/item/seeds/proc/harvest_userless()
var/obj/machinery/hydroponics/parent = loc //for ease of access
var/t_amount = 0
var/list/result = list()
var/output_loc = parent.loc
var/product_name
while(t_amount < getYield())
var/obj/item/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, src)
if(parent.myseed.plantname != initial(parent.myseed.plantname))
t_prod.name = lowertext(parent.myseed.plantname)
if(productdesc)
t_prod.desc = productdesc
t_prod.seed.name = parent.myseed.name
t_prod.seed.desc = parent.myseed.desc
t_prod.seed.plantname = parent.myseed.plantname
result.Add(t_prod) // User gets a consumable
if(!t_prod)
return
t_amount++
product_name = parent.myseed.plantname
if(getYield() >= 1)
SSblackbox.record_feedback("tally", "food_harvested", getYield(), product_name)
parent.investigate_log("autmoatic harvest of [getYield()] of [src], with seed traits [english_list(genes)] and reagents_add [english_list(reagents_add)] and potency [potency].", INVESTIGATE_BOTANY)
parent.update_tray()
return result
/obj/item/seeds/proc/prepare_result(var/obj/item/reagent_containers/food/snacks/grown/T)
if(!T.reagents)
+433
View File
@@ -0,0 +1,433 @@
/*
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"
///bitfield with the directions we're connected in
var/connects
///set to TRUE to disable smart duct 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 = "#ffffff", layer_of_duct = DUCT_LAYER_DEFAULT, force_connects)
. = ..()
if(no_anchor)
active = FALSE
set_anchored(FALSE)
else if(!can_anchor())
qdel(src)
CRASH("Overlapping ducts detected")
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()
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 scenarios in attempt connect
return
if((duct == D.duct) && duct)//check if we're not just comparing two null values
add_neighbour(D, direction)
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, direction)
//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
D.attempt_connect()
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()
if(duct.add_plumber(P, opposite_dir))
neighbours[P.parent] = direction
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(skipanchor)
if(!skipanchor) //since set_anchored calls us too.
set_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)
///''''''''''''''''optimized''''''''''''''''' proc for quickly reconnecting after a duct net was destroyed
/obj/machinery/duct/proc/reconnect()
if(neighbours.len && !duct)
create_duct()
for(var/atom/movable/AM in neighbours)
if(istype(AM, /obj/machinery/duct))
var/obj/machinery/duct/D = AM
if(D.duct)
if(D.duct == duct) //we're already connected
continue
else
duct.assimilate(D.duct)
continue
else
duct.add_duct(D)
D.reconnect()
else
var/datum/component/plumbing/P = AM.GetComponent(/datum/component/plumbing)
if(AM in get_step(src, neighbours[AM])) //did we move?
if(P)
connect_plumber(P, neighbours[AM])
else
neighbours -= AM //we moved
///Special proc to draw a new connect frame based on neighbours. not the norm so we can support multiple duct kinds
/obj/machinery/duct/proc/generate_connects()
if(lock_connects)
return
connects = 0
for(var/A in neighbours)
connects |= neighbours[A]
update_icon()
///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, direction)
if(!(D in neighbours))
neighbours[D] = direction
if(!(src in D.neighbours))
D.neighbours[src] = turn(direction, 180)
///remove all our neighbours, and remove us from our neighbours aswell
/obj/machinery/duct/proc/lose_neighbours()
for(var/obj/machinery/duct/D in neighbours)
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 a connect direction
/obj/machinery/duct/proc/remove_connects(dead_connects)
if(!lock_connects)
connects &= ~dead_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_state()
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/set_anchored(anchorvalue)
. = ..()
if(isnull(.))
return
if(anchorvalue)
active = TRUE
attempt_connect()
else
disconnect_duct(TRUE)
/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 || can_anchor())
set_anchored(!anchored)
user.visible_message( \
"[user] [anchored ? null : "un"]fastens \the [src].", \
"<span class='notice'>You [anchored ? null : "un"]fasten \the [src].</span>", \
"<span class='hear'>You hear ratcheting.</span>")
return TRUE
///collection of all the sanity checks to prevent us from stacking ducts that shouldn't 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 || D == src)
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, direction)
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/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_blocker)
/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 shouldn't 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"
custom_materials = list(/datum/material/iron=500)
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,98 @@
/**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, null, CALLBACK(src, .proc/can_be_rotated))
/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
ui_x = 320
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
@@ -0,0 +1,65 @@
/obj/machinery/hydroponics/constructable/automagic
name = "automated hydroponics system"
desc = "The bane of botanists everywhere. Accepts chemical reagents via plumbing, automatically harvests and removes dead plants."
obj_flags = CAN_BE_HIT | UNIQUE_RENAME
circuit = /obj/item/circuitboard/machine/hydroponics/automagic
self_sufficiency_req = 400 //automating hydroponics makes gaia sad so she needs more drugs to turn they tray godly.
canirrigate = FALSE
/obj/machinery/hydroponics/constructable/automagic/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/reagent_containers))
return FALSE //avoid fucky wuckies
..()
/obj/machinery/hydroponics/constructable/automagic/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/machinery/hydroponics/constructable/automagic/Destroy()
. = ..()
STOP_PROCESSING(SSobj, src)
/obj/machinery/hydroponics/constructable/automagic/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
create_reagents(100 , AMOUNT_VISIBLE)
/obj/machinery/hydroponics/constructable/automagic/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated))
AddComponent(/datum/component/plumbing/simple_demand)
/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type)
return !anchored
/obj/machinery/hydroponics/constructable/automagic/process()
if(reagents)
applyChemicals(reagents)
reagents.clear_reagents()
if(dead)
dead = 0
qdel(myseed)
myseed = null
update_icon()
name = initial(name)
desc = initial(desc)
if(harvest)
myseed.harvest_userless()
harvest = 0
lastproduce = age
if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest))
qdel(myseed)
myseed = null
dead = 0
name = initial(name)
desc = initial(desc)
update_icon()
..()
+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(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)
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)
return
if(istype(AM, /obj/item/slimecross/industrial)) ///no need to move slimecross industrial things
reagents.trans_to(AM, wanted_amount)
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,59 @@
/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/fermenter/can_be_rotated(mob/user,rotation_type)
if(anchored)
to_chat(user, "<span class='warning'>It is fastened to the floor!</span>")
return FALSE
switch(eat_dir)
if(WEST)
eat_dir = NORTH
return TRUE
if(EAST)
eat_dir = SOUTH
return TRUE
if(NORTH)
eat_dir = EAST
return TRUE
if(SOUTH)
eat_dir = WEST
return TRUE
/obj/machinery/plumbing/fermenter/CanPass(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)
/obj/machinery/plumbing/fermenter/proc/ferment(atom/AM)
if(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)
+65
View File
@@ -0,0 +1,65 @@
///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()
/obj/machinery/plumbing/filter/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/filter, bolt)
/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,64 @@
/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 = NORTH
/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
switch(eat_dir)
if(WEST)
eat_dir = NORTH
return TRUE
if(EAST)
eat_dir = SOUTH
return TRUE
if(NORTH)
eat_dir = EAST
return TRUE
if(SOUTH)
eat_dir = WEST
return TRUE
/obj/machinery/plumbing/grinder_chemical/CanPass(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(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)
qdel(I)
return
I.on_grind()
reagents.add_reagent_list(I.grind_results)
qdel(I)
@@ -0,0 +1,94 @@
/obj/machinery/medipen_refiller
name = "Medipen Refiller"
desc = "A machine that refills used medipens with chemicals."
icon = 'icons/obj/machines/medipen_refiller.dmi'
icon_state = "medipen_refiller"
density = TRUE
circuit = /obj/item/circuitboard/machine/medipen_refiller
idle_power_usage = 100
/// list of medipen subtypes it can refill
var/list/allowed = list(/obj/item/reagent_containers/hypospray/medipen = /datum/reagent/medicine/epinephrine,
/obj/item/reagent_containers/hypospray/medipen/ekit = /datum/reagent/medicine/epinephrine,
/obj/item/reagent_containers/hypospray/medipen/firelocker = /datum/reagent/medicine/oxandrolone,
/obj/item/reagent_containers/hypospray/medipen/stimpack = /datum/reagent/medicine/ephedrine,
/obj/item/reagent_containers/hypospray/medipen/blood_loss = /datum/reagent/medicine/coagulant/weak)
/// var to prevent glitches in the animation
var/busy = FALSE
/obj/machinery/medipen_refiller/Initialize()
. = ..()
create_reagents(100, TRANSPARENT)
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
reagents.maximum_volume += 100 * B.rating
AddComponent(/datum/component/plumbing/simple_demand)
/obj/machinery/medipen_refiller/RefreshParts()
var/new_volume = 100
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
new_volume += 100 * B.rating
if(!reagents)
create_reagents(new_volume, TRANSPARENT)
reagents.maximum_volume = new_volume
return TRUE
/// handles the messages and animation, calls refill to end the animation
/obj/machinery/medipen_refiller/attackby(obj/item/I, mob/user, params)
if(busy)
to_chat(user, "<span class='danger'>The machine is busy.</span>")
return
if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
var/obj/item/reagent_containers/RC = I
var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this)
if(units)
to_chat(user, "<span class='notice'>You transfer [units] units of the solution to the [name].</span>")
return
else
to_chat(user, "<span class='danger'>The [name] is full.</span>")
return
if(istype(I, /obj/item/reagent_containers/hypospray/medipen))
var/obj/item/reagent_containers/hypospray/medipen/P = I
if(!(LAZYFIND(allowed, P.type)))
to_chat(user, "<span class='danger'>Error! Unknown schematics.</span>")
return
if(P.reagents?.reagent_list.len)
to_chat(user, "<span class='notice'>The medipen is already filled.</span>")
return
if(reagents.has_reagent(allowed[P.type], 10))
busy = TRUE
add_overlay("active")
addtimer(CALLBACK(src, .proc/refill, P, user), 20)
qdel(P)
return
to_chat(user, "<span class='danger'>There aren't enough reagents to finish this operation.</span>")
return
..()
/obj/machinery/medipen_refiller/plunger_act(obj/item/plunger/P, mob/living/user, reinforced)
to_chat(user, "<span class='notice'>You start furiously plunging [name].</span>")
if(do_after(user, 30, target = src))
to_chat(user, "<span class='notice'>You finish plunging the [name].</span>")
reagents.clear_reagents()
/obj/machinery/medipen_refiller/wrench_act(mob/living/user, obj/item/I)
..()
default_unfasten_wrench(user, I)
return TRUE
/obj/machinery/medipen_refiller/crowbar_act(mob/user, obj/item/I)
..()
default_deconstruction_crowbar(I)
return TRUE
/obj/machinery/medipen_refiller/screwdriver_act(mob/living/user, obj/item/I)
. = ..()
if(!.)
return default_deconstruction_screwdriver(user, "medipen_refiller_open", "medipen_refiller", I)
/// refills the medipen
/obj/machinery/medipen_refiller/proc/refill(obj/item/reagent_containers/hypospray/medipen/P, mob/user)
new P.type(loc)
reagents.remove_reagent(allowed[P.type], 10)
cut_overlays()
busy = FALSE
to_chat(user, "<span class='notice'>Medipen refilled.</span>")
@@ -0,0 +1,127 @@
///We take a constant input of reagents, and produce a pill once a set volume is reached
/obj/machinery/plumbing/pill_press
name = "chemical press"
desc = "A press that makes pills, patches and bottles."
icon_state = "pill_press"
///maximum size of a pill
var/max_pill_volume = 50
///maximum size of a patch
var/max_patch_volume = 40
///maximum size of a bottle
var/max_bottle_volume = 30
///current operating product (pills or patches)
var/product = "pill"
///the minimum size a pill or patch can be
var/min_volume = 5
///the maximum size a pill or patch can be
var/max_volume = 50
///selected size of the product
var/current_volume = 10
///prefix for the product name
var/product_name = "factory"
///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 products stored in the machine, so we dont have 610 pills on one tile
var/list/stored_products = list()
///max amount of pills allowed on our tile before we start storing them instead
var/max_floor_products = 50 //haha massive pill piles
/obj/machinery/plumbing/pill_press/examine(mob/user)
. = ..()
. += "<span class='notice'>The [name] currently has [stored_products.len] stored. There needs to be less than [max_floor_products ] 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 >= current_volume)
if (product == "pill")
var/obj/item/reagent_containers/pill/P = new(src)
reagents.trans_to(P, current_volume)
P.name = trim("[product_name] pill")
stored_products += 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."
else if (product == "patch")
var/obj/item/reagent_containers/pill/patch/P = new(src)
reagents.trans_to(P, current_volume)
P.name = trim("[product_name] patch")
stored_products += P
else if (product == "bottle")
var/obj/item/reagent_containers/glass/bottle/P = new(src)
reagents.trans_to(P, current_volume)
P.name = trim("[product_name] bottle")
stored_products += P
if(stored_products.len)
var/pill_amount = 0
for(var/obj/item/reagent_containers/pill/P in loc)
pill_amount++
if(pill_amount >= max_floor_products) //too much so just stop
break
if(pill_amount < max_floor_products)
var/atom/movable/AM = stored_products[1] //AM because forceMove is all we need
stored_products -= 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)
+64
View File
@@ -0,0 +1,64 @@
///We pump liquids from activated(plungerated) geysers to a plumbing outlet. We don't need to be wired.
/obj/machinery/plumbing/liquid_pump
name = "liquid pump"
desc = "Pump up those sweet liquids from under the surface. Uses thermal energy from geysers to power itself." //better than placing 200 cables, because it wasnt fun
icon = 'icons/obj/plumbing/plumbers.dmi'
icon_state = "pump"
anchored = FALSE
density = TRUE
idle_power_usage = 10
active_power_usage = 1000
rcd_cost = 30
rcd_delay = 40
///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/plumbing/liquid_pump/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt)
///please note that the component has a hook in the parent call, wich handles activating and deactivating
/obj/machinery/plumbing/liquid_pump/default_unfasten_wrench(mob/user, obj/item/I, time = 20)
. = ..()
if(. == SUCCESSFUL_UNFASTEN)
geyser = null
update_icon()
geyserless = FALSE //we switched state, so lets just set this back aswell
/obj/machinery/plumbing/liquid_pump/process()
if(!anchored || panel_open || geyserless)
return
if(!geyser)
for(var/obj/structure/geyser/G in loc.contents)
geyser = G
update_icon()
if(!geyser) //we didnt find one, abort
geyserless = TRUE
visible_message("<span class='warning'>The [name] makes a sad beep!</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50)
return
pump()
///pump up that sweet geyser nectar
/obj/machinery/plumbing/liquid_pump/proc/pump()
if(!geyser || !geyser.reagents)
return
geyser.reagents.trans_to(src, pump_power)
/obj/machinery/plumbing/liquid_pump/update_icon_state()
if(geyser)
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/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(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,5 +1,3 @@
#define PILL_STYLE_COUNT 22 //Update this if you add more pill icons or you die
#define RANDOM_PILL_STYLE 22 //Dont change this one though
/obj/machinery/chem_master
name = "ChemMaster 3000"
@@ -36,6 +36,14 @@
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
reagents.maximum_volume += REAGENTS_BASE_VOLUME * B.rating
/obj/machinery/smoke_machine/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated))
AddComponent(/datum/component/plumbing/simple_demand) //this SURELY CANT' LEAD TO BAD THINGS HAPPENING.
/obj/machinery/smoke_machine/proc/can_be_rotated(mob/user, rotation_type)
return !anchored
/obj/machinery/smoke_machine/update_icon_state()
if((!is_operational()) || (!on) || (reagents.total_volume == 0))
if (panel_open)
+9 -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
@@ -52,6 +53,14 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
var/metabolizing = FALSE
var/chemical_flags // See fermi/readme.dm REAGENT_DEAD_PROCESS, REAGENT_DONOTSPLIT, REAGENT_ONLYINVERSE, REAGENT_ONMOBMERGE, REAGENT_INVISIBLE, REAGENT_FORCEONNEW, REAGENT_SNEAKYNAME
var/value = REAGENT_VALUE_NONE //How much does it sell for in cargo?
var/datum/material/material //are we made of material?
/datum/reagent/New()
. = ..()
if(material)
material = SSmaterials.GetMaterialRef(material)
/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
. = ..()
@@ -220,4 +229,3 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
bloodsuckerdatum.handle_eat_human_food(disgust, blood_puke, force)
if(blood_change)
bloodsuckerdatum.AddBloodVolume(blood_change)
@@ -515,12 +515,13 @@
overdose_threshold = 30
pH = 2
value = REAGENT_VALUE_UNCOMMON
var/healing = 0.5
/datum/reagent/medicine/omnizine/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-0.5*REM, 0)
M.adjustOxyLoss(-0.5*REM, 0)
M.adjustBruteLoss(-0.5*REM, 0)
M.adjustFireLoss(-0.5*REM, 0)
M.adjustToxLoss(-healing*REM, 0)
M.adjustOxyLoss(-healing*REM, 0)
M.adjustBruteLoss(-healing*REM, 0)
M.adjustFireLoss(-healing*REM, 0)
..()
. = 1
@@ -532,6 +533,12 @@
..()
. = 1
/datum/reagent/medicine/omnizine/protozine
name = "Protozine"
description = "A less environmentally friendly and somewhat weaker variant of omnizine."
color = "#d8c7b7"
healing = 0.2
/datum/reagent/medicine/calomel
name = "Calomel"
description = "Quickly purges the body of all chemicals. Toxin damage is dealt if the patient is in good condition."
@@ -313,6 +313,13 @@
metabolization_rate = 45 * REAGENTS_METABOLISM
. = 1
/datum/reagent/water/hollowwater
name = "Hollow Water"
description = "An ubiquitous chemical substance that is composed of hydrogen and oxygen, but it looks kinda hollow."
color = "#88878777"
taste_description = "emptyiness"
/datum/reagent/water/holywater
name = "Holy Water"
description = "Water blessed by some deity."
@@ -950,6 +957,7 @@
color = "#1C1300" // rgb: 30, 20, 0
taste_description = "sour chalk"
pH = 5
material = /datum/material/diamond
/datum/reagent/carbon/reaction_turf(turf/T, reac_volume)
if(!isspaceturf(T))
@@ -1072,6 +1080,7 @@
pH = 6
overdose_threshold = 30
color = "#c2391d"
material = /datum/material/iron
/datum/reagent/iron/on_mob_life(mob/living/carbon/C)
if((HAS_TRAIT(C, TRAIT_NOMARROW)))
@@ -1103,6 +1112,7 @@
reagent_state = SOLID
color = "#F7C430" // rgb: 247, 196, 48
taste_description = "expensive metal"
material = /datum/material/gold
/datum/reagent/silver
name = "Silver"
@@ -1110,6 +1120,7 @@
reagent_state = SOLID
color = "#D0D0D0" // rgb: 208, 208, 208
taste_description = "expensive yet reasonable metal"
material = /datum/material/silver
/datum/reagent/silver/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(M.has_bane(BANE_SILVER))
@@ -1123,6 +1134,7 @@
color = "#B8B8C0" // rgb: 184, 184, 192
taste_description = "the inside of a reactor"
pH = 4
material = /datum/material/uranium
/datum/reagent/uranium/on_mob_life(mob/living/carbon/M)
M.apply_effect(1/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
@@ -1144,6 +1156,7 @@
taste_description = "fizzling blue"
pH = 12
value = REAGENT_VALUE_RARE
material = /datum/material/bluespace
/datum/reagent/bluespace/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
@@ -1182,6 +1195,7 @@
color = "#A8A8A8" // rgb: 168, 168, 168
taste_mult = 0
pH = 10
material = /datum/material/glass
/datum/reagent/fuel
name = "Welding fuel"
@@ -2206,6 +2220,66 @@
color = "#f7685e"
metabolization_rate = REAGENTS_METABOLISM * 0.25
/datum/reagent/wittel
name = "Wittel"
description = "An extremely rare metallic-white substance only found on demon-class planets."
color = "#FFFFFF" // rgb: 255, 255, 255
taste_mult = 0 // oderless and tasteless
/datum/reagent/metalgen
name = "Metalgen"
data = list("material"=null)
description = "A purple metal morphic liquid, said to impose it's metallic properties on whatever it touches."
color = "#b000aa"
taste_mult = 0 // oderless and tasteless
var/applied_material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR
var/minumum_material_amount = 100
/datum/reagent/metalgen/reaction_obj(obj/O, volume)
metal_morph(O)
return
/datum/reagent/metalgen/reaction_turf(turf/T, volume)
metal_morph(T)
return
///turn an object into a special material
/datum/reagent/metalgen/proc/metal_morph(atom/A)
var/metal_ref = data["material"]
if(!metal_ref)
return
var/metal_amount = 0
for(var/B in A.custom_materials) //list with what they're made of
metal_amount += A.custom_materials[B]
if(!metal_amount)
metal_amount = minumum_material_amount //some stuff doesn't have materials at all. To still give them properties, we give them a material. Basically doesnt exist
var/list/metal_dat = list()
metal_dat[metal_ref] = metal_amount //if we pass the list directly, byond turns metal_ref into "metal_ref" kjewrg8fwcyvf
A.material_flags = applied_material_flags
A.set_custom_materials(metal_dat)
/datum/reagent/gravitum
name = "Gravitum"
description = "A rare kind of null fluid, capable of temporalily removing all weight of whatever it touches." //i dont even
color = "#050096" // rgb: 5, 0, 150
taste_mult = 0 // oderless and tasteless
metabolization_rate = 0.1 * REAGENTS_METABOLISM //20 times as long, so it's actually viable to use
var/time_multiplier = 1 MINUTES //1 minute per unit of gravitum on objects. Seems overpowered, but the whole thing is very niche
/datum/reagent/gravitum/reaction_obj(obj/O, volume)
O.AddElement(/datum/element/forced_gravity, 0)
addtimer(CALLBACK(O, .proc/_RemoveElement, /datum/element/forced_gravity, 0), volume * time_multiplier)
/datum/reagent/gravitum/on_mob_add(mob/living/L)
L.AddElement(/datum/element/forced_gravity, 0) //0 is the gravity, and in this case weightless
/datum/reagent/gravitum/on_mob_end_metabolize(mob/living/L)
L.RemoveElement(/datum/element/forced_gravity, 0)
//body bluids
/datum/reagent/consumable/semen
@@ -2334,6 +2408,7 @@ datum/reagent/eldritch
color = "#E6E6DA"
taste_mult = 0
/datum/reagent/hairball
name = "Hairball"
description = "A bundle of keratinous bits and fibers, not easily digestible."
@@ -64,6 +64,7 @@
toxpwr = 3
pH = 4
value = REAGENT_VALUE_RARE //sheets are worth more
material = /datum/material/plasma
/datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C)
if(holder.has_reagent(/datum/reagent/medicine/epinephrine))
@@ -219,6 +219,12 @@
results = list(/datum/reagent/medicine/strange_reagent = 3)
required_reagents = list(/datum/reagent/medicine/omnizine = 1, /datum/reagent/water/holywater = 1, /datum/reagent/toxin/mutagen = 1)
/datum/chemical_reaction/strange_reagent/alt
name = "Strange Reagent"
id = /datum/reagent/medicine/strange_reagent
results = list(/datum/reagent/medicine/strange_reagent = 2)
required_reagents = list(/datum/reagent/medicine/omnizine/protozine = 1, /datum/reagent/water/holywater = 1, /datum/reagent/toxin/mutagen = 1)
/datum/chemical_reaction/mannitol
name = "Mannitol"
id = /datum/reagent/medicine/mannitol
@@ -345,4 +351,20 @@
/datum/chemical_reaction/medmesh/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/stack/medical/mesh/advanced(location)
new /obj/item/stack/medical/mesh/advanced(location)
/datum/chemical_reaction/suture
required_reagents = list(/datum/reagent/cellulose = 2, /datum/reagent/medicine/styptic_powder = 2)
/datum/chemical_reaction/suture/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/stack/medical/suture/(location)
/datum/chemical_reaction/mesh
required_reagents = list(/datum/reagent/cellulose = 2, /datum/reagent/medicine/silver_sulfadiazine = 2)
/datum/chemical_reaction/mesh/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/stack/medical/mesh/(location)
@@ -1,3 +1,34 @@
/datum/chemical_reaction/metalgen
name = "metalgen"
id = /datum/reagent/metalgen
required_reagents = list(/datum/reagent/wittel = 1, /datum/reagent/bluespace = 1, /datum/reagent/toxin/mutagen = 1)
results = list(/datum/reagent/metalgen = 1)
/datum/chemical_reaction/metalgen_imprint
name = "metalgen imprint"
id = /datum/reagent/metalgen
required_reagents = list(/datum/reagent/metalgen = 1, /datum/reagent/liquid_dark_matter = 1)
results = list(/datum/reagent/metalgen = 1)
/datum/chemical_reaction/holywater
name = "Holy Water"
id = /datum/reagent/water/holywater
results = list(/datum/reagent/water/holywater = 1)
required_reagents = list(/datum/reagent/water/hollowwater = 1)
required_catalysts = list(/datum/reagent/water/holywater = 1)
/datum/chemical_reaction/metalgen_imprint/on_reaction(datum/reagents/holder, created_volume)
var/datum/reagent/metalgen/MM = holder.get_reagent(/datum/reagent/metalgen)
for(var/datum/reagent/R in holder.reagent_list)
if(R.material && R.volume >= 40)
MM.data["material"] = R.material
holder.remove_reagent(R.type, 40)
/datum/chemical_reaction/gravitum
name = "gravitum"
id = /datum/reagent/gravitum
required_reagents = list(/datum/reagent/wittel = 1, /datum/reagent/sorium = 10)
results = list(/datum/reagent/gravitum = 10)
/datum/chemical_reaction/sterilizine
name = "Sterilizine"
@@ -711,7 +742,7 @@
/datum/chemical_reaction/slime_extractification/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
new /obj/item/slime_extract/grey(location)
// Liquid Carpets
/datum/chemical_reaction/carpet
+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//
//////////////
@@ -271,5 +304,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
@@ -105,3 +105,11 @@
build_path = /obj/item/circuitboard/machine/bloodbankgen
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
category = list ("Medical Machinery")
/datum/design/board/medipen_refiller
name = "Machine Design (Medipen Refiller)"
desc = "The circuit board for a Medipen Refiller."
id = "medipen_refiller"
build_path = /obj/item/circuitboard/machine/medipen_refiller
category = list ("Medical Machinery")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
@@ -81,6 +81,14 @@
category = list ("Hydroponics Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/board/hydroponics/auto
name = "Machine Design (Automatic Hydroponics Tray Board)"
desc = "The circuit board for an automatic hydroponics tray. GIVE ME THE PLANT, CAPTAIN."
id = "autohydrotray"
build_path = /obj/machinery/hydroponics/constructable/automagic
category = list ("Hydroponics Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_MEDICAL
/datum/design/board/monkey_recycler
name = "Machine Design (Monkey Recycler Board)"
desc = "The circuit board for a monkey recycler."
@@ -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(/datum/material/iron = 1000, /datum/material/glass = 500)
construction_time = 15
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(/datum/material/iron = 500, /datum/material/glass = 100)
construction_time = 15
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(/datum/material/iron = 1000, /datum/material/glass = 500)
construction_time = 15
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(/datum/material/iron = 5000, /datum/material/glass = 1000, /datum/material/plastic = 1000)
construction_time = 15
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(/datum/material/iron = 2000, /datum/material/glass = 1500)
construction_time = 15
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(/datum/material/iron = 1000, /datum/material/glass = 500)
construction_time = 15
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(/datum/material/plastic = 400)
construction_time = 1
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(/datum/material/iron = 750, /datum/material/glass = 250)
construction_time = 15
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(/datum/material/iron = 1000, /datum/material/glass = 500)
construction_time = 15
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(/datum/material/iron = 1000, /datum/material/glass = 500)
construction_time = 15
build_path = /obj/machinery/plumbing/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(/datum/material/iron = 400, /datum/material/glass = 400)
construction_time = 15
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(/datum/material/iron = 400, /datum/material/glass = 400)
construction_time = 15
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(/datum/material/iron = 10000, /datum/material/glass = 10000, /datum/material/plastic = 4000)
construction_time = 15
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(/datum/material/iron = 20000, /datum/material/glass = 10000, /datum/material/plastic = 20000, /datum/material/titanium = 2000, /datum/material/diamond = 800, /datum/material/gold = 2000, /datum/material/silver = 2000)
construction_time = 150
build_path = /obj/item/construction/plumbing
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
@@ -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", "medipen_refiller")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
/datum/techweb_node/advplumbing
id = "advplumbing"
display_name = "Advanced Plumbing Technology"
description = "Plumbing RCD."
prereq_ids = list("plumbing", "adv_engi")
design_ids = list("plumb_rcd", "autohydrotray")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
//////////////////////Cybernetics/////////////////////
/datum/techweb_node/surplus_limbs
+2 -1
View File
@@ -46,7 +46,8 @@
/obj/item/wrench/medical = 1,
/obj/item/storage/belt/medolier/full = 2,
/obj/item/gun/syringe/dart = 2,
/obj/item/storage/briefcase/medical = 2)
/obj/item/storage/briefcase/medical = 2,
/obj/item/plunger/reinforced = 2)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
@@ -0,0 +1,5 @@
author: "Time-Green (copypasta'd by lolman360)"
delete-after: True
changes:
- rscadd: "plumbing"
- rscadd: "automatic hydro trays"
Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

+24
View File
@@ -81,6 +81,7 @@
#include "code\__DEFINES\networks.dm"
#include "code\__DEFINES\pinpointers.dm"
#include "code\__DEFINES\pipe_construction.dm"
#include "code\__DEFINES\plumbing.dm"
#include "code\__DEFINES\pool.dm"
#include "code\__DEFINES\power.dm"
#include "code\__DEFINES\preferences.dm"
@@ -301,6 +302,7 @@
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\fail2topic.dm"
#include "code\controllers\subsystem\fire_burning.dm"
#include "code\controllers\subsystem\fluid.dm"
#include "code\controllers\subsystem\garbage.dm"
#include "code\controllers\subsystem\holodeck.dm"
#include "code\controllers\subsystem\icon_smooth.dm"
@@ -376,6 +378,7 @@
#include "code\datums\datumvars.dm"
#include "code\datums\dna.dm"
#include "code\datums\dog_fashion.dm"
#include "code\datums\ductnet.dm"
#include "code\datums\emotes.dm"
#include "code\datums\ert.dm"
#include "code\datums\explosion.dm"
@@ -489,6 +492,11 @@
#include "code\datums\components\fantasy\affix.dm"
#include "code\datums\components\fantasy\prefixes.dm"
#include "code\datums\components\fantasy\suffixes.dm"
#include "code\datums\components\plumbing\_plumbing.dm"
#include "code\datums\components\plumbing\chemical_acclimator.dm"
#include "code\datums\components\plumbing\filter.dm"
#include "code\datums\components\plumbing\reaction_chamber.dm"
#include "code\datums\components\plumbing\splitter.dm"
#include "code\datums\components\storage\storage.dm"
#include "code\datums\components\storage\ui.dm"
#include "code\datums\components\storage\concrete\_concrete.dm"
@@ -1282,6 +1290,7 @@
#include "code\game\objects\structures\crates_lockers\crates\secure.dm"
#include "code\game\objects\structures\crates_lockers\crates\wooden.dm"
#include "code\game\objects\structures\icemoon\cave_entrance.dm"
#include "code\game\objects\structures\lavaland\geyser.dm"
#include "code\game\objects\structures\lavaland\necropolis_tendril.dm"
#include "code\game\objects\structures\signs\_signs.dm"
#include "code\game\objects\structures\signs\signs_departments.dm"
@@ -2859,6 +2868,21 @@
#include "code\modules\photography\photos\album.dm"
#include "code\modules\photography\photos\frame.dm"
#include "code\modules\photography\photos\photo.dm"
#include "code\modules\plumbing\ducts.dm"
#include "code\modules\plumbing\plumbers\_plumb_machinery.dm"
#include "code\modules\plumbing\plumbers\acclimator.dm"
#include "code\modules\plumbing\plumbers\autohydro.dm"
#include "code\modules\plumbing\plumbers\bottler.dm"
#include "code\modules\plumbing\plumbers\destroyer.dm"
#include "code\modules\plumbing\plumbers\fermenter.dm"
#include "code\modules\plumbing\plumbers\filter.dm"
#include "code\modules\plumbing\plumbers\grinder_chemical.dm"
#include "code\modules\plumbing\plumbers\medipenrefill.dm"
#include "code\modules\plumbing\plumbers\pill_press.dm"
#include "code\modules\plumbing\plumbers\pumps.dm"
#include "code\modules\plumbing\plumbers\reaction_chamber.dm"
#include "code\modules\plumbing\plumbers\splitters.dm"
#include "code\modules\plumbing\plumbers\synthesizer.dm"
#include "code\modules\pool\pool_controller.dm"
#include "code\modules\pool\pool_drain.dm"
#include "code\modules\pool\pool_effects.dm"