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