mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-24 17:11:40 +00:00
Reagent Hoses (#7386)
* Starts work on basic reagent hose machinery. * Continue Work, Add Spray Nozzle * Tubing is craftable. * Changeling * Upkeep * TRUE
This commit is contained in:
@@ -57,3 +57,14 @@
|
||||
var/turf/simulated/S = T
|
||||
S.freeze_floor()
|
||||
return
|
||||
|
||||
/datum/reagent/modapplying/vatstabilizer
|
||||
name = "clone growth inhibitor"
|
||||
id = "vatstabilizer"
|
||||
description = "A compound produced by NanoTrasen using a secret blend of phoron and toxins to stop the rampant growth of a clone beyond intended states."
|
||||
taste_description = "sour glue"
|
||||
color = "#060501"
|
||||
metabolism = REM * 0.2
|
||||
|
||||
modifier_to_add = /datum/modifier/clone_stabilizer
|
||||
modifier_duration = 30 SECONDS
|
||||
|
||||
@@ -524,6 +524,14 @@
|
||||
reagent_state = LIQUID
|
||||
color = "#DF9FBF"
|
||||
|
||||
/datum/reagent/mineralfluid
|
||||
name = "Mineral-Rich Fluid"
|
||||
id = "mineralizedfluid"
|
||||
description = "A warm, mineral-rich fluid."
|
||||
taste_description = "salt"
|
||||
reagent_state = LIQUID
|
||||
color = "#ff205255"
|
||||
|
||||
// The opposite to healing nanites, exists to make unidentified hypos implied to have nanites not be 100% safe.
|
||||
/datum/reagent/defective_nanites
|
||||
name = "Defective Nanites"
|
||||
|
||||
@@ -120,6 +120,13 @@
|
||||
spawn(rand(30, 60))
|
||||
M.IgniteMob()
|
||||
|
||||
/datum/reagent/toxin/lead
|
||||
name = "lead"
|
||||
id = "lead"
|
||||
description = "Elemental Lead."
|
||||
color = "#273956"
|
||||
strength = 4
|
||||
|
||||
/datum/reagent/toxin/spidertoxin
|
||||
name = "Spidertoxin"
|
||||
id = "spidertoxin"
|
||||
|
||||
138
code/modules/reagents/hoses/connector.dm
Normal file
138
code/modules/reagents/hoses/connector.dm
Normal file
@@ -0,0 +1,138 @@
|
||||
|
||||
/obj/attackby(var/obj/item/O, var/mob/user)
|
||||
. = ..()
|
||||
|
||||
if(locate(/obj/item/hose_connector) in src)
|
||||
if(O.is_wirecutter())
|
||||
var/list/available_sockets = list()
|
||||
|
||||
for(var/obj/item/hose_connector/HC in src)
|
||||
if(HC.my_hose)
|
||||
available_sockets |= HC
|
||||
|
||||
if(LAZYLEN(available_sockets))
|
||||
if(available_sockets.len == 1)
|
||||
var/obj/item/hose_connector/AC = available_sockets[1]
|
||||
var/choice = alert("Are you sure you want to disconnect [AC]?", "Confirm", "Yes", "No")
|
||||
|
||||
if(choice == "Yes" && Adjacent(user))
|
||||
visible_message("[user] disconnects \the hose from \the [src].")
|
||||
AC.my_hose.disconnect()
|
||||
return
|
||||
|
||||
else
|
||||
|
||||
var/choice = input("Select a target hose connector.", "Socket Disconnect", null) as null|anything in available_sockets
|
||||
|
||||
if(choice)
|
||||
var/obj/item/hose_connector/AC = choice
|
||||
var/confirm = alert("Are you sure you want to disconnect [AC]?", "Confirm", "Yes", "No")
|
||||
|
||||
if(confirm == "Yes" && Adjacent(user))
|
||||
visible_message("[user] disconnects \the hose from \the [src].")
|
||||
AC.my_hose.disconnect()
|
||||
|
||||
return
|
||||
|
||||
/obj/item/hose_connector
|
||||
name = "hose connector"
|
||||
desc = "A socket for a hose. It.. doesn't do anything on its own."
|
||||
|
||||
var/obj/carrier = null
|
||||
|
||||
var/flow_direction = HOSE_NEUTRAL
|
||||
|
||||
var/datum/hose/my_hose = null
|
||||
|
||||
/obj/item/hose_connector/Destroy()
|
||||
if(my_hose)
|
||||
my_hose.disconnect()
|
||||
my_hose = null
|
||||
if(carrier)
|
||||
carrier = null
|
||||
..()
|
||||
|
||||
/obj/item/hose_connector/Initialize()
|
||||
..()
|
||||
|
||||
create_reagents(100)
|
||||
|
||||
if(!istype(loc, /turf))
|
||||
name = "[flow_direction] hose connector ([loc])"
|
||||
|
||||
/obj/item/hose_connector/proc/valid_connection(var/obj/item/hose_connector/C)
|
||||
if(istype(C))
|
||||
if(C.my_hose)
|
||||
return FALSE
|
||||
|
||||
if(C.flow_direction in list(HOSE_INPUT, HOSE_OUTPUT) - flow_direction)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/hose_connector/proc/disconnect()
|
||||
my_hose = null
|
||||
|
||||
/obj/item/hose_connector/proc/connect(var/datum/hose/H = null)
|
||||
if(istype(H))
|
||||
my_hose = H
|
||||
|
||||
/obj/item/hose_connector/proc/setup_hoses(var/obj/item/hose_connector/target)
|
||||
if(target)
|
||||
var/datum/hose/H = new()
|
||||
|
||||
H.set_hose(src, target)
|
||||
|
||||
/obj/item/hose_connector/proc/get_pairing()
|
||||
if(my_hose)
|
||||
return my_hose.get_pairing(src)
|
||||
|
||||
return
|
||||
|
||||
/*
|
||||
* Subtypes
|
||||
*/
|
||||
|
||||
/obj/item/hose_connector/input
|
||||
name = "hose input"
|
||||
flow_direction = HOSE_INPUT
|
||||
|
||||
/obj/item/hose_connector/input/active
|
||||
name = "active hose"
|
||||
|
||||
/obj/item/hose_connector/input/active/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
..()
|
||||
|
||||
/obj/item/hose_connector/input/active/Initialize()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
if(!isturf(loc))
|
||||
carrier = loc
|
||||
|
||||
/obj/item/hose_connector/input/active/process()
|
||||
if(carrier)
|
||||
reagents.trans_to_obj(carrier, reagents.maximum_volume)
|
||||
|
||||
/obj/item/hose_connector/output
|
||||
name = "hose output"
|
||||
flow_direction = HOSE_OUTPUT
|
||||
|
||||
/obj/item/hose_connector/output/active
|
||||
name = "active hose"
|
||||
|
||||
/obj/item/hose_connector/output/active/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
..()
|
||||
|
||||
/obj/item/hose_connector/output/active/Initialize()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
if(!isturf(loc))
|
||||
carrier = loc
|
||||
|
||||
/obj/item/hose_connector/output/active/process()
|
||||
if(carrier)
|
||||
carrier.reagents.trans_to_holder(reagents, reagents.maximum_volume)
|
||||
113
code/modules/reagents/hoses/hose.dm
Normal file
113
code/modules/reagents/hoses/hose.dm
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
GLOBAL_LIST_EMPTY(hoses)
|
||||
|
||||
/obj/effect/ebeam/hose
|
||||
plane = OBJ_PLANE
|
||||
layer = STAIRS_LAYER
|
||||
|
||||
/datum/hose
|
||||
var/name = "hose"
|
||||
|
||||
var/obj/item/hose_connector/node1 = null
|
||||
var/obj/item/hose_connector/node2 = null
|
||||
|
||||
var/hose_color = "#ffffff"
|
||||
|
||||
var/initial_distance = 7
|
||||
|
||||
var/datum/beam/hose = null
|
||||
|
||||
/datum/hose/proc/get_pairing(var/obj/item/hose_connector/target)
|
||||
if(target)
|
||||
if(target == node1)
|
||||
return node2
|
||||
else if(target == node2)
|
||||
return node1
|
||||
|
||||
return
|
||||
|
||||
/datum/hose/proc/disconnect()
|
||||
if(node1)
|
||||
node1.disconnect()
|
||||
node1 = null
|
||||
if(node2)
|
||||
node2.disconnect()
|
||||
node2 = null
|
||||
|
||||
/datum/hose/proc/set_hose(var/obj/item/hose_connector/target1, var/obj/item/hose_connector/target2)
|
||||
if(target1 && target2)
|
||||
node1 = target1
|
||||
node2 = target2
|
||||
|
||||
node1.connect(src)
|
||||
node2.connect(src)
|
||||
|
||||
name = "[name] ([node1],[node2])"
|
||||
|
||||
initial_distance = get_dist(get_turf(node1), get_turf(node2))
|
||||
|
||||
GLOB.hoses |= src
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/hose/process()
|
||||
if(node1 && node2)
|
||||
if(get_dist(get_turf(node1), get_turf(node2)) > 0)
|
||||
hose = node1.loc.Beam(node2.loc, icon_state = "hose", beam_color = hose_color, maxdistance = world.view, beam_type = /obj/effect/ebeam/hose)
|
||||
|
||||
if(!hose || get_dist(get_turf(node1), get_turf(node2)) > initial_distance) // The hose didn't form. Something's fucky.
|
||||
disconnect()
|
||||
return
|
||||
|
||||
var/datum/reagents/reagent_node1 = node1.reagents
|
||||
var/datum/reagents/reagent_node2 = node2.reagents
|
||||
|
||||
switch(node1.flow_direction) // Node 1 is the default 'master', interactions are considered in all current possible states in regards to it, however.
|
||||
if(HOSE_INPUT)
|
||||
if(node2.flow_direction == HOSE_NEUTRAL) // We're input, they're neutral. Take half of our volume.
|
||||
reagent_node2.trans_to_holder(reagent_node1, reagent_node1.maximum_volume / 2)
|
||||
else if(node2.flow_direction == HOSE_OUTPUT) // We're input, they're output. Take all of our volume.
|
||||
reagent_node2.trans_to_holder(reagent_node1, reagent_node1.maximum_volume)
|
||||
|
||||
if(HOSE_OUTPUT) // We're output, give all of their maximum volume.
|
||||
reagent_node1.trans_to_holder(reagent_node2, reagent_node2.maximum_volume)
|
||||
|
||||
if(HOSE_NEUTRAL)
|
||||
switch(node2.flow_direction)
|
||||
if(HOSE_INPUT) // We're neutral, they're input. Give them half of their volume.
|
||||
reagent_node1.trans_to_holder(reagent_node2, reagent_node2.maximum_volume / 2)
|
||||
|
||||
if(HOSE_NEUTRAL) // We're neutral, they're neutral. Balance our values.
|
||||
var/volume_difference_perc = (reagent_node1.total_volume / reagent_node1.maximum_volume) - (reagent_node2.total_volume / reagent_node2.maximum_volume)
|
||||
var/volume_difference = 0
|
||||
|
||||
var/pulling = FALSE
|
||||
if(volume_difference_perc > 0) // They are smaller, so they determine the transfer amount. Half of the difference will equalize.
|
||||
volume_difference = reagent_node2.maximum_volume * volume_difference_perc / 2
|
||||
|
||||
else if(volume_difference_perc < 0) // We're smaller, so we determine the transfer amount. Half of the difference will equalize.
|
||||
volume_difference_perc *= -1
|
||||
|
||||
pulling = TRUE
|
||||
|
||||
volume_difference = reagent_node1.maximum_volume * volume_difference_perc / 2
|
||||
|
||||
if(volume_difference)
|
||||
if(pulling)
|
||||
reagent_node2.trans_to_holder(reagent_node1, volume_difference)
|
||||
else
|
||||
reagent_node1.trans_to_holder(reagent_node2, volume_difference)
|
||||
|
||||
if(HOSE_OUTPUT)
|
||||
reagent_node2.trans_to_holder(reagent_node1, reagent_node2.maximum_volume)
|
||||
|
||||
else
|
||||
if(node1)
|
||||
node1.disconnect()
|
||||
node1 = null
|
||||
if(node2)
|
||||
node2.disconnect()
|
||||
node2 = null
|
||||
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
GLOB.hoses -= src
|
||||
qdel(src)
|
||||
92
code/modules/reagents/hoses/hose_connector.dm
Normal file
92
code/modules/reagents/hoses/hose_connector.dm
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
/obj/item/stack/hose
|
||||
name = "plastic tubing"
|
||||
singular_name = "plastic tube"
|
||||
desc = "A non-reusable plastic tube for moving reagents to and fro. It looks flimsy."
|
||||
|
||||
description_info = "This tubing may be used to join two hose sockets, if able.<br>\
|
||||
Clicking on an object with a connector, such as a water tank, will display a list of possible sockets.<br>\
|
||||
Neutral can link to all socket types, and Input/Output sockets can link to all but their own type.<br><br>\
|
||||
<span class='warning'>This hose does not stretch. The maximum distance you can move two objects from eachother\
|
||||
without snapping the tube is determined by distance upon connection.</span>"
|
||||
|
||||
icon = 'icons/obj/machines/reagent.dmi'
|
||||
icon_state = "hose"
|
||||
origin_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 1)
|
||||
amount = 1
|
||||
w_class = ITEMSIZE_SMALL
|
||||
no_variants = TRUE
|
||||
|
||||
var/obj/item/hose_connector/remembered = null
|
||||
|
||||
/obj/item/stack/hose/Destroy()
|
||||
remembered = null
|
||||
..()
|
||||
|
||||
/obj/item/stack/hose/CtrlClick(mob/user)
|
||||
if(remembered)
|
||||
to_chat(user, "<span class='notice'>You wind \the [src] back up.</span>")
|
||||
remembered = null
|
||||
return
|
||||
|
||||
/obj/item/stack/hose/afterattack(var/atom/target, var/mob/living/user, proximity, params)
|
||||
if(!proximity)
|
||||
return
|
||||
|
||||
var/list/available_sockets = list()
|
||||
|
||||
for(var/obj/item/hose_connector/HC in target.contents)
|
||||
if(!HC.my_hose)
|
||||
if(remembered)
|
||||
if(HC.flow_direction == HOSE_NEUTRAL || HC.flow_direction != remembered.flow_direction)
|
||||
available_sockets |= HC
|
||||
|
||||
else
|
||||
available_sockets |= HC
|
||||
|
||||
if(LAZYLEN(available_sockets))
|
||||
if(available_sockets.len == 1)
|
||||
var/obj/item/hose_connector/AC = available_sockets[1]
|
||||
if(remembered && remembered.valid_connection(AC))
|
||||
var/distancetonode = get_dist(remembered,AC)
|
||||
if(distancetonode > world.view)
|
||||
to_chat(user, "<span class='notice'>\The [src] would probably burst if it were this long.</span>")
|
||||
else if(distancetonode <= amount)
|
||||
to_chat(user, "<span class='notice'>You join \the [remembered] to \the [AC]")
|
||||
remembered.setup_hoses(AC)
|
||||
use(distancetonode)
|
||||
remembered = null
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You do not have enough tubing to connect the sockets.</span>")
|
||||
|
||||
else
|
||||
remembered = AC
|
||||
to_chat(user, "<span class='notice'>You connect one end of tubing to \the [AC].</span>")
|
||||
|
||||
else
|
||||
var/choice = input("Select a target hose connector.", "Socket Selection", null) as null|anything in available_sockets
|
||||
|
||||
if(choice)
|
||||
var/obj/item/hose_connector/CC = choice
|
||||
if(remembered)
|
||||
if(remembered.valid_connection(CC))
|
||||
var/distancetonode = get_dist(remembered, CC)
|
||||
if(distancetonode > world.view)
|
||||
to_chat(user, "<span class='notice'>\The [src] would probably burst if it were this long.</span>")
|
||||
else if(distancetonode <= amount)
|
||||
to_chat(user, "<span class='notice'>You join \the [remembered] to \the [CC]")
|
||||
remembered.setup_hoses(CC)
|
||||
use(distancetonode)
|
||||
remembered = null
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You do not have enough tubing to connect the sockets.</span>")
|
||||
|
||||
else
|
||||
remembered = CC
|
||||
to_chat(user, "<span class='notice'>You connect one end of tubing to \the [CC].</span>")
|
||||
|
||||
return
|
||||
|
||||
else
|
||||
..()
|
||||
@@ -204,4 +204,97 @@
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/plantbgone/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent("plantbgone", 100)
|
||||
reagents.add_reagent("plantbgone", 100)
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed
|
||||
name = "hose nozzle"
|
||||
desc = "A heavy spray nozzle that must be attached to a hose."
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "cleaner-industrial"
|
||||
item_state = "cleaner"
|
||||
center_of_mass = list("x" = 16,"y" = 10)
|
||||
|
||||
possible_transfer_amounts = list(5,10,20)
|
||||
|
||||
var/heavy_spray = FALSE
|
||||
var/spray_particles = 3
|
||||
|
||||
var/icon/hose_overlay
|
||||
|
||||
var/obj/item/hose_connector/input/active/InputSocket
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/Initialize()
|
||||
..()
|
||||
|
||||
InputSocket = new(src)
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/update_icon()
|
||||
..()
|
||||
|
||||
overlays.Cut()
|
||||
|
||||
if(!hose_overlay)
|
||||
hose_overlay = new icon(icon, "[icon_state]+hose")
|
||||
|
||||
if(InputSocket.get_pairing())
|
||||
add_overlay(hose_overlay)
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/AltClick(mob/living/carbon/user)
|
||||
if(++spray_particles > 3) spray_particles = 1
|
||||
|
||||
to_chat(user, "<span class='notice'>You turn the dial on \the [src] to [spray_particles].</span>")
|
||||
return
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/CtrlClick(var/mob/user)
|
||||
if(loc != get_turf(src))
|
||||
heavy_spray = !heavy_spray
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/chemsprayer/hosed/Spray_at(atom/A as mob|obj)
|
||||
update_icon()
|
||||
|
||||
var/direction = get_dir(src, A)
|
||||
var/turf/T = get_turf(A)
|
||||
var/turf/T1 = get_step(T,turn(direction, 90))
|
||||
var/turf/T2 = get_step(T,turn(direction, -90))
|
||||
var/list/the_targets = list(T, T1, T2)
|
||||
|
||||
if(src.reagents.total_volume < 1)
|
||||
to_chat(usr, "<span class='notice'>\The [src] is empty.</span>")
|
||||
return
|
||||
|
||||
if(!heavy_spray)
|
||||
for(var/a = 1 to 3)
|
||||
spawn(0)
|
||||
if(reagents.total_volume < 1) break
|
||||
playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src))
|
||||
var/turf/my_target = the_targets[a]
|
||||
D.create_reagents(amount_per_transfer_from_this)
|
||||
if(!src)
|
||||
return
|
||||
reagents.trans_to_obj(D, amount_per_transfer_from_this)
|
||||
D.set_color()
|
||||
D.set_up(my_target, rand(6, 8), 2)
|
||||
return
|
||||
|
||||
else
|
||||
playsound(src, 'sound/effects/extinguish.ogg', 75, 1, -3)
|
||||
|
||||
for(var/a = 1 to spray_particles)
|
||||
spawn(0)
|
||||
if(!src || !reagents.total_volume) return
|
||||
|
||||
var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(src))
|
||||
var/turf/my_target
|
||||
if(a <= the_targets.len)
|
||||
my_target = the_targets[a]
|
||||
else
|
||||
my_target = pick(the_targets)
|
||||
W.create_reagents(amount_per_transfer_from_this)
|
||||
reagents.trans_to_obj(W, amount_per_transfer_from_this)
|
||||
W.set_color()
|
||||
W.set_up(my_target)
|
||||
|
||||
return
|
||||
|
||||
@@ -10,18 +10,33 @@
|
||||
anchored = 0
|
||||
pressure_resistance = 2*ONE_ATMOSPHERE
|
||||
|
||||
var/obj/item/hose_connector/input/active/InputSocket
|
||||
var/obj/item/hose_connector/output/active/OutputSocket
|
||||
|
||||
var/amount_per_transfer_from_this = 10
|
||||
var/possible_transfer_amounts = list(10,25,50,100)
|
||||
|
||||
attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
/obj/structure/reagent_dispensers/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/structure/reagent_dispensers/Destroy()
|
||||
QDEL_NULL(InputSocket)
|
||||
QDEL_NULL(OutputSocket)
|
||||
|
||||
..()
|
||||
|
||||
/obj/structure/reagent_dispensers/Initialize()
|
||||
var/datum/reagents/R = new/datum/reagents(5000)
|
||||
reagents = R
|
||||
R.my_atom = src
|
||||
if (!possible_transfer_amounts)
|
||||
src.verbs -= /obj/structure/reagent_dispensers/verb/set_APTFT
|
||||
|
||||
InputSocket = new(src)
|
||||
InputSocket.carrier = src
|
||||
OutputSocket = new(src)
|
||||
OutputSocket.carrier = src
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/structure/reagent_dispensers/examine(mob/user)
|
||||
|
||||
Reference in New Issue
Block a user