diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm
index 7bd28f35382..8de71be7f84 100644
--- a/code/__DEFINES/misc_defines.dm
+++ b/code/__DEFINES/misc_defines.dm
@@ -94,6 +94,7 @@
#define AI_TRANS_TO_CARD 1 //Downloading AI to InteliCard.
#define AI_TRANS_FROM_CARD 2 //Uploading AI from InteliCard
#define AI_MECH_HACK 3 //Malfunctioning AI hijacking mecha
+#define AI_SHUTTLE_HACK 4 //Malfunctioning AI hijacking shuttle
//singularity defines
#define STAGE_ONE 1
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index fe3d53e93f8..1d101d51dde 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -385,8 +385,8 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/block
name = "Silicon hijack"
- explanation_text = "Hijack the shuttle with no loyalist Nanotrasen crew on board and free. \
- Syndicate agents, other enemies of Nanotrasen, cyborgs, pets, and cuffed/restrained hostages may be allowed on the shuttle alive. \
+ explanation_text = "Hijack the shuttle by alt-clicking on the shuttle console. Do not let the crew wipe you off of it! \
+ Crew and agents can be on the shuttle when you do this, and may try to wipe you! \
Using the doomsday device successfully is also an option."
martyr_compatible = FALSE
needs_target = FALSE
@@ -397,6 +397,8 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
return FALSE
if(SSticker.mode.station_was_nuked)
return TRUE
+ if(SSshuttle.emergency.aihacked)
+ return TRUE
if(SSshuttle.emergency.mode < SHUTTLE_ENDGAME)
return FALSE
if(!SSshuttle.emergency.is_hijacked(TRUE))
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 1a7dd0f29ba..5f8aff4e82a 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -23,6 +23,8 @@
var/hijack_completion_flight_time_set = 10 SECONDS
var/hijack_hacking = FALSE
var/hijack_announce = TRUE
+ ///The malfunctioning AI that uploaded itself to the shuttle computer.
+ var/mob/living/silicon/ai/windows_33_exe
/obj/machinery/computer/emergency_shuttle/examine(mob/user)
. = ..()
@@ -34,12 +36,12 @@
if(hijack_announce)
. += "It is probably best to fortify your position as to be uninterrupted during the attempt, given the automatic announcements..."
-/obj/machinery/computer/emergency_shuttle/attackby(obj/item/card/W, mob/user, params)
+/obj/machinery/computer/emergency_shuttle/attackby(obj/item/card/id/W, mob/user, params)
if(stat & (BROKEN|NOPOWER))
return
- if(!istype(W, /obj/item/card))
+ if(!istype(W, /obj/item/card/id))
return
- if(SSshuttle.emergency.mode != SHUTTLE_DOCKED)
+ if(SSshuttle.emergency.mode != SHUTTLE_DOCKED && !SSshuttle.emergency.aihacked)
return
if(!user)
return
@@ -49,48 +51,76 @@
if(istype(W, /obj/item/pda))
var/obj/item/pda/pda = W
W = pda.id
- if(!W:access) //no access
- to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ")
+ if(!W.access) //no access
+ to_chat(user, "The access level of [W.registered_name]\'s card is not high enough. ")
return
- var/list/cardaccess = W:access
+ var/list/cardaccess = W.access
if(!istype(cardaccess, /list) || !length(cardaccess)) //no access
- to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ")
+ to_chat(user, "The access level of [W.registered_name]\'s card is not high enough. ")
return
- if(!(ACCESS_HEADS in W:access)) //doesn't have this access
- to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ")
+ if(!(ACCESS_HEADS in W.access)) //doesn't have this access
+ to_chat(user, "The access level of [W.registered_name]\'s card is not high enough. ")
return 0
+ if(!SSshuttle.emergency.aihacked)
+ var/choice = tgui_alert(user, "Would you like to (un)authorize a shortened launch time? [auth_need - length(authorized)] authorization\s are still needed. Use abort to cancel all authorizations.", "Shuttle Launch", list("Authorize", "Repeal", "Abort"))
+ if(SSshuttle.emergency.mode != SHUTTLE_DOCKED || user.get_active_hand() != W)
+ return 0
- var/choice = tgui_alert(user, "Would you like to (un)authorize a shortened launch time? [auth_need - length(authorized)] authorization\s are still needed. Use abort to cancel all authorizations.", "Shuttle Launch", list("Authorize", "Repeal", "Abort"))
- if(SSshuttle.emergency.mode != SHUTTLE_DOCKED || user.get_active_hand() != W)
- return 0
+ var/seconds = SSshuttle.emergency.timeLeft()
+ if(seconds <= 10)
+ return 0
- var/seconds = SSshuttle.emergency.timeLeft()
- if(seconds <= 10)
- return 0
+ switch(choice)
+ if("Authorize")
+ if(!authorized.Find(W.registered_name))
+ authorized += W.registered_name
+ if(auth_need - length(authorized) > 0)
+ message_admins("[key_name_admin(user)] has authorized early shuttle launch.")
+ log_game("[key_name(user)] has authorized early shuttle launch in ([x], [y], [z]).")
+ GLOB.minor_announcement.Announce("[auth_need - length(authorized)] more authorization(s) needed until shuttle is launched early")
+ else
+ message_admins("[key_name_admin(user)] has launched the emergency shuttle [seconds] seconds before launch.")
+ log_game("[key_name(user)] has launched the emergency shuttle in ([x], [y], [z]) [seconds] seconds before launch.")
+ GLOB.minor_announcement.Announce("The emergency shuttle will launch in 10 seconds")
+ SSshuttle.emergency.setTimer(10 SECONDS)
+ if("Repeal")
+ if(authorized.Remove(W.registered_name))
+ GLOB.minor_announcement.Announce("[auth_need - length(authorized)] authorizations needed until shuttle is launched early")
+
+ if("Abort")
+ if(length(authorized))
+ GLOB.minor_announcement.Announce("All authorizations to launch the shuttle early have been revoked.")
+ authorized.Cut()
+ return FALSE
+ var/choice = tgui_alert(user, "\[ERROR] HOSTILE AI DETECTED IN SHUTTLE CONTROL. RESTORE SHUTTLE CONSOLE TO BACKUP SYSTEM? [auth_need - length(authorized)] AUTHORIZATIONS\s REQUIRED TO RESTORE. ABORT TO REMOVE ALL AUTHORIZATION OF BACKUP RESTORAL, P-P--PLEASE...", "HOSTILE VIRAL AI INTRUSION", list("Authorize", "Repeal", "Abort"))
+ if(user.get_active_hand() != W)
+ return FALSE
switch(choice)
if("Authorize")
- if(!authorized.Find(W:registered_name))
- authorized += W:registered_name
+ if(!authorized.Find(W.registered_name))
+ authorized += W.registered_name
if(auth_need - length(authorized) > 0)
- message_admins("[key_name_admin(user)] has authorized early shuttle launch.")
- log_game("[key_name(user)] has authorized early shuttle launch in ([x], [y], [z]).")
- GLOB.minor_announcement.Announce("[auth_need - length(authorized)] more authorization(s) needed until shuttle is launched early")
+ message_admins("[key_name_admin(user)] has authorized restoring shuttle AI backup.")
+ log_game("[key_name(user)] has authorized restoring shuttle AI backup in ([x], [y], [z]).")
+ GLOB.minor_announcement.Announce("[auth_need - length(authorized)] more authorization(s) needed until sh-tt- STOP STOP STOP STOP!")
else
- message_admins("[key_name_admin(user)] has launched the emergency shuttle [seconds] seconds before launch.")
- log_game("[key_name(user)] has launched the emergency shuttle in ([x], [y], [z]) [seconds] seconds before launch.")
- GLOB.minor_announcement.Announce("The emergency shuttle will launch in 10 seconds")
- SSshuttle.emergency.setTimer(100)
+ message_admins("[key_name_admin(user)] has wiped the AI in the shuttle computer.")
+ log_game("[key_name(user)] has wiped the AI in the shuttle computer in ([x], [y], [z])")
+ GLOB.minor_announcement.Announce("NO NO NO N---\[[Gibberish("###########", 100, 90)]\]...")
+ GLOB.minor_announcement.Announce("Shuttle AI restored to emergency backup. Avoiding toll hyperlanes. Recalculating route. Recalculating. Recalculating. Please stand by...")
+ SSshuttle.emergency.setTimer(60 SECONDS)
+ kill_the_ai()
if("Repeal")
- if(authorized.Remove(W:registered_name))
- GLOB.minor_announcement.Announce("[auth_need - length(authorized)] authorizations needed until shuttle is launched early")
+ if(authorized.Remove(W.registered_name))
+ GLOB.minor_announcement.Announce("[auth_need - length(authorized)] authorizations needed unti- THE SHUTTLE EXPLODES. PLEASE REVO-KE ALL AUTHORIZATIONS.")
if("Abort")
if(length(authorized))
- GLOB.minor_announcement.Announce("All authorizations to launch the shuttle early have been revoked.")
+ GLOB.minor_announcement.Announce("All authorizations to restore shuttle AI backup have been re-- Really applied. The AI is gone. There is no reason to worry. Enjoy your flight.")
authorized.Cut()
/obj/machinery/computer/emergency_shuttle/emag_act(mob/user)
@@ -99,10 +129,39 @@
message_admins("[key_name_admin(user)] has emagged the emergency shuttle: [time] seconds before launch.")
log_game("[key_name(user)] has emagged the emergency shuttle in ([x], [y], [z]): [time] seconds before launch.")
GLOB.minor_announcement.Announce("The emergency shuttle will launch in 10 seconds", "SYSTEM ERROR:")
- SSshuttle.emergency.setTimer(100)
+ SSshuttle.emergency.setTimer(10 SECONDS)
emagged = TRUE
return TRUE
+/obj/machinery/computer/emergency_shuttle/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card)
+ if(!..())
+ return
+ if(!AI.malf_picker)
+ return FALSE //If you put an AI that isn't malf in it I'm shooting you
+ if(interaction == AI_TRANS_TO_CARD) //No patrick you can't card the AI out of the computer.
+ return
+ AI.linked_core = new /obj/structure/AIcore/deactivated(AI.loc)
+ ai_enter_emergency_computer(AI)
+
+/obj/machinery/computer/emergency_shuttle/proc/ai_enter_emergency_computer(mob/living/silicon/ai/AI)
+ AI.aiRestorePowerRoutine = 0
+ AI.forceMove(src)
+ windows_33_exe = AI
+ icon_screen = "syndishuttle"
+ update_icon()
+ AI.cancel_camera()
+ AI.can_shunt = FALSE //ONE AI ENTERS. NO AI LEAVES.
+ to_chat(AI, "You are now loaded into the shuttle computer. Make sure command does not wipe you from it, there is no going back...")
+ SSshuttle.emergency.aihacked = TRUE
+ authorized.Cut() //In case command was already swiping to early launch or something
+
+/obj/machinery/computer/emergency_shuttle/proc/kill_the_ai()
+ if(windows_33_exe)
+ windows_33_exe.emote("scream")
+ windows_33_exe.dust()
+ SSshuttle.emergency.aihacked = FALSE
+ icon_screen = initial(icon_screen)
+ update_icon()
/obj/machinery/computer/emergency_shuttle/proc/increase_hijack_stage()
var/obj/docking_port/mobile/emergency/shuttle = SSshuttle.emergency
@@ -135,6 +194,14 @@
if(!speed)
to_chat(user, "You manage to open a user-mode shell on [src], and hundreds of lines of debugging output fly through your vision. It is probably best to leave this alone.")
return
+ if(is_ai && isnull(windows_33_exe))
+ var/mob/living/silicon/ai/AI = user
+ if(AI.doomsday_device)
+ return
+ transfer_ai(AI_SHUTTLE_HACK, AI, AI)
+ GLOB.minor_announcement.Announce("Warning! B.A.S.I.C shuttle piloting AI comp-- Comparing notes with the engine system to maximize efficency. Do not be alarmed.")
+ SSshuttle.emergency.setTimer(60 SECONDS)
+ return
if(hijack_hacking)
return
if(SSshuttle.emergency.hijack_status >= HIJACKED)
@@ -207,6 +274,8 @@
var/canRecall = TRUE //no bad condom, do not recall the crew transfer shuttle!
///State of the emergency shuttles hijack status.
var/hijack_status = NOT_BEGUN
+ ///Is the AI currently in control of the shuttle?
+ var/aihacked = FALSE
/obj/docking_port/mobile/emergency/register()
if(!..())
@@ -297,6 +366,8 @@
/obj/docking_port/mobile/emergency/proc/is_hijacked(fullcheck = FALSE)
if(hijack_status == HIJACKED && !fullcheck) //Don't even bother if it was done via computer.
return TRUE
+ if(SSshuttle.emergency.aihacked)
+ return TRUE
for(var/mob/living/player in GLOB.player_list)
if(!player.mind)
continue