diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index ed078b997a3..80f2ad9797f 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -469,10 +469,6 @@
require_module = 1
module_type = list(/obj/item/robot_module/medical)
module_flags = BORG_MODULE_MEDICAL
- var/backpack = FALSE //True if we get the defib from a physical backpack unit rather than an upgrade card, so that we can return that upon deactivate()
-
-/obj/item/borg/upgrade/defib/backpack
- backpack = TRUE
/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -490,10 +486,33 @@
if (.)
var/obj/item/shockpaddles/cyborg/S = locate() in R.module
R.module.remove_module(S, TRUE)
- if(backpack)
- new /obj/item/defibrillator(get_turf(R))
- qdel(src)
+///A version of the above that also acts as a holder of an actual defibrillator item used in place of the upgrade chip.
+/obj/item/borg/upgrade/defib/backpack
+ var/obj/item/defibrillator/defib_instance
+
+/obj/item/borg/upgrade/defib/backpack/Initialize(mapload, obj/item/defibrillator/D)
+ . = ..()
+ if(!D)
+ D = new /obj/item/defibrillator
+ defib_instance = D
+ name = defib_instance.name
+ defib_instance.moveToNullspace()
+ RegisterSignal(defib_instance, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED), .proc/on_defib_instance_qdel_or_moved)
+
+/obj/item/borg/upgrade/defib/backpack/proc/on_defib_instance_qdel_or_moved(obj/item/defibrillator/D)
+ defib_instance = null
+ qdel(src)
+
+/obj/item/borg/upgrade/defib/backpack/Destroy()
+ if(defib_instance)
+ QDEL_NULL(defib_instance)
+ return ..()
+
+/obj/item/borg/upgrade/defib/backpack/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ defib_instance?.forceMove(R.drop_location()) // [on_defib_instance_qdel_or_moved()] handles the rest.
/obj/item/borg/upgrade/processor
name = "medical cyborg surgical processor"
diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm
index 3636c95d59a..51d56bf5b61 100644
--- a/code/modules/admin/verbs/borgpanel.dm
+++ b/code/modules/admin/verbs/borgpanel.dm
@@ -149,11 +149,9 @@
var/upgradepath = text2path(params["upgrade"])
var/obj/item/borg/upgrade/installedupgrade = locate(upgradepath) in borg
if (installedupgrade)
- installedupgrade.deactivate(borg, user)
- borg.upgrades -= installedupgrade
message_admins("[key_name_admin(user)] removed the [installedupgrade] upgrade from [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] removed the [installedupgrade] upgrade from [key_name(borg)].")
- qdel(installedupgrade)
+ qdel(installedupgrade) // see [mob/living/silicon/robot/on_upgrade_deleted()].
else
var/obj/item/borg/upgrade/upgrade = new upgradepath(borg)
upgrade.action(borg, user)
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 335a74754a8..7d3f1fcad14 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -85,7 +85,7 @@
Field repairs can be done with a welder."}
if(stored_gun?.max_mod_capacity)
. += "[stored_gun.get_remaining_mod_capacity()]% mod capacity remaining."
- for(var/A in stored_gun.get_modkits())
+ for(var/A in stored_gun.modkits)
var/obj/item/borg/upgrade/modkit/M = A
. += "There is \a [M] installed, using [M.cost]% capacity."
@@ -140,7 +140,7 @@
if(istype(O, /obj/projectile/kinetic))
var/obj/projectile/kinetic/K = O
if(K.kinetic_gun)
- for(var/A in K.kinetic_gun.get_modkits())
+ for(var/A in K.kinetic_gun.modkits)
var/obj/item/borg/upgrade/modkit/M = A
if(istype(M, /obj/item/borg/upgrade/modkit/minebot_passthrough))
return TRUE
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 2f07c89e894..bb3d7408917 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -852,11 +852,8 @@
// Remove upgrades.
for(var/obj/item/borg/upgrade/I in upgrades)
- I.deactivate(src)
I.forceMove(get_turf(src))
- upgrades.Cut()
-
ionpulse = FALSE
revert_shell()
@@ -904,7 +901,43 @@
hat = null
if(!QDELETED(src)) //Don't update icons if we are deleted.
update_icons()
- . = ..()
+ return ..()
+
+///Use this to add upgrades to robots. It'll register signals for when the upgrade is moved or deleted, if not single use.
+/mob/living/silicon/robot/proc/add_to_upgrades(obj/item/borg/upgrade/new_upgrade, mob/user)
+ if(new_upgrade in upgrades)
+ return
+ if(!new_upgrade.action(src, user))
+ to_chat(user, "Upgrade error.")
+ return FALSE
+ to_chat(user, "You apply the upgrade to [src].")
+ to_chat(src, "----------------\nNew hardware detected...Identified as \"[new_upgrade]\"...Setup complete.\n----------------")
+ if(new_upgrade.one_use)
+ logevent("Firmware [new_upgrade] run successfully.")
+ qdel(new_upgrade)
+ return FALSE
+ upgrades += new_upgrade
+ new_upgrade.forceMove(src)
+ RegisterSignal(new_upgrade, COMSIG_MOVABLE_MOVED, .proc/remove_from_upgrades)
+ RegisterSignal(new_upgrade, COMSIG_PARENT_QDELETING, .proc/on_upgrade_deleted)
+ logevent("Hardware [new_upgrade] installed successfully.")
+
+///Called when an upgrade is moved outside the robot. So don't call this directly, use forceMove etc.
+/mob/living/silicon/robot/proc/remove_from_upgrades(obj/item/borg/upgrade/old_upgrade)
+ SIGNAL_HANDLER
+ if(loc == src)
+ return
+ old_upgrade.deactivate(src)
+ upgrades -= old_upgrade
+ UnregisterSignal(old_upgrade, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
+
+///Called when an applied upgrade is deleted.
+/mob/living/silicon/robot/proc/on_upgrade_deleted(obj/item/borg/upgrade/old_upgrade)
+ SIGNAL_HANDLER
+ if(!QDELETED(src))
+ old_upgrade.deactivate(src)
+ upgrades -= old_upgrade
+ UnregisterSignal(old_upgrade, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
/**
* make_shell: Makes an AI shell out of a cyborg unit
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 5196b095945..d196684e89d 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -116,6 +116,9 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
if(!istype(module, /obj/item/robot_module/medical))
to_chat(user, "[src] does not have correct mounting points for a defibrillator!")
return
+ if(stat == DEAD)
+ to_chat(user, "This defibrillator unit will not function on a deceased cyborg!")
+ return
var/obj/item/defibrillator/D = W
if(D.slot_flags != ITEM_SLOT_BACK) //belt defibs need not apply
to_chat(user, "This defibrillator unit doesn't seem to fit correctly!")
@@ -126,13 +129,8 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
if(locate(/obj/item/borg/upgrade/defib) in src || locate(/obj/item/borg/upgrade/defib/backpack) in src)
to_chat(user, "[src] already has a defibrillator!")
return
- var/obj/item/borg/upgrade/defib/backpack/B = new /obj/item/borg/upgrade/defib/backpack(src)
- B.action(src, user)
- to_chat(user, "You apply the upgrade to [src].")
- to_chat(src, "----------------\nNew hardware detected...Identified as \"[D]\"...Setup complete.\n----------------")
- upgrades += B
- logevent("Hardware [D] detected and installed successfully.")
- qdel(D)
+ var/obj/item/borg/upgrade/defib/backpack/B = new(null, D)
+ add_to_upgrades(B, user)
return
if(istype(W, /obj/item/ai_module))
@@ -190,23 +188,9 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
to_chat(user, "The cyborg 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.temporarilyRemoveItemFromInventory(U))
- return
- if(U.action(src))
- to_chat(user, "You apply the upgrade to [src].")
- to_chat(src, "----------------\nNew hardware detected...Identified as \"[U]\"...Setup complete.\n----------------")
- if(U.one_use)
- logevent("Firmware [U] run successfully.")
- qdel(U)
- else
- U.forceMove(src)
- upgrades += U
- logevent("Hardware [U] installed successfully.")
-
- else
- to_chat(user, "Upgrade error.")
- U.forceMove(drop_location())
+ else if(user.canUnEquip(U))
+ return
+ add_to_upgrades(U, user)
return
if(istype(W, /obj/item/toner))
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index bc705726ded..cdc58f7062f 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -32,7 +32,7 @@
if(max_mod_capacity)
. += "[get_remaining_mod_capacity()]% mod capacity remaining."
. += "You can use a crowbar to remove modules."
- for(var/A in get_modkits())
+ for(var/A in modkits)
var/obj/item/borg/upgrade/modkit/M = A
. += "There is \a [M] installed, using [M.cost]% capacity."
@@ -41,11 +41,18 @@
if(modkits.len)
to_chat(user, "You pry the modifications out.")
I.play_tool_sound(src, 100)
- for(var/obj/item/borg/upgrade/modkit/M in modkits)
- M.uninstall(src)
+ for(var/a in modkits)
+ var/obj/item/borg/upgrade/modkit/M = a
+ M.forceMove(drop_location()) //uninstallation handled in Exited(), or /mob/living/silicon/robot/remove_from_upgrades() for borgs
else
to_chat(user, "There are no modifications currently installed.")
+/obj/item/gun/energy/kinetic_accelerator/Exited(atom/A)
+ if(modkits.len && (A in modkits))
+ var/obj/item/borg/upgrade/modkit/MK = A
+ MK.uninstall(src)
+ . = ..()
+
/obj/item/gun/energy/kinetic_accelerator/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/borg/upgrade/modkit))
var/obj/item/borg/upgrade/modkit/MK = I
@@ -55,19 +62,14 @@
/obj/item/gun/energy/kinetic_accelerator/proc/get_remaining_mod_capacity()
var/current_capacity_used = 0
- for(var/A in get_modkits())
+ for(var/A in modkits)
var/obj/item/borg/upgrade/modkit/M = A
current_capacity_used += M.cost
return max_mod_capacity - current_capacity_used
-/obj/item/gun/energy/kinetic_accelerator/proc/get_modkits()
- . = list()
- for(var/A in modkits)
- . += A
-
/obj/item/gun/energy/kinetic_accelerator/proc/modify_projectile(obj/projectile/kinetic/K)
K.kinetic_gun = src //do something special on-hit, easy!
- for(var/A in get_modkits())
+ for(var/A in modkits)
var/obj/item/borg/upgrade/modkit/M = A
M.modify_projectile(K)
@@ -188,7 +190,7 @@
. = ..()
if(.)
if(kinetic_gun)
- var/list/mods = kinetic_gun.get_modkits()
+ var/list/mods = kinetic_gun.modkits
for(var/obj/item/borg/upgrade/modkit/M in mods)
M.projectile_prehit(src, target, kinetic_gun)
if(!lavaland_equipment_pressure_check(get_turf(target)))
@@ -209,7 +211,7 @@
if(!target_turf)
target_turf = get_turf(src)
if(kinetic_gun) //hopefully whoever shot this was not very, very unfortunate.
- var/list/mods = kinetic_gun.get_modkits()
+ var/list/mods = kinetic_gun.modkits
for(var/obj/item/borg/upgrade/modkit/M in mods)
M.projectile_strike_predamage(src, target_turf, target, kinetic_gun)
for(var/obj/item/borg/upgrade/modkit/M in mods)
@@ -259,9 +261,9 @@
. = ..()
if (.)
for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/H in R.module.modules)
- return install(H, usr)
+ return install(H, usr, FALSE)
-/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user)
+/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user, transfer_to_loc = TRUE)
. = TRUE
if(minebot_upgrade)
if(minebot_exclusive && !istype(KA.loc, /mob/living/simple_animal/hostile/mining_drone))
@@ -272,7 +274,7 @@
return FALSE
if(denied_type)
var/number_of_denied = 0
- for(var/A in KA.get_modkits())
+ for(var/A in KA.modkits)
var/obj/item/borg/upgrade/modkit/M = A
if(istype(M, denied_type))
number_of_denied++
@@ -281,7 +283,7 @@
break
if(KA.get_remaining_mod_capacity() >= cost)
if(.)
- if(!user.transferItemToLoc(src, KA))
+ if(transfer_to_loc && !user.transferItemToLoc(src, KA))
return
to_chat(user, "You install the modkit.")
playsound(loc, 'sound/items/screwdriver.ogg', 100, TRUE)
@@ -299,11 +301,8 @@
uninstall(KA)
/obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/gun/energy/kinetic_accelerator/KA)
- forceMove(get_turf(KA))
KA.modkits -= src
-
-
/obj/item/borg/upgrade/modkit/proc/modify_projectile(obj/projectile/kinetic/K)
//use this one for effects you want to trigger before any damage is done at all and before damage is decreased by pressure