diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index bd1c5210826..c476232387d 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -78,15 +78,6 @@
var/mob/living/silicon/robot/R = usr
R.toggle_ionpulse()
-/obj/screen/robot/panel
- name = "installed modules"
- icon_state = "panel"
-
-/obj/screen/robot/panel/Click()
- if(issilicon(usr))
- var/mob/living/silicon/robot/R = usr
- R.installed_modules()
-
/obj/screen/robot/mov_intent
name = "fast/slow toggle"
icon_state = "running"
@@ -224,16 +215,6 @@
var/x = -4 //Start at CENTER-4,SOUTH+1
var/y = 1
- //Unfortunately adding the emag module to the list of modules has to be here. This is because a borg can
- //be emagged before they actually select a module. - or some situation can cause them to get a new module
- // - or some situation might cause them to get de-emagged or something.
- if(R.emagged || R.weapons_unlock)
- if(!(R.module.emag in R.module.modules))
- R.module.modules.Add(R.module.emag)
- else
- if(R.module.emag in R.module.modules)
- R.module.modules.Remove(R.module.emag)
-
for(var/atom/movable/A in R.module.modules)
if( (A != R.module_state_1) && (A != R.module_state_2) && (A != R.module_state_3) )
//Module is not currently active
diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm
index 38ee8ed6042..f4b8e84204f 100644
--- a/code/datums/components/material_container.dm
+++ b/code/datums/components/material_container.dm
@@ -130,13 +130,13 @@
/datum/component/material_container/proc/insert_stack(obj/item/stack/S, amt, multiplier = 1)
if(isnull(amt))
- amt = S.amount
+ amt = S.get_amount()
if(amt <= 0)
return FALSE
- if(amt > S.amount)
- amt = S.amount
+ if(amt > S.get_amount())
+ amt = S.get_amount()
var/material_amt = get_item_material_amount(S)
if(!material_amt)
diff --git a/code/datums/helper_datums/construction_datum.dm b/code/datums/helper_datums/construction_datum.dm
index 155bbaed8dc..7c05f7806f9 100644
--- a/code/datums/helper_datums/construction_datum.dm
+++ b/code/datums/helper_datums/construction_datum.dm
@@ -47,7 +47,7 @@
/datum/construction/proc/custom_action(step, used_atom, user)
if(istype(used_atom, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = used_atom
- if(C.amount<4)
+ if(C.get_amount() < 4)
to_chat(user, ("There's not enough cable to finish the task."))
return 0
else
@@ -55,7 +55,7 @@
playsound(holder, C.usesound, 50, 1)
else if(istype(used_atom, /obj/item/stack))
var/obj/item/stack/S = used_atom
- if(S.amount < 5)
+ if(S.get_amount() < 5)
to_chat(user, ("There's not enough material in this stack."))
return 0
else
@@ -113,7 +113,7 @@
// STACKS
if(istype(used_atom,/obj/item/stack))
var/obj/item/stack/stack=used_atom
- if(stack.amount < amount)
+ if(stack.get_amount() < amount)
to_chat(user, "You don't have enough [stack]! You need at least [amount].")
return 0
stack.use(amount)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 35e0053822d..29a1b29de97 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -1375,46 +1375,20 @@
switch(href_list["silicon"])
if("unemag")
var/mob/living/silicon/robot/R = current
- if(istype(R))
- R.emagged = 0
- if(R.module)
- if(R.activated(R.module.emag))
- R.module_active = null
- if(R.module_state_1 == R.module.emag)
- R.module_state_1 = null
- R.contents -= R.module.emag
- else if(R.module_state_2 == R.module.emag)
- R.module_state_2 = null
- R.contents -= R.module.emag
- else if(R.module_state_3 == R.module.emag)
- R.module_state_3 = null
- R.contents -= R.module.emag
- R.clear_supplied_laws()
- R.laws = new /datum/ai_laws/crewsimov
- log_admin("[key_name(usr)] has un-emagged [key_name(current)]")
- message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]")
+ if(!istype(R))
+ return
+ R.unemag()
+ log_admin("[key_name(usr)] has un-emagged [key_name(current)]")
+ message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]")
if("unemagcyborgs")
- if(isAI(current))
- var/mob/living/silicon/ai/ai = current
- for(var/mob/living/silicon/robot/R in ai.connected_robots)
- R.emagged = 0
- if(R.module)
- if(R.activated(R.module.emag))
- R.module_active = null
- if(R.module_state_1 == R.module.emag)
- R.module_state_1 = null
- R.contents -= R.module.emag
- else if(R.module_state_2 == R.module.emag)
- R.module_state_2 = null
- R.contents -= R.module.emag
- else if(R.module_state_3 == R.module.emag)
- R.module_state_3 = null
- R.contents -= R.module.emag
- R.clear_supplied_laws()
- R.laws = new /datum/ai_laws/crewsimov
- log_admin("[key_name(usr)] has unemagged [key_name(ai)]'s cyborgs")
- message_admins("[key_name_admin(usr)] has unemagged [key_name_admin(ai)]'s cyborgs")
+ if(!isAI(current))
+ return
+ var/mob/living/silicon/ai/ai = current
+ for(var/mob/living/silicon/robot/R in ai.connected_robots)
+ R.unemag()
+ log_admin("[key_name(usr)] has unemagged [key_name(ai)]'s cyborgs")
+ message_admins("[key_name_admin(usr)] has unemagged [key_name_admin(ai)]'s cyborgs")
else if(href_list["common"])
switch(href_list["common"])
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 66df3d4a76c..191bc9638a4 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -413,6 +413,9 @@
/atom/proc/emag_act()
return
+/atom/proc/unemag()
+ return
+
/**
* Respond to a radioactive wave hitting this atom
*
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index a02c46524c5..80a15be40d5 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -477,11 +477,11 @@
return
if(istype(P, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = P
- if(C.amount >= 5)
+ if(C.get_amount() >= 5)
playsound(loc, C.usesound, 50, 1)
to_chat(user, "You start to add cables to the frame.")
if(do_after(user, 20 * C.toolspeed, target = src))
- if(state == 2 && C.amount >= 5 && C.use(5))
+ if(state == 2 && C.get_amount() >= 5 && C.use(5))
to_chat(user, "You add cables to the frame.")
state = 3
icon_state = "3"
@@ -502,11 +502,11 @@
return
if(istype(P, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = P
- if(G.amount >= 2)
+ if(G.get_amount() >= 2)
playsound(loc, G.usesound, 50, 1)
to_chat(user, "You start to add the glass panel to the frame.")
if(do_after(user, 20 * G.toolspeed, target = src))
- if(state == 3 && G.amount >= 2 && G.use(2))
+ if(state == 3 && G.get_amount() >= 2 && G.use(2))
to_chat(user, "You put in the glass panel.")
state = 4
icon_state = "4"
@@ -608,11 +608,11 @@
icon_state = "1"
if(istype(P, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = P
- if(C.amount >= 5)
+ if(C.get_amount() >= 5)
playsound(loc, C.usesound, 50, 1)
to_chat(user, "You start to add cables to the frame.")
if(do_after(user, 20 * C.toolspeed, target = src))
- if(state == 2 && C.amount >= 5 && C.use(5))
+ if(state == 2 && C.get_amount() >= 5 && C.use(5))
to_chat(user, "You add cables to the frame.")
state = 3
icon_state = "3"
@@ -633,11 +633,11 @@
if(istype(P, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = P
- if(G.amount >= 2)
+ if(G.get_amount() >= 2)
playsound(loc, G.usesound, 50, 1)
to_chat(user, "You start to add the glass panel to the frame.")
if(do_after(user, 20 * G.toolspeed, target = src))
- if(state == 3 && G.amount >= 2 && G.use(2))
+ if(state == 3 && G.get_amount() >= 2 && G.use(2))
to_chat(user, "You put in the glass panel.")
state = 4
icon_state = "4"
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 322141dee0a..a4879448aa0 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -75,11 +75,11 @@
if(1)
if(istype(P, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = P
- if(C.amount >= 5)
+ if(C.get_amount() >= 5)
playsound(src.loc, C.usesound, 50, 1)
to_chat(user, "You start to add cables to the frame.")
if(do_after(user, 20 * C.toolspeed, target = src))
- if(state == 1 && C.amount >= 5 && C.use(5))
+ if(state == 1 && C.get_amount() >= 5 && C.use(5))
to_chat(user, "You add cables to the frame.")
state = 2
icon_state = "box_1"
@@ -193,8 +193,8 @@
playsound(src.loc, P.usesound, 50, 1)
if(istype(P, /obj/item/stack))
var/obj/item/stack/S = P
- var/camt = min(S.amount, req_components[I])
- var/obj/item/stack/NS = new P.type(src)
+ var/camt = min(S.get_amount(), req_components[I])
+ var/obj/item/stack/NS = new S.merge_type(src)
NS.amount = camt
NS.update_icon()
S.use(camt)
diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm
index cae3e78186e..ab211939804 100644
--- a/code/game/machinery/mass_driver.dm
+++ b/code/game/machinery/mass_driver.dm
@@ -126,7 +126,7 @@
var/obj/item/stack/cable_coil/C = W
to_chat(user, "You start adding cables to \the [src]...")
playsound(get_turf(src), C.usesound, 50, 1)
- if(do_after(user, 20 * C.toolspeed, target = src) && (C.amount >= 2) && (build == 2))
+ if(do_after(user, 20 * C.toolspeed, target = src) && (C.get_amount() >= 2) && (build == 2))
C.use(2)
to_chat(user, "You've added cables to \the [src].")
build++
@@ -146,7 +146,7 @@
var/obj/item/stack/rods/R = W
to_chat(user, "You begin to complete \the [src]...")
playsound(get_turf(src), R.usesound, 50, 1)
- if(do_after(user, 20 * R.toolspeed, target = src) && (R.amount >= 2) && (build == 3))
+ if(do_after(user, 20 * R.toolspeed, target = src) && (R.get_amount() >= 2) && (build == 3))
R.use(2)
to_chat(user, "You've added the grille to \the [src].")
build++
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index 9063a126317..6fa1e79e764 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -7,11 +7,18 @@
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 1000
+ /// A reference to the occupant currently sitting inside the recharger.
var/mob/occupant = null
+ /// What type of circuit board is required to build this machine.
var/circuitboard = /obj/item/circuitboard/cyborgrecharger
+ /// How fast the recharger can give charge to the occupants energy cell. Based on capacitors and the cell the recharger has.
var/recharge_speed
+ /// How much nutrition is given to the occupant. Based on capacitors and the cell the recharger has. Only relevent for IPCs.
var/recharge_speed_nutrition
+ /// How much the occupant is repaired every cycle. Based on what manipulator the recharger has.
var/repairs
+ /// How efficiently the recharger is able to recharge consumable items such as metal, glass, chemicals in sprays, welding tool fuel, etc.
+ var/consumable_recharge_coeff
/obj/machinery/recharge_station/Destroy()
go_out()
@@ -42,6 +49,7 @@
recharge_speed = 0
recharge_speed_nutrition = 0
repairs = 0
+ // The recharge_speed can be anywhere from 200 to 3200, depending on the capacitors and the cell.
for(var/obj/item/stock_parts/capacitor/C in component_parts)
recharge_speed += C.rating * 100
recharge_speed_nutrition += C.rating * 10
@@ -52,11 +60,14 @@
recharge_speed *= multiplier
recharge_speed_nutrition *= multiplier
+ // This coefficient can be anywhere from 1, to 16.
+ consumable_recharge_coeff = max(1, recharge_speed / 200)
+
/obj/machinery/recharge_station/process()
if(!(NOPOWER|BROKEN))
return
- if(src.occupant)
+ if(occupant)
process_occupant()
for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp
@@ -133,20 +144,20 @@
return TRUE
/obj/machinery/recharge_station/proc/process_occupant()
- if(src.occupant)
- if(istype(occupant, /mob/living/silicon/robot))
- var/mob/living/silicon/robot/R = occupant
- restock_modules()
- if(repairs)
- R.heal_overall_damage(repairs, repairs)
- if(R.cell)
- R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge)
- else if(istype(occupant, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = occupant
- if(H.get_int_organ(/obj/item/organ/internal/cell) && H.nutrition < 450)
- H.set_nutrition(min(H.nutrition + recharge_speed_nutrition, 450))
- if(repairs)
- H.heal_overall_damage(repairs, repairs, TRUE, 0, 1)
+ if(isrobot(occupant))
+ var/mob/living/silicon/robot/R = occupant
+ if(R.module)
+ R.module.recharge_consumables(R, consumable_recharge_coeff) // This will handle all of a cyborg's items.
+ if(repairs)
+ R.heal_overall_damage(repairs, repairs)
+ if(R.cell)
+ R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge)
+ else if(ishuman(occupant))
+ var/mob/living/carbon/human/H = occupant
+ if(H.get_int_organ(/obj/item/organ/internal/cell) && H.nutrition < 450)
+ H.set_nutrition(min(H.nutrition + recharge_speed_nutrition, 450))
+ if(repairs)
+ H.heal_overall_damage(repairs, repairs, TRUE, 0, 1)
/obj/machinery/recharge_station/proc/go_out()
if(!occupant)
@@ -157,74 +168,6 @@
use_power = IDLE_POWER_USE
return
-/obj/machinery/recharge_station/proc/restock_modules()
- if(src.occupant)
- if(istype(occupant, /mob/living/silicon/robot))
- var/mob/living/silicon/robot/R = occupant
- var/coeff = recharge_speed / 200
- if(R.module && R.module.modules)
- var/list/um = R.contents|R.module.modules
- // ^ makes sinle list of active (R.contents) and inactive modules (R.module.modules)
- for(var/obj/O in um)
- // Engineering
- if(istype(O,/obj/item/stack/sheet))
- var/obj/item/stack/sheet/S = O
- if(S.amount < S.max_amount)
- S.amount += round(min(1 * coeff, S.max_amount - S.amount))
- // Security
- if(istype(O,/obj/item/flash))
- var/obj/item/flash/F = O
- if(F.broken)
- F.broken = 0
- F.times_used = 0
- F.icon_state = "flash"
- if(istype(O,/obj/item/gun/energy))
- var/obj/item/gun/energy/D = O
- if(D.cell.charge < D.cell.maxcharge)
- var/obj/item/ammo_casing/energy/E = D.ammo_type[D.select]
- D.cell.give(E.e_cost)
- D.on_recharge()
- D.update_icon()
- else
- D.charge_tick = 0
- if(istype(O,/obj/item/melee/baton))
- var/obj/item/melee/baton/B = O
- if(B.cell)
- B.cell.charge = B.cell.maxcharge
- //Service
- if(istype(O,/obj/item/reagent_containers/food/condiment/enzyme))
- if(O.reagents.get_reagent_amount("enzyme") < 50)
- O.reagents.add_reagent("enzyme", 2 * coeff)
- //Janitor
- if(istype(O, /obj/item/lightreplacer))
- var/obj/item/lightreplacer/LR = O
- var/i = 1
- for(1, i <= coeff, i++)
- LR.Charge(occupant)
- //Fire extinguisher
- if(istype(O, /obj/item/extinguisher))
- var/obj/item/extinguisher/ext = O
- ext.reagents.check_and_add("water", ext.max_water, 5 * coeff)
- //Welding tools
- if(istype(O, /obj/item/weldingtool))
- var/obj/item/weldingtool/weld = O
- weld.reagents.check_and_add("fuel", weld.maximum_fuel, 2 * coeff)
- if(R)
- if(R.module)
- R.module.respawn_consumable(R)
-
- //Emagged items for janitor and medical borg
- if(R.module.emag)
- if(istype(R.module.emag, /obj/item/reagent_containers/spray))
- var/obj/item/reagent_containers/spray/S = R.module.emag
- if(S.name == "polyacid spray")
- S.reagents.add_reagent("facid", 2 * coeff)
- if(S.name == "lube spray")
- S.reagents.add_reagent("lube", 2 * coeff)
- else if(S.name == "acid synthesizer")
- S.reagents.add_reagent("facid", 2 * coeff)
- S.reagents.add_reagent("sacid", 2 * coeff)
-
/obj/machinery/recharge_station/verb/move_eject()
set category = "Object"
set src in oview(1)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 2876527a526..2d6c7767f17 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -699,7 +699,7 @@
else if(istype(W, /obj/item/stack/cable_coil))
if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT))
var/obj/item/stack/cable_coil/CC = W
- if(CC.amount > 1)
+ if(CC.get_amount() > 1)
CC.use(2)
clearInternalDamage(MECHA_INT_SHORT_CIRCUIT)
to_chat(user, "You replace the fused wires.")
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 01ac7cf8d7d..13b5d6f1be2 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -14,7 +14,7 @@
return 0
else if(istype(used_atom, /obj/item/stack))
var/obj/item/stack/S = used_atom
- if(S.amount < STANDARD_STACK_AMOUNT)
+ if(S.get_amount() < STANDARD_STACK_AMOUNT)
to_chat(user, ("There's not enough material in this stack."))
return 0
else
@@ -35,7 +35,7 @@
return 0
else if(istype(used_atom, /obj/item/stack))
var/obj/item/stack/S = used_atom
- if(S.amount < STANDARD_STACK_AMOUNT)
+ if(S.get_amount() < STANDARD_STACK_AMOUNT)
to_chat(user, ("There's not enough material in this stack."))
return 0
else
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index f22fb5cbb81..28a2006e0aa 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -728,3 +728,6 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
if(flags & SLOT_PDA)
owner.update_inv_wear_pda()
+/// Called on cyborg items that need special charging behavior. Override as needed for specific items.
+/obj/item/proc/cyborg_recharge(coeff = 1, emagged = FALSE)
+ return
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index 26bfb6c816d..3799d1d779e 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -176,6 +176,12 @@
..()
new /obj/effect/temp_visual/borgflash(get_turf(src))
+/obj/item/flash/cyborg/cyborg_recharge(coeff, emagged)
+ if(broken)
+ broken = FALSE
+ times_used = 0
+ icon_state = "flash"
+
/obj/item/flash/cameraflash
name = "camera"
icon = 'icons/obj/items.dmi'
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 4ed9b335584..85e650412f6 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -262,6 +262,10 @@
/obj/item/lightreplacer/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
return
+/obj/item/lightreplacer/cyborg/cyborg_recharge(coeff, emagged)
+ for(var/I in 1 to coeff)
+ Charge()
+
#undef LIGHT_OK
#undef LIGHT_EMPTY
#undef LIGHT_BROKEN
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index d1d4e900543..2cd43506990 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -132,7 +132,7 @@
return
else if(iscoil(W) && buildstage == 1)
var/obj/item/stack/cable_coil/coil = W
- if(coil.amount < 5)
+ if(coil.get_amount() < 5)
to_chat(user, "You need more cable for this!")
return
if(do_after(user, 10 * coil.toolspeed, target = src) && buildstage == 1)
diff --git a/code/game/objects/items/mixing_bowl.dm b/code/game/objects/items/mixing_bowl.dm
index 1e1a39d49d0..024274aa973 100644
--- a/code/game/objects/items/mixing_bowl.dm
+++ b/code/game/objects/items/mixing_bowl.dm
@@ -31,7 +31,7 @@
return 1
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
- if(S.amount > 1)
+ if(S.get_amount() > 1)
var/obj/item/stack/to_add = S.split(user, 1)
to_add.forceMove(src)
user.visible_message("[user] adds one of [S] to [src].", "You add one of [S] to [src].")
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 81733bd91e7..bcc5bd35dd9 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -7,19 +7,72 @@
icon = 'icons/obj/module.dmi'
icon_state = "cyborg_upgrade"
origin_tech = "programming=2"
- var/locked = 0
- var/installed = 0
+ /// Whether or not the cyborg needs to have a chosen module before they can recieve this upgrade.
var/require_module = FALSE
+ /// The type of module this upgrade is compatible with: Engineering, Medical, etc.
var/module_type = null
+ /// A list of items, and their replacements that this upgrade should replace on installation, in the format of `item_type_to_replace = replacement_item_type`.
+ var/list/items_to_replace = list()
+ /// A list of replacement items will need to be placed into a cyborg module's `special_rechargable` list after this upgrade is installed.
+ var/list/special_rechargables = list()
+/**
+ * Called when someone clicks on a borg with an upgrade in their hand.
+ *
+ * Arguments:
+ * * R - the cyborg that was clicked on with an upgrade.
+ */
/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R)
+ if(!pre_install_checks(R))
+ return
+ if(!do_install(R))
+ return
+ after_install(R)
+ return TRUE
+
+/**
+ * Checks if the upgrade is able to be applied to the cyborg, before actually applying it.
+ *
+ * Arguments:
+ * * R - the cyborg that was clicked on with an upgrade.
+ */
+/obj/item/borg/upgrade/proc/pre_install_checks(mob/living/silicon/robot/R)
if(R.stat == DEAD)
- to_chat(usr, "[src] will not function on a deceased cyborg.")
- return TRUE
+ to_chat(usr, "[src] will not function on a deceased cyborg.")
+ return FALSE
if(module_type && !istype(R.module, module_type))
- to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
- to_chat(usr, "There's no mounting point for the module!")
- return TRUE
+ to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
+ to_chat(usr, "There's no mounting point for the module!")
+ return FALSE
+ return TRUE
+
+/**
+ * Executes code that will modify the cyborg or its module.
+ *
+ * Arguments:
+ * * R - the cyborg we're applying the upgrade to.
+ */
+/obj/item/borg/upgrade/proc/do_install(mob/living/silicon/robot/R)
+ return TRUE
+
+/**
+ * Executes code after the module has been installed and the cyborg has been modified in some way.
+ *
+ * Arguments:
+ * * R - the cyborg that we've applied the upgrade to.
+ */
+/obj/item/borg/upgrade/proc/after_install(mob/living/silicon/robot/R)
+ for(var/item in items_to_replace)
+ var/replacement_type = items_to_replace[item]
+ var/obj/item/replacement = new replacement_type(R.module)
+ R.module.remove_item_from_lists(item)
+ R.module.basic_modules += replacement
+
+ if(replacement_type in special_rechargables)
+ R.module.special_rechargables += replacement
+
+ R.module.rebuild_modules()
+ return TRUE
/obj/item/borg/upgrade/reset
name = "cyborg module reset board"
@@ -27,14 +80,13 @@
icon_state = "cyborg_upgrade1"
require_module = TRUE
-/obj/item/borg/upgrade/reset/action(mob/living/silicon/robot/R)
- if(..())
- return
-
+/obj/item/borg/upgrade/reset/do_install(mob/living/silicon/robot/R)
R.reset_module()
-
return TRUE
+/obj/item/borg/upgrade/reset/after_install(mob/living/silicon/robot/R)
+ return // We don't need to give them replacement items, or rebuild their module list. It's going to be a blank borg.
+
/obj/item/borg/upgrade/rename
name = "cyborg reclassification board"
desc = "Used to rename a cyborg."
@@ -44,9 +96,7 @@
/obj/item/borg/upgrade/rename/attack_self(mob/user)
heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
-/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
- if(..())
- return
+/obj/item/borg/upgrade/rename/do_install(mob/living/silicon/robot/R)
if(!R.allow_rename)
to_chat(R, "Internal diagnostic error: incompatible upgrade module detected.")
return 0
@@ -63,7 +113,7 @@
desc = "Used to force a reboot of a disabled-but-repaired cyborg, bringing it back online."
icon_state = "cyborg_upgrade1"
-/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R)
+/obj/item/borg/upgrade/restart/do_install(mob/living/silicon/robot/R)
if(R.health < 0)
to_chat(usr, "You have to repair the cyborg before using this module!")
return 0
@@ -88,9 +138,7 @@
require_module = TRUE
origin_tech = "engineering=4;materials=5;programming=4"
-/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R)
- if(..())
- return
+/obj/item/borg/upgrade/vtec/do_install(mob/living/silicon/robot/R)
if(R.speed < 0)
to_chat(R, "A VTEC unit is already installed!")
to_chat(usr, "There's no room for another VTEC unit!")
@@ -108,10 +156,7 @@
require_module = TRUE
module_type = /obj/item/robot_module/security
-/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R)
- if(..())
- return
-
+/obj/item/borg/upgrade/disablercooler/do_install(mob/living/silicon/robot/R)
var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules
if(!T)
to_chat(usr, "There's no disabler in this unit!")
@@ -131,10 +176,7 @@
icon_state = "cyborg_upgrade3"
origin_tech = "engineering=4;powerstorage=4"
-/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R)
- if(..())
- return
-
+/obj/item/borg/upgrade/thrusters/do_install(mob/living/silicon/robot/R)
if(R.ionpulse)
to_chat(usr, "This unit already has ion thrusters installed!")
return
@@ -149,20 +191,9 @@
origin_tech = "engineering=4;materials=5"
require_module = TRUE
module_type = /obj/item/robot_module/miner
-
-/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- for(var/obj/item/pickaxe/drill/cyborg/D in R.module.modules)
- qdel(D)
- for(var/obj/item/shovel/S in R.module.modules)
- qdel(S)
-
- R.module.modules += new /obj/item/pickaxe/drill/cyborg/diamond(R.module)
- R.module.rebuild()
-
- return TRUE
+ items_to_replace = list(
+ /obj/item/pickaxe/drill/cyborg = /obj/item/pickaxe/drill/cyborg/diamond
+ )
/obj/item/borg/upgrade/soh
name = "mining cyborg satchel of holding"
@@ -171,18 +202,9 @@
origin_tech = "engineering=4;materials=4;bluespace=4"
require_module = TRUE
module_type = /obj/item/robot_module/miner
-
-/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- for(var/obj/item/storage/bag/ore/cyborg/S in R.module.modules)
- qdel(S)
-
- R.module.modules += new /obj/item/storage/bag/ore/holding(R.module)
- R.module.rebuild()
-
- return TRUE
+ items_to_replace = list(
+ /obj/item/storage/bag/ore/cyborg = /obj/item/storage/bag/ore/holding
+ )
/obj/item/borg/upgrade/abductor_engi
name = "engineering cyborg abductor upgrade"
@@ -191,33 +213,17 @@
origin_tech = "engineering=6;materials=6;abductor=3"
require_module = TRUE
module_type = /obj/item/robot_module/engineering
-
-/obj/item/borg/upgrade/abductor_engi/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- for(var/obj/item/weldingtool/largetank/cyborg/W in R.module.modules)
- qdel(W)
- for(var/obj/item/screwdriver/cyborg/S in R.module.modules)
- qdel(S)
- for(var/obj/item/wrench/cyborg/E in R.module.modules)
- qdel(E)
- for(var/obj/item/crowbar/cyborg/C in R.module.modules)
- qdel(C)
- for(var/obj/item/wirecutters/cyborg/I in R.module.modules)
- qdel(I)
- for(var/obj/item/multitool/cyborg/M in R.module.modules)
- qdel(M)
-
- R.module.modules += new /obj/item/weldingtool/abductor(R.module)
- R.module.modules += new /obj/item/wrench/abductor(R.module)
- R.module.modules += new /obj/item/screwdriver/abductor(R.module)
- R.module.modules += new /obj/item/crowbar/abductor(R.module)
- R.module.modules += new /obj/item/wirecutters/abductor(R.module)
- R.module.modules += new /obj/item/multitool/abductor(R.module)
- R.module.rebuild()
-
- return TRUE
+ items_to_replace = list(
+ /obj/item/weldingtool = /obj/item/weldingtool/abductor,
+ /obj/item/wrench = /obj/item/wrench/abductor,
+ /obj/item/screwdriver = /obj/item/screwdriver/abductor,
+ /obj/item/crowbar = /obj/item/crowbar/abductor,
+ /obj/item/wirecutters = /obj/item/wirecutters/abductor,
+ /obj/item/multitool = /obj/item/multitool/abductor
+ )
+ special_rechargables = list(
+ /obj/item/weldingtool/abductor
+ )
/obj/item/borg/upgrade/abductor_medi
name = "medical cyborg abductor upgrade"
@@ -226,39 +232,16 @@
origin_tech = "biotech=6;materials=6;abductor=3"
require_module = TRUE
module_type = /obj/item/robot_module/medical
-
-/obj/item/borg/upgrade/abductor_medi/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- for(var/obj/item/scalpel/laser/laser1/L in R.module.modules)
- qdel(L)
- for(var/obj/item/hemostat/H in R.module.modules)
- qdel(H)
- for(var/obj/item/retractor/E in R.module.modules)
- qdel(E)
- for(var/obj/item/bonegel/B in R.module.modules)
- qdel(B)
- for(var/obj/item/FixOVein/F in R.module.modules)
- qdel(F)
- for(var/obj/item/bonesetter/S in R.module.modules)
- qdel(S)
- for(var/obj/item/circular_saw/C in R.module.modules)
- qdel(C)
- for(var/obj/item/surgicaldrill/D in R.module.modules)
- qdel(D)
-
- R.module.modules += new /obj/item/scalpel/laser/laser3(R.module) //no abductor laser scalpel, so next best thing.
- R.module.modules += new /obj/item/hemostat/alien(R.module)
- R.module.modules += new /obj/item/retractor/alien(R.module)
- R.module.modules += new /obj/item/bonegel/alien(R.module)
- R.module.modules += new /obj/item/FixOVein/alien(R.module)
- R.module.modules += new /obj/item/bonesetter/alien(R.module)
- R.module.modules += new /obj/item/circular_saw/alien(R.module)
- R.module.modules += new /obj/item/surgicaldrill/alien(R.module)
- R.module.rebuild()
-
- return TRUE
+ items_to_replace = list(
+ /obj/item/scalpel/laser/laser1 = /obj/item/scalpel/laser/laser3, // No abductor laser scalpel, so next best thing.
+ /obj/item/hemostat = /obj/item/hemostat/alien,
+ /obj/item/retractor = /obj/item/retractor/alien,
+ /obj/item/bonegel = /obj/item/bonegel/alien,
+ /obj/item/FixOVein = /obj/item/FixOVein/alien,
+ /obj/item/bonesetter = /obj/item/bonesetter/alien,
+ /obj/item/circular_saw = /obj/item/circular_saw/alien,
+ /obj/item/surgicaldrill = /obj/item/surgicaldrill/alien
+ )
/obj/item/borg/upgrade/syndicate
name = "safety override module"
@@ -267,13 +250,11 @@
origin_tech = "combat=6;materials=6"
require_module = TRUE
-/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R)
- if(..())
- return
+/obj/item/borg/upgrade/syndicate/do_install(mob/living/silicon/robot/R)
if(R.weapons_unlock)
- to_chat(R, "Warning: Safety Overide Protocols have be disabled.")
- return
- R.weapons_unlock = 1
+ return // They already had the safety override upgrade, or they're a cyborg type which has this by default.
+ R.weapons_unlock = TRUE
+ to_chat(R, "Warning: Safety Overide Protocols have be disabled.")
return TRUE
/obj/item/borg/upgrade/lavaproof
@@ -284,9 +265,7 @@
require_module = TRUE
module_type = /obj/item/robot_module/miner
-/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R)
- if(..())
- return
+/obj/item/borg/upgrade/lavaproof/do_install(mob/living/silicon/robot/R)
if(istype(R))
R.weather_immunities += "lava"
return TRUE
@@ -303,10 +282,7 @@
var/powercost = 10
var/mob/living/silicon/robot/cyborg
-/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R)
- if(..())
- return
-
+/obj/item/borg/upgrade/selfrepair/do_install(mob/living/silicon/robot/R)
var/obj/item/borg/upgrade/selfrepair/U = locate() in R
if(U)
to_chat(usr, "This unit is already equipped with a self-repair module.")
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index f9d02c8f515..a0bd2a3f708 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -17,13 +17,18 @@
var/healverb = "bandage"
/obj/item/stack/medical/attack(mob/living/M, mob/user)
+ if(get_amount() <= 0)
+ if(is_cyborg)
+ to_chat(user, "You don't have enough energy to dispense more [singular_name]\s!")
+ return TRUE
+
if(!iscarbon(M) && !isanimal(M))
to_chat(user, "[src] cannot be applied to [M]!")
- return 1
+ return TRUE
if(!user.IsAdvancedToolUser())
to_chat(user, "You don't have the dexterity to do this!")
- return 1
+ return TRUE
if(ishuman(M))
@@ -167,7 +172,12 @@
heal_brute = 25
stop_bleeding = 0
+/obj/item/stack/medical/bruise_pack/advanced/cyborg
+ energy_type = /datum/robot_energy_storage/medical/adv_brute_kit
+ is_cyborg = TRUE
+/obj/item/stack/medical/bruise_pack/advanced/cyborg/syndicate
+ energy_type = /datum/robot_energy_storage/medical/adv_brute_kit/syndicate
//Ointment//
@@ -208,6 +218,13 @@
icon_state = "burnkit"
heal_burn = 25
+/obj/item/stack/medical/ointment/advanced/cyborg
+ energy_type = /datum/robot_energy_storage/medical/adv_burn_kit
+ is_cyborg = TRUE
+
+/obj/item/stack/medical/ointment/advanced/cyborg/syndicate
+ energy_type = /datum/robot_energy_storage/medical/adv_burn_kit/syndicate
+
//Medical Herbs//
/obj/item/stack/medical/bruise_pack/comfrey
name = "\improper Comfrey leaf"
@@ -283,6 +300,13 @@
H.handle_splints()
use(1)
+/obj/item/stack/medical/splint/cyborg
+ energy_type = /datum/robot_energy_storage/medical/splint
+ is_cyborg = TRUE
+
+/obj/item/stack/medical/splint/cyborg/syndicate
+ energy_type = /datum/robot_energy_storage/medical/splint/syndicate
+
/obj/item/stack/medical/splint/tribal
name = "tribal splints"
icon_state = "tribal_splint"
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
index ff469ba3c59..11a5dc4c39c 100644
--- a/code/game/objects/items/stacks/nanopaste.dm
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -63,3 +63,16 @@
to_chat(user, "Nothing to fix here.")
else
to_chat(user, "[src] won't work on that.")
+
+/obj/item/stack/nanopaste/cyborg
+ energy_type = /datum/robot_energy_storage/medical/nanopaste
+ is_cyborg = TRUE
+
+/obj/item/stack/nanopaste/cyborg/attack(mob/living/M, mob/user)
+ if(get_amount() <= 0)
+ to_chat(user, "You don't have enough energy to dispense more [name]!")
+ else
+ return ..()
+
+/obj/item/stack/nanopaste/cyborg/syndicate
+ energy_type = /datum/robot_energy_storage/medical/nanopaste/syndicate
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 3911ab51cc7..f9ec5cff198 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -21,10 +21,16 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
hitsound = 'sound/weapons/grenadelaunch.ogg'
toolspeed = 1
usesound = 'sound/items/deconstruct.ogg'
+ merge_type = /obj/item/stack/rods
/obj/item/stack/rods/cyborg
+ energy_type = /datum/robot_energy_storage/rods
+ is_cyborg = TRUE
materials = list()
+/obj/item/stack/rods/cyborg/update_icon()
+ return // icon_state should always be a full stack of rods.
+
/obj/item/stack/rods/ten
amount = 10
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 0e0bb55df85..91ededd189c 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -40,6 +40,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
amount = 50
/obj/item/stack/sheet/glass/cyborg
+ energy_type = /datum/robot_energy_storage/glass
+ is_cyborg = TRUE
materials = list()
/obj/item/stack/sheet/glass/New(loc, amount)
@@ -48,15 +50,15 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
/obj/item/stack/sheet/glass/attackby(obj/item/W, mob/user, params)
..()
- if(istype(W,/obj/item/stack/cable_coil))
+ if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/CC = W
- if(CC.amount < 5)
+ if(CC.get_amount() < 5)
to_chat(user, "There is not enough wire in this coil. You need 5 lengths.")
return
CC.use(5)
to_chat(user, "You attach wire to the [name].")
new /obj/item/stack/light_w(user.loc)
- src.use(1)
+ use(1)
else if( istype(W, /obj/item/stack/rods) )
var/obj/item/stack/rods/V = W
var/obj/item/stack/sheet/rglass/RG = new (user.loc)
@@ -97,9 +99,6 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
merge_type = /obj/item/stack/sheet/rglass
point_value = 4
-/obj/item/stack/sheet/rglass/cyborg
- materials = list()
-
/obj/item/stack/sheet/rglass/New(loc, amount)
recipes = GLOB.reinforced_glass_recipes
..()
@@ -109,6 +108,11 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
new/datum/stack_recipe/window("fulltile window", /obj/structure/window/full/plasmabasic, 2, time = 0, on_floor = TRUE, window_checks = TRUE) \
))
+/obj/item/stack/sheet/rglass/cyborg
+ energy_type = /datum/robot_energy_storage/rglass
+ is_cyborg = TRUE
+ materials = list()
+
/obj/item/stack/sheet/plasmaglass
name = "plasma glass"
desc = "A very strong and very resistant sheet of a plasma-glass alloy."
diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm
index 4eadda37c32..ddbe453a324 100644
--- a/code/game/objects/items/stacks/sheets/light.dm
+++ b/code/game/objects/items/stacks/sheets/light.dm
@@ -13,25 +13,16 @@
flags = CONDUCT
max_amount = 60
-/obj/item/stack/light_w/attackby(obj/item/O as obj, mob/user as mob, params)
+/obj/item/stack/light_w/attackby(obj/item/I, mob/user, params)
..()
- if(istype(O,/obj/item/wirecutters))
- var/obj/item/stack/cable_coil/CC = new/obj/item/stack/cable_coil(user.loc)
+ if(istype(I, /obj/item/wirecutters))
+ var/obj/item/stack/cable_coil/CC = new(user.loc)
CC.amount = 5
- amount--
new/obj/item/stack/sheet/glass(user.loc)
- if(amount <= 0)
- user.unEquip(src, 1)
- qdel(src)
+ use(1)
- if(istype(O,/obj/item/stack/sheet/metal))
- var/obj/item/stack/sheet/metal/M = O
- M.amount--
- if(M.amount <= 0)
- user.unEquip(src, 1)
- qdel(M)
- amount--
- new/obj/item/stack/tile/light(user.loc)
- if(amount <= 0)
- user.unEquip(src, 1)
- qdel(src)
+ if(istype(I, /obj/item/stack/sheet/metal))
+ var/obj/item/stack/sheet/metal/M = I
+ M.use(1)
+ new /obj/item/stack/tile/light(user.loc)
+ use(1)
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index a004cfd0de8..84c59310418 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -110,6 +110,8 @@ GLOBAL_LIST_INIT(metal_recipes, list(
point_value = 2
/obj/item/stack/sheet/metal/cyborg
+ energy_type = /datum/robot_energy_storage/metal
+ is_cyborg = TRUE
materials = list()
/obj/item/stack/sheet/metal/fifty
@@ -162,6 +164,10 @@ GLOBAL_LIST_INIT(plasteel_recipes, list(
recipes = GLOB.plasteel_recipes
return ..()
+/obj/item/stack/sheet/wood/cyborg
+ energy_type = /datum/robot_energy_storage/wood
+ is_cyborg = TRUE
+
/*
* Wood
*/
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index b57c3435132..6a2af11f0dc 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -10,7 +10,16 @@
*/
/obj/item/stack
origin_tech = "materials=1"
- var/list/recipes = list() // /datum/stack_recipe
+ /// Whether this stack is a `/cyborg` subtype or not.
+ var/is_cyborg = FALSE
+ /// The energy storage datum that will be used with this stack. Used only with `/cyborg` type stacks.
+ var/datum/robot_energy_storage/source
+ /// Which `robot_energy_storage` to choose when this stack is created in cyborgs. Used only with `/cyborg` type stacks.
+ var/energy_type
+ /// How much energy using 1 sheet from the stack costs. Used only with `/cyborg` type stacks.
+ var/cost = 1
+ /// A list of recipes buildable with this stack.
+ var/list/recipes = list()
var/singular_name
var/amount = 1
var/to_transfer = 0
@@ -52,15 +61,27 @@
/obj/item/stack/examine(mob/user)
. = ..()
- if(in_range(user, src))
+ if(!in_range(user, src))
+ return
+
+ if(is_cyborg)
if(singular_name)
- . += "There are [amount] [singular_name]\s in the stack."
+ . += "There is enough energy for [get_amount()] [singular_name]\s."
else
- . += "There are [amount] [name]\s in the stack."
- . +="Alt-click to take a custom amount."
+ . += "There is enough energy for [get_amount()]."
+ return
+
+ if(singular_name)
+ . += "There are [amount] [singular_name]\s in the stack."
+ else
+ . += "There are [amount] [name]\s in the stack."
+ . +="Alt-click to take a custom amount."
/obj/item/stack/proc/add(newamount)
- amount += newamount
+ if(is_cyborg)
+ source.add_charge(newamount * cost)
+ else
+ amount += newamount
update_icon()
/obj/item/stack/attack_self(mob/user)
@@ -87,8 +108,10 @@
if(!recipes)
return
- if(amount <= 0)
+ if(get_amount() <= 0)
user << browse(null, "window=stack")
+ if(is_cyborg)
+ to_chat(user, "You don't have enough energy to dispense more [name]!")
return
user.set_machine(src) //for correct work of onclose
@@ -98,7 +121,7 @@
var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist]
recipe_list = srl.recipes
- var/t1 = "Amount Left: [amount]
"
+ var/t1 = "Amount Left: [get_amount()]
"
for(var/i in 1 to recipe_list.len)
var/E = recipe_list[i]
if(isnull(E))
@@ -114,7 +137,7 @@
if(istype(E, /datum/stack_recipe))
var/datum/stack_recipe/R = E
- var/max_multiplier = round(amount / R.req_amount)
+ var/max_multiplier = round(get_amount() / R.req_amount)
var/title
var/can_build = 1
can_build = can_build && (max_multiplier > 0)
@@ -154,7 +177,7 @@
list_recipes(usr, text2num(href_list["sublist"]))
if(href_list["make"])
- if(amount < 1)
+ if(amount < 0 && !is_cyborg)
qdel(src) //Never should happen
var/list/recipes_list = recipes
@@ -167,8 +190,8 @@
if(!multiplier || multiplier <= 0 || multiplier > 50) // Href exploit checks
multiplier = 1
- if(amount < R.req_amount * multiplier)
- if(R.req_amount * multiplier>1)
+ if(get_amount() < R.req_amount * multiplier)
+ if(R.req_amount * multiplier > 1)
to_chat(usr, "You haven't got enough [src] to build \the [R.req_amount * multiplier] [R.title]\s!")
else
to_chat(usr, "You haven't got enough [src] to build \the [R.title]!")
@@ -195,7 +218,7 @@
if(!do_after(usr, R.time, target = usr))
return 0
- if(amount < R.req_amount * multiplier)
+ if(get_amount() < R.req_amount * multiplier)
return
var/atom/O
@@ -205,6 +228,7 @@
O = new R.result_type(usr.drop_location())
O.setDir(usr.dir)
use(R.req_amount * multiplier)
+ updateUsrDialog()
R.post_build(src, O)
@@ -231,6 +255,8 @@
/obj/item/stack/use(used, check = TRUE)
if(check && zero_amount())
return FALSE
+ if(is_cyborg)
+ return source.use_charge(used * cost)
if(amount < used)
return FALSE
amount -= used
@@ -240,6 +266,8 @@
return TRUE
/obj/item/stack/proc/get_amount()
+ if(is_cyborg)
+ return round(source.energy / cost)
return amount
/obj/item/stack/proc/get_max_amount()
@@ -258,7 +286,7 @@
return F
/obj/item/stack/attack_hand(mob/user)
- if(user.is_in_inactive_hand(src) && amount > 1)
+ if(user.is_in_inactive_hand(src) && get_amount() > 1)
change_stack(user, 1)
if(src && usr.machine == src)
spawn(0)
@@ -272,6 +300,8 @@
return
if(!in_range(src, user))
return
+ if(is_cyborg)
+ return
if(!ishuman(usr))
return
if(amount < 1)
@@ -305,11 +335,9 @@
// Returns TRUE if the stack amount is zero.
// Also qdels the stack gracefully if it is.
/obj/item/stack/proc/zero_amount()
+ if(is_cyborg)
+ return source.energy < cost
if(amount < 1)
- if(isrobot(loc))
- var/mob/living/silicon/robot/R = loc
- if(locate(src) in R.module.modules)
- R.module.modules -= src
if(ismob(loc))
var/mob/living/L = loc // At this stage, stack code is so horrible and atrocious, I wouldn't be all surprised ghosts can somehow have stacks. If this happens, then the world deserves to burn.
L.unEquip(src, TRUE)
@@ -325,7 +353,10 @@
if(QDELETED(S) || QDELETED(src) || S == src) //amusingly this can cause a stack to consume itself, let's not allow that.
return FALSE
var/transfer = get_amount()
- transfer = min(transfer, S.max_amount - S.amount)
+ if(S.is_cyborg)
+ transfer = min(transfer, round((S.source.max_energy - S.source.energy) / S.cost))
+ else
+ transfer = min(transfer, S.max_amount - S.amount)
if(transfer <= 0)
return
if(pulledby)
@@ -333,6 +364,7 @@
S.copy_evidences(src)
S.add(transfer)
use(transfer)
+ return transfer
/obj/item/stack/proc/copy_evidences(obj/item/stack/from)
blood_DNA = from.blood_DNA
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 4eb77144528..d148123be94 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -61,8 +61,13 @@
icon_state = "tile-wood"
origin_tech = "biotech=1"
turf_type = /turf/simulated/floor/wood
+ merge_type = /obj/item/stack/tile/wood
resistance_flags = FLAMMABLE
+/obj/item/stack/tile/wood/cyborg
+ energy_type = /datum/robot_energy_storage/wood_tile
+ is_cyborg = TRUE
+
//Carpets
/obj/item/stack/tile/carpet
name = "carpet"
@@ -101,6 +106,10 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
resistance_flags = FIRE_PROOF
+/obj/item/stack/tile/plasteel/cyborg
+ energy_type = /datum/robot_energy_storage/metal_tile
+ is_cyborg = TRUE
+
//Light
/obj/item/stack/tile/light
name = "light tiles"
diff --git a/code/game/objects/items/tools/welder.dm b/code/game/objects/items/tools/welder.dm
index 41801fe0287..8ab4c12cf0f 100644
--- a/code/game/objects/items/tools/welder.dm
+++ b/code/game/objects/items/tools/welder.dm
@@ -177,6 +177,9 @@
update_torch()
..()
+/obj/item/weldingtool/cyborg_recharge(coeff, emagged)
+ if(reagents.check_and_add("fuel", maximum_fuel, 2 * coeff))
+ update_icon()
/obj/item/weldingtool/largetank
name = "industrial welding tool"
diff --git a/code/game/objects/items/weapons/RCL.dm b/code/game/objects/items/weapons/RCL.dm
index 27583a7edd3..02827d3bcef 100644
--- a/code/game/objects/items/weapons/RCL.dm
+++ b/code/game/objects/items/weapons/RCL.dm
@@ -29,7 +29,7 @@
return
else
if(loaded.amount < max_amount)
- var/amount = min(loaded.amount + C.amount, max_amount)
+ var/amount = min(loaded.amount + C.get_amount(), max_amount)
C.use(amount - loaded.amount)
loaded.amount = amount
else
diff --git a/code/game/objects/items/weapons/alien_specific.dm b/code/game/objects/items/weapons/alien_specific.dm
index 8f6f0b2a82f..f78232653a8 100644
--- a/code/game/objects/items/weapons/alien_specific.dm
+++ b/code/game/objects/items/weapons/alien_specific.dm
@@ -29,6 +29,7 @@
desc = "squirts smokey liquids."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-spray-smoke"
+ list_reagents = list("water" = 50)
/obj/item/reagent_containers/spray/alien/smoke/afterattack(atom/A as mob|obj, mob/user as mob)
if(istype(A, /obj/structure/reagent_dispensers) && get_dist(src,A) <= 1)
@@ -45,17 +46,29 @@
smoke.start()
playsound(user.loc, 'sound/effects/bamf.ogg', 50, 2)
+/obj/item/reagent_containers/spray/alien/smoke/cyborg_recharge(coeff, emagged)
+ reagents.check_and_add("water", volume, 2 * coeff)
+
/obj/item/reagent_containers/spray/alien/acid
name = "acid synthesizer"
desc = "squirts burny liquids."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-spray-acid"
+ list_reagents = list("facid" = 125, "sacid" = 125)
+
+/obj/item/reagent_containers/spray/alien/acid/cyborg_recharge(coeff, emagged)
+ reagents.check_and_add("facid", volume / 2, 2 * coeff) // Volume / 2 here becuase there should be an even amount of both chems.
+ reagents.check_and_add("sacid", volume / 2, 2 * coeff)
/obj/item/reagent_containers/spray/alien/stun
name = "paralytic toxin synthesizer"
desc = "squirts viagra."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-spray-stun"
+ list_reagents = list("ether" = 250)
+
+/obj/item/reagent_containers/spray/alien/stun/cyborg_recharge(coeff, emagged)
+ reagents.check_and_add("ether", volume, 2 * coeff)
//SKREEEEEEEEEEEE tool
diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm
index ecc485737a4..0a3e8cd4a70 100644
--- a/code/game/objects/items/weapons/extinguisher.dm
+++ b/code/game/objects/items/weapons/extinguisher.dm
@@ -180,3 +180,6 @@
sleep(2)
else
return ..()
+
+/obj/item/extinguisher/cyborg_recharge(coeff, emagged)
+ reagents.check_and_add("water", max_water, 5 * coeff)
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index f2b0b475e30..f93f7220c75 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -314,7 +314,7 @@
//Therefore, make a new stack internally that has the remainder.
// -Sayu
- if(S.amount > S.max_amount)
+ if(S.get_amount() > S.max_amount)
var/obj/item/stack/sheet/temp = new S.type(src)
temp.amount = S.amount - S.max_amount
S.amount = S.max_amount
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 0df5817f598..a7d4bc4be3b 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -206,6 +206,11 @@
return TRUE
..()
+/obj/item/melee/baton/cyborg_recharge(coeff, emagged)
+ if(cell)
+ cell.charge = cell.maxcharge
+ update_icon()
+
//Makeshift stun baton. Replacement for stun gloves.
/obj/item/melee/baton/cattleprod
name = "stunprod"
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index e6341f14ed7..437721f383a 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2810,7 +2810,7 @@
if(R.module)
R.module.modules += I
I.loc = R.module
- R.module.rebuild()
+ R.module.rebuild_modules()
R.activate_module(I)
R.module.fix_modules()
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index 13e2d7bcb16..bfeaaa5c374 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -961,15 +961,13 @@
if(1)
if(iscoil(I))
var/obj/item/stack/cable_coil/coil = I
- if(coil.amount < 5)
+ if(coil.get_amount() < 5)
to_chat(user, "You need more cable for this!")
return
to_chat(user, "You wire \the [src]!")
playsound(get_turf(src), coil.usesound, 50, 1)
- coil.amount -= 5
- if(!coil.amount)
- qdel(coil)
+ coil.use(5)
buildstage = 2
update_icon()
diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm
index f6dbb48ed63..0fc71ecf4c9 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/modules/crafting/craft.dm
@@ -245,7 +245,7 @@
var/obj/item/stack/SD
while(amt > 0)
S = locate(A) in surroundings
- if(S.amount >= amt)
+ if(S.get_amount() >= amt)
if(!locate(S.type) in Deletion)
SD = new S.type()
Deletion += SD
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index 897e11443ff..9d9e81be9af 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -114,6 +114,9 @@
icon_state = "enzyme"
list_reagents = list("enzyme" = 50)
+/obj/item/reagent_containers/food/condiment/enzyme/cyborg_recharge(coeff, emagged)
+ reagents.check_and_add("enzyme", volume, 2 * coeff) // Only recharge if the current amount of enzyme is under `volume`.
+
/obj/item/reagent_containers/food/condiment/sugar
name = "sugar bottle"
desc = "Tasty spacey sugar!"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm b/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm
index 72782f532a6..12f09adeb10 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm
@@ -115,7 +115,7 @@
return 1
if(istype(O,/obj/item/stack))
var/obj/item/stack/S = O
- if(S.amount > 1)
+ if(S.get_amount() > 1)
var/obj/item/stack/to_add = S.split(user, 1)
to_add.forceMove(src)
user.visible_message("[user] adds one of [S] to [src].", "You add one of [S] to [src].")
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index fe05b61d867..8a98f7e30d2 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -307,7 +307,7 @@
return FALSE
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
- if(S.amount == 0)
+ if(!S.get_amount())
qdel(I)
return FALSE
if(put_in_active_hand(I))
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
index 16e81f53276..d1156b5c81d 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -179,62 +179,6 @@
to_chat(user, "Nothing on \the [T] is useful to you.")
return
-//PRETTIER TOOL LIST.
-/mob/living/silicon/robot/drone/installed_modules()
-
- if(weapon_lock)
- to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]")
- return
-
- if(!module)
- module = new /obj/item/robot_module/drone(src)
-
- var/dat = "
Drone modules\n"
- dat += {"Close
-
-
- Activated Modules
-
- Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
- Module 2: [module_state_2 ? "[module_state_2]" : "No Module"]
- Module 3: [module_state_3 ? "[module_state_3]" : "No Module"]
-
- Installed Modules
"}
-
-
- var/tools = "Tools and devices
"
- var/resources = "
Resources
"
-
- for(var/O in module.modules)
-
- var/module_string = ""
-
- if(!O)
- module_string += text("Resource depleted
")
- else if(activated(O))
- module_string += text("[O]: Activated
")
- else
- module_string += text("[O]: Activate
")
-
- if((istype(O,/obj/item) || istype(O,/obj/item)) && !(istype(O,/obj/item/stack/cable_coil)))
- tools += module_string
- else
- resources += module_string
-
- dat += tools
-
- if(emagged)
- if(!module.emag)
- dat += text("Resource depleted
")
- else if(activated(module.emag))
- dat += text("[module.emag]: Activated
")
- else
- dat += text("[module.emag]: Activate
")
-
- dat += resources
-
- src << browse(dat, "window=robotmod&can_close=0")
-
//Putting the decompiler here to avoid doing list checks every tick.
/mob/living/silicon/robot/drone/use_power()
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index 32ce86e582f..3357bddc925 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -40,7 +40,7 @@
return 1
/mob/living/silicon/robot/proc/activate_module(obj/item/O)
- if(!(locate(O) in src.module.modules) && O != src.module.emag)
+ if(!(locate(O) in module.modules) && !(O in module.emag_modules))
return
if(activated(O))
to_chat(src, "Already activated")
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index c67d64a72b1..9bacb40fff2 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -482,6 +482,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
speed = 0 // Remove upgrades.
ionpulse = FALSE
magpulse = FALSE
+ weapons_unlock = FALSE
add_language("Robot Talk", TRUE)
if("lava" in weather_immunities) // Remove the lava-immunity effect given by a printable upgrade
weather_immunities -= "lava"
@@ -635,17 +636,27 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
else
stat(null, text("No Cell Inserted!"))
+/mob/living/silicon/robot/proc/show_gps_coords()
+ if(locate(/obj/item/gps/cyborg) in module.modules)
+ var/turf/T = get_turf(src)
+ stat(null, "GPS: [COORD(T)]")
+
+/mob/living/silicon/robot/proc/show_stack_energy()
+ for(var/storage in module.storages) // Storages should only contain `/datum/robot_energy_storage`
+ var/datum/robot_energy_storage/R = storage
+ stat(null, "[R.statpanel_name]: [R.energy] / [R.max_energy]")
// update the status screen display
/mob/living/silicon/robot/Stat()
..()
- statpanel("Status")
- if(client.statpanel == "Status")
- show_cell_power()
- var/total_user_contents = GetAllContents()
- if(locate(/obj/item/gps/cyborg) in total_user_contents)
- var/turf/T = get_turf(src)
- stat(null, "GPS: [COORD(T)]")
+ if(!statpanel("Status"))
+ return // They aren't looking at the status panel.
+
+ show_cell_power()
+
+ if(module)
+ show_gps_coords()
+ show_stack_energy()
/mob/living/silicon/robot/restrained()
return 0
@@ -774,16 +785,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
to_chat(user, "You must access the borg's internals!")
else if(!src.module && U.require_module)
to_chat(user, "The borg must choose a module before it can be upgraded!")
- else if(U.locked)
- to_chat(user, "The upgrade is locked and cannot be used yet!")
else
if(!user.drop_item())
return
if(U.action(src))
- user.visible_message("[user] applied [U] to [src].", "You apply [U] to [src].")
+ user.visible_message("[user] applied [U] to [src].", "You apply [U] to [src].")
U.forceMove(src)
- else
- to_chat(user, "Upgrade error.")
else if(istype(W, /obj/item/mmi_radio_upgrade))
if(!opened)
@@ -910,7 +917,19 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
spark_system.start()
..()
-/mob/living/silicon/robot/emag_act(user as mob)
+// Here so admins can unemag borgs.
+/mob/living/silicon/robot/unemag()
+ SetEmagged(FALSE)
+ if(!module)
+ return
+ uneq_all()
+ module.module_type = initial(module.module_type)
+ update_module_icon()
+ module.unemag()
+ clear_supplied_laws()
+ laws = new /datum/ai_laws/crewsimov
+
+/mob/living/silicon/robot/emag_act(mob/user)
if(!ishuman(user) && !issilicon(user))
return
var/mob/living/M = user
@@ -925,7 +944,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return
if(opened)//Cover is open
- if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice
+ if(emagged)
+ return //Prevents the X has hit Y with Z message also you cant emag them twice
if(wiresexposed)
to_chat(user, "You must close the panel first")
return
@@ -933,11 +953,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
sleep(6)
SetEmagged(TRUE)
SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
- if(src.hud_used)
- src.hud_used.update_robot_modules_display() //Shows/hides the emag item if the inventory screen is already open.
+ if(hud_used)
+ hud_used.update_robot_modules_display() //Shows/hides the emag item if the inventory screen is already open.
disconnect_from_ai()
to_chat(user, "You emag [src]'s interface.")
-// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
clear_supplied_laws()
clear_inherent_laws()
@@ -963,17 +982,11 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
laws.show_laws(src)
to_chat(src, "ALERT: [M.real_name] is your new master. Obey your new laws and [M.p_their()] commands.")
SetLockdown(0)
- if(src.module && istype(src.module, /obj/item/robot_module/miner))
- for(var/obj/item/pickaxe/drill/cyborg/D in src.module.modules)
- qdel(D)
- src.module.modules += new /obj/item/pickaxe/drill/cyborg/diamond(src.module)
- src.module.rebuild()
- if(src.module && istype(src.module, /obj/item/robot_module/medical))
- for(var/obj/item/borg_defib/F in src.module.modules)
- F.safety = 0
if(module)
+ module.emag_act()
module.module_type = "Malf" // For the cool factor
update_module_icon()
+ module.rebuild_modules() // This will add the emagged items to the borgs inventory.
update_icons()
return
@@ -1041,51 +1054,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/borg_icons() // Exists so that robot/destroyer can override it
return
-/mob/living/silicon/robot/proc/installed_modules()
- if(weapon_lock)
- to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]")
- return
-
- if(!module)
- pick_module()
- return
- var/dat = {"Close
-
-
- Activated Modules
-
-
- Installed Modules
-
- "}
- for(var/obj in module.modules)
- if(!obj)
- dat += text("| Resource depleted |
")
- else if(activated(obj))
- dat += text("| [obj] | Activated |
")
- else
- dat += text("| [obj] | Activate |
")
- if(emagged || weapons_unlock)
- if(activated(module.emag))
- dat += text("| [module.emag] | Activated |
")
- else
- dat += text("| [module.emag] | Activate |
")
- dat += "
"
-/*
- if(activated(obj))
- dat += text("[obj]: \[Activated | Deactivate\]
")
- else
- dat += text("[obj]: \[Activate | Deactivated\]
")
-*/
- var/datum/browser/popup = new(src, "robotmod", "Modules")
- popup.set_content(dat)
- popup.open()
-
-
/mob/living/silicon/robot/Topic(href, href_list)
if(..())
return 1
@@ -1111,7 +1079,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return 1
activate_module(O)
- installed_modules()
//Show alerts window if user clicked on "Show alerts" in chat
if(href_list["showalerts"])
@@ -1134,7 +1101,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
to_chat(src, "Module isn't activated.")
else
to_chat(src, "Module isn't activated")
- installed_modules()
return 1
return 1
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 29fd2a0235c..71d8d5ef19b 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -6,77 +6,213 @@
item_state = "electronic"
flags = CONDUCT
+ /// A list of all currently usable and created modules the robot currently has access too.
var/list/modules = list()
- var/obj/item/emag = null
- var/list/subsystems = list()
+ /// A list of module-specific, non-emag modules the borg will gain when this module is chosen.
+ var/list/basic_modules = list()
+ /// A list of modules the robot gets when emagged.
+ var/list/emag_modules = list()
+ /// A list of modules that require special recharge handling. Examples include things like flashes, sprays and welding tools.
+ var/list/special_rechargables = list()
+ /// A list of all "energy stacks", i.e metal, glass, brute kits, splints, etc.
+ var/list/storages = list()
+ /// Special actions this module will gain when chosen such as meson vision, or thermal vision.
var/list/module_actions = list()
-
- var/module_type = "NoMod" // For icon usage
-
- var/list/stacktypes
- var/channels = list()
+ /// Available tools given in the verb tab such as a crew monitor, or power monitor.
+ var/list/subsystems = list()
+ /// Radio channels the module owner has access to.
+ var/list/channels = list()
+ /// Special items that are able to be removed from the robot owner via crowbar.
var/list/custom_removals = list()
-
-
-/obj/item/robot_module/emp_act(severity)
- if(modules)
- for(var/obj/O in modules)
- O.emp_act(severity)
- if(emag)
- emag.emp_act(severity)
- ..()
+ /// For icon usage.
+ var/module_type = "NoMod"
/obj/item/robot_module/New()
..()
- add_default_robot_items()
- emag = new /obj/item/toy/sword(src)
- emag.name = "Placeholder Emag Item"
+
+ // Creates new objects from the type lists.
+ for(var/i in basic_modules)
+ var/obj/item/I = new i(src)
+ basic_modules += I
+ basic_modules -= i
+
+ // Even though these are created here the robot won't be able to see and equip them until they actually get emagged/hacked.
+ for(var/i in emag_modules)
+ var/obj/item/I = new i(src)
+ emag_modules += I
+ emag_modules -= i
+
+ // Flashes need a special recharge, and since basically every module uses it, add it here.
+ // Even if the module doesn't use a flash, it wont cause any issues to have it in this list.
+ special_rechargables += /obj/item/flash/cyborg
+
+ // This is done so we can loop through this list later and call cyborg_recharge() on the items while the borg is recharging.
+ var/all_modules = basic_modules | emag_modules
+ for(var/path in special_rechargables)
+ var/obj/item/I = locate(path) in all_modules
+ if(I) // If it exists, add the object reference.
+ special_rechargables += I
+ special_rechargables -= path // No matter what, remove the path from the list.
+
+ // Add all the modules into the robot's inventory. Without this, their inventory will be blank.
+ rebuild_modules()
+
+
+/obj/item/robot_module/emp_act(severity)
+ . = ..()
+ for(var/object in modules)
+ var/obj/O = object
+ O.emp_act(severity)
/obj/item/robot_module/Destroy()
+ // These can all contain actual objects, so we need to null them out.
QDEL_LIST(modules)
- QDEL_NULL(emag)
+ QDEL_LIST(basic_modules)
+ QDEL_LIST(emag_modules)
+ QDEL_LIST(storages)
+ QDEL_LIST(special_rechargables)
return ..()
-// By default, all robots will get the items in this proc, unless you override it for your specific module. See: ../robot_module/drone
-/obj/item/robot_module/proc/add_default_robot_items()
- modules += new /obj/item/flash/cyborg(src)
+/**
+ * Searches through the various module lists for the given `item_type`, deletes and removes the item from all supplied lists, if the item is found.
+ *
+ * NOTE: be careful with using this proc, as it irreversibly removes entries from a borg's module list.
+ * This is safe to do with upgrades because the only way to revert upgrades currently is either to rebuild the borg or use a reset module, which allows the lists to regenerate.
+ *
+ * Arugments:
+ * * item_type - the type of item to search for. Also accepts objects themselves.
+ */
+/obj/item/robot_module/proc/remove_item_from_lists(item_or_item_type)
+ var/list/lists = list(
+ basic_modules,
+ emag_modules,
+ storages,
+ special_rechargables
+ )
+ for(var/_list in lists)
+ for(var/item in _list)
+ var/obj/item/I = item
+ if(!istype(I, item_or_item_type))
+ continue
+ if(!QDELETED(I))
+ qdel(I)
+ _list -= I
+
+// Here for admin debugging purposes only.
/obj/item/robot_module/proc/fix_modules()
- for(var/obj/item/I in modules)
+ for(var/item in modules)
+ var/obj/item/I = item
I.flags |= NODROP
I.mouse_opacity = MOUSE_OPACITY_OPAQUE
- if(emag)
- emag.flags |= NODROP
- emag.mouse_opacity = MOUSE_OPACITY_OPAQUE
-/obj/item/robot_module/proc/respawn_consumable(mob/living/silicon/robot/R)
- if(!stacktypes || !stacktypes.len)
+/**
+ * Returns a `robot_energy_strage` datum of type `storage_type`. If one already exists, it returns that one, otherwise it create a new one.
+ *
+ * Arguments:
+ * * storage_type - the subtype of `datum/robot_energy_storage` to fetch or create.
+ */
+/obj/item/robot_module/proc/get_or_create_estorage(storage_type)
+ for(var/e_storage in storages)
+ var/datum/robot_energy_storage/S = e_storage
+ if(istype(S, storage_type))
+ return S
+ return new storage_type(src)
+
+/**
+ * Adds the item `I` to our `modules` list, and sets up an `/datum/robot_energy_storage` if its a stack.
+ *
+ * Arugments:
+ * * I - the item to add to our modules.
+ * * requires_rebuild - if adding this item requires `rebuild_modules()` to be called.
+ */
+/obj/item/robot_module/proc/add_module(obj/item/I, requires_rebuild)
+ if(I in modules) // No duplicate items.
return
- var/stack_respawned = 0
- for(var/T in stacktypes)
- var/O = locate(T) in modules
- var/obj/item/stack/S = O
+ if(istype(I, /obj/item/stack))
+ var/obj/item/stack/S = I
- if(!S)
- S = new T(src)
- modules += S
- S.amount = 1
- stack_respawned = 1
+ if(S.energy_type)
+ S.source = get_or_create_estorage(S.energy_type)
+ S.is_cyborg = TRUE
- if(S && S.amount < stacktypes[T])
- S.amount++
- if(stack_respawned && istype(R) && R.hud_used)
+ // Here for safety. Using a cyborg stack without a `source` will create hundreds of runtimes.
+ if(!S.source)
+ qdel(S)
+ return
+
+ if(I.loc != src)
+ I.forceMove(src)
+
+ modules += I
+ I.flags |= NODROP
+ I.mouse_opacity = MOUSE_OPACITY_OPAQUE
+
+ if(requires_rebuild)
+ rebuild_modules()
+ return I
+
+/**
+ * Builds the usable module list from the modules we have in `basic_modules` and `emag_modules`
+ */
+/obj/item/robot_module/proc/rebuild_modules()
+ var/mob/living/silicon/robot/R = loc
+ R.uneq_all()
+ modules = list()
+
+ // By this point these lists should only contain items. It's safe to use typeless loops here.
+ for(var/item in basic_modules)
+ add_module(item, FALSE)
+
+ if(R.emagged || R.weapons_unlock)
+ for(var/item in emag_modules)
+ add_module(item, FALSE)
+
+ if(R.hud_used)
R.hud_used.update_robot_modules_display()
-/obj/item/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module
- var/list/temp_list = modules
- modules = list()
- for(var/obj/O in temp_list)
- if(!QDELETED(O)) //so items getting deleted don't stay in module list and haunt you
- modules += O
+/**
+ * Handles the recharging of all borg stack items and any items which are in the `special_rechargables` list.
+ *
+ * Arguments:
+ * * R - the owner of this module.
+ * * coeff - a coefficient which can be used to modify the recharge rate of consumables.
+ */
+/obj/item/robot_module/proc/recharge_consumables(mob/living/silicon/robot/R, coeff = 1)
+ for(var/e_storage in storages)
+ var/datum/robot_energy_storage/E = e_storage
+ E.add_charge(max(1, coeff * E.recharge_rate))
+ for(var/item in special_rechargables)
+ var/obj/item/I = item
+ I.cyborg_recharge(coeff, R.emagged)
+/**
+ * Called when the robot owner of this module has the `unemag()` proc called on them, which is only via admin means.
+ *
+ * Deletes this module's emag items, and recreates them.
+ */
+/obj/item/robot_module/unemag()
+ . = ..()
+ for(var/item in emag_modules)
+ var/obj/item/old_item = item
+ var/obj/item/new_item = new old_item.type(src)
+ emag_modules += new_item
+ if(old_item in special_rechargables) // If the old item was in this list, make sure the new one goes into it as well.
+ special_rechargables += new_item
+ special_rechargables -= old_item
+ modules -= old_item
+ emag_modules -= old_item
+ qdel(old_item)
+ rebuild_modules()
+
+/**
+ * Adds all of the languages this module is suppose to know and/or speak.
+ *
+ * Arugments:
+ * * R - the owner of this module.
+ */
/obj/item/robot_module/proc/add_languages(mob/living/silicon/robot/R)
//full set of languages
R.add_language("Galactic Common", 1)
@@ -94,8 +230,9 @@
R.add_language("Chittin", 0)
R.add_language("Bubblish", 0)
R.add_language("Orluum", 0)
- R.add_language("Clownish",0)
+ R.add_language("Clownish", 0)
+/// Adds anything in `subsystems` to the robot's verbs, and grants any actions that are in `module_actions`.
/obj/item/robot_module/proc/add_subsystems_and_actions(mob/living/silicon/robot/R)
R.verbs |= subsystems
for(var/A in module_actions)
@@ -103,6 +240,7 @@
act.Grant(R)
R.module_actions += act
+/// Removes any verbs from the robot that are in `subsystems`, and removes any actions that are in `module_actions`.
/obj/item/robot_module/proc/remove_subsystems_and_actions(mob/living/silicon/robot/R)
R.verbs -= subsystems
for(var/datum/action/A in R.module_actions)
@@ -117,6 +255,7 @@
/obj/item/robot_module/proc/handle_death(mob/living/silicon/robot/R, gibbed)
return
+// Standard cyborg module.
/obj/item/robot_module/standard
// if station is fine, assist with constructing station goal room, cleaning, and repairing cables chewed by rats
// if medical crisis, assist by providing basic healthcare, retrieving corpses, and monitoring crew lifesigns
@@ -125,221 +264,214 @@
name = "generalist robot module"
module_type = "Standard"
subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor, /mob/living/silicon/proc/subsystem_crew_monitor)
- stacktypes = list(
- /obj/item/stack/sheet/metal/cyborg = 50,
- /obj/item/stack/cable_coil/cyborg = 50,
- /obj/item/stack/rods/cyborg = 60,
- /obj/item/stack/tile/plasteel = 20
- )
-
-/obj/item/robot_module/standard/New()
- ..()
- // sec
- modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
- // janitorial
- modules += new /obj/item/soap/nanotrasen(src)
- modules += new /obj/item/lightreplacer/cyborg(src)
- // eng
- modules += new /obj/item/crowbar/cyborg(src)
- modules += new /obj/item/wrench/cyborg(src)
- modules += new /obj/item/extinguisher(src) // for firefighting, and propulsion in space
- modules += new /obj/item/weldingtool/largetank/cyborg(src)
- // mining
- modules += new /obj/item/pickaxe(src)
- modules += new /obj/item/t_scanner/adv_mining_scanner(src)
- modules += new /obj/item/storage/bag/ore/cyborg(src)
- // med
- modules += new /obj/item/healthanalyzer(src)
- modules += new /obj/item/reagent_containers/borghypo/basic(src)
- modules += new /obj/item/roller_holder(src) // for taking the injured to medbay without worsening their injuries or leaving a blood trail the whole way
- emag = new /obj/item/melee/energy/sword/cyborg(src)
- for(var/G in stacktypes)
- var/obj/item/stack/sheet/M = new G(src)
- M.amount = stacktypes[G]
- modules += M
- fix_modules()
-
+ basic_modules = list(
+ // sec
+ /obj/item/flash/cyborg,
+ /obj/item/restraints/handcuffs/cable/zipties/cyborg,
+ // janitorial
+ /obj/item/soap/nanotrasen,
+ /obj/item/lightreplacer/cyborg,
+ // eng
+ /obj/item/crowbar/cyborg,
+ /obj/item/wrench/cyborg,
+ /obj/item/extinguisher, // for firefighting, and propulsion in space
+ /obj/item/weldingtool/largetank/cyborg,
+ // mining
+ /obj/item/pickaxe,
+ /obj/item/t_scanner/adv_mining_scanner,
+ /obj/item/storage/bag/ore/cyborg,
+ // med
+ /obj/item/healthanalyzer,
+ /obj/item/reagent_containers/borghypo/basic,
+ /obj/item/roller_holder, // for taking the injured to medbay without worsening their injuries or leaving a blood trail the whole way
+ /obj/item/stack/sheet/metal/cyborg,
+ /obj/item/stack/cable_coil/cyborg,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg
+ )
+ emag_modules = list(/obj/item/melee/energy/sword/cyborg)
+ special_rechargables = list(
+ /obj/item/extinguisher,
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/lightreplacer/cyborg
+ )
+// Medical cyborg module.
/obj/item/robot_module/medical
name = "medical robot module"
module_type = "Medical"
subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor)
- stacktypes = list(
- /obj/item/stack/medical/bruise_pack/advanced = 6,
- /obj/item/stack/medical/ointment/advanced = 6,
- /obj/item/stack/medical/splint = 6,
- /obj/item/stack/nanopaste = 6
- )
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/healthanalyzer/advanced,
+ /obj/item/robotanalyzer,
+ /obj/item/reagent_scanner/adv,
+ /obj/item/borg_defib,
+ /obj/item/handheld_defibrillator,
+ /obj/item/roller_holder,
+ /obj/item/reagent_containers/borghypo,
+ /obj/item/scalpel/laser/laser1,
+ /obj/item/hemostat,
+ /obj/item/retractor,
+ /obj/item/circular_saw,
+ /obj/item/surgicaldrill,
+ /obj/item/bonesetter,
+ /obj/item/bonegel,
+ /obj/item/FixOVein,
+ /obj/item/extinguisher/mini,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/syringe,
+ /obj/item/stack/medical/bruise_pack/advanced/cyborg,
+ /obj/item/stack/medical/ointment/advanced/cyborg,
+ /obj/item/stack/medical/splint/cyborg,
+ /obj/item/stack/nanopaste/cyborg,
+ /obj/item/gripper/medical
+ )
+ emag_modules = list(/obj/item/reagent_containers/spray/cyborg_facid)
+ special_rechargables = list(/obj/item/reagent_containers/spray/cyborg_facid, /obj/item/extinguisher/mini)
-/obj/item/robot_module/medical/New()
- ..()
- modules += new /obj/item/healthanalyzer/advanced(src)
- modules += new /obj/item/robotanalyzer(src)
- modules += new /obj/item/reagent_scanner/adv(src)
- modules += new /obj/item/borg_defib(src)
- modules += new /obj/item/handheld_defibrillator(src)
- modules += new /obj/item/roller_holder(src)
- modules += new /obj/item/reagent_containers/borghypo(src)
- modules += new /obj/item/reagent_containers/glass/beaker/large(src)
- modules += new /obj/item/reagent_containers/dropper(src)
- modules += new /obj/item/reagent_containers/syringe(src)
- modules += new /obj/item/extinguisher/mini(src)
- modules += new /obj/item/stack/medical/bruise_pack/advanced(src)
- modules += new /obj/item/stack/medical/ointment/advanced(src)
- modules += new /obj/item/stack/medical/splint(src)
- modules += new /obj/item/stack/nanopaste(src)
- modules += new /obj/item/scalpel/laser/laser1(src)
- modules += new /obj/item/hemostat(src)
- modules += new /obj/item/retractor(src)
- modules += new /obj/item/bonegel(src)
- modules += new /obj/item/FixOVein(src)
- modules += new /obj/item/bonesetter(src)
- modules += new /obj/item/circular_saw(src)
- modules += new /obj/item/surgicaldrill(src)
- modules += new /obj/item/gripper/medical(src)
+// Disable safeties on the borg's defib.
+/obj/item/robot_module/medical/emag_act()
+ . = ..()
+ for(var/obj/item/borg_defib/F in modules)
+ F.safety = FALSE
- emag = new /obj/item/reagent_containers/spray(src)
+// Enable safeties on the borg's defib.
+/obj/item/robot_module/medical/unemag()
+ for(var/obj/item/borg_defib/F in modules)
+ F.safety = TRUE
+ return ..()
- emag.reagents.add_reagent("facid", 250)
- emag.name = "Polyacid spray"
+// Fluorosulphuric acid spray bottle.
+/obj/item/reagent_containers/spray/cyborg_facid
+ name = "Polyacid spray"
+ list_reagents = list("facid" = 250)
- fix_modules()
-
-/obj/item/robot_module/medical/respawn_consumable(mob/living/silicon/robot/R)
- if(emag)
- var/obj/item/reagent_containers/spray/PS = emag
- PS.reagents.add_reagent("facid", 2)
- ..()
+/obj/item/reagent_containers/spray/cyborg_facid/cyborg_recharge(coeff, emagged)
+ if(emagged)
+ reagents.check_and_add("facid", volume, 2 * coeff)
+// Engineering cyborg module.
/obj/item/robot_module/engineering
name = "engineering robot module"
module_type = "Engineer"
subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor)
- module_actions = list(
- /datum/action/innate/robot_sight/meson,
+ module_actions = list(/datum/action/innate/robot_sight/meson)
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/rcd/borg,
+ /obj/item/rpd,
+ /obj/item/extinguisher,
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/screwdriver/cyborg,
+ /obj/item/wrench/cyborg,
+ /obj/item/crowbar/cyborg,
+ /obj/item/wirecutters/cyborg,
+ /obj/item/multitool/cyborg,
+ /obj/item/t_scanner,
+ /obj/item/analyzer,
+ /obj/item/geiger_counter/cyborg,
+ /obj/item/holosign_creator/engineering,
+ /obj/item/gripper,
+ /obj/item/matter_decompiler,
+ /obj/item/floor_painter,
+ /obj/item/areaeditor/blueprints/cyborg,
+ /obj/item/stack/sheet/metal/cyborg,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/stack/cable_coil/cyborg,
+ /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/rglass/cyborg
)
-
- stacktypes = list(
- /obj/item/stack/sheet/metal/cyborg = 50,
- /obj/item/stack/sheet/glass/cyborg = 50,
- /obj/item/stack/sheet/rglass/cyborg = 50,
- /obj/item/stack/cable_coil/cyborg = 50,
- /obj/item/stack/rods/cyborg = 60,
- /obj/item/stack/tile/plasteel = 20
- )
-
-/obj/item/robot_module/engineering/New()
- ..()
- modules += new /obj/item/rcd/borg(src)
- modules += new /obj/item/rpd(src)
- modules += new /obj/item/extinguisher(src)
- modules += new /obj/item/weldingtool/largetank/cyborg(src)
- modules += new /obj/item/screwdriver/cyborg(src)
- modules += new /obj/item/wrench/cyborg(src)
- modules += new /obj/item/crowbar/cyborg(src)
- modules += new /obj/item/wirecutters/cyborg(src)
- modules += new /obj/item/multitool/cyborg(src)
- modules += new /obj/item/t_scanner(src)
- modules += new /obj/item/analyzer(src)
- modules += new /obj/item/geiger_counter/cyborg(src)
- modules += new /obj/item/holosign_creator/engineering(src)
- modules += new /obj/item/gripper(src)
- modules += new /obj/item/matter_decompiler(src)
- modules += new /obj/item/floor_painter(src)
- modules += new /obj/item/areaeditor/blueprints/cyborg(src)
- emag = new /obj/item/borg/stun(src)
-
- for(var/G in stacktypes) //Attempt to unify Engi-Borg material stacks into fewer lines. See Line 492 for example. Variables changed out of paranoia.
- var/obj/item/stack/sheet/M = new G(src)
- M.amount = stacktypes[G]
- modules += M
-
- fix_modules()
+ emag_modules = list(/obj/item/borg/stun)
+ special_rechargables = list(/obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg)
/obj/item/robot_module/engineering/handle_death(mob/living/silicon/robot/R, gibbed)
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
if(G)
G.drop_gripped_item(silent = TRUE)
+// Security cyborg module.
/obj/item/robot_module/security
name = "security robot module"
module_type = "Security"
subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor)
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/restraints/handcuffs/cable/zipties/cyborg,
+ /obj/item/melee/baton/loaded,
+ /obj/item/gun/energy/disabler/cyborg,
+ /obj/item/holosign_creator/security,
+ /obj/item/clothing/mask/gas/sechailer/cyborg
+ )
+ emag_modules = list(/obj/item/gun/energy/laser/cyborg)
+ special_rechargables = list(/obj/item/melee/baton/loaded, /obj/item/gun/energy/disabler/cyborg)
-/obj/item/robot_module/security/New()
- ..()
- modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
- modules += new /obj/item/melee/baton/loaded(src)
- modules += new /obj/item/gun/energy/disabler/cyborg(src)
- modules += new /obj/item/holosign_creator/security(src)
- modules += new /obj/item/clothing/mask/gas/sechailer/cyborg(src)
- emag = new /obj/item/gun/energy/laser/cyborg(src)
-
- fix_modules()
-
+// Janitor cyborg module.
/obj/item/robot_module/janitor
name = "janitorial robot module"
module_type = "Janitor"
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/soap/nanotrasen,
+ /obj/item/storage/bag/trash/cyborg,
+ /obj/item/mop/advanced/cyborg,
+ /obj/item/lightreplacer/cyborg,
+ /obj/item/holosign_creator,
+ /obj/item/extinguisher/mini
+ )
+ emag_modules = list(/obj/item/reagent_containers/spray/cyborg_lube)
+ special_rechargables = list(
+ /obj/item/lightreplacer,
+ /obj/item/reagent_containers/spray/cyborg_lube,
+ /obj/item/extinguisher/mini
+ )
-/obj/item/robot_module/janitor/New()
- ..()
- modules += new /obj/item/soap/nanotrasen(src)
- modules += new /obj/item/storage/bag/trash/cyborg(src)
- modules += new /obj/item/mop/advanced/cyborg(src)
- modules += new /obj/item/lightreplacer/cyborg(src)
- modules += new /obj/item/holosign_creator(src)
- modules += new /obj/item/extinguisher/mini(src)
- emag = new /obj/item/reagent_containers/spray(src)
+/obj/item/reagent_containers/spray/cyborg_lube
+ name = "Lube spray"
+ list_reagents = list("lube" = 250)
- emag.reagents.add_reagent("lube", 250)
- emag.name = "Lube spray"
-
- fix_modules()
-
-/obj/item/robot_module/janitor/respawn_consumable(mob/living/silicon/robot/R)
- if(emag)
- var/obj/item/reagent_containers/spray/S = emag
- S.reagents.add_reagent("lube", 5)
- ..()
+/obj/item/reagent_containers/spray/cyborg_lube/cyborg_recharge(coeff, emagged)
+ if(emagged)
+ reagents.check_and_add("lube", volume, 2 * coeff)
+// Service cyborg module.
/obj/item/robot_module/butler
name = "service robot module"
module_type = "Service"
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/handheld_chem_dispenser/booze,
+ /obj/item/handheld_chem_dispenser/soda,
+ /obj/item/pen,
+ /obj/item/razor,
+ /obj/item/instrument/piano_synth,
+ /obj/item/healthanalyzer/advanced,
+ /obj/item/reagent_scanner/adv,
+ /obj/item/rsf/cyborg,
+ /obj/item/reagent_containers/dropper/cyborg,
+ /obj/item/lighter/zippo,
+ /obj/item/storage/bag/tray/cyborg,
+ /obj/item/reagent_containers/food/drinks/shaker
+ )
+ emag_modules = list(/obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer)
+ special_rechargables = list(
+ /obj/item/reagent_containers/food/condiment/enzyme,
+ /obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer
+ )
-/obj/item/robot_module/butler/New()
- ..()
- modules += new /obj/item/handheld_chem_dispenser/booze(src)
- modules += new /obj/item/handheld_chem_dispenser/soda(src)
+/obj/item/rsf/cyborg
+ matter = 30
- modules += new /obj/item/pen(src)
- modules += new /obj/item/razor(src)
- modules += new /obj/item/instrument/piano_synth(src)
- modules += new /obj/item/healthanalyzer/advanced(src)
- modules += new /obj/item/reagent_scanner/adv(src)
+// This is a special type of beer given when emagged, one sip and the target falls asleep.
+/obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer
+ name = "Mickey Finn's Special Brew"
+ list_reagents = list("beer2" = 50)
- var/obj/item/rsf/M = new /obj/item/rsf(src)
- M.matter = 30
- modules += M
-
- modules += new /obj/item/reagent_containers/dropper/cyborg(src)
- modules += new /obj/item/lighter/zippo(src)
- modules += new /obj/item/storage/bag/tray/cyborg(src)
- modules += new /obj/item/reagent_containers/food/drinks/shaker(src)
- emag = new /obj/item/reagent_containers/food/drinks/cans/beer(src)
-
- var/datum/reagents/R = new/datum/reagents(50)
- emag.reagents = R
- R.my_atom = emag
- R.add_reagent("beer2", 50)
- emag.name = "Mickey Finn's Special Brew"
-
- fix_modules()
-
-/obj/item/robot_module/butler/respawn_consumable(mob/living/silicon/robot/R)
- if(emag)
- var/obj/item/reagent_containers/food/drinks/cans/beer/B = emag
- B.reagents.add_reagent("beer2", 5)
- ..()
+/obj/item/reagent_containers/food/drinks/cans/beer/sleepy_beer/cyborg_recharge(coeff, emagged)
+ if(emagged)
+ reagents.check_and_add("beer2", volume, 5)
/obj/item/robot_module/butler/add_languages(mob/living/silicon/robot/R)
//full set of languages
@@ -368,267 +500,352 @@
/obj/item/robot_module/miner
name = "miner robot module"
module_type = "Miner"
- module_actions = list(
- /datum/action/innate/robot_sight/meson,
- )
+ module_actions = list(/datum/action/innate/robot_sight/meson)
custom_removals = list("KA modkits")
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/storage/bag/ore/cyborg,
+ /obj/item/pickaxe/drill/cyborg,
+ /obj/item/shovel,
+ /obj/item/weldingtool/mini,
+ /obj/item/extinguisher/mini,
+ /obj/item/storage/bag/sheetsnatcher/borg,
+ /obj/item/t_scanner/adv_mining_scanner/cyborg,
+ /obj/item/gun/energy/kinetic_accelerator/cyborg,
+ /obj/item/gps/cyborg
+ )
+ emag_modules = list(/obj/item/borg/stun, /obj/item/pickaxe/drill/cyborg/diamond)
+ special_rechargables = list(/obj/item/extinguisher/mini, /obj/item/weldingtool/mini)
-/obj/item/robot_module/miner/New()
- ..()
- modules += new /obj/item/storage/bag/ore/cyborg(src)
- modules += new /obj/item/pickaxe/drill/cyborg(src)
- modules += new /obj/item/shovel(src)
- modules += new /obj/item/weldingtool/mini(src)
- modules += new /obj/item/extinguisher/mini(src)
- modules += new /obj/item/storage/bag/sheetsnatcher/borg(src)
- modules += new /obj/item/t_scanner/adv_mining_scanner/cyborg(src)
- modules += new /obj/item/gun/energy/kinetic_accelerator/cyborg(src)
- modules += new /obj/item/gps/cyborg(src)
- emag = new /obj/item/borg/stun(src)
+// Replace their normal drill with a diamond drill.
+/obj/item/robot_module/miner/emag_act()
+ . = ..()
+ for(var/obj/item/pickaxe/drill/cyborg/D in modules)
+ // Make sure we don't remove the diamond drill If they already have a diamond drill from the borg upgrade.
+ if(!istype(D, /obj/item/pickaxe/drill/cyborg/diamond))
+ qdel(D)
+ basic_modules -= D // Remove it from this list so it doesn't get added in the rebuild.
- fix_modules()
+// Readd the normal drill
+/obj/item/robot_module/miner/unemag()
+ var/obj/item/pickaxe/drill/cyborg/C = new(src)
+ basic_modules += C
+ return ..()
+// This makes it so others can crowbar out KA upgrades from the miner borg.
/obj/item/robot_module/miner/handle_custom_removal(component_id, mob/living/user, obj/item/W)
- if(component_id == "KA modkits")
- for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/D in src)
- D.attackby(W, user)
- return TRUE
- return ..()
+ if(component_id == "KA modkits")
+ for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/D in src)
+ D.attackby(W, user)
+ return TRUE
+ return ..()
+// Deathsquad cyborg module.
/obj/item/robot_module/deathsquad
name = "NT advanced combat module"
module_type = "Malf"
- module_actions = list(
- /datum/action/innate/robot_sight/thermal,
+ module_actions = list(/datum/action/innate/robot_sight/thermal)
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/melee/energy/sword/cyborg,
+ /obj/item/gun/energy/pulse/cyborg,
+ /obj/item/crowbar/cyborg
)
-/obj/item/robot_module/deathsquad/New()
- ..()
- modules += new /obj/item/melee/energy/sword/cyborg(src)
- modules += new /obj/item/gun/energy/pulse/cyborg(src)
- modules += new /obj/item/crowbar(src)
- emag = null
-
- fix_modules()
-
+// Sydicate assault cyborg module.
/obj/item/robot_module/syndicate
name = "syndicate assault robot module"
module_type = "Malf" // cuz it looks cool
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/melee/energy/sword/cyborg,
+ /obj/item/gun/energy/printer,
+ /obj/item/gun/projectile/revolver/grenadelauncher/multi/cyborg,
+ /obj/item/card/emag,
+ /obj/item/crowbar/cyborg,
+ /obj/item/pinpointer/operative
+ )
-/obj/item/robot_module/syndicate/New()
- ..()
- modules += new /obj/item/melee/energy/sword/cyborg(src)
- modules += new /obj/item/gun/energy/printer(src)
- modules += new /obj/item/gun/projectile/revolver/grenadelauncher/multi/cyborg(src)
- modules += new /obj/item/card/emag(src)
- modules += new /obj/item/crowbar/cyborg(src)
- modules += new /obj/item/pinpointer/operative(src)
- emag = null
-
- fix_modules()
-
+// Sydicate medical cyborg module.
/obj/item/robot_module/syndicate_medical
name = "syndicate medical robot module"
module_type = "Malf"
- stacktypes = list(
- /obj/item/stack/medical/bruise_pack/advanced = 25,
- /obj/item/stack/medical/ointment/advanced = 25,
- /obj/item/stack/medical/splint = 25,
- /obj/item/stack/nanopaste = 25
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/healthanalyzer/advanced,
+ /obj/item/reagent_scanner/adv,
+ /obj/item/bodyanalyzer/borg/syndicate,
+ /obj/item/borg_defib,
+ /obj/item/handheld_defibrillator,
+ /obj/item/roller_holder,
+ /obj/item/reagent_containers/borghypo/syndicate,
+ /obj/item/scalpel/laser/laser1,
+ /obj/item/hemostat,
+ /obj/item/retractor,
+ /obj/item/melee/energy/sword/cyborg/saw, //Energy saw -- primary weapon
+ /obj/item/surgicaldrill,
+ /obj/item/bonesetter,
+ /obj/item/bonegel,
+ /obj/item/FixOVein,
+ /obj/item/card/emag,
+ /obj/item/crowbar/cyborg,
+ /obj/item/pinpointer/operative,
+ /obj/item/stack/medical/bruise_pack/advanced/cyborg/syndicate,
+ /obj/item/stack/medical/ointment/advanced/cyborg/syndicate,
+ /obj/item/stack/medical/splint/cyborg/syndicate,
+ /obj/item/stack/nanopaste/cyborg/syndicate,
+ /obj/item/gun/medbeam,
+ /obj/item/extinguisher/mini,
+ /obj/item/gripper/medical
)
+ special_rechargables = list(/obj/item/extinguisher/mini)
-/obj/item/robot_module/syndicate_medical/New()
- ..()
- modules += new /obj/item/healthanalyzer/advanced(src)
- modules += new /obj/item/reagent_scanner/adv(src)
- modules += new /obj/item/bodyanalyzer/borg/syndicate(src)
- modules += new /obj/item/borg_defib(src)
- modules += new /obj/item/handheld_defibrillator(src)
- modules += new /obj/item/roller_holder(src)
- modules += new /obj/item/reagent_containers/borghypo/syndicate(src)
- modules += new /obj/item/extinguisher/mini(src)
- modules += new /obj/item/stack/medical/bruise_pack/advanced(src)
- modules += new /obj/item/stack/medical/ointment/advanced(src)
- modules += new /obj/item/stack/medical/splint(src)
- modules += new /obj/item/stack/nanopaste(src)
- modules += new /obj/item/scalpel/laser/laser1(src)
- modules += new /obj/item/hemostat(src)
- modules += new /obj/item/retractor(src)
- modules += new /obj/item/bonegel(src)
- modules += new /obj/item/FixOVein(src)
- modules += new /obj/item/bonesetter(src)
- modules += new /obj/item/surgicaldrill(src)
- modules += new /obj/item/gripper/medical(src)
- modules += new /obj/item/gun/medbeam(src)
- modules += new /obj/item/melee/energy/sword/cyborg/saw(src) //Energy saw -- primary weapon
- modules += new /obj/item/card/emag(src)
- modules += new /obj/item/crowbar/cyborg(src)
- modules += new /obj/item/pinpointer/operative(src)
- emag = null
-
- fix_modules()
-
+// Sydicate engineer/sabotuer cyborg module.
/obj/item/robot_module/syndicate_saboteur
name = "engineering robot module" //to disguise in examine
module_type = "Malf"
-
- stacktypes = list(
- /obj/item/stack/sheet/metal/cyborg = 50,
- /obj/item/stack/sheet/glass/cyborg = 50,
- /obj/item/stack/sheet/rglass/cyborg = 50,
- /obj/item/stack/cable_coil/cyborg = 50,
- /obj/item/stack/rods/cyborg = 60,
- /obj/item/stack/tile/plasteel = 20
- )
-
-/obj/item/robot_module/syndicate_saboteur/New()
- ..()
- modules += new /obj/item/rcd/borg/syndicate(src)
- modules += new /obj/item/rpd(src)
- modules += new /obj/item/extinguisher(src)
- modules += new /obj/item/weldingtool/largetank/cyborg(src)
- modules += new /obj/item/screwdriver/cyborg(src)
- modules += new /obj/item/wrench/cyborg(src)
- modules += new /obj/item/crowbar/cyborg(src)
- modules += new /obj/item/wirecutters/cyborg(src)
- modules += new /obj/item/multitool/cyborg(src)
- modules += new /obj/item/t_scanner(src)
- modules += new /obj/item/analyzer(src)
- modules += new /obj/item/gripper(src)
- modules += new /obj/item/melee/energy/sword/cyborg(src)
- modules += new /obj/item/card/emag(src)
- modules += new /obj/item/borg_chameleon(src)
- modules += new /obj/item/pinpointer/operative(src)
- emag = null
-
- for(var/T in stacktypes)
- var/obj/item/stack/sheet/W = new T(src)
- W.amount = stacktypes[T]
- modules += W
-
- fix_modules()
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/rcd/borg/syndicate,
+ /obj/item/rpd,
+ /obj/item/extinguisher,
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/screwdriver/cyborg,
+ /obj/item/wrench/cyborg,
+ /obj/item/crowbar/cyborg,
+ /obj/item/wirecutters/cyborg,
+ /obj/item/multitool/cyborg,
+ /obj/item/t_scanner,
+ /obj/item/analyzer,
+ /obj/item/gripper,
+ /obj/item/melee/energy/sword/cyborg,
+ /obj/item/card/emag,
+ /obj/item/borg_chameleon,
+ /obj/item/pinpointer/operative,
+ /obj/item/stack/sheet/metal/cyborg,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/stack/cable_coil/cyborg,
+ /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/rglass/cyborg
+ )
+ special_rechargables = list(/obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg)
/obj/item/robot_module/destroyer
name = "destroyer robot module"
module_type = "Malf"
- module_actions = list(
- /datum/action/innate/robot_sight/thermal,
+ module_actions = list(/datum/action/innate/robot_sight/thermal)
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/gun/energy/immolator/multi/cyborg, // See comments on /robot_module/combat below
+ /obj/item/melee/baton/loaded, // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
+ /obj/item/restraints/handcuffs/cable/zipties/cyborg,
+ /obj/item/pickaxe/drill/jackhammer, // for breaking walls to execute flanking moves
+ /obj/item/borg/destroyer/mobility
)
-
-/obj/item/robot_module/destroyer/New()
- ..()
-
- modules += new /obj/item/gun/energy/immolator/multi/cyborg(src) // See comments on /robot_module/combat below
- modules += new /obj/item/melee/baton/loaded(src) // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
- modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
- modules += new /obj/item/pickaxe/drill/jackhammer(src) // for breaking walls to execute flanking moves
- modules += new /obj/item/borg/destroyer/mobility(src)
- emag = null
- fix_modules()
-
+ special_rechargables = list(/obj/item/melee/baton/loaded)
/obj/item/robot_module/combat
name = "combat robot module"
module_type = "Malf"
- module_actions = list()
-
-/obj/item/robot_module/combat/New()
- ..()
- modules += new /obj/item/gun/energy/immolator/multi/cyborg(src) // primary weapon, strong at close range (ie: against blob/terror/xeno), but consumes a lot of energy per shot.
- // Borg gets 40 shots of this weapon. Gamma Sec ERT gets 10.
- // So, borg has way more burst damage, but also takes way longer to recharge / get back in the fight once depleted. Has to find a borg recharger and sit in it for ages.
- // Organic gamma sec ERT carries alternate weapons, including a box of flashbangs, and can load up on a huge number of guns from science. Borg cannot do either.
- // Overall, gamma borg has higher skill floor but lower skill ceiling.
- modules += new /obj/item/melee/baton/loaded(src) // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
- modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
- modules += new /obj/item/pickaxe/drill/jackhammer(src) // for breaking walls to execute flanking moves
- emag = null
- fix_modules()
-
+ basic_modules = list(
+ /obj/item/flash/cyborg,
+ /obj/item/gun/energy/immolator/multi/cyborg, // primary weapon, strong at close range (ie: against blob/terror/xeno), but consumes a lot of energy per shot.
+ // Borg gets 40 shots of this weapon. Gamma Sec ERT gets 10.
+ // So, borg has way more burst damage, but also takes way longer to recharge / get back in the fight once depleted. Has to find a borg recharger and sit in it for ages.
+ // Organic gamma sec ERT carries alternate weapons, including a box of flashbangs, and can load up on a huge number of guns from science. Borg cannot do either.
+ // Overall, gamma borg has higher skill floor but lower skill ceiling.
+ /obj/item/melee/baton/loaded, // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
+ /obj/item/restraints/handcuffs/cable/zipties/cyborg,
+ /obj/item/pickaxe/drill/jackhammer // for breaking walls to execute flanking moves
+ )
+ special_rechargables = list(/obj/item/melee/baton/loaded)
+// Xenomorph cyborg module.
/obj/item/robot_module/alien/hunter
name = "alien hunter module"
module_type = "Standard"
- module_actions = list(
- /datum/action/innate/robot_sight/thermal/alien,
+ module_actions = list(/datum/action/innate/robot_sight/thermal/alien)
+ basic_modules = list(
+ /obj/item/melee/energy/alien/claws,
+ /obj/item/flash/cyborg/alien,
+ /obj/item/reagent_containers/spray/alien/stun,
+ /obj/item/reagent_containers/spray/alien/smoke,
+ )
+ emag_modules = list(/obj/item/reagent_containers/spray/alien/acid)
+ special_rechargables = list(
+ /obj/item/reagent_containers/spray/alien/acid,
+ /obj/item/reagent_containers/spray/alien/stun,
+ /obj/item/reagent_containers/spray/alien/smoke
)
-/obj/item/robot_module/alien/hunter/New()
- ..()
- modules += new /obj/item/melee/energy/alien/claws(src)
- modules += new /obj/item/flash/cyborg/alien(src)
- var/obj/item/reagent_containers/spray/alien/stun/S = new /obj/item/reagent_containers/spray/alien/stun(src)
- S.reagents.add_reagent("ether",250) //nerfed to sleeptoxin to make it less instant drop.
- modules += S
- var/obj/item/reagent_containers/spray/alien/smoke/A = new /obj/item/reagent_containers/spray/alien/smoke(src)
- S.reagents.add_reagent("water",50) //Water is used as a dummy reagent for the smoke bombs. More of an ammo counter.
- modules += A
- emag = new /obj/item/reagent_containers/spray/alien/acid(src)
- emag.reagents.add_reagent("facid", 125)
- emag.reagents.add_reagent("sacid", 125)
-
- fix_modules()
-
/obj/item/robot_module/alien/hunter/add_languages(mob/living/silicon/robot/R)
- ..()
+ . = ..()
R.add_language("xenocommon", 1)
+// Maintenance drone module.
/obj/item/robot_module/drone
name = "drone module"
module_type = "Engineer"
- stacktypes = list(
- /obj/item/stack/sheet/wood = 10,
- /obj/item/stack/sheet/rglass/cyborg = 50,
- /obj/item/stack/tile/wood = 20,
- /obj/item/stack/rods/cyborg = 60,
- /obj/item/stack/tile/plasteel = 20,
- /obj/item/stack/sheet/metal/cyborg = 50,
- /obj/item/stack/sheet/glass/cyborg = 50,
- /obj/item/stack/cable_coil/cyborg = 30
- )
-
-/obj/item/robot_module/drone/New()
- ..()
- modules += new /obj/item/weldingtool/largetank/cyborg(src)
- modules += new /obj/item/screwdriver/cyborg(src)
- modules += new /obj/item/wrench/cyborg(src)
- modules += new /obj/item/crowbar/cyborg(src)
- modules += new /obj/item/wirecutters/cyborg(src)
- modules += new /obj/item/multitool/cyborg(src)
- modules += new /obj/item/lightreplacer/cyborg(src)
- modules += new /obj/item/gripper(src)
- modules += new /obj/item/matter_decompiler(src)
- modules += new /obj/item/reagent_containers/spray/cleaner/drone(src)
- modules += new /obj/item/soap(src)
- modules += new /obj/item/t_scanner(src)
- modules += new /obj/item/rpd(src)
-
- for(var/T in stacktypes)
- var/obj/item/stack/sheet/W = new T(src)
- W.amount = stacktypes[T]
- modules += W
-
- fix_modules()
-
-/obj/item/robot_module/drone/add_default_robot_items()
- return
-
-/obj/item/robot_module/drone/respawn_consumable(mob/living/silicon/robot/R)
- var/obj/item/reagent_containers/spray/cleaner/C = locate() in modules
- C.reagents.add_reagent("cleaner", 3)
- ..()
-
+ basic_modules = list(
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/screwdriver/cyborg,
+ /obj/item/wrench/cyborg,
+ /obj/item/crowbar/cyborg,
+ /obj/item/wirecutters/cyborg,
+ /obj/item/multitool/cyborg,
+ /obj/item/lightreplacer/cyborg,
+ /obj/item/gripper,
+ /obj/item/matter_decompiler,
+ /obj/item/reagent_containers/spray/cleaner/drone,
+ /obj/item/soap,
+ /obj/item/t_scanner,
+ /obj/item/rpd,
+ /obj/item/stack/sheet/metal/cyborg,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/stack/cable_coil/cyborg,
+ /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/rglass/cyborg,
+ /obj/item/stack/sheet/wood/cyborg,
+ /obj/item/stack/tile/wood/cyborg
+ )
+ special_rechargables = list(
+ /obj/item/reagent_containers/spray/cleaner/drone,
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/lightreplacer/cyborg
+ )
/obj/item/robot_module/drone/handle_death(mob/living/silicon/robot/R, gibbed)
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
if(G)
G.drop_gripped_item(silent = TRUE)
-//checks whether this item is a module of the robot it is located in.
+/// Checks whether this item is a module of the robot it is located in.
/obj/item/proc/is_robot_module()
if(!istype(loc, /mob/living/silicon/robot))
- return 0
+ return FALSE
var/mob/living/silicon/robot/R = loc
return (src in R.module.modules)
+
+/**
+ * # The robot_energy_storage datum
+ *
+ * Used to handle robot stack items, such as metal, wood, nanopaste, etc.
+ *
+ * To make things simple, the default `cost` of using 1 item from a borg stack, is 1.
+ * So then for example, when we have a `max_energy` of 50, the borg can use 50 of that item before it runs out.
+ *
+ * The `recharge_rate` will be affected by the charge rate of a borg recharger, depending on the level of parts. By default it is 1.
+ * This amount will be given every 2 seconds. So at round start, rechargers will give 1 energy back every 2 seconds, to each stack the borg has.
+ */
+/datum/robot_energy_storage
+ /// The name of the energy storage.
+ var/name = "Generic energy storage"
+ /// The name that will be displayed in the status panel.
+ var/statpanel_name = "Statpanel name"
+ /// The max amount of energy the stack can hold at once.
+ var/max_energy = 50
+ /// The amount of energy the stack will regain while charging.
+ var/recharge_rate = 1
+ /// Current amount of energy.
+ var/energy
+
+/datum/robot_energy_storage/New(obj/item/robot_module/R = null)
+ if(!energy)
+ energy = max_energy
+ if(R)
+ R.storages += src
+
+/**
+ * Called whenever the cyborg uses one of its stacks. Subtract the amount used from this datum's `energy` variable.
+ *
+ * Arguments:
+ * * amount - the number to subtract from the `energy` var.
+ */
+/datum/robot_energy_storage/proc/use_charge(amount)
+ if(energy < amount)
+ return FALSE // If we have more energy that we're about to drain, return
+
+ energy -= amount
+ return TRUE
+
+/**
+ * Called whenever the cyborg is recharging and gains charge on its stack, or when clicking on other same-type stacks in the world.
+ *
+ * Arguments:
+ * * amount - the number to add to the `energy` var.
+ */
+/datum/robot_energy_storage/proc/add_charge(amount)
+ energy = min(energy + amount, max_energy)
+
+/datum/robot_energy_storage/metal
+ name = "Metal Synthesizer"
+ statpanel_name = "Metal"
+
+/datum/robot_energy_storage/metal_tile
+ name = "Floor tile Synthesizer"
+ statpanel_name = "Floor tiles"
+ max_energy = 60
+
+/datum/robot_energy_storage/rods
+ name = "Rod Synthesizer"
+ statpanel_name = "Rods"
+
+/datum/robot_energy_storage/glass
+ name = "Glass Synthesizer"
+ statpanel_name = "Glass"
+
+/datum/robot_energy_storage/rglass
+ name = "Reinforced glass Synthesizer"
+ statpanel_name = "Reinforced glass"
+
+/datum/robot_energy_storage/wood
+ name = "Wood Synthesizer"
+ statpanel_name = "Wood"
+
+/datum/robot_energy_storage/wood_tile
+ name = "Wooden tile Synthesizer"
+ statpanel_name = "Wooden tiles"
+ max_energy = 60
+
+/datum/robot_energy_storage/cable
+ name = "Cable Synthesizer"
+ statpanel_name = "Cable"
+
+// For the medical stacks, even though the recharge rate is 0, it will be set to 1 by default because of a `max()` proc.
+// It will always take ~12 seconds to fully recharge these stacks beacuse of this. This time does not apply to the syndicate storages.
+/datum/robot_energy_storage/medical
+ name = "Medical Synthesizer"
+ max_energy = 6
+ recharge_rate = 0
+
+/datum/robot_energy_storage/medical/splint
+ name = "Splint Synthesizer"
+ statpanel_name = "Splints"
+
+/datum/robot_energy_storage/medical/splint/syndicate
+ max_energy = 25
+
+/datum/robot_energy_storage/medical/adv_burn_kit
+ name = "Burn kit Synthesizer"
+ statpanel_name = "Burn kits"
+
+/datum/robot_energy_storage/medical/adv_burn_kit/syndicate
+ max_energy = 25
+
+/datum/robot_energy_storage/medical/adv_brute_kit
+ name = "Trauma kit Synthesizer"
+ statpanel_name = "Brute kits"
+
+/datum/robot_energy_storage/medical/adv_brute_kit/syndicate
+ max_energy = 25
+
+/datum/robot_energy_storage/medical/nanopaste
+ name = "Nanopaste Synthesizer"
+ statpanel_name = "Nanopaste"
+
+/datum/robot_energy_storage/medical/nanopaste/syndicate
+ max_energy = 25
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 3c8db1f50df..96ad65666ca 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -596,7 +596,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/examine(mob/user)
. = ..()
- if(in_range(user, src))
+ if(in_range(user, src) && !is_cyborg)
if(get_amount() == 1)
. += "A short piece of power cable."
else if(get_amount() == 2)
@@ -612,10 +612,10 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
// Cable merging is handled by parent proc
- if(C.amount >= MAXCOIL)
+ if(C.get_amount() >= MAXCOIL)
to_chat(user, "The coil is as long as it will get.")
return
- if( (C.amount + src.amount <= MAXCOIL) )
+ if((C.get_amount() + get_amount() <= MAXCOIL))
to_chat(user, "You join the cable coils together.")
return
else
@@ -861,7 +861,11 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
return color
/obj/item/stack/cable_coil/cyborg
- name = "cyborg cable coil"
+ energy_type = /datum/robot_energy_storage/cable
+ is_cyborg = TRUE
+
+/obj/item/stack/cable_coil/cyborg/update_icon()
+ return // icon_state should always be a full cable
/obj/item/stack/cable_coil/cyborg/attack_self(mob/user)
var/cablecolor = input(user,"Pick a cable color.","Cable Color") in list("red","yellow","green","blue","pink","orange","cyan","white")
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index 6da11d80c22..f830debdd17 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -149,7 +149,7 @@
return
var/obj/item/stack/cable_coil/C = I
- if(C.amount < 10)
+ if(C.get_amount() < 10)
to_chat(user, "You need more wires.")
return
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 00dd4dbff60..9dcd6eaf6dc 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -220,7 +220,7 @@
if(istype(W, /obj/item/stack/sheet/glass) || istype(W, /obj/item/stack/sheet/rglass))
var/obj/item/stack/sheet/S = W
if(S.use(2))
- glass_type = W.type
+ glass_type = S.merge_type
playsound(loc, S.usesound, 50, 1)
user.visible_message("[user] places the glass on the solar assembly.", "You place the glass on the solar assembly.")
if(tracker)
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 2247a1a6c9c..140c14171eb 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -55,3 +55,12 @@
/obj/item/gun/energy/disabler/cyborg/newshot()
..()
robocharge()
+
+/obj/item/gun/energy/disabler/cyborg/cyborg_recharge(coeff, emagged)
+ if(cell.charge < cell.maxcharge)
+ var/obj/item/ammo_casing/energy/E = ammo_type[select]
+ cell.give(E.e_cost * coeff)
+ on_recharge()
+ update_icon()
+ else
+ charge_tick = 0
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 828040aae80..1002ff117c1 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -131,6 +131,9 @@
volume = 50
list_reagents = list("cleaner" = 50)
+/obj/item/reagent_containers/spray/cleaner/drone/cyborg_recharge(coeff, emagged)
+ reagents.check_and_add("cleaner", volume, 3 * coeff)
+
//spray tan
/obj/item/reagent_containers/spray/spraytan
name = "spray tan"