diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm
index e3d3a0e2acb..00b446c2b27 100644
--- a/code/game/machinery/computer/robot.dm
+++ b/code/game/machinery/computer/robot.dm
@@ -6,6 +6,9 @@
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/computer/robotics
light_color = LIGHT_COLOR_PINK
+ var/mob/living/silicon/robot/locked_down_borg = null
+ active_power_usage = 10000 //no idea how much is it
+
/obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R)
. = FALSE
@@ -88,21 +91,37 @@
if(allowed(usr))
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
if(can_control(usr, R) && !..())
- if(isAI(usr) && (R.ai_lockdown && R.lockcharge || !R.lockcharge) || !isAI(usr))
- R.ai_lockdown = FALSE
- if(isAI(usr) && !R.lockcharge)
+ if(isAI(usr))
+ if(R.lockcharge)
+ if(R.ai_lockdown)
+ R.ai_lockdown = FALSE
+ lock_unlock_borg(R)
+ else
+ to_chat(usr, span_danger("Cyborg locked by an user with superior permissions."))
+ else
R.ai_lockdown = TRUE
- message_admins(span_notice("[ADMIN_LOOKUPFLW(usr)] [!R.lockcharge ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!"))
- log_silicon("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)]!")
- log_combat(usr, R, "[!R.lockcharge ? "locked down" : "released"] cyborg")
- R.SetLockdown(!R.lockcharge)
- to_chat(R, !R.lockcharge ? span_notice("Your lockdown has been lifted!") : span_alert("You have been locked down!"))
- if(R.connected_ai)
- to_chat(R.connected_ai, "[!R.lockcharge ? span_notice("NOTICE - Cyborg lockdown lifted") : span_alert("ALERT - Cyborg lockdown detected")]: [R.name]
")
+ lock_unlock_borg(R)
else
- to_chat(usr, span_danger("Cyborg locked by an user with superior permissions."))
+ if(isnull(locked_down_borg) && !R.lockcharge) //If there is no borg locked down by the console yet
+ lock_unlock_borg(R, src.loc.loc.name)
+ R.ai_lockdown = FALSE //Just in case I'm stupid
+ locked_down_borg = R
+ RegisterSignal(R, COMSIG_QDELETING, PROC_REF(borg_destroyed))
+ else if(locked_down_borg == R) //If the borg locked down by the console is the same as the one we're trying to unlock
+ lock_unlock_borg(R)
+ else if(R.lockcharge&&R.ai_lockdown)
+ R.ai_lockdown = FALSE
+ lock_unlock_borg(R)
+ else if(R.lockcharge&&locked_down_borg!=R)
+ to_chat(usr, span_danger("The cyborg was locked by a different console."))
+ else
+ to_chat(usr, span_danger("You can lock down only one cyborg at a time."))
else
to_chat(usr, span_danger("Access Denied."))
+ if(!isnull(locked_down_borg))
+ use_power = ACTIVE_POWER_USE
+ else
+ use_power = IDLE_POWER_USE
if("killbot") //Malf AIs, and AIs with a combat upgrade, can detonate their cyborgs remotely.
if(!isAI(usr))
@@ -142,3 +161,44 @@
drone.visible_message(span_danger("\the [drone] self-destructs!"))
drone.investigate_log("has been gibbed by a robotics console.", INVESTIGATE_DEATHS)
drone.gib()
+
+
+// I feel like this should be changed, but I have no idea in what way exactly, so I just extracted it to make the code less of a mess
+/obj/machinery/computer/robotics/proc/lock_unlock_borg(mob/living/silicon/robot/R, console_location = null)
+ if(R.lockcharge && locked_down_borg == R)
+ UnregisterSignal(locked_down_borg, COMSIG_QDELETING)
+ locked_down_borg = null
+ message_admins(span_notice("[ADMIN_LOOKUPFLW(usr)] [!R.lockcharge ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!"))
+ log_silicon("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)]!")
+ log_combat(usr, R, "[!R.lockcharge ? "locked down" : "released"] cyborg")
+ R.SetLockdown(!R.lockcharge)
+ to_chat(R, !R.lockcharge ? span_notice("Your lockdown has been lifted!") : span_alert("You have been locked down!"))
+ if(!isnull(console_location))
+ to_chat(R, span_alert("The approximate location of the console that is keeping you locked down is [console_location]"))
+ if(R.connected_ai)
+ to_chat(R.connected_ai, "[!R.lockcharge ? span_notice("NOTICE - Cyborg lockdown lifted") : span_alert("ALERT - Cyborg lockdown detected")]: [R.name]
")
+
+/obj/machinery/computer/robotics/proc/borg_destroyed()
+ SIGNAL_HANDLER
+ locked_down_borg = null
+
+/obj/machinery/computer/robotics/on_set_machine_stat(old_value) //depowering the console unlocks the borg
+ if(!isnull(locked_down_borg))
+ if(machine_stat & (NOPOWER|BROKEN|MAINT) && locked_down_borg.lockcharge)
+ src.lock_unlock_borg(locked_down_borg)
+ return ..()
+
+/obj/machinery/computer/robotics/atom_break() // This shouldnt be needed, but hitting console doesnt trigger destroy apparently
+ if(!isnull(locked_down_borg))
+ lock_unlock_borg(locked_down_borg)
+ return ..()
+
+/obj/machinery/computer/robotics/Destroy()
+ if(!isnull(locked_down_borg))
+ lock_unlock_borg(locked_down_borg)
+ return ..()
+
+
+
+
+
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index 45000bf4353..f56cc83e116 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -121,7 +121,7 @@
log_combat(user, S, "shone in the sensors", src)
//chance to actually hit the eyes depends on internal component
if(prob(effectchance * diode.rating) && S.flash_act(affect_silicon = TRUE))
- S.Paralyze(rand(100,200))
+ S.set_temp_blindness_if_lower(5 SECONDS)
to_chat(S, span_danger("Your sensors were overloaded by a laser!"))
outmsg = span_notice("You overload [S] by shining [src] at [S.p_their()] sensors.")
else
diff --git a/code/game/objects/items/robot/items/generic.dm b/code/game/objects/items/robot/items/generic.dm
index a7477357779..65436e5c8f4 100644
--- a/code/game/objects/items/robot/items/generic.dm
+++ b/code/game/objects/items/robot/items/generic.dm
@@ -15,10 +15,17 @@
/obj/item/borg/stun
name = "electrically-charged arm"
icon_state = "elecarm"
+ var/stamina_damage = 60 //Same as normal batong
/// Cost to use the stun arm
- var/charge_cost = 1000
+ var/charge_cost = 200
+ var/cooldown_check = 0
+ /// cooldown between attacks
+ var/cooldown = 4 SECONDS // same as baton
/obj/item/borg/stun/attack(mob/living/attacked_mob, mob/living/user)
+ if(cooldown_check > world.time)
+ user.balloon_alert(user, "still recharging!")
+ return
if(ishuman(attacked_mob))
var/mob/living/carbon/human/human = attacked_mob
if(human.check_shields(src, 0, "[attacked_mob]'s [name]", MELEE_ATTACK))
@@ -30,14 +37,20 @@
return
user.do_attack_animation(attacked_mob)
- attacked_mob.Paralyze(100)
- attacked_mob.adjust_stutter(10 SECONDS)
-
- attacked_mob.visible_message(span_danger("[user] prods [attacked_mob] with [src]!"), \
+ attacked_mob.adjustStaminaLoss(stamina_damage)
+ attacked_mob.set_confusion_if_lower(5 SECONDS)
+ attacked_mob.adjust_stutter(20 SECONDS)
+ attacked_mob.set_jitter_if_lower(5 SECONDS)
+ if(issilicon(attacked_mob))
+ attacked_mob.emp_act(EMP_HEAVY)
+ attacked_mob.visible_message(span_danger("[user] shocks [attacked_mob] with [src]!"), \
+ span_userdanger("[user] shocks you with [src]!"))
+ else
+ attacked_mob.visible_message(span_danger("[user] prods [attacked_mob] with [src]!"), \
span_userdanger("[user] prods you with [src]!"))
playsound(loc, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
-
+ cooldown_check = world.time + cooldown
log_combat(user, attacked_mob, "stunned", src, "(Combat mode: [user.combat_mode ? "On" : "Off"])")
/obj/item/borg/cyborghug
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index b170ba204c4..553118aae24 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -243,12 +243,18 @@
var/mob/living/silicon/robot/flashed_borgo = M
log_combat(user, flashed_borgo, "flashed", src)
update_icon(ALL, TRUE)
- if(!flashed_borgo.flash_act(affect_silicon = TRUE))
+ if(flashed_borgo.flash_act(affect_silicon = TRUE))
+ if(flashed_borgo.is_blind())
+ var/flash_duration = rand(8,12) SECONDS
+ flashed_borgo.Paralyze(flash_duration)
+ flashed_borgo.set_temp_blindness_if_lower(flash_duration)
+ user.visible_message(span_warning("[user] overloads [flashed_borgo]'s sensors and computing with the flash!"), span_danger("You overload [flashed_borgo]'s sensors and computing with the flash!"))
+ else
+ user.visible_message(span_warning("[user] blinds [flashed_borgo] with the flash!"), span_danger("You blind [flashed_borgo] with the flash!"))
+ flashed_borgo.set_temp_blindness_if_lower( (rand(5,15) SECONDS))
+ flashed_borgo.set_confusion_if_lower(5 SECONDS * CONFUSION_STACK_MAX_MULTIPLIER)
+ else
user.visible_message(span_warning("[user] fails to blind [flashed_borgo] with the flash!"), span_warning("You fail to blind [flashed_borgo] with the flash!"))
- return
- flashed_borgo.Paralyze(rand(80,120))
- flashed_borgo.set_confusion_if_lower(5 SECONDS * CONFUSION_STACK_MAX_MULTIPLIER)
- user.visible_message(span_warning("[user] overloads [flashed_borgo]'s sensors with the flash!"), span_danger("You overload [flashed_borgo]'s sensors with the flash!"))
return
user.visible_message(span_warning("[user] fails to blind [M] with the flash!"), span_warning("You fail to blind [M] with the flash!"))
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 8e928a9189e..d773e49a003 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -411,12 +411,25 @@
// They stay locked down if their wire is cut.
if(wires?.is_cut(WIRE_LOCKDOWN))
state = TRUE
+ else if(!ai_lockdown)
+ lockdown_timer = addtimer(CALLBACK(src,PROC_REF(lockdown_override), FALSE), 10 MINUTES, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_DELETE_ME | TIMER_STOPPABLE)
+ to_chat(src, "
[span_alert("ALERT - Remote system lockdown engaged. Trying to hack the lockdown subsystem...")]
")
if(state)
throw_alert(ALERT_HACKED, /atom/movable/screen/alert/locked)
else
+ deltimer(lockdown_timer)
clear_alert(ALERT_HACKED)
set_lockcharge(state)
+/// Allows the borg to unlock themselves after a lenghty period of time.
+/mob/living/silicon/robot/proc/lockdown_override()
+ if(ai_lockdown)
+ to_chat(src, "
[span_alert("ALERT - Remote system lockdown override failed.")]
")
+ return
+ set_lockcharge(FALSE)
+ to_chat(src, "
[span_notice("ALERT - Remote system lockdown override successful.")]
")
+ if(connected_ai)
+ to_chat(connected_ai, "
[span_notice("ALERT - Cyborg [name] succesfully overriden the lockdown system")]
")
///Reports the event of the change in value of the lockcharge variable.
/mob/living/silicon/robot/proc/set_lockcharge(new_lockcharge)
@@ -658,10 +671,6 @@
death()
toggle_headlamp(1)
return
- if(HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || IsStun() || IsKnockdown() || IsParalyzed())
- set_stat(UNCONSCIOUS)
- else
- set_stat(CONSCIOUS)
diag_hud_set_status()
diag_hud_set_health()
diag_hud_set_aishell()
@@ -677,6 +686,7 @@
builtInCamera.toggle_cam(src, 0)
if(full_heal_flags & HEAL_ADMIN)
locked = TRUE
+ src.set_stat(CONSCIOUS)
notify_ai(AI_NOTIFICATION_NEW_BORG)
toggle_headlamp(FALSE, TRUE) //This will reenable borg headlamps if doomsday is currently going on still.
return TRUE
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 61cccd35f9b..277b36c274b 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -320,9 +320,17 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
return
switch(severity)
if(1)
- Stun(160)
+ emp_knockout(16 SECONDS)
if(2)
- Stun(60)
+ emp_knockout(6 SECONDS)
+
+/mob/living/silicon/robot/proc/emp_knockout(deciseconds)
+ set_stat(UNCONSCIOUS)
+ addtimer(CALLBACK(src, PROC_REF(wake_from_emp)), deciseconds, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_DELETE_ME)
+
+/mob/living/silicon/robot/proc/wake_from_emp()
+ set_stat(CONSCIOUS)
+ update_stat()
/mob/living/silicon/robot/emag_act(mob/user, obj/item/card/emag/emag_card)
if(user == src)//To prevent syndieborgs from emagging themselves
@@ -430,3 +438,12 @@ 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/on_hit(obj/projectile/P)
+ if(!has_movespeed_modifier(/datum/movespeed_modifier/borg_throw))
+ add_movespeed_modifier(/datum/movespeed_modifier/borg_throw)
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living/silicon, clear_throw_slowdown)), (P.throwforce / 10) SECONDS)
+ return ..()
+
+/mob/living/silicon/proc/clear_throw_slowdown()
+ src.remove_movespeed_modifier(/datum/movespeed_modifier/borg_throw)
diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm
index 308a7a838c6..a39bfb4b623 100644
--- a/code/modules/mob/living/silicon/robot/robot_defines.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defines.dm
@@ -100,6 +100,8 @@
var/lockcharge = FALSE
///Boolean of whether the borg was locked by its AI or nothing
var/ai_lockdown = FALSE
+ ///Timer that allows the borg to self-unlock after a set amount of time
+ var/lockdown_timer = null
///Random serial number generated for each cyborg upon its initialization
var/ident = 0
var/locked = TRUE
diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm
index ad70a6fa7ec..033d52a9622 100644
--- a/code/modules/mob/living/silicon/robot/robot_model.dm
+++ b/code/modules/mob/living/silicon/robot/robot_model.dm
@@ -276,6 +276,7 @@
flick("[cyborg_base_icon]_transform", cyborg)
cyborg.notransform = TRUE
if(locked_transform)
+ cyborg.ai_lockdown = TRUE
cyborg.SetLockdown(TRUE)
cyborg.set_anchored(TRUE)
cyborg.logevent("Chassis model has been set to [name].")
@@ -284,6 +285,7 @@
playsound(cyborg, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, TRUE, -1)
sleep(0.7 SECONDS)
cyborg.SetLockdown(FALSE)
+ cyborg.ai_lockdown = FALSE
cyborg.setDir(SOUTH)
cyborg.set_anchored(FALSE)
cyborg.notransform = FALSE
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 0106202e32d..847e6867521 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -100,7 +100,7 @@
/mob/living/silicon/emp_act(severity)
. = ..()
to_chat(src, span_danger("Warning: Electromagnetic pulse detected."))
- if(. & EMP_PROTECT_SELF)
+ if(. & EMP_PROTECT_SELF || QDELETED(src))
return
switch(severity)
if(1)
diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm
index bc879368b64..1b27af0eb9f 100644
--- a/code/modules/movespeed/modifiers/mobs.dm
+++ b/code/modules/movespeed/modifiers/mobs.dm
@@ -84,6 +84,9 @@
/datum/movespeed_modifier/shove
multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH
+/datum/movespeed_modifier/borg_throw
+ multiplicative_slowdown = 0.9
+
/datum/movespeed_modifier/human_carry
multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN
blacklisted_movetypes = FLOATING