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