diff --git a/code/modules/integrated_electronics/input_output.dm b/code/modules/integrated_electronics/input_output.dm
index d94bfa32da..5196617a83 100644
--- a/code/modules/integrated_electronics/input_output.dm
+++ b/code/modules/integrated_electronics/input_output.dm
@@ -150,6 +150,38 @@
O.push_data()
+/obj/item/integrated_circuit/input/adjacent_locator
+ name = "adjacent locator"
+ desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \
+ that is standing a meter away from the machine."
+ extended_desc = "The first pin requires a ref to a kind of object that you want the locator to acquire. This means that it will \
+ give refs to nearby objects that are similar. If more than one valid object is found nearby, it will choose one of them at \
+ random."
+ inputs = list("desired type ref")
+ outputs = list("located ref")
+ activators = list("locate")
+
+/obj/item/integrated_circuit/input/adjacent_locator/do_work()
+ var/datum/integrated_io/I = inputs[1]
+ var/datum/integrated_io/O = outputs[1]
+ O.data = null
+
+ if(!isweakref(I.data))
+ return
+ var/weakref/w = I.data
+ var/atom/A = w.resolve()
+ var/desired_type = A.type
+
+ var/list/nearby_things = range(1, get_turf(src))
+ var/list/valid_things = list()
+ for(var/atom/thing in nearby_things)
+ if(thing.type != desired_type)
+ continue
+ valid_things.Add(thing)
+ if(valid_things.len)
+ O.data = weakref(pick(valid_things))
+ O.push_data()
+
/obj/item/integrated_circuit/input/signaler
name = "integrated signaler"
desc = "Signals from a signaler can be received with this, allowing for remote control. Additionally, it can send signals as well."
diff --git a/code/modules/integrated_electronics/manipulation.dm b/code/modules/integrated_electronics/manipulation.dm
index c9b10f4647..1fac6ba19c 100644
--- a/code/modules/integrated_electronics/manipulation.dm
+++ b/code/modules/integrated_electronics/manipulation.dm
@@ -111,6 +111,140 @@
smoke_system.start()
reagents.clear_reagents()
+/obj/item/integrated_circuit/manipulation/injector
+ name = "integrated hypo-injector"
+ desc = "This scary looking thing is able to pump liquids into whatever it's pointed at."
+ icon_state = "injector"
+ extended_desc = "This autoinjector can push reagents into another container or someone else outside of the machine. The target \
+ must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing."
+ flags = OPENCONTAINER
+ complexity = 20
+ cooldown_per_use = 6 SECONDS
+ inputs = list("target ref", "injection amount")
+ outputs = list()
+ activators = list("inject")
+ var/inject_amount = 5
+
+/obj/item/integrated_circuit/manipulation/injector/New()
+ ..()
+ create_reagents(30)
+ var/datum/integrated_io/amount = inputs[2]
+ amount.data = inject_amount
+
+/obj/item/integrated_circuit/manipulation/injector/on_data_written()
+ var/datum/integrated_io/amount = inputs[2]
+ if(isnum(amount.data))
+ amount.data = Clamp(amount.data, 0, 30)
+ inject_amount = amount.data
+
+/obj/item/integrated_circuit/manipulation/injector/do_work()
+ var/datum/integrated_io/target = inputs[1]
+ var/atom/movable/AM = target.data_as_type(/atom/movable)
+ if(!istype(AM)) //Invalid input
+ return
+ if(!reagents.total_volume) // Empty
+ return
+ if(AM.Adjacent(get_turf(src)))
+ if(!AM.reagents)
+ return
+ if(!AM.is_open_container() && !ismob(AM) )
+ return
+ if(!AM.reagents.get_free_space())
+ return
+
+ if(isliving(AM))
+ var/mob/living/L = AM
+ if(!L.can_inject(null, 0, BP_TORSO))
+ return
+ loc.visible_message("[src] is trying to inject [AM]!")
+ sleep(3 SECONDS)
+ if(!AM.Adjacent(get_turf(src)))
+ return
+ var/contained = reagents.get_reagents()
+ var/trans = reagents.trans_to_mob(target, inject_amount, CHEM_BLOOD)
+ message_admins("[src] injected \the [AM] with [trans]u of [english_list(contained)].")
+ to_chat(AM, "You feel a tiny prick!")
+ visible_message("[src] injects [AM]!")
+ else
+ reagents.trans_to(AM, inject_amount)
+
+/obj/item/integrated_circuit/manipulation/reagent_pump
+ name = "reagent pump"
+ desc = "Moves liquids safely inside a machine, or even nearby it."
+ icon_state = "reagent_pump"
+ extended_desc = "This is a pump, which will move liquids from the source ref to the target ref. The third pin determines \
+ how much liquid is moved per pulse, between 0 and 50. The pump can move reagents to any open container inside the machine, or \
+ outside the machine if it is next to the machine. Note that this cannot be used on entities."
+ flags = OPENCONTAINER
+ complexity = 8
+ inputs = list("source ref", "target ref", "injection amount")
+ outputs = list()
+ activators = list("transfer reagents")
+ var/transfer_amount = 10
+
+/obj/item/integrated_circuit/manipulation/reagent_pump/New()
+ ..()
+ var/datum/integrated_io/amount = inputs[3]
+ amount.data = transfer_amount
+
+/obj/item/integrated_circuit/manipulation/reagent_pump/on_data_written()
+ var/datum/integrated_io/amount = inputs[3]
+ if(isnum(amount.data))
+ amount.data = Clamp(amount.data, 0, 50)
+ transfer_amount = amount.data
+
+/obj/item/integrated_circuit/manipulation/reagent_pump/do_work()
+ var/datum/integrated_io/A = inputs[1]
+ var/datum/integrated_io/B = inputs[2]
+ var/atom/movable/source = A.data_as_type(/atom/movable)
+ var/atom/movable/target = B.data_as_type(/atom/movable)
+ if(!istype(source) || !istype(target)) //Invalid input
+ return
+ var/turf/T = get_turf(src)
+ if(source.Adjacent(T) && target.Adjacent(T))
+ if(!source.reagents || !target.reagents)
+ return
+ if(ismob(source) || ismob(target))
+ return
+ if(!source.is_open_container() || !target.is_open_container())
+ return
+ if(!source.reagents.get_free_space() || !target.reagents.get_free_space())
+ return
+
+ source.reagents.trans_to(target, transfer_amount)
+
+// May make a reagent subclass of circuits in future.
+/obj/item/integrated_circuit/manipulation/reagent_storage
+ name = "reagent storage"
+ desc = "Stores liquid inside, and away from electrical components. Can store up to 60u."
+ icon_state = "reagent_storage"
+ extended_desc = "This is effectively an internal beaker."
+ flags = OPENCONTAINER
+ complexity = 4
+ inputs = list()
+ outputs = list("volume used")
+ activators = list()
+
+/obj/item/integrated_circuit/manipulation/reagent_storage/New()
+ ..()
+ create_reagents(60)
+
+/obj/item/integrated_circuit/manipulation/reagent_storage/on_reagent_change()
+ var/datum/integrated_io/A = outputs[1]
+ A.data = reagents.total_volume
+ A.push_data()
+
+/obj/item/integrated_circuit/manipulation/reagent_storage/cryo
+ name = "cryo reagent storage"
+ desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. This will also suppress reactions."
+ icon_state = "reagent_storage_cryo"
+ extended_desc = "This is effectively an internal cryo beaker."
+ flags = OPENCONTAINER | NOREACT
+ complexity = 8
+ inputs = list()
+ outputs = list("volume used")
+ activators = list()
+
/obj/item/integrated_circuit/manipulation/locomotion
name = "locomotion circuit"
desc = "This allows a machine to move in a given direction."
@@ -126,7 +260,7 @@
Southwest = 10
\
\
Pulsing the 'step towards dir' activator pin will cause the machine to move a meter in that direction, assuming it is not \
- being held, or anchored in some way."
+ being held, or anchored in some way. It should be noted that heavy machines will be unable to move."
complexity = 20
inputs = list("dir num")
outputs = list()
@@ -137,7 +271,7 @@
var/turf/T = get_turf(src)
if(istype(loc, /obj/item/device/electronic_assembly))
var/obj/item/device/electronic_assembly/machine = loc
- if(machine.anchored || machine.w_class >= 4)
+ if(machine.anchored || machine.w_class >= ITEMSIZE_LARGE)
return
if(machine.loc && machine.loc == T) // Check if we're held by someone. If the loc is the floor, we're not held.
var/datum/integrated_io/wanted_dir = inputs[1]
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index 6f08e674bc..bbb54d7f7e 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -1523,6 +1523,14 @@ CIRCUITS BELOW
materials = list(DEFAULT_WALL_MATERIAL = 20000)
build_path = /obj/item/device/electronic_assembly/medium
+/datum/design/item/custom_circuit_assembly/drone
+ name = "Drone custom assembly"
+ desc = "An customizable assembly optimized for autonomous devices."
+ id = "assembly-drone"
+ req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 4, TECH_POWER = 4)
+ materials = list(DEFAULT_WALL_MATERIAL = 30000)
+ build_path = /obj/item/device/electronic_assembly/drone
+
/datum/design/item/custom_circuit_assembly/large
name = "Large custom assembly"
desc = "An customizable assembly for large machines."
@@ -1717,6 +1725,11 @@ CIRCUITS BELOW
build_path = /obj/item/integrated_circuit/input/local_locator
sort_string = "WAAEG"
+/datum/design/circuit/integrated_circuit/input_output/adjacent_locator
+ id = "cc-adjacentlocator"
+ build_path = /obj/item/integrated_circuit/input/adjacent_locator
+ sort_string = "WAAEH"
+
/datum/design/circuit/integrated_circuit/input_output/signaler
id = "cc-signaler"
build_path = /obj/item/integrated_circuit/input/signaler
@@ -1821,7 +1834,33 @@ CIRCUITS BELOW
sort_string = "WAAGB"
req_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3)
+/datum/design/circuit/integrated_circuit/manipulation/injector
+ name = "injector"
+ id = "cc-injector"
+ build_path = /obj/item/integrated_circuit/manipulation/injector
+ sort_string = "WAAGC"
+ req_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 3)
+/datum/design/circuit/integrated_circuit/manipulation/reagent_pump
+ name = "reagent pump"
+ id = "cc-reagent_pump"
+ build_path = /obj/item/integrated_circuit/manipulation/reagent_pump
+ sort_string = "WAAGD"
+ req_tech = list(TECH_ENGINEERING = 1, TECH_DATA = 1, TECH_BIO = 2)
+
+/datum/design/circuit/integrated_circuit/manipulation/reagent_storage
+ name = "reagent storage"
+ id = "cc-reagent_storage"
+ build_path = /obj/item/integrated_circuit/manipulation/reagent_storage
+ sort_string = "WAAGE"
+ req_tech = list(TECH_ENGINEERING = 1, TECH_DATA = 1, TECH_BIO = 1)
+
+/datum/design/circuit/integrated_circuit/manipulation/reagent_storage_cryo
+ name = "cryo reagent storage"
+ id = "cc-reagent_storage_cryo"
+ build_path = /obj/item/integrated_circuit/manipulation/reagent_storage/cryo
+ sort_string = "WAAGF"
+ req_tech = list(TECH_MATERIALS = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2)
/datum/design/circuit/integrated_circuit/memory/AssembleDesignName()
..()
diff --git a/icons/obj/electronic_assemblies.dmi b/icons/obj/electronic_assemblies.dmi
index 1e020c396a..ab83834d66 100644
Binary files a/icons/obj/electronic_assemblies.dmi and b/icons/obj/electronic_assemblies.dmi differ