diff --git a/code/datums/action.dm b/code/datums/action.dm index 9edb458a7e..8c97a38fe6 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -559,7 +559,7 @@ return var/area/area = areas[removeAPC] var/obj/machinery/power/apc/apc = area.get_apc() - if (!apc || !(apc in owner.siliconaccessareas)) + if (!apc || !(area in owner.siliconaccessareas)) return apc.hijacker = null apc.update_icon() @@ -581,10 +581,33 @@ return var/area/area = areas[accessAPC] var/obj/machinery/power/apc/apc = area.get_apc() - if (!apc || !(apc in owner.siliconaccessareas)) + if (!apc || !(area in owner.siliconaccessareas)) return apc.ui_interact(owner) +/datum/action/item_action/stealthmodetoggle + name = "Toggle Stealth Mode" + desc = "Toggles the stealth mode on the hijack implant." + icon_icon = 'icons/obj/implants.dmi' + button_icon_state = "hijackz" + +/datum/action/item_action/stealthmodetoggle/Trigger() + var/obj/item/implant/hijack/H = target + if (!istype(H)) + return + if (H.stealthcooldown > world.time) + to_chat(owner,"The hijack implant's stealth mode toggle is still rebooting!") + return + H.stealthmode = !H.stealthmode + for (var/area/area in H.imp_in.siliconaccessareas) + var/obj/machinery/power/apc/apc = area.get_apc() + if (apc) + apc.set_hijacked_lighting() + apc.update_icon() + H.stealthcooldown = world.time + 30 SECONDS + H.toggle_eyes(H.toggled && !H.stealthmode) + to_chat(owner,"You toggle the hijack implant's stealthmode [H.stealthmode ? "on" : "off"].") + /datum/action/item_action/flash name = "Flash" diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index a93dcec285..b6699540c3 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -52,7 +52,7 @@ /datum/wires/airlock/interactable(mob/user) var/obj/machinery/door/airlock/A = holder - if(!hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100)) + if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100)) return FALSE if(A.panel_open) return TRUE diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm index 8e75a52276..114791e873 100644 --- a/code/datums/wires/vending.dm +++ b/code/datums/wires/vending.dm @@ -12,7 +12,7 @@ /datum/wires/vending/interactable(mob/user) var/obj/machinery/vending/V = holder - if(!hasSiliconAccessInArea(user) && V.seconds_electrified && V.shock(user, 100)) + if(!V.hasSiliconAccessInArea(user) && V.seconds_electrified && V.shock(user, 100)) return FALSE if(V.panel_open) return TRUE diff --git a/code/game/objects/items/implants/implant_hijack.dm b/code/game/objects/items/implants/implant_hijack.dm index 442d94a491..952f5f82e2 100644 --- a/code/game/objects/items/implants/implant_hijack.dm +++ b/code/game/objects/items/implants/implant_hijack.dm @@ -3,39 +3,29 @@ /obj/item/implant/hijack name = "hijack implant" desc = "Allows you to control the machinery in a room by hacking into the APC." - actions_types = list(/datum/action/item_action/hands_free/activate, /datum/action/item_action/removeAPCs, /datum/action/item_action/accessAPCs) + actions_types = list(/datum/action/item_action/hands_free/activate, /datum/action/item_action/removeAPCs, /datum/action/item_action/accessAPCs, /datum/action/item_action/stealthmodetoggle) activated = 1 var/toggled = FALSE icon_state = "hijack" var/eye_color + var/stealthmode = FALSE + var/stealthcooldown = 0 /obj/item/implant/hijack/activate() . = ..() toggled = !toggled - if (toggled) - imp_in.click_intercept = src - imp_in.siliconaccesstoggle = TRUE - to_chat(imp_in,"You turn on [src]'s silicon interactions.") - if (ishuman(imp_in)) - toggle_eyes(TRUE) - else - imp_in.click_intercept = null - imp_in.siliconaccesstoggle = FALSE - to_chat(imp_in,"You turn off [src]'s silicon interactions.") - if (ishuman(imp_in)) - toggle_eyes(FALSE) + imp_in.click_intercept = toggled ? src : null + imp_in.siliconaccesstoggle = toggled ? TRUE : FALSE + to_chat(imp_in,"You turn [toggled ? "on" : "off"] [src]'s silicon interactions.") + toggle_eyes(toggled && !stealthmode) /obj/item/implant/hijack/proc/toggle_eyes(on) - if (!on) - var/mob/living/carbon/human/H = imp_in - H.eye_color = eye_color - H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK) - H.update_body() - else - var/mob/living/carbon/human/H = imp_in - H.eye_color = "ff0" - H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK) - H.update_body() + if (!ishuman(imp_in)) + return + var/mob/living/carbon/human/H = imp_in + H.eye_color = on ? "ff0" : eye_color + H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK) + H.update_body() /obj/item/implant/hijack/implant(mob/living/target, mob/user, silent = FALSE) if(..()) @@ -48,6 +38,13 @@ /obj/item/implant/hijack/removed(mob/target, silent = FALSE, special = 0) if(..()) REMOVE_TRAIT(target, TRAIT_HIJACKER, "implant") + for (var/area/area in imp_in.siliconaccessareas) + imp_in.toggleSiliconAccessArea(area) + var/obj/machinery/power/apc/apc = area.get_apc() + if (apc) + apc.hijacker = null + apc.set_hijacked_lighting() + apc.update_icon() if (ishuman(target)) var/mob/living/carbon/human/H = target H.eye_color = eye_color @@ -56,6 +53,11 @@ /obj/item/implant/hijack/proc/InterceptClickOn(mob/living/user,params,atom/object) if (user.get_active_held_item() || isitem(object) || !toggled || user.incapacitated()) return + if (stealthmode == FALSE && istype(object,/obj/machinery/power/apc) && !user.CanReach(object)) + if (hijack_remotely(object)) + return + if (stealthmode && !user.CanReach(object)) + return if (!object.hasSiliconAccessInArea(imp_in)) return var/list/modifiers = params2list(params) @@ -73,4 +75,33 @@ object.AIAltClick(imp_in) return TRUE object.attack_ai(imp_in) + return TRUE + +/obj/item/implant/hijack/proc/hijack_remotely(obj/machinery/power/apc/apc) + if (apc.hijacker) + return FALSE //can't remotely hijack an already hijacked APC + to_chat(imp_in, "Establishing remote connection with APC.") + if (!do_after(imp_in, 4 SECONDS,target=apc)) + to_chat(imp_in, "Aborting.") + return TRUE + imp_in.light_power = 2 + imp_in.light_range = 2 + imp_in.light_color = COLOR_YELLOW + imp_in.update_light() + imp_in.visible_message("[imp_in] starts glowing a with a hollow yellow light!") + to_chat(imp_in, "Beginning hijack of APC.") + if (do_after(imp_in, 21 SECONDS,target=apc)) + apc.hijacker = imp_in + stealthmode = FALSE + apc.set_hijacked_lighting() + imp_in.toggleSiliconAccessArea(apc.area) + apc.update_icon() + stealthcooldown = world.time + 3 MINUTES + toggle_eyes(TRUE) + else + to_chat(imp_in, "Aborting.") + imp_in.light_power = 0 + imp_in.light_range = 0 + imp_in.light_color = COLOR_YELLOW + imp_in.update_light() return TRUE \ No newline at end of file diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 84d1168ba0..81362a92ab 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -412,9 +412,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp /atom/proc/hasSiliconAccessInArea(mob/user) return user && (issilicon(user) || (user.siliconaccesstoggle && (get_area(src) in user.siliconaccessareas))) -/area/proc/hasSiliconAccessInArea(mob/user) - return user && (issilicon(user) || (user.siliconaccesstoggle && (src in user.siliconaccessareas))) - /mob/proc/toggleSiliconAccessArea(area/area) if (area in siliconaccessareas) siliconaccessareas -= area @@ -429,6 +426,15 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return FALSE return TRUE +/mob/proc/getImplant(type) + if (!istype(src,/mob/living)) + return + var/mob/living/L = src + for (var/I in L.implants) + if (istype(I,type)) + return I + return null + /proc/offer_control(mob/M) to_chat(M, "Control of your mob has been offered to dead players.") if(usr) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 80e5498c35..a655832934 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -311,12 +311,15 @@ if(!(update_state & UPSTATE_ALLGOOD)) SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) - + var/hijackerreturn + if (hijacker) + var/obj/item/implant/hijack/H = hijacker.getImplant(/obj/item/implant/hijack) + hijackerreturn = H && !H.stealthmode if(update & 2) SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) if(!(stat & (BROKEN|MAINT)) && update_state & UPSTATE_ALLGOOD) SSvis_overlays.add_vis_overlay(src, icon, "apcox-[locked]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) - SSvis_overlays.add_vis_overlay(src, icon, "apco3-[hijacker ? "3" : charging]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) + SSvis_overlays.add_vis_overlay(src, icon, "apco3-[hijackerreturn ? "3" : charging]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) if(operating) SSvis_overlays.add_vis_overlay(src, icon, "apco0-[equipment]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) SSvis_overlays.add_vis_overlay(src, icon, "apco1-[lighting]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir) @@ -331,7 +334,7 @@ light_color = LIGHT_COLOR_BLUE if(APC_FULLY_CHARGED) light_color = LIGHT_COLOR_GREEN - if (hijacker) + if (hijackerreturn) light_color = LIGHT_COLOR_YELLOW set_light(lon_range) else if(update_state & UPSTATE_BLUESCREEN) @@ -402,14 +405,18 @@ update_overlay |= APC_UPOVERLAY_ENVIRON2 var/results = 0 - if(last_update_state == update_state && last_update_overlay == update_overlay && hijacker ? hijackerlast : !hijackerlast) + var/hijackerreturn + if (hijacker) + var/obj/item/implant/hijack/H = hijacker.getImplant(/obj/item/implant/hijack) + hijackerreturn = H && !H.stealthmode + if(last_update_state == update_state && last_update_overlay == update_overlay && hijackerreturn ? hijackerlast : !hijackerlast) return 0 if(last_update_state != update_state) results += 1 - if(last_update_overlay != update_overlay || hijacker ? !hijackerlast : hijackerlast) + if(last_update_overlay != update_overlay || hijackerreturn ? !hijackerlast : hijackerlast) results += 2 - if (hijacker ? !hijackerlast : hijackerlast) - hijackerlast = hijacker ? TRUE : FALSE + if (hijackerreturn ? !hijackerlast : hijackerlast) + hijackerlast = hijackerreturn ? TRUE : FALSE return results // Used in process so it doesn't update the icon too much @@ -879,8 +886,8 @@ "nightshiftLights" = nightshift_lights, "hijackable" = HAS_TRAIT(user,TRAIT_HIJACKER), "hijacker" = hijacker == user ? TRUE : FALSE, - "drainavail" = cell.percent() > 85, - "lockdownavail" = cell.percent() > 35, + "drainavail" = cell.percent() > 85 && user.getImplant(/obj/item/implant/hijack) && !user.getImplant(/obj/item/implant/hijack).stealthmode, + "lockdownavail" = cell.percent() > 35 && user.getImplant(/obj/item/implant/hijack) && !user.getImplant(/obj/item/implant/hijack).stealthmode, "powerChannels" = list( list( "title" = "Equipment", @@ -963,7 +970,8 @@ . = ..() if (!. && !QDELETED(remote_control)) . = remote_control.can_interact(user) - if (area.hasSiliconAccessInArea(user)) + message_admins("[area.hasSiliconAccessInArea(user)] & [hijacker == user && area.hasSiliconAccessInArea(user)]") + if (hijacker == user && area.hasSiliconAccessInArea(user)) return TRUE /obj/machinery/power/apc/ui_status(mob/user) @@ -1054,6 +1062,8 @@ hijacker = null set_hijacked_lighting() update_icon() + var/obj/item/implant/hijack/H = usr.getImplant(/obj/item/implant/hijack) + H.stealthcooldown = world.time + 2 MINUTES energy_fail(30 SECONDS * (cell.charge / cell.maxcharge)) if("lockdown") var/celluse = rand(20,35) @@ -1063,6 +1073,8 @@ INVOKE_ASYNC(D,/obj/machinery/door.proc/hostile_lockdown,usr, FALSE) addtimer(CALLBACK(D,/obj/machinery/door.proc/disable_lockdown, FALSE), 30 SECONDS) cell.charge -= cell.maxcharge*celluse + var/obj/item/implant/hijack/H = usr.getImplant(/obj/item/implant/hijack) + H.stealthcooldown = world.time + 3 MINUTES return TRUE /obj/machinery/power/apc/proc/toggle_breaker() @@ -1088,7 +1100,8 @@ to_chat(L, "Aborting.") return to_chat(L, "Beginning hijack of APC.") - if (do_after(L,5 SECONDS,target=src)) + var/obj/item/implant/hijack/H = L.getImplant(/obj/item/implant/hijack) + if (do_after(L,H.stealthmode ? 12 SECONDS : 5 SECONDS,target=src)) if (L.toggleSiliconAccessArea(area)) hijacker = L update_icon() @@ -1505,8 +1518,12 @@ /obj/machinery/power/apc/proc/set_hijacked_lighting() set waitfor = FALSE + var/hijackerreturn + if (hijacker) + var/obj/item/implant/hijack/H = hijacker.getImplant(/obj/item/implant/hijack) + hijackerreturn = H && !H.stealthmode for(var/obj/machinery/light/L in area) - L.hijacked = hijacker ? TRUE : FALSE + L.hijacked = hijackerreturn L.update(FALSE) CHECK_TICK diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index ef718ae71d..8002d55fd9 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -333,7 +333,7 @@ else if (hijacked) BR = BR * 1.5 PO = PO * 1.5 - CO = color || LIGHT_COLOR_YELLOW + CO = color ? color : LIGHT_COLOR_YELLOW else if (nightshift_enabled) BR = nightshift_brightness PO = nightshift_light_power diff --git a/icons/obj/implants.dmi b/icons/obj/implants.dmi index 7e97f0349d..a6d4697673 100644 Binary files a/icons/obj/implants.dmi and b/icons/obj/implants.dmi differ