diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm
index 495d47129c3..87e0be05820 100644
--- a/code/__DEFINES/robots.dm
+++ b/code/__DEFINES/robots.dm
@@ -55,3 +55,8 @@
#define ASSEMBLY_FIFTH_STEP 4
#define BORG_LAMP_CD_RESET -1 //special value to reset cyborg's lamp_cooldown
+
+/// Defines for whether or not module slots are broken.
+#define BORG_MODULE_ALL_DISABLED (1<<0)
+#define BORG_MODULE_TWO_DISABLED (1<<1)
+#define BORG_MODULE_THREE_DISABLED (1<<2)
diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm
index 5de7edc5410..0c1c96a4d53 100644
--- a/code/game/machinery/computer/aifixer.dm
+++ b/code/game/machinery/computer/aifixer.dm
@@ -62,11 +62,9 @@
/obj/machinery/computer/aifixer/proc/Fix()
use_power(1000)
- occupier.adjustOxyLoss(-5, 0)
- occupier.adjustFireLoss(-5, 0)
- occupier.adjustToxLoss(-5, 0)
+ occupier.adjustOxyLoss(-5, 0, FALSE)
+ occupier.adjustFireLoss(-5, 0, FALSE)
occupier.adjustBruteLoss(-5, 0)
- occupier.updatehealth()
if(occupier.health >= 0 && occupier.stat == DEAD)
occupier.revive(full_heal = FALSE, admin_revive = FALSE)
if(!occupier.radio_enabled)
diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm
index 15bb5f2f1fa..3f0ce34d971 100644
--- a/code/modules/mob/living/silicon/damage_procs.dm
+++ b/code/modules/mob/living/silicon/damage_procs.dm
@@ -9,9 +9,6 @@
adjustBruteLoss(damage_amount, forced = forced)
if(BURN)
adjustFireLoss(damage_amount, forced = forced)
- if(OXY)
- if(damage < 0 || forced) //we shouldn't be taking oxygen damage through this proc, but we'll let it heal.
- adjustOxyLoss(damage_amount, forced = forced)
return 1
@@ -30,14 +27,26 @@
/mob/living/silicon/setCloneLoss(amount, updating_health = TRUE, forced = FALSE)
return FALSE
-/mob/living/silicon/adjustStaminaLoss(amount, updating_health = TRUE, forced = FALSE)//immune to stamina damage.
+/mob/living/silicon/adjustStaminaLoss(amount, updating_health = TRUE, forced = FALSE) //immune to stamina damage.
return FALSE
/mob/living/silicon/setStaminaLoss(amount, updating_health = TRUE)
return FALSE
-/mob/living/silicon/adjustOrganLoss(slot, amount, maximum = 500)
+/mob/living/silicon/adjustOrganLoss(slot, amount, maximum = 500) //immune to organ damage (no organs, duh)
return FALSE
/mob/living/silicon/setOrganLoss(slot, amount)
return FALSE
+
+/mob/living/silicon/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE) //immune to oxygen damage
+ if(istype(src, /mob/living/silicon/ai)) //ais are snowflakes and use oxyloss for being in AI cards and having no battery
+ return ..()
+
+ return FALSE
+
+/mob/living/silicon/setOxyLoss(amount, updating_health = TRUE, forced = FALSE)
+ if(istype(src, /mob/living/silicon/ai)) //ditto
+ return ..()
+
+ return FALSE
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index 3272173da24..e21b73ad1cd 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -86,15 +86,6 @@
/mob/living/silicon/pai/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
return take_holo_damage(amount)
-/mob/living/silicon/pai/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
- return FALSE
-
-/mob/living/silicon/pai/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE)
- return FALSE
-
-/mob/living/silicon/pai/adjustCloneLoss(amount, updating_health = TRUE, forced = FALSE)
- return FALSE
-
/mob/living/silicon/pai/adjustStaminaLoss(amount, updating_health, forced = FALSE)
if(forced)
take_holo_damage(amount)
@@ -106,27 +97,3 @@
/mob/living/silicon/pai/getFireLoss()
return emittermaxhealth - emitterhealth
-
-/mob/living/silicon/pai/getToxLoss()
- return FALSE
-
-/mob/living/silicon/pai/getOxyLoss()
- return FALSE
-
-/mob/living/silicon/pai/getCloneLoss()
- return FALSE
-
-/mob/living/silicon/pai/getStaminaLoss()
- return FALSE
-
-/mob/living/silicon/pai/setCloneLoss()
- return FALSE
-
-/mob/living/silicon/pai/setStaminaLoss(amount, updating_health = TRUE)
- return FALSE
-
-/mob/living/silicon/pai/setToxLoss()
- return FALSE
-
-/mob/living/silicon/pai/setOxyLoss()
- return FALSE
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index 60ac3f975cd..e7bed84146c 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -1,215 +1,387 @@
//These procs handle putting stuff in your hand. It's probably best to use these rather than setting stuff manually
//as they handle all relevant stuff like adding it to the player's screen and such
-//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
+/**
+ * Returns the thing in our active hand (whatever is in our active module-slot, in this case)
+ */
/mob/living/silicon/robot/get_active_held_item()
return module_active
+/**
+ * Parent proc - triggers when an item/module is unequipped from a cyborg.
+ */
/obj/item/proc/cyborg_unequip(mob/user)
return
-/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
- if(!O)
- return 0
- O.mouse_opacity = MOUSE_OPACITY_OPAQUE
- if(istype(O, /obj/item/borg/sight))
- var/obj/item/borg/sight/S = O
- sight_mode &= ~S.sight_mode
- update_sight()
- else if(istype(O, /obj/item/storage/bag/tray/))
- SEND_SIGNAL(O, COMSIG_TRY_STORAGE_QUICK_EMPTY)
- if(client)
- client.screen -= O
- observer_screen_update(O,FALSE)
+/**
+ * Finds the first available slot and attemps to put item item_module in it.
+ *
+ * Arguments
+ * * item_module - the item being equipped to a slot.
+ */
+/mob/living/silicon/robot/proc/activate_module(obj/item/item_module)
+ if(QDELETED(item_module))
+ CRASH("activate_module called with improper item_module")
- if(module_active == O)
- module_active = null
- if(held_items[1] == O)
- inv1.icon_state = "inv1"
- held_items[1] = null
- else if(held_items[2] == O)
- inv2.icon_state = "inv2"
- held_items[2] = null
- else if(held_items[3] == O)
- inv3.icon_state = "inv3"
- held_items[3] = null
+ if(!(item_module in module.modules))
+ CRASH("activate_module called with item_module not in module.modules")
- if(O.item_flags & DROPDEL)
- O.item_flags &= ~DROPDEL //we shouldn't HAVE things with DROPDEL_1 in our modules, but better safe than runtiming horribly
-
- O.forceMove(module) //Return item to module so it appears in its contents, so it can be taken out again.
- O.cyborg_unequip(src)
-
- hud_used.update_robot_modules_display()
- return 1
-
-/mob/living/silicon/robot/proc/activate_module(obj/item/O)
- . = FALSE
- if(!(O in module.modules))
- return
- if(activated(O))
+ if(activated(item_module))
to_chat(src, "That module is already activated.")
- return
- if(!held_items[1])
- held_items[1] = O
- O.screen_loc = inv1.screen_loc
- . = TRUE
- else if(!held_items[2])
- held_items[2] = O
- O.screen_loc = inv2.screen_loc
- . = TRUE
- else if(!held_items[3])
- held_items[3] = O
- O.screen_loc = inv3.screen_loc
- . = TRUE
- else
- to_chat(src, "You need to disable a module first!")
- if(.)
- O.equipped(src, ITEM_SLOT_HANDS)
- O.mouse_opacity = initial(O.mouse_opacity)
- O.layer = ABOVE_HUD_LAYER
- O.plane = ABOVE_HUD_PLANE
- observer_screen_update(O,TRUE)
- O.forceMove(src)
- if(istype(O, /obj/item/borg/sight))
- var/obj/item/borg/sight/S = O
- sight_mode |= S.sight_mode
- update_sight()
+ return FALSE
+
+ if(disabled_modules & BORG_MODULE_ALL_DISABLED)
+ to_chat(src, "All modules are disabled!")
+ return FALSE
+
+ /// What's the first free slot for the borg?
+ var/first_free_slot = !held_items[1] ? 1 : (!held_items[2] ? 2 : (!held_items[3] ? 3 : null))
+
+ if(!first_free_slot || is_invalid_module_number(first_free_slot))
+ to_chat(src, "Deactivate a module first!")
+ return FALSE
+
+ return equip_module_to_slot(item_module, first_free_slot)
+
+/**
+ * Is passed an item and a module slot. Equips the item to that borg slot.
+ *
+ * Arguments
+ * * item_module - the item being equipped to a slot
+ * * module_num - the slot number being equipped to.
+ */
+/mob/living/silicon/robot/proc/equip_module_to_slot(obj/item/item_module, module_num)
+ switch(module_num)
+ if(1)
+ item_module.screen_loc = inv1.screen_loc
+ if(2)
+ item_module.screen_loc = inv2.screen_loc
+ if(3)
+ item_module.screen_loc = inv3.screen_loc
+
+ held_items[module_num] = item_module
+ item_module.equipped(src, ITEM_SLOT_HANDS)
+ item_module.mouse_opacity = initial(item_module.mouse_opacity)
+ item_module.layer = ABOVE_HUD_LAYER
+ item_module.plane = ABOVE_HUD_PLANE
+ item_module.forceMove(src)
+
+ if(istype(item_module, /obj/item/borg/sight))
+ var/obj/item/borg/sight/borg_sight = item_module
+ sight_mode |= borg_sight.sight_mode
+ update_sight()
+
+ observer_screen_update(item_module, TRUE)
+ return TRUE
+
+/**
+ * Unequips item item_module from slot module_num. Deletes it if delete_after = TRUE.
+ *
+ * Arguments
+ * * item_module - the item being unequipped
+ * * module_num - the slot number being unequipped.
+ */
+/mob/living/silicon/robot/proc/unequip_module_from_slot(obj/item/item_module, module_num)
+ if(QDELETED(item_module))
+ CRASH("unequip_module_from_slot called with improper item_module")
+
+ if(!(item_module in module.modules))
+ CRASH("unequip_module_from_slot called with item_module not in module.modules")
+
+ item_module.mouse_opacity = MOUSE_OPACITY_OPAQUE
+
+ if(istype(item_module, /obj/item/storage/bag/tray/))
+ SEND_SIGNAL(item_module, COMSIG_TRY_STORAGE_QUICK_EMPTY)
+ if(istype(item_module, /obj/item/borg/sight))
+ var/obj/item/borg/sight/borg_sight = item_module
+ sight_mode &= ~borg_sight.sight_mode
+ update_sight()
+
+ if(client)
+ client.screen -= item_module
+
+ if(module_active == item_module)
+ module_active = null
+
+ switch(module_num)
+ if(1)
+ if(!(disabled_modules & BORG_MODULE_ALL_DISABLED))
+ inv1.icon_state = initial(inv1.icon_state)
+ if(2)
+ if(!(disabled_modules & BORG_MODULE_TWO_DISABLED))
+ inv2.icon_state = initial(inv2.icon_state)
+ if(3)
+ if(!(disabled_modules & BORG_MODULE_THREE_DISABLED))
+ inv3.icon_state = initial(inv3.icon_state)
+
+ if(item_module.item_flags & DROPDEL)
+ item_module.item_flags &= ~DROPDEL //we shouldn't HAVE things with DROPDEL_1 in our modules, but better safe than runtiming horribly
+
+ held_items[module_num] = null
+ item_module.cyborg_unequip(src)
+ item_module.forceMove(module) //Return item to module so it appears in its contents, so it can be taken out again.
+
+ observer_screen_update(item_module, FALSE)
+ hud_used.update_robot_modules_display()
+ return TRUE
+
+/**
+ * Breaks the slot number, changing the icon.
+ *
+ * Arguments
+ * * module_num - the slot number being repaired.
+ */
+/mob/living/silicon/robot/proc/break_cyborg_slot(module_num)
+ if(is_invalid_module_number(module_num, TRUE))
+ return FALSE
+
+ if(held_items[module_num]) //If there's a held item, unequip it first.
+ if(!unequip_module_from_slot(held_items[module_num], module_num)) //If we fail to unequip it, then don't continue
+ return FALSE
+
+ switch(module_num)
+ if(1)
+ if(disabled_modules & BORG_MODULE_ALL_DISABLED)
+ return FALSE
+
+ inv1.icon_state = "[initial(inv1.icon_state)] +b"
+ disabled_modules |= BORG_MODULE_ALL_DISABLED
+
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 75, TRUE, TRUE)
+ audible_message("[src] sounds an alarm! \"CRITICAL ERROR: ALL modules OFFLINE.\"")
+ to_chat(src, "CRITICAL ERROR: ALL modules OFFLINE.")
+
+ if(2)
+ if(disabled_modules & BORG_MODULE_TWO_DISABLED)
+ return FALSE
+
+ inv2.icon_state = "[initial(inv2.icon_state)] +b"
+ disabled_modules |= BORG_MODULE_TWO_DISABLED
+
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 60, TRUE, TRUE)
+ audible_message("[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\"")
+ to_chat(src, "SYSTEM ERROR: Module [module_num] OFFLINE.")
+
+ if(3)
+ if(disabled_modules & BORG_MODULE_THREE_DISABLED)
+ return FALSE
+
+ inv3.icon_state = "[initial(inv3.icon_state)] +b"
+ disabled_modules |= BORG_MODULE_THREE_DISABLED
+
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 50, TRUE, TRUE)
+ audible_message("[src] sounds an alarm! \"SYSTEM ERROR: Module [module_num] OFFLINE.\"")
+ to_chat(src, "SYSTEM ERROR: Module [module_num] OFFLINE.")
+
+ return TRUE
-/mob/living/silicon/robot/proc/observer_screen_update(obj/item/I,add = TRUE)
+/**
+ * Breaks all of a cyborg's slots.
+ */
+/mob/living/silicon/robot/proc/break_all_cyborg_slots()
+ for(var/cyborg_slot in 1 to 3)
+ break_cyborg_slot(cyborg_slot)
+
+/**
+ * Repairs the slot number, updating the icon.
+ *
+ * Arguments
+ * * module_num - the module number being repaired.
+ */
+/mob/living/silicon/robot/proc/repair_cyborg_slot(module_num)
+ if(is_invalid_module_number(module_num, TRUE))
+ return FALSE
+
+ switch(module_num)
+ if(1)
+ if(!(disabled_modules & BORG_MODULE_ALL_DISABLED))
+ return FALSE
+
+ inv1.icon_state = initial(inv1.icon_state)
+ disabled_modules &= ~BORG_MODULE_ALL_DISABLED
+ if(2)
+ if(!(disabled_modules & BORG_MODULE_TWO_DISABLED))
+ return FALSE
+
+ inv2.icon_state = initial(inv2.icon_state)
+ disabled_modules &= ~BORG_MODULE_TWO_DISABLED
+ if(3)
+ if(!(disabled_modules & BORG_MODULE_THREE_DISABLED))
+ return FALSE
+
+ inv3.icon_state = initial(inv3.icon_state)
+ disabled_modules &= ~BORG_MODULE_THREE_DISABLED
+
+ to_chat(src, "ERROR CLEARED: Module [module_num] back online.")
+
+ return TRUE
+
+/**
+ * Repairs all slots. Unbroken slots are unaffected.
+ */
+/mob/living/silicon/robot/proc/repair_all_cyborg_slots()
+ for(var/cyborg_slot in 1 to 3)
+ repair_cyborg_slot(cyborg_slot)
+
+/**
+ * Updates the observers's screens with cyborg itemss.
+ * Arguments
+ * * item_module - the item being added or removed from the screen
+ * * add - whether or not the item is being added, or removed.
+ */
+/mob/living/silicon/robot/proc/observer_screen_update(obj/item/item_module, add = TRUE)
if(observers && observers.len)
for(var/M in observers)
var/mob/dead/observe = M
if(observe.client && observe.client.eye == src)
if(add)
- observe.client.screen += I
+ observe.client.screen += item_module
else
- observe.client.screen -= I
+ observe.client.screen -= item_module
else
observers -= observe
if(!observers.len)
observers = null
break
+/**
+ * Unequips the active held item.
+ */
/mob/living/silicon/robot/proc/uneq_active()
- uneq_module(module_active)
+ unequip_module_from_slot(module_active, get_selected_module())
+/**
+ * Unequips all held items.
+ */
/mob/living/silicon/robot/proc/uneq_all()
- for(var/obj/item/I in held_items)
- uneq_module(I)
+ for(var/cyborg_slot in 1 to 3)
+ if(!held_items[cyborg_slot])
+ continue
+ unequip_module_from_slot(held_items[cyborg_slot], cyborg_slot)
-/mob/living/silicon/robot/proc/activated(obj/item/O)
- if(O in held_items)
+/**
+ * Checks if the item is currently in a slot.
+ *
+ * If the item is found in a slot, this returns TRUE. Otherwise, it returns FALSE
+ * Arguments
+ * * item_module - the item being checked
+ */
+/mob/living/silicon/robot/proc/activated(obj/item/item_module)
+ if(item_module in held_items)
return TRUE
return FALSE
-//Helper procs for cyborg modules on the UI.
-//These are hackish but they help clean up code elsewhere.
+/**
+ * Checks if the provided module number is a valid number.
+ *
+ * If the number is between 1 and 3 (if check_all_slots is true) or between 1 and the number of disabled
+ * modules (if check_all_slots is false), then it returns FALSE. Otherwise, it returns TRUE.
+ * Arguments
+ * * module_num - the passed module num that is checked for validity.
+ * * check_all_slots - TRUE = the proc checks all slots | FALSE = the proc only checks un-disabled slots
+ */
+/mob/living/silicon/robot/proc/is_invalid_module_number(module_num, check_all_slots = FALSE)
+ if(!module_num)
+ return TRUE
-//module_selected(module) - Checks whether the module slot specified by "module" is currently selected.
-/mob/living/silicon/robot/proc/module_selected(module) //Module is 1-3
- return module == get_selected_module()
+ /// The number of module slots we're checking
+ var/max_number = 3
+ if(!check_all_slots)
+ if(disabled_modules & BORG_MODULE_ALL_DISABLED)
+ max_number = 0
+ else if(disabled_modules & BORG_MODULE_TWO_DISABLED)
+ max_number = 1
+ else if(disabled_modules & BORG_MODULE_THREE_DISABLED)
+ max_number = 2
-//module_active(module) - Checks whether there is a module active in the slot specified by "module".
-/mob/living/silicon/robot/proc/module_active(module) //Module is 1-3
- if(module < 1 || module > 3)
- return FALSE
+ return module_num < 1 || module_num > max_number
- if(LAZYLEN(held_items) >= module)
- if(held_items[module])
- return TRUE
- return FALSE
-
-//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected.
+/**
+ * Returns the slot number of the selected module, or zero if no modules are selected.
+ */
/mob/living/silicon/robot/proc/get_selected_module()
if(module_active)
return held_items.Find(module_active)
return 0
-//select_module(module) - Selects the module slot specified by "module"
-/mob/living/silicon/robot/proc/select_module(module) //Module is 1-3
- if(module < 1 || module > 3)
- return
+/**
+ * Selects the module in the slot module_num.
+ * Arguments
+ * * module_num - the slot number being selected
+ */
+/mob/living/silicon/robot/proc/select_module(module_num)
+ if(!held_items[module_num])
+ return FALSE
- if(!module_active(module))
- return
-
- switch(module)
+ switch(module_num)
if(1)
- if(module_active != held_items[module])
- inv1.icon_state = "inv1 +a"
- inv2.icon_state = "inv2"
- inv3.icon_state = "inv3"
+ if(module_active != held_items[module_num])
+ inv1.icon_state = "[initial(inv1.icon_state)] +a"
if(2)
- if(module_active != held_items[module])
- inv1.icon_state = "inv1"
- inv2.icon_state = "inv2 +a"
- inv3.icon_state = "inv3"
+ if(module_active != held_items[module_num])
+ inv2.icon_state = "[initial(inv2.icon_state)] +a"
if(3)
- if(module_active != held_items[module])
- inv1.icon_state = "inv1"
- inv2.icon_state = "inv2"
- inv3.icon_state = "inv3 +a"
- module_active = held_items[module]
+ if(module_active != held_items[module_num])
+ inv3.icon_state = "[initial(inv3.icon_state)] +a"
+ module_active = held_items[module_num]
-//deselect_module(module) - Deselects the module slot specified by "module"
-/mob/living/silicon/robot/proc/deselect_module(module) //Module is 1-3
- if(module < 1 || module > 3)
- return
-
- if(!module_active(module))
- return
-
- switch(module)
+/**
+ * Deselects the module in the slot module_num.
+ * Arguments
+ * * module_num - the slot number being de-selected
+ */
+/mob/living/silicon/robot/proc/deselect_module(module_num)
+ switch(module_num)
if(1)
- if(module_active == held_items[module])
- inv1.icon_state = "inv1"
+ if(module_active == held_items[module_num])
+ inv1.icon_state = initial(inv1.icon_state)
if(2)
- if(module_active == held_items[module])
- inv2.icon_state = "inv2"
+ if(module_active == held_items[module_num])
+ inv2.icon_state = initial(inv2.icon_state)
if(3)
- if(module_active == held_items[module])
- inv3.icon_state = "inv3"
+ if(module_active == held_items[module_num])
+ inv3.icon_state = initial(inv3.icon_state)
module_active = null
-//toggle_module(module) - Toggles the selection of the module slot specified by "module".
-/mob/living/silicon/robot/proc/toggle_module(module) //Module is 1-3
- if(module < 1 || module > 3)
- return
+/**
+ * Toggles selection of the module in the slot module_num.
+ * Arguments
+ * * module_num - the slot number being toggled
+ */
+/mob/living/silicon/robot/proc/toggle_module(module_num)
+ if(is_invalid_module_number(module_num))
+ return FALSE
- if(module_selected(module))
- deselect_module(module)
- else
- if(module_active(module))
- select_module(module)
- else
- deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module.
- return
+ if(module_num == get_selected_module())
+ deselect_module(module_num)
+ return TRUE
-//cycle_modules() - Cycles through the list of selected modules.
+ if(module_active != held_items[module_num])
+ deselect_module(get_selected_module())
+
+ return select_module(module_num)
+
+/**
+ * Cycles through the list of enabled modules, deselecting the current one and selecting the next one.
+ */
/mob/living/silicon/robot/proc/cycle_modules()
var/slot_start = get_selected_module()
+ var/slot_num
if(slot_start)
deselect_module(slot_start) //Only deselect if we have a selected slot.
-
- var/slot_num
- if(slot_start == 0)
+ slot_num = slot_start + 1
+ else
slot_num = 1
slot_start = 4
- else
- slot_num = slot_start + 1
while(slot_num != slot_start) //If we wrap around without finding any free slots, just give up.
- if(module_active(slot_num))
- select_module(slot_num)
+ if(select_module(slot_num))
return
slot_num++
if(slot_num > 4) // not >3 otherwise cycling with just one item on module 3 wouldn't work
slot_num = 1 //Wrap around.
-
-
/mob/living/silicon/robot/swap_hand()
cycle_modules()
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 910a2a6fea0..afad167f231 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -4,7 +4,6 @@
return
..()
- adjustOxyLoss(-10) //we're a robot!
handle_robot_hud_updates()
handle_robot_cell()
@@ -100,4 +99,3 @@
mobility_flags = MOBILITY_FLAGS_DEFAULT
update_transform()
update_action_buttons_icon()
-
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 57fa699c111..9ee28f6aeea 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -24,6 +24,8 @@
var/mob/living/silicon/ai/mainframe = null
var/datum/action/innate/undeployment/undeployment_action = new
+ /// the last health before updating - to check net change in health
+ var/previous_health
//Hud stuff
var/obj/screen/inv1 = null
@@ -41,6 +43,9 @@
var/obj/item/module_active = null
held_items = list(null, null, null) //we use held_items for the module holding, because that makes sense to do!
+ /// For checking which modules are disabled or not.
+ var/disabled_modules
+
var/mutable_appearance/eye_lights
var/mob/living/silicon/ai/connected_ai = null
@@ -110,6 +115,8 @@
ident = rand(1, 999)
+ previous_health = health
+
if(ispath(cell))
cell = new cell(src)
@@ -220,7 +227,6 @@
module.transform_to(modulelist[input_module])
-
/mob/living/silicon/robot/proc/updatename(client/C)
if(shell)
return
@@ -705,21 +711,30 @@
/mob/living/silicon/robot/updatehealth()
..()
- if(health < maxHealth*0.5) //Gradual break down of modules as more damage is sustained
- if(uneq_module(held_items[3]))
- playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, TRUE, TRUE)
- audible_message("[src] sounds an alarm! \"SYSTEM ERROR: Module 3 OFFLINE.\"")
- to_chat(src, "SYSTEM ERROR: Module 3 OFFLINE.")
- if(health < 0)
- if(uneq_module(held_items[2]))
- audible_message("[src] sounds an alarm! \"SYSTEM ERROR: Module 2 OFFLINE.\"")
- to_chat(src, "SYSTEM ERROR: Module 2 OFFLINE.")
- playsound(loc, 'sound/machines/warning-buzzer.ogg', 60, TRUE, TRUE)
- if(health < -maxHealth*0.5)
- if(uneq_module(held_items[1]))
- audible_message("[src] sounds an alarm! \"CRITICAL ERROR: All modules OFFLINE.\"")
- to_chat(src, "CRITICAL ERROR: All modules OFFLINE.")
- playsound(loc, 'sound/machines/warning-buzzer.ogg', 75, TRUE, TRUE)
+
+ /// the current percent health of the robot (-1 to 1)
+ var/percent_hp = health/maxHealth
+ if(health <= previous_health) //if change in health is negative (we're losing hp)
+ if(percent_hp <= 0.5)
+ break_cyborg_slot(3)
+
+ if(percent_hp <= 0)
+ break_cyborg_slot(2)
+
+ if(percent_hp <= -0.5)
+ break_cyborg_slot(1)
+
+ else //if change in health is positive (we're gaining hp)
+ if(percent_hp >= 0.5)
+ repair_cyborg_slot(3)
+
+ if(percent_hp >= 0)
+ repair_cyborg_slot(2)
+
+ if(percent_hp >= -0.5)
+ repair_cyborg_slot(1)
+
+ previous_health = health
/mob/living/silicon/robot/update_sight()
if(!client)
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 358464b81be..bc872ba0608 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -18,7 +18,6 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
return
adjustBruteLoss(-30)
- updatehealth()
add_fingerprint(user)
visible_message("[user] fixes some of the dents on [src].")
return
@@ -33,8 +32,6 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
return
if (coil.use(1))
adjustFireLoss(-30)
- adjustToxLoss(-30)
- updatehealth()
user.visible_message("[user] fixes some of the burnt wires on [src].", "You fix some of the burnt wires on [src].")
else
to_chat(user, "You need more cable to repair [src]!")
@@ -268,7 +265,6 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
damage = rand(5, 35)
damage = round(damage / 2) // borgs receive half damage
adjustBruteLoss(damage)
- updatehealth()
return
@@ -399,25 +395,3 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
updatehealth()
if(prob(75) && Proj.damage > 0)
spark_system.start()
-
-
-/mob/living/silicon/robot/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE)
- . = ..()
- if(isnull(.))
- return
- if(. <= (maxHealth * 0.5))
- if(getOxyLoss() > (maxHealth * 0.5))
- ADD_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
- else if(getOxyLoss() <= (maxHealth * 0.5))
- REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
-
-
-/mob/living/silicon/robot/setOxyLoss(amount, updating_health = TRUE, forced = FALSE)
- . = ..()
- if(isnull(.))
- return
- if(. <= (maxHealth * 0.5))
- if(getOxyLoss() > (maxHealth * 0.5))
- ADD_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
- else if(getOxyLoss() <= (maxHealth * 0.5))
- REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index a9cbaf00e81..3a848165d13 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -161,7 +161,8 @@
/obj/item/robot_module/proc/rebuild_modules() //builds the usable module list from the modules we have
var/mob/living/silicon/robot/R = loc
- var/held_modules = R.held_items.Copy()
+ var/list/held_modules = R.held_items.Copy()
+ var/active_module = R.module_active
R.uneq_all()
modules = list()
for(var/obj/item/I in basic_modules)
@@ -173,7 +174,9 @@
add_module(I, FALSE, FALSE)
for(var/i in held_modules)
if(i)
- R.activate_module(i)
+ R.equip_module_to_slot(i, held_modules.Find(i))
+ if(active_module)
+ R.select_module(held_modules.Find(active_module))
if(R.hud_used)
R.hud_used.update_robot_modules_display()
@@ -225,6 +228,7 @@
R.setDir(SOUTH)
R.anchored = FALSE
R.notransform = FALSE
+ R.updatehealth()
R.update_headlamp(FALSE, BORG_LAMP_CD_RESET)
R.notify_ai(NEW_MODULE)
if(R.hud_used)
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 13c4364f73c..5068397f9cd 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -41,14 +41,6 @@
adjustBruteLoss(damage)
if(BURN)
adjustFireLoss(damage)
- if(TOX)
- adjustToxLoss(damage)
- if(OXY)
- adjustOxyLoss(damage)
- if(CLONE)
- adjustCloneLoss(damage)
- if(STAMINA)
- adjustStaminaLoss(damage)
/mob/living/silicon/attack_paw(mob/living/user)
return attack_hand(user)
diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm
index c2a1aa4ca75..c1bb40d1b89 100644
--- a/code/modules/modular_computers/file_system/programs/airestorer.dm
+++ b/code/modules/modular_computers/file_system/programs/airestorer.dm
@@ -72,11 +72,9 @@
restoring = FALSE
return
ai_slot.locked =TRUE
- A.adjustOxyLoss(-5, 0)
- A.adjustFireLoss(-5, 0)
- A.adjustToxLoss(-5, 0)
+ A.adjustOxyLoss(-5, 0, FALSE)
+ A.adjustFireLoss(-5, 0, FALSE)
A.adjustBruteLoss(-5, 0)
- A.updatehealth()
if(A.health >= 0 && A.stat == DEAD)
A.revive(full_heal = FALSE, admin_revive = FALSE)
// Finished restoring
diff --git a/icons/mob/screen_cyborg.dmi b/icons/mob/screen_cyborg.dmi
index 2f87e9796f1..c0c112bdeb9 100644
Binary files a/icons/mob/screen_cyborg.dmi and b/icons/mob/screen_cyborg.dmi differ