diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index c594b02ce0b..1896b57a898 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -12,6 +12,8 @@
max_integrity = 40
novariants = FALSE
item_flags = NOBLUDGEON
+ cost = 250
+ source = /datum/robot_energy_storage/medical
var/self_delay = 50
var/other_delay = 0
var/repeating = FALSE
@@ -189,11 +191,6 @@
absorption_rate = 0.15
absorption_capacity = 4
-/obj/item/stack/medical/gauze/cyborg
- custom_materials = null
- is_cyborg = 1
- cost = 250
-
/obj/item/stack/medical/suture
name = "suture"
desc = "Basic sterile sutures used to seal up cuts and lacerations and stop bleeding."
@@ -445,11 +442,6 @@
C.visible_message("[C] screws up like an idiot and still dies anyway!")
return (BRUTELOSS)
-/obj/item/stack/medical/bone_gel/cyborg
- custom_materials = null
- is_cyborg = 1
- cost = 250
-
/obj/item/stack/medical/poultice
name = "mourning poultices"
singular_name = "mourning poultice"
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 3ccd9c541e3..c0b1b03a113 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -28,6 +28,8 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
embedding = list()
novariants = TRUE
matter_amount = 2
+ cost = 250
+ source = /datum/robot_energy_storage/metal
/obj/item/stack/rods/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins to stuff \the [src] down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide!")//it looks like theyre ur mum
@@ -69,9 +71,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
return ..()
/obj/item/stack/rods/cyborg
- mats_per_unit = null
- is_cyborg = 1
- cost = 250
+ merge_type = /obj/item/stack/rods
/obj/item/stack/rods/cyborg/ComponentInitialize()
. = ..()
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index eac538cbce1..0470fdcca56 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -29,16 +29,13 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
point_value = 1
tableVariant = /obj/structure/table/glass
matter_amount = 4
+ cost = 500
+ source = /datum/robot_energy_storage/glass
/obj/item/stack/sheet/glass/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins to slice [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
return BRUTELOSS
-/obj/item/stack/sheet/glass/cyborg
- mats_per_unit = null
- is_cyborg = 1
- cost = 500
-
/obj/item/stack/sheet/glass/fifty
amount = 50
@@ -152,21 +149,25 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
/obj/item/stack/sheet/rglass/cyborg
mats_per_unit = null
- var/datum/robot_energy_storage/glasource
- var/metcost = 250
+ cost = 250
+ source = /datum/robot_energy_storage/metal
+
+ /// What energy storage this draws glass from as a robot module.
+ var/datum/robot_energy_storage/glasource = /datum/robot_energy_storage/glass
+ /// The amount of energy this draws from the glass source per stack unit.
var/glacost = 500
/obj/item/stack/sheet/rglass/cyborg/get_amount()
- return min(round(source.energy / metcost), round(glasource.energy / glacost))
+ return min(round(source.energy / cost), round(glasource.energy / glacost))
/obj/item/stack/sheet/rglass/cyborg/use(used, transfer = FALSE) // Requires special checks, because it uses two storages
if(get_amount(used)) //ensure we still have enough energy if called in a do_after chain
- source.use_charge(used * metcost)
+ source.use_charge(used * cost)
glasource.use_charge(used * glacost)
return TRUE
/obj/item/stack/sheet/rglass/cyborg/add(amount)
- source.add_charge(amount * metcost)
+ source.add_charge(amount * cost)
glasource.add_charge(amount * glacost)
/obj/item/stack/sheet/rglass/get_main_recipes()
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 58f961bc775..9d0249c4fc0 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -138,6 +138,8 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
tableVariant = /obj/structure/table
material_type = /datum/material/iron
matter_amount = 4
+ cost = 500
+ source = /datum/robot_energy_storage/metal
/obj/item/stack/sheet/metal/narsie_act()
new /obj/item/stack/sheet/runed_metal(loc, amount)
@@ -155,11 +157,6 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
/obj/item/stack/sheet/metal/five
amount = 5
-/obj/item/stack/sheet/metal/cyborg
- mats_per_unit = null
- is_cyborg = 1
- cost = 500
-
/obj/item/stack/sheet/metal/get_main_recipes()
. = ..()
. += GLOB.metal_recipes
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index d71930252e8..aeeaecefb18 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -18,7 +18,7 @@
var/singular_name
var/amount = 1
var/max_amount = 50 //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount
- var/is_cyborg = 0 // It's 1 if module is used by a cyborg, and uses its storage
+ var/is_cyborg = FALSE // It's TRUE if module is used by a cyborg, and uses its storage
var/datum/robot_energy_storage/source
var/cost = 1 // How much energy from storage it costs
var/merge_type = null // This path and its children should merge with this stack, defaults to src.type
@@ -403,7 +403,7 @@
/obj/item/stack/proc/can_merge(obj/item/stack/check)
if(!istype(check, merge_type))
return FALSE
- if(mats_per_unit != check.mats_per_unit)
+ if(!check.is_cyborg && (mats_per_unit != check.mats_per_unit)) // Cyborg stacks don't have materials. This lets them recycle sheets and floor tiles.
return FALSE
return TRUE
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index c5187007faf..976c528d28f 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -373,11 +373,8 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70)
resistance_flags = FIRE_PROOF
matter_amount = 1
-
-/obj/item/stack/tile/plasteel/cyborg
- mats_per_unit = null // All other Borg versions of items have no Metal or Glass - RR
- is_cyborg = 1
cost = 125
+ source = /datum/robot_energy_storage/metal
/obj/item/stack/tile/plastic
name = "plastic tile"
diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm
index 8288db4f6f5..f08f01d4d18 100644
--- a/code/modules/mining/equipment/marker_beacons.dm
+++ b/code/modules/mining/equipment/marker_beacons.dm
@@ -23,6 +23,8 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sortList(list(
merge_type = /obj/item/stack/marker_beacon
max_amount = 100
novariants = TRUE
+ cost = 1
+ source = /datum/robot_energy_storage/beacon
var/picked_color = "random"
/obj/item/stack/marker_beacon/ten //miners start with 10 of these
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 35b1089a966..be2a272cb66 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -77,50 +77,23 @@
. += m
/obj/item/robot_module/proc/get_or_create_estorage(storage_type)
- for(var/datum/robot_energy_storage/S in storages)
- if(istype(S, storage_type))
- return S
-
- return new storage_type(src)
+ return (locate(storage_type) in storages) || new storage_type(src)
/obj/item/robot_module/proc/add_module(obj/item/I, nonstandard, requires_rebuild)
if(istype(I, /obj/item/stack))
- var/obj/item/stack/S = I
+ var/obj/item/stack/sheet_module = I
+ if(ispath(sheet_module.source, /datum/robot_energy_storage))
+ sheet_module.source = get_or_create_estorage(sheet_module.source)
- if(is_type_in_list(S, list(/obj/item/stack/sheet/metal, /obj/item/stack/rods, /obj/item/stack/tile/plasteel)))
- if(S.custom_materials?.len)
- if(S.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)])
- S.cost = S.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] * 0.25
- S.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
+ if(istype(sheet_module, /obj/item/stack/sheet/rglass/cyborg))
+ var/obj/item/stack/sheet/rglass/cyborg/rglass_module = sheet_module
+ if(ispath(rglass_module.glasource, /datum/robot_energy_storage))
+ rglass_module.glasource = get_or_create_estorage(rglass_module.glasource)
- else if(istype(S, /obj/item/stack/sheet/glass))
- S.cost = 500
- S.source = get_or_create_estorage(/datum/robot_energy_storage/glass)
-
- else if(istype(S, /obj/item/stack/sheet/rglass/cyborg))
- var/obj/item/stack/sheet/rglass/cyborg/G = S
- G.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
- G.glasource = get_or_create_estorage(/datum/robot_energy_storage/glass)
-
- else if(istype(S, /obj/item/stack/medical))
- S.cost = 250
- S.source = get_or_create_estorage(/datum/robot_energy_storage/medical)
-
- else if(istype(S, /obj/item/stack/cable_coil))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/wire)
-
- else if(istype(S, /obj/item/stack/marker_beacon))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon)
-
- else if(istype(S, /obj/item/stack/pipe_cleaner_coil))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/pipe_cleaner)
-
- if(S?.source)
- S.set_custom_materials(null)
- S.is_cyborg = 1
+ if(istype(sheet_module.source))
+ sheet_module.cost = max(sheet_module.cost, 1) // Must not cost 0 to prevent div/0 errors.
+ sheet_module.set_mats_per_unit(null)
+ sheet_module.is_cyborg = TRUE
if(I.loc != src)
I.forceMove(src)
@@ -278,8 +251,8 @@
/obj/item/extinguisher/mini,
/obj/item/roller/robo,
/obj/item/borg/cyborghug/medical,
- /obj/item/stack/medical/gauze/cyborg,
- /obj/item/stack/medical/bone_gel/cyborg,
+ /obj/item/stack/medical/gauze,
+ /obj/item/stack/medical/bone_gel,
/obj/item/organ_storage,
/obj/item/borg/lollipop)
radio_channels = list(RADIO_CHANNEL_MEDICAL)
@@ -309,12 +282,12 @@
/obj/item/assembly/signaler/cyborg,
/obj/item/areaeditor/blueprints/cyborg,
/obj/item/electroadaptive_pseudocircuit,
- /obj/item/stack/sheet/metal/cyborg,
- /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/metal,
+ /obj/item/stack/sheet/glass,
/obj/item/stack/sheet/rglass/cyborg,
/obj/item/stack/rods/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
- /obj/item/stack/cable_coil/cyborg)
+ /obj/item/stack/tile/plasteel,
+ /obj/item/stack/cable_coil)
radio_channels = list(RADIO_CHANNEL_ENGINEERING)
emag_modules = list(/obj/item/borg/stun)
cyborg_base_icon = "engineer"
@@ -382,7 +355,7 @@
/obj/item/assembly/flash/cyborg,
/obj/item/screwdriver/cyborg,
/obj/item/crowbar/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/stack/tile/plasteel,
/obj/item/soap/nanotrasen,
/obj/item/storage/bag/trash/cyborg,
/obj/item/melee/flyswatter,
@@ -610,7 +583,7 @@
/obj/item/crowbar/cyborg,
/obj/item/extinguisher/mini,
/obj/item/pinpointer/syndicate_cyborg,
- /obj/item/stack/medical/gauze/cyborg,
+ /obj/item/stack/medical/gauze,
/obj/item/gun/medbeam,
/obj/item/organ_storage)
@@ -634,13 +607,13 @@
/obj/item/crowbar/cyborg,
/obj/item/wirecutters/cyborg,
/obj/item/multitool/cyborg,
- /obj/item/stack/sheet/metal/cyborg,
- /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/metal,
+ /obj/item/stack/sheet/glass,
/obj/item/stack/sheet/rglass/cyborg,
/obj/item/stack/rods/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/stack/tile/plasteel,
/obj/item/dest_tagger/borg,
- /obj/item/stack/cable_coil/cyborg,
+ /obj/item/stack/cable_coil,
/obj/item/pinpointer/syndicate_cyborg,
/obj/item/borg_chameleon,
)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 4cea5c9b027..e712fbcbb54 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -408,6 +408,8 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
full_w_class = WEIGHT_CLASS_SMALL
grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil
usesound = 'sound/items/deconstruct.ogg'
+ cost = 1
+ source = /datum/robot_energy_storage/wire
var/cable_color = "yellow"
var/obj/structure/cable/target_type = /obj/structure/cable
var/target_layer = CABLE_LAYER_2
@@ -597,11 +599,6 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
pixel_y = base_pixel_y + rand(-2, 2)
update_icon()
-/obj/item/stack/cable_coil/cyborg
- is_cyborg = 1
- mats_per_unit = null
- cost = 1
-
#undef CABLE_RESTRAINTS_COST
#undef UNDER_SMES
#undef UNDER_TERMINAL
diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm
index aae3bdf38e3..e2cadd35dbc 100644
--- a/code/modules/power/pipecleaners.dm
+++ b/code/modules/power/pipecleaners.dm
@@ -203,14 +203,11 @@ By design, d1 is the smallest direction and d2 is the highest
full_w_class = WEIGHT_CLASS_SMALL
grind_results = list("copper" = 2) //2 copper per pipe_cleaner in the coil
usesound = 'sound/items/deconstruct.ogg'
+ cost = 1
+ source = /datum/robot_energy_storage/pipe_cleaner
/// Currently set cable color
var/pipe_cleaner_color = COLOR_RED
-/obj/item/stack/pipe_cleaner_coil/cyborg
- is_cyborg = 1
- mats_per_unit = null
- cost = 1
-
/obj/item/stack/pipe_cleaner_coil/cyborg/attack_self(mob/user)
var/selected_color = input(user, "Pick a pipe cleaner color.", "Cable Color") as null|anything in list("blue", "cyan", "green", "orange", "pink", "red", "white", "yellow")
if(!selected_color)
diff --git a/modular_skyrat/modules/altborgs/code/modules/mob/living/silicon/robot/robot_modules.dm b/modular_skyrat/modules/altborgs/code/modules/mob/living/silicon/robot/robot_modules.dm
index 71ffb53fc70..f3aec554b5d 100644
--- a/modular_skyrat/modules/altborgs/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/modular_skyrat/modules/altborgs/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -781,14 +781,14 @@
/obj/item/wirecutters/cyborg,
/obj/item/multitool/cyborg,
/obj/item/lightreplacer/cyborg,
- /obj/item/stack/sheet/metal/cyborg,
- /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/metal,
+ /obj/item/stack/sheet/glass,
/obj/item/stack/sheet/rglass/cyborg,
/obj/item/stack/rods/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
- /obj/item/stack/cable_coil/cyborg,
+ /obj/item/stack/tile/plasteel,
+ /obj/item/stack/cable_coil,
/obj/item/restraints/handcuffs/cable/zipties,
- /obj/item/stack/medical/gauze/cyborg,
+ /obj/item/stack/medical/gauze,
/obj/item/shockpaddles/cyborg,
/obj/item/healthanalyzer/advanced,
/obj/item/retractor/advanced,