diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm
index 0bad588e678..7a8151ef7fd 100644
--- a/code/__defines/flags.dm
+++ b/code/__defines/flags.dm
@@ -32,6 +32,9 @@
/// This atom is queued for an overlay update.
#define ATOM_AWAITING_OVERLAY_UPDATE (1<<5)
+///The Reagent cannot be refilled
+#define ATOM_REAGENTS_NO_REFILL (1<<6)
+
/* -- /turf/var/turf_flags -- */
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index e63a02358aa..9e59e0f1ae3 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -129,6 +129,9 @@ var/global/list/pre_init_created_atoms // atom creation ordering means some stuf
/atom/proc/is_open_container()
return atom_flags & ATOM_REAGENTS_IS_OPEN
+/atom/proc/can_refill()
+ return atom_flags & ~ATOM_REAGENTS_NO_REFILL
+
/*//Convenience proc to see whether a container can be accessed in a certain way.
proc/can_subract_container()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index a7ca3385ce0..93f81f97900 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -113,6 +113,9 @@ Class Procs:
var/obj/item/circuitboard/circuit = null
var/list/materials = list() //Exclusively used for machines that take materials - lathes, fabricators etc. Honestly overdue for a whole lathe/fab refactor at some point.
+ var/anchor_type = null //What type of object can be anchored to a machine
+ var/anchor_direction = null //The immediate directions an object can be anchored to a machine. If null, any direction is allowed.
+
var/speed_process = FALSE //If false, SSmachines. If true, SSfastprocess.
required_dexterity = MOB_DEXTERITY_TOUCHSCREENS
@@ -486,4 +489,4 @@ Class Procs:
S.amount = round(materials[mat] / S.perunit)
else
qdel(S) //Prevents stacks smaller than 1
- return
\ No newline at end of file
+ return
diff --git a/code/modules/reagents/machinery/dispenser/reagent_tank.dm b/code/modules/reagents/machinery/dispenser/reagent_tank.dm
index bfe7dc58114..ae8cdc6a36d 100644
--- a/code/modules/reagents/machinery/dispenser/reagent_tank.dm
+++ b/code/modules/reagents/machinery/dispenser/reagent_tank.dm
@@ -10,9 +10,12 @@
anchored = 0
pressure_resistance = 2*ONE_ATMOSPHERE
+ var/volume = 5000
+
+ var/has_hose = TRUE
var/obj/item/hose_connector/input/active/InputSocket
var/obj/item/hose_connector/output/active/OutputSocket
-
+ atom_flags = ATOM_REAGENTS_NO_REFILL
var/amount_per_transfer_from_this = 10
var/possible_transfer_amounts = list(10,25,50,100)
@@ -20,25 +23,28 @@
src.add_fingerprint(user)
/obj/structure/reagent_dispensers/Destroy()
- QDEL_NULL(InputSocket)
- QDEL_NULL(OutputSocket)
+ if(has_hose)
+ QDEL_NULL(InputSocket)
+ QDEL_NULL(OutputSocket)
..()
/obj/structure/reagent_dispensers/Initialize()
- var/datum/reagents/R = new/datum/reagents(5000)
+ var/datum/reagents/R = new/datum/reagents(volume)
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
-
+ if(has_hose)
+ InputSocket = new(src)
+ InputSocket.carrier = src
+ OutputSocket = new(src)
+ OutputSocket.carrier = src
. = ..()
+
+
/obj/structure/reagent_dispensers/examine(mob/user)
. = ..()
if(get_dist(user, src) <= 2)
@@ -57,6 +63,9 @@
if (N)
amount_per_transfer_from_this = N
+/obj/structure/reagent_dispensers/blob_act()
+ qdel(src)
+
/obj/structure/reagent_dispensers/ex_act(severity)
switch(severity)
if(1.0)
@@ -75,8 +84,6 @@
else
return
-/obj/structure/reagent_dispensers/blob_act()
- qdel(src)
diff --git a/code/modules/reagents/reagent_containers/_reagent_containers.dm b/code/modules/reagents/reagent_containers/_reagent_containers.dm
index 322fe5389dc..078e4fb2002 100644
--- a/code/modules/reagents/reagent_containers/_reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers/_reagent_containers.dm
@@ -22,6 +22,9 @@
src.verbs -= /obj/item/reagent_containers/verb/set_APTFT
create_reagents(volume)
+/obj/item/reagent_containers/on_reagent_change()
+ update_icon()
+
/obj/item/reagent_containers/attack_self(mob/user as mob)
return
@@ -38,12 +41,14 @@
return 0
if(!target.reagents || !target.reagents.total_volume)
- to_chat(user, "[target] is empty.")
- return 1
+ if(target.can_refill())
+ return 0
+ else
+ to_chat(user, "[target] is empty.")
+ return 1
if(reagents && !reagents.get_free_space())
- to_chat(user, "[src] is full.")
- return 1
+ return 0
var/trans = target.reagents.trans_to_obj(src, target:amount_per_transfer_from_this)
to_chat(user, "You fill [src] with [trans] units of the contents of [target].")
@@ -98,12 +103,12 @@
return FALSE
user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
- if(user == target)
+ if(user == target)
self_feed_message(user)
reagents.trans_to_mob(user, issmall(user) ? CEILING(amount_per_transfer_from_this/2, 1) : amount_per_transfer_from_this, CHEM_INGEST)
feed_sound(user)
return TRUE
-
+
else
other_feed_message_start(user, target)
if(!do_mob(user, target))
@@ -116,8 +121,8 @@
feed_sound(user)
return TRUE
-/obj/item/reagent_containers/proc/standard_pour_into(var/mob/user, var/atom/target) // This goes into afterattack and yes, it's atom-level
- if(!target.is_open_container() || !target.reagents)
+/obj/item/reagent_containers/proc/standard_pour_into(var/mob/user, var/atom/target, var/pour_all = FALSE) // This goes into afterattack and yes, it's atom-level
+ if(!target.is_open_container() || !target.reagents || !target.can_refill())
return 0
if(!reagents || !reagents.total_volume)
@@ -128,6 +133,7 @@
to_chat(user, "[target] is full.")
return 1
- var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
+ var/trans = pour_all ? reagents.total_volume : amount_per_transfer_from_this
+ trans = reagents.trans_to(target, trans)
to_chat(user, "You transfer [trans] units of the solution to [target].")
return 1
diff --git a/code/modules/reagents/reagent_containers/bidon.dm b/code/modules/reagents/reagent_containers/bidon.dm
new file mode 100644
index 00000000000..c9cf0ff0881
--- /dev/null
+++ b/code/modules/reagents/reagent_containers/bidon.dm
@@ -0,0 +1,163 @@
+
+//this is big movable beaker
+/obj/structure/reagent_dispensers/bidon
+ name = "B.I.D.O.N. canister"
+ desc = "Banded Industrial Drum for Organic Nonvolatiles. A canister with acid-resistant linings intended for handling big volumes of chemicals."
+ icon = 'icons/obj/machines/chemistry.dmi'
+ icon_state = "bidon"
+ amount_per_transfer_from_this = 30
+ possible_transfer_amounts = list(10,30,60,120,200,300)
+ var/filling_states = list(10,20,30,40,50,60,70,80,100)
+ unacidable = 1
+ anchored = 0
+ var/obj/machinery/anchored_machine
+ density = TRUE
+ volume = 6000
+ var/lid = TRUE
+ var/starting_reagent
+ var/starting_volume = 0
+ has_hose=FALSE
+ atom_flags = EMPTY_BITFIELD
+
+/obj/structure/reagent_dispensers/bidon/Initialize()
+ . = ..()
+ if(starting_reagent && starting_volume)
+ reagents.add_reagent(starting_reagent, starting_volume)
+
+/obj/structure/reagent_dispensers/bidon/advanced
+ name = "stasis B.I.D.O.N. canister"
+ desc = "An advanced B.I.D.O.N. canister with stasis function."
+ icon_state = "bidon_adv"
+ atom_flags = ATOM_REAGENTS_SKIP_REACTIONS // It's a stasis BIDON, shouldn't allow chems to react inside it.
+ filling_states = list(20,40,60,80,100)
+ volume = 9000
+
+/obj/structure/reagent_dispensers/bidon/trigger
+ name = "trigger-stasis B.I.D.O.N. canister"
+ desc = "An advanced B.I.D.O.N. canister with a stasis function that can be temporarily disabled with a multitool."
+ icon_state = "bidon_adv"
+ atom_flags = ATOM_REAGENTS_SKIP_REACTIONS //Tho its not a subtype its meant to be
+ filling_states = list(20,40,60,80,100)
+ volume = 9000
+ var/timer_till_mixing = 120
+ var/timing = FALSE
+
+/obj/structure/reagent_dispensers/bidon/trigger/examine(mob/user)
+ . = ..()
+ if(timing)
+ to_chat(user, SPAN_DANGER("[timer_till_mixing] seconds until stasis is disabled."))
+ else
+ to_chat(user, SPAN_NOTICE("[src]'s timer isn't activated."))
+
+/obj/structure/reagent_dispensers/bidon/trigger/attackby(obj/item/I, mob/user)
+ if(!timing)
+ if(I.is_multitool())
+ timing=TRUE
+ to_chat(user, SPAN_NOTICE("You start the timer."))
+ addtimer(CALLBACK(src, ./proc/timer_end), (1 SECOND * timer_till_mixing))
+ timing=FALSE
+ return
+ else
+ . = ..()
+ update_icon()
+
+/obj/structure/reagent_dispensers/bidon/trigger/proc/timer_end()
+ atom_flags &= ~(ATOM_REAGENTS_SKIP_REACTIONS)
+ reagents.handle_reactions()
+ atom_flags |= ATOM_REAGENTS_SKIP_REACTIONS
+
+
+/obj/structure/reagent_dispensers/bidon/Initialize(mapload, ...)
+ . = ..()
+ update_icon()
+
+/obj/structure/reagent_dispensers/bidon/examine(mob/user)
+ . = ..()
+ if(get_dist(user, src) <= 2)
+ if(lid)
+ . += "It has lid on it."
+ if(reagents.total_volume)
+ . += "It's filled with [reagents.total_volume]/[volume] units of reagents."
+
+/obj/structure/reagent_dispensers/bidon/attack_hand(mob/user as mob)
+ //Prevent the bidon from being messed with while it is anchored.
+ if(anchored)
+ to_chat(user, SPAN_NOTICE("You can't remove the lid while the canister is anchored!"))
+ return
+ lid = !lid
+ if(lid)
+ to_chat(user, SPAN_NOTICE("You put the lid on."))
+ atom_flags &= ~(ATOM_REAGENTS_IS_OPEN)
+ else
+ atom_flags |= ATOM_REAGENTS_IS_OPEN
+ to_chat(user, SPAN_NOTICE("You removed the lid."))
+ playsound(src,'sound/items/trayhit2.ogg',50,1)
+ update_icon()
+
+/obj/structure/reagent_dispensers/bidon/attackby(obj/item/I, mob/user)
+
+ //Handle attaching the BIDON to a valid machine, should one exist
+ if(I.is_wrench())
+ if(anchored)
+ anchored = FALSE
+ anchored_machine = null
+ playsound(src, I.usesound, 50, 1)
+ else
+ var/list/directions = list(WEST, NORTH, SOUTH, EAST)
+ for(var/direction_from_obj in directions)
+ for (var/obj/machinery/valid_machine in get_step(get_turf(src), direction_from_obj))
+ if(ispath(valid_machine.anchor_type) && istype(src, valid_machine.anchor_type))
+ if(valid_machine.anchor_direction)
+ if(valid_machine.anchor_direction == reverse_direction(direction_from_obj))
+ anchored_machine = valid_machine
+ break
+ else
+ anchored_machine = valid_machine
+ break
+ if(anchored_machine)
+ to_chat(user, SPAN_NOTICE("You [anchored ? "detach" : "attach"] the B.I.D.O.N canister to the [anchored_machine]."))
+ anchored = TRUE
+ playsound(src, I.usesound, 50, 1)
+ //Remove the lid if it is currently sealed, so we don't have to deal with checking for it
+ if(lid)
+ to_chat(user, SPAN_NOTICE("The machine removes the lid automatically!"))
+ lid = FALSE
+ atom_flags |= ATOM_REAGENTS_IS_OPEN
+ playsound(src,'sound/items/trayhit2.ogg',50,1)
+ else if(lid)
+ to_chat(user, SPAN_NOTICE("Remove the lid first."))
+ return
+ . = ..()
+ update_icon()
+
+/obj/structure/reagent_dispensers/bidon/update_icon()
+ cut_overlays()
+ if(lid)
+ var/mutable_appearance/lid_icon = mutable_appearance(icon, "[icon_state]_lid")
+ add_overlay(lid_icon)
+ if(anchored)
+ var/mutable_appearance/anchor_icon = mutable_appearance(icon, "bidon_anchored")
+ add_overlay(anchor_icon)
+ if(reagents.total_volume)
+ var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "[icon_state][get_filling_state()]")
+ if(!istype(src,/obj/structure/reagent_dispensers/bidon/advanced))
+ filling.color = reagents.get_color()
+ add_overlay(filling)
+
+/obj/structure/reagent_dispensers/bidon/proc/get_filling_state()
+ var/percent = round((reagents.total_volume / volume) * 100)
+ for(var/increment in filling_states)
+ if(increment >= percent)
+ return increment
+
+/obj/structure/reagent_dispensers/bidon/advanced/examine(mob/user)
+ . = ..()
+ if(reagents.reagent_list.len && get_dist(user, src) <= 2)
+ for(var/I in reagents.reagent_list)
+ var/datum/reagent/R = I
+ . += "[R.volume] units of [R.name]"
+
+//Department starting protein to get the process off the ground
+/obj/structure/reagent_dispensers/bidon/protein_can/si
+ starting_reagent = "protein"
+ starting_volume = 1000
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index ad6877fd37f..0c020de9992 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -106,10 +106,18 @@
for(var/type in can_be_placed_into) //Is it something it can be placed into?
if(istype(target, type))
return 1
+
+
+ //Disarm intent tries to empty the beaker
+ if(user.a_intent == I_DISARM && standard_pour_into(user, target, TRUE))
+ return TRUE
+
if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser?
return 1
+
if(standard_pour_into(user, target)) //Pouring into another beaker?
return
+
if(user.a_intent == I_HURT)
if(standard_splash_mob(user,target))
return 1
diff --git a/code/modules/research/designs/bio_devices.dm b/code/modules/research/designs/bio_devices.dm
index f3aa33845ff..3ab18846b3f 100644
--- a/code/modules/research/designs/bio_devices.dm
+++ b/code/modules/research/designs/bio_devices.dm
@@ -59,3 +59,26 @@
build_path = /obj/item/analyzer/plant_analyzer
sort_string = "JAADA"
+/datum/design/item/biotech/bidon
+ desc = "A lumbering metal drum used to hold large amounts of chemicals."
+ id = "bidon"
+ req_tech = list(TECH_MATERIAL = 4, TECH_BIO = 4)
+ materials = list(MAT_STEEL = 2000, "glass" = 1000)
+ build_path = /obj/structure/reagent_dispensers/bidon
+ sort_string = "IAAAC"
+
+/datum/design/item/biotech/advanced_bidon
+ desc = "A lumbering metal drum used to hold large amounts of chemicals in sustained cryostasis."
+ id = "advanced_bidon"
+ req_tech = list(TECH_MATERIAL = 6, TECH_BIO = 4, TECH_DATA = 5)
+ materials = list(MAT_STEEL = 2000, "glass" = 1000, MAT_SILVER = 100)
+ build_path = /obj/structure/reagent_dispensers/bidon/advanced
+ sort_string = "IAAAD"
+
+/datum/design/item/biotech/trigger_bidon
+ desc = "A dubiously legal metal drum that can be triggered to mix all of its contents at the same time."
+ id = "trigger_bidon"
+ req_tech = list(TECH_MATERIAL = 6, TECH_BIO = 4, TECH_DATA = 5, TECH_ILLEGAL = 3)
+ materials = list(MAT_STEEL = 2000, "glass" = 1000, MAT_GOLD = 500)
+ build_path = /obj/structure/reagent_dispensers/bidon/trigger
+ sort_string = "IAAAE"
diff --git a/icons/obj/machines/chemistry.dmi b/icons/obj/machines/chemistry.dmi
new file mode 100644
index 00000000000..ccab439b84e
Binary files /dev/null and b/icons/obj/machines/chemistry.dmi differ
diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi
index ab553f5f922..34ea6e3112b 100644
Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ
diff --git a/polaris.dme b/polaris.dme
index be8eeacc525..b16e0aac039 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -2983,6 +2983,7 @@
#include "code\modules\reagents\reactions\instant\instant.dm"
#include "code\modules\reagents\reactions\instant\vox.dm"
#include "code\modules\reagents\reagent_containers\_reagent_containers.dm"
+#include "code\modules\reagents\reagent_containers\bidon.dm"
#include "code\modules\reagents\reagent_containers\blood_pack.dm"
#include "code\modules\reagents\reagent_containers\borghypo.dm"
#include "code\modules\reagents\reagent_containers\dropper.dm"