diff --git a/code/__DEFINES/ARES.dm b/code/__DEFINES/ARES.dm
index 55aa68f97309..712d37f93336 100644
--- a/code/__DEFINES/ARES.dm
+++ b/code/__DEFINES/ARES.dm
@@ -82,3 +82,11 @@
/// Time until someone can respawn as Working Joe
#define JOE_JOIN_DEAD_TIME (15 MINUTES)
+
+
+
+#define FACTION_ARES "Ares"
+#define FACTION_LIST_ARES_MARINE list(FACTION_MARINE, FACTION_ARES)
+#define FACTION_LIST_ARES_ALL list(FACTION_ARES, FACTION_MARINE, FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY)
+#define FACTION_LIST_ARES_WY list(FACTION_ARES, FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY)
+#define FACTION_LIST_ARES_ALONE list(FACTION_ARES)
diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm
index 71b2b6f4b6ac..4b0650e61b3b 100644
--- a/code/__DEFINES/access.dm
+++ b/code/__DEFINES/access.dm
@@ -169,6 +169,8 @@ most of them are tied into map-placed objects. This should be reworked in the fu
#define ACCESS_LIST_MARINE_ALL "Almayer (ALL)"
///Used by the Wey-Yu - USCM Liaison
#define ACCESS_LIST_MARINE_LIAISON "Wey-Yu (Liaison)"
+///Used by the Wey-Yu AIST aboard Almayer
+#define ACCESS_LIST_MARINE_LIAISON_AIST "Wey-Yu (AIST)"
///The accesses granted to emergency responders.
#define ACCESS_LIST_EMERGENCY_RESPONSE "Almayer (ERT)"
diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm
index 3fd552f5369f..035d3b50f481 100644
--- a/code/__DEFINES/job.dm
+++ b/code/__DEFINES/job.dm
@@ -124,6 +124,7 @@ GLOBAL_LIST_INIT(job_command_roles, JOB_COMMAND_ROLES_LIST)
#define JOB_GENERAL "USCM General"
#define JOB_ACMC "Assistant Commandant of the Marine Corps"
#define JOB_CMC "Commandant of the Marine Corps"
+#define JOB_AI_TECH "AI Service Technician"
// Used to add a timelock to a job. Will be passed onto derivatives
#define AddTimelock(Path, timelockList) \
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index cf6d6c64d9a9..d5c02029ecc7 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -310,6 +310,9 @@
#define COOLDOWN_COMM_CENTRAL 30 SECONDS
#define COOLDOWN_COMM_DESTRUCT 5 MINUTES
+#define FORCE_SCAN_LOCK 25 MINUTES
+#define COOLDOWN_FORCE_SCAN 15 MINUTES
+
///Cooldown for pred recharge
#define COOLDOWN_BRACER_CHARGE 3 MINUTES
diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm
index 4c3a658ff421..2c5c9261a164 100644
--- a/code/__DEFINES/mode.dm
+++ b/code/__DEFINES/mode.dm
@@ -117,6 +117,7 @@
#define ROLE_WHITELISTED 16
#define ROLE_NO_ACCOUNT 32
#define ROLE_CUSTOM_SPAWN 64
+#define ROLE_HIDDEN 128
//=================================================
//Role defines, specifically lists of roles for job bans, crew manifests and the like.
@@ -128,7 +129,7 @@ GLOBAL_LIST_INIT(ROLES_CIC, list(JOB_CO, JOB_XO, JOB_SO, JOB_WO_CO, JOB_WO_XO))
GLOBAL_LIST_INIT(ROLES_AUXIL_SUPPORT, list(JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_CAS_PILOT, JOB_DROPSHIP_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_TANK_CREW, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT))
GLOBAL_LIST_INIT(ROLES_MISC, list(JOB_SYNTH, JOB_WORKING_JOE, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_MESS_SERGEANT, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH))
GLOBAL_LIST_INIT(ROLES_POLICE, list(JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE))
-GLOBAL_LIST_INIT(ROLES_ENGINEERING, list(JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH))
+GLOBAL_LIST_INIT(ROLES_ENGINEERING, list(JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_AI_TECH))
GLOBAL_LIST_INIT(ROLES_REQUISITION, list(JOB_CHIEF_REQUISITION, JOB_CARGO_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION))
GLOBAL_LIST_INIT(ROLES_MEDICAL, list(JOB_CMO, JOB_RESEARCHER, JOB_DOCTOR, JOB_NURSE, JOB_WO_CMO, JOB_WO_RESEARCHER, JOB_WO_DOCTOR))
GLOBAL_LIST_INIT(ROLES_MARINES, list(JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE))
@@ -153,7 +154,7 @@ GLOBAL_LIST_INIT(ROLES_UNASSIGNED, list(JOB_SQUAD_MARINE))
JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE
#define BLURB_USCM_FLIGHT JOB_CAS_PILOT, JOB_DROPSHIP_PILOT, JOB_DROPSHIP_CREW_CHIEF
#define BLURB_USCM_MP JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE
-#define BLURB_USCM_ENGI JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_TANK_CREW, JOB_WO_PILOT
+#define BLURB_USCM_ENGI JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_TANK_CREW, JOB_WO_PILOT, JOB_AI_TECH
#define BLURB_USCM_MEDICAL JOB_CMO, JOB_RESEARCHER, JOB_DOCTOR, JOB_NURSE, JOB_WO_CMO, JOB_WO_RESEARCHER, JOB_WO_DOCTOR
#define BLURB_USCM_REQ JOB_CHIEF_REQUISITION, JOB_CARGO_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION
#define BLURB_USCM_WY JOB_CORPORATE_LIAISON
diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm
index cc1831501bad..8a94fa9dec78 100644
--- a/code/__DEFINES/radio.dm
+++ b/code/__DEFINES/radio.dm
@@ -73,3 +73,4 @@
#define RADIO_CHANNEL_YAUTJA "Yautja"
+#define RADIO_CHANNEL_AICORE "AI Core"
diff --git a/code/__HELPERS/job.dm b/code/__HELPERS/job.dm
index 51cc496feeae..4603516317c5 100644
--- a/code/__HELPERS/job.dm
+++ b/code/__HELPERS/job.dm
@@ -58,5 +58,6 @@
JOB_CHIEF_POLICE,
JOB_WARDEN,
JOB_SEA,
- JOB_MARINE
+ JOB_MARINE,
+ JOB_AI_TECH
)
diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm
index 7397d98a0d52..962b6c92ad1b 100644
--- a/code/controllers/subsystem/communications.dm
+++ b/code/controllers/subsystem/communications.dm
@@ -146,6 +146,7 @@ Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency
#define MAX_FREE_FREQ 1599 // -------------------------------------------------
GLOBAL_LIST_INIT(radiochannels, list(
+ RADIO_CHANNEL_AICORE = AI_FREQ,
RADIO_CHANNEL_YAUTJA = YAUT_FREQ,
RADIO_CHANNEL_VAI = VAI_FREQ,
RADIO_CHANNEL_CMB = CMB_FREQ,
diff --git a/code/datums/factions/uscm.dm b/code/datums/factions/uscm.dm
index f7c49321f305..0ea8e9749c6c 100644
--- a/code/datums/factions/uscm.dm
+++ b/code/datums/factions/uscm.dm
@@ -148,6 +148,8 @@
if(JOB_PROVOST_MARSHAL, JOB_PROVOST_CMARSHAL, JOB_PROVOST_SMARSHAL)
marine_rk = "pvm"
border_rk = "command"
+ if(JOB_AI_TECH)
+ marine_rk = "aist"
// TIS
if(JOB_TIS_IO)
marine_rk = "tisio"
diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm
index a065a0b8671f..8a8f36ae51bd 100644
--- a/code/game/area/almayer.dm
+++ b/code/game/area/almayer.dm
@@ -79,6 +79,16 @@
is_resin_allowed = FALSE
resin_construction_allowed = FALSE
+/area/almayer/command/aist_office
+ name = "\improper AIST Office"
+ icon_state = "airoom"
+ fake_zlevel = 1 // upperdeck
+ soundscape_playlist = list()
+ flags_area = AREA_NOTUNNEL|AREA_UNWEEDABLE
+ can_build_special = FALSE
+ is_resin_allowed = FALSE
+ resin_construction_allowed = FALSE
+
/area/almayer/command/securestorage
name = "\improper Upper Deck Secure Storage"
icon_state = "corporatespace"
diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm
index 5c10e8e7d934..3d9c1e7811e1 100644
--- a/code/game/jobs/access.dm
+++ b/code/game/jobs/access.dm
@@ -168,6 +168,19 @@
ACCESS_MARINE_MEDBAY,
) + get_access(ACCESS_LIST_COLONIAL_ALL)
+ if(ACCESS_LIST_MARINE_LIAISON_AIST)
+ return list(
+ ACCESS_WY_GENERAL,
+ ACCESS_WY_COLONIAL,
+ ACCESS_WY_EXEC,
+ ACCESS_MARINE_COMMAND,
+ ACCESS_MARINE_MEDBAY,
+ ACCESS_MARINE_ENGINEERING,
+ ACCESS_MARINE_SYNTH,
+ ACCESS_MARINE_AI,
+ ACCESS_ARES_DEBUG,
+ ) + get_access(ACCESS_LIST_COLONIAL_ALL)
+
if(ACCESS_LIST_COLONIAL_ALL)
return list(
ACCESS_CIVILIAN_PUBLIC,
diff --git a/code/game/jobs/job/special/uscm.dm b/code/game/jobs/job/special/uscm.dm
index 751322539f77..c7b3f91da7b0 100644
--- a/code/game/jobs/job/special/uscm.dm
+++ b/code/game/jobs/job/special/uscm.dm
@@ -14,3 +14,43 @@
title = JOB_RIOT
/datum/job/special/uscm/riot/chief
title = JOB_RIOT_CHIEF
+
+#define USCM_TECH "USCM"
+#define WY_TECH "Wey-Yu"
+
+/datum/job/special/uscm/ai_tech
+ title = JOB_AI_TECH
+ selection_class = "job_ce"
+ supervisors = "the acting commanding officer"
+ total_positions = 1
+ spawn_positions = 1
+ flags_startup_parameters = ROLE_WHITELISTED
+ gear_preset = /datum/equipment_preset/uscm_event/ai_tech
+
+ // job option
+ job_options = list(USCM_TECH = "USCM", WY_TECH = "WY")
+ var/corporate = FALSE
+
+//check the job option. and change the gear preset
+/datum/job/special/uscm/ai_tech/handle_job_options(option)
+ if(option != USCM_TECH)
+ corporate = TRUE
+ supervisors = "Weyland Yutani"
+ gear_preset = /datum/equipment_preset/uscm_event/ai_tech/corporate
+ else
+ corporate = FALSE
+ gear_preset = /datum/equipment_preset/uscm_event/ai_tech
+
+/datum/job/special/uscm/ai_tech/check_whitelist_status(mob/user)
+ if(check_rights(R_PERMISSIONS, show_msg = FALSE))
+ return TRUE
+ return FALSE
+
+/datum/job/special/uscm/ai_tech/generate_entry_message()
+ entry_message_body = "You are a [corporate ? FACTION_WY : FACTION_MARINE] AI Service Technician temporarily assigned to the [MAIN_SHIP_NAME]. Your goal is to ensure the onboard AI, [MAIN_AI_SYSTEM], is operating effectively. Your job involves heavy roleplay and requires you to behave like [corporate ? "a senior corporate representative, remaining in character at all times.
As a Weyland Yutani Technician you have access to the Corporate Office aboard the USS Almayer. Although you should cooperate with the onboard Liaison, you are not their subordinate nor they yours. You should help The Company interests where applicable but do not abuse your access to the AI Systems." : "an officer and to stay in character at all times. You are required to adhere to and obey Marine Law. Failure to do so may result in punitive action against you. Godspeed.\n\nThe access code for APOLLO Interface is [GLOB.ares_link.code_apollo].\nThe access code for ARES Interface is [GLOB.ares_link.code_interface]."]"
+ return ..()
+
+/obj/effect/landmark/start/aist
+ name = JOB_AI_TECH
+ icon_state = "aist_spawn"
+ job = /datum/job/special/uscm/ai_tech
diff --git a/code/game/machinery/ARES/ARES.dm b/code/game/machinery/ARES/ARES.dm
index 1ecbb4a5d7d6..3236abe44f6d 100644
--- a/code/game/machinery/ARES/ARES.dm
+++ b/code/game/machinery/ARES/ARES.dm
@@ -115,3 +115,35 @@
name = "ARES Substrate"
desc = "The memory substrate of ARES, containing complex protocols and information. Limited capabilities can operate on substrate alone, without the main ARES Unit operational."
icon_state = "substrate"
+
+
+/// Sentry
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares
+ name = "UA X512-S mini sentry"
+ faction_group = FACTION_LIST_ARES_MARINE
+
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/Initialize()
+ link_sentry()
+ . = ..()
+
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/Destroy()
+ delink_sentry()
+ . = ..()
+
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/start_processing()
+ sync_iff()
+ ..()
+
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/proc/sync_iff()
+ var/datum/ares_link/ares_link = GLOB.ares_link
+ if(!ares_link || !ares_link.faction_group)
+ faction_group = FACTION_LIST_ARES_MARINE
+ faction_group = ares_link.faction_group
+
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/proc/link_sentry()
+ var/datum/ares_link/link = GLOB.ares_link
+ link.core_sentries += src
+
+/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/proc/delink_sentry()
+ var/datum/ares_link/link = GLOB.ares_link
+ link.core_sentries -= src
diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm
index 0316274774be..243d0e169f63 100644
--- a/code/game/machinery/ARES/ARES_interface.dm
+++ b/code/game/machinery/ARES/ARES_interface.dm
@@ -220,6 +220,10 @@
data["security_vents"] = link.get_ares_vents()
+ data["sentry_setting"] = link.faction_label
+ data["sentry_setting"] = link.faction_label
+ data["faction_options"] = link.faction_options
+
return data
/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state)
@@ -573,6 +577,24 @@
COOLDOWN_START(datacore, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT)
return TRUE
+ if("bioscan")
+ if(!SSticker.mode)
+ return FALSE //Not a game mode?
+ if(world.time < FORCE_SCAN_LOCK)
+ to_chat(operator, SPAN_WARNING("Bio sensors are not yet ready to initiate a scan!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!(COOLDOWN_FINISHED(datacore, ares_bioscan_cooldown)) || (world.time < (GLOB.last_human_bioscan + COOLDOWN_FORCE_SCAN)))
+ to_chat(operator, SPAN_WARNING("It is too soon since the last scan, wait for the sensor array to reset!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ GLOB.bioscan_data.ares_bioscan(FALSE, 2)
+ COOLDOWN_START(datacore, ares_bioscan_cooldown, COOLDOWN_FORCE_SCAN)
+ playsound(src, 'sound/machines/terminal_processing.ogg', 15, 1)
+ message_admins("BIOSCAN: [key_name(operator)] triggered a Marine bioscan via ARES AIST.")
+ return TRUE
+
if("trigger_vent")
playsound = FALSE
var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"])
@@ -599,5 +621,20 @@
aicore_lockdown(user)
return TRUE
+ if("update_sentries")
+ playsound = FALSE
+ var/new_iff = params["chosen_iff"]
+ if(!new_iff)
+ to_chat(user, SPAN_WARNING("ERROR: Unknown setting."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(new_iff == link.faction_label)
+ return FALSE
+ link.change_iff(new_iff)
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ message_admins("ARES: [key_name(user)] updated ARES Sentry IFF to [new_iff].")
+ to_chat(user, SPAN_WARNING("Sentry IFF settings updated!"))
+ return TRUE
+
if(playsound)
playsound(src, "keyboard_alt", 15, 1)
diff --git a/code/game/machinery/ARES/ARES_interface_admin.dm b/code/game/machinery/ARES/ARES_interface_admin.dm
index 758ba9fbb5e7..d97798f1d086 100644
--- a/code/game/machinery/ARES/ARES_interface_admin.dm
+++ b/code/game/machinery/ARES/ARES_interface_admin.dm
@@ -50,8 +50,10 @@
return FALSE
var/list/data = list()
+ data["is_pda"] = FALSE
+
data["admin_login"] = "[admin_interface.logged_in], [user.client.admin_holder?.rank]"
- data["admin_access_log"] = list(admin_interface.access_list)
+ data["admin_access_log"] = admin_interface.access_list
data["current_menu"] = admin_interface.current_menu
data["last_page"] = admin_interface.last_menu
@@ -232,6 +234,8 @@
data["access_tickets"] = logged_access
data["security_vents"] = get_ares_vents()
+ data["sentry_setting"] = faction_label
+ data["faction_options"] = faction_options
return data
@@ -514,3 +518,22 @@
log_ares_security("Nerve Gas Release", "Released Nerve Gas from Vent '[sec_vent.vent_tag]'.", MAIN_AI_SYSTEM)
sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS)
log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.")
+
+ if("security_lockdown")
+ if(!COOLDOWN_FINISHED(datacore, aicore_lockdown))
+ to_chat(user, SPAN_BOLDWARNING("AI Core Lockdown procedures are on cooldown! They will be ready in [COOLDOWN_SECONDSLEFT(datacore, aicore_lockdown)] seconds!"))
+ return FALSE
+ aicore_lockdown(user)
+ return TRUE
+
+ if("update_sentries")
+ var/new_iff = params["chosen_iff"]
+ if(!new_iff)
+ to_chat(user, SPAN_WARNING("ERROR: Unknown setting."))
+ return FALSE
+ if(new_iff == faction_label)
+ return FALSE
+ change_iff(new_iff)
+ message_admins("ARES: [key_name(user)] updated ARES Sentry IFF to [new_iff].")
+ to_chat(user, SPAN_WARNING("Sentry IFF settings updated!"))
+ return TRUE
diff --git a/code/game/machinery/ARES/ARES_interface_apollo.dm b/code/game/machinery/ARES/ARES_interface_apollo.dm
index 93637f39d1a7..ac8e4864c9d1 100644
--- a/code/game/machinery/ARES/ARES_interface_apollo.dm
+++ b/code/game/machinery/ARES/ARES_interface_apollo.dm
@@ -142,6 +142,8 @@
data["access_tickets"] = logged_access
data["security_vents"] = link.get_ares_vents()
+ data["sentry_setting"] = link.faction_label
+ data["faction_options"] = link.faction_options
return data
@@ -444,6 +446,21 @@
aicore_lockdown(user)
return TRUE
+ if("update_sentries")
+ playsound = FALSE
+ var/new_iff = params["chosen_iff"]
+ if(!new_iff)
+ to_chat(user, SPAN_WARNING("ERROR: Unknown setting."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(new_iff == link.faction_label)
+ return FALSE
+ link.change_iff(new_iff)
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ message_admins("ARES: [key_name(user)] updated ARES Sentry IFF to [new_iff].")
+ to_chat(user, SPAN_WARNING("Sentry IFF settings updated!"))
+ return TRUE
+
if(playsound)
playsound(src, "keyboard_alt", 15, 1)
diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm
index ef1b836a3d4b..67eee9df56d1 100644
--- a/code/game/machinery/ARES/ARES_procs.dm
+++ b/code/game/machinery/ARES/ARES_procs.dm
@@ -40,10 +40,24 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
var/list/waiting_ids = list()
var/list/active_ids = list()
+ ///Sentry faction stuff
+ var/faction_label = FACTION_MARINE
+ var/list/faction_group = FACTION_LIST_ARES_MARINE
+ var/list/faction_options = list(FACTION_MARINE, FACTION_WY, "USCM-WY", FACTION_ARES)
+ var/list/core_sentries = list()
+
+ var/code_apollo = 1
+ var/code_interface = 1
+ var/code_debug = 1
+
/datum/ares_link/New()
admin_interface = new
datacore = GLOB.ares_datacore
+ code_apollo = "[pick(GLOB.alphabet_uppercase)][rand(1000, 9999)][pick(GLOB.alphabet_uppercase)][pick(GLOB.alphabet_uppercase)]"
+ code_interface = "[pick(GLOB.alphabet_uppercase)][rand(1000, 9999)][pick(GLOB.alphabet_uppercase)][pick(GLOB.alphabet_uppercase)]"
+ code_debug = "X[rand(1000, 9999)][pick(GLOB.alphabet_uppercase)][pick(GLOB.alphabet_uppercase)]"
+
/datum/ares_link/Destroy()
qdel(admin_interface)
for(var/obj/structure/machinery/ares/link in linked_systems)
@@ -70,6 +84,28 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
security_vents += list(current_vent)
return security_vents
+/datum/ares_link/proc/change_iff(selection)
+ faction_label = selection
+ var/list/new_iff = list()
+ var/setting
+ switch(selection)
+ if("USCM-WY")
+ setting = "all USCM and Corporate personnel!"
+ new_iff = FACTION_LIST_ARES_ALL
+ if(FACTION_WY)
+ setting = "Corporate personnel only!"
+ new_iff = FACTION_LIST_ARES_WY
+ if(FACTION_ARES)
+ setting = "authenticated Core Assets!"
+ new_iff = FACTION_LIST_ARES_ALONE
+ else
+ setting = "USCM personnel only!"
+ faction_label = FACTION_MARINE
+ new_iff = FACTION_LIST_ARES_MARINE
+ faction_group = new_iff
+ ares_apollo_talk("Security IFF systems updated to [setting]")
+ for(var/obj/structure/machinery/defenses/sentry/premade/deployable/almayer/mini/ares/sentry in core_sentries)
+ sentry.sync_iff()
/* BELOW ARE IN AdminAres.dm
/datum/ares_link/tgui_interact(mob/user, datum/tgui/ui)
@@ -113,6 +149,7 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
COOLDOWN_DECLARE(ares_nuclear_cooldown)
COOLDOWN_DECLARE(ares_quarters_cooldown)
COOLDOWN_DECLARE(aicore_lockdown)
+ COOLDOWN_DECLARE(ares_bioscan_cooldown)
// ------ ARES Logging Procs ------ //
/proc/ares_is_active()
diff --git a/code/game/machinery/ARES/ARES_records.dm b/code/game/machinery/ARES/ARES_records.dm
index 5bfe50dce068..9516c676777b 100644
--- a/code/game/machinery/ARES/ARES_records.dm
+++ b/code/game/machinery/ARES/ARES_records.dm
@@ -49,6 +49,15 @@
src.details = details
src.user = user
+/datum/ares_record/flight
+ record_name = ARES_RECORD_FLIGHT
+
+/datum/ares_record/flight/New(details, user)
+ time = worldtime2text()
+ src.title = "Flight Log"
+ src.details = details
+ src.user = user
+
/datum/ares_record/bombardment
record_name = ARES_RECORD_BOMB
diff --git a/code/game/machinery/ARES/apollo_pda.dm b/code/game/machinery/ARES/apollo_pda.dm
index 7b92b869daeb..51c2a6aa280a 100644
--- a/code/game/machinery/ARES/apollo_pda.dm
+++ b/code/game/machinery/ARES/apollo_pda.dm
@@ -167,6 +167,8 @@
data["access_tickets"] = logged_access
data["security_vents"] = link.get_ares_vents()
+ data["sentry_setting"] = link.faction_label
+ data["faction_options"] = link.faction_options
return data
@@ -470,6 +472,21 @@
aicore_lockdown(user)
return TRUE
+ if("update_sentries")
+ playsound = FALSE
+ var/new_iff = params["chosen_iff"]
+ if(!new_iff)
+ to_chat(user, SPAN_WARNING("ERROR: Unknown setting."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(new_iff == link.faction_label)
+ return FALSE
+ link.change_iff(new_iff)
+ message_admins("ARES: [key_name(user)] updated ARES Sentry IFF to [new_iff].")
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ to_chat(user, SPAN_WARNING("Sentry IFF settings updated!"))
+ return TRUE
+
if(playsound)
var/sound = pick('sound/machines/pda_button1.ogg', 'sound/machines/pda_button2.ogg')
playsound(src, sound, 15, TRUE)
diff --git a/code/game/machinery/ARES/debug_data.dm b/code/game/machinery/ARES/debug_data.dm
new file mode 100644
index 000000000000..eaab382e14e8
--- /dev/null
+++ b/code/game/machinery/ARES/debug_data.dm
@@ -0,0 +1,308 @@
+/obj/item/device/ai_tech_pda/ui_data(mob/user)
+ if(!link.interface)
+ to_chat(user, SPAN_WARNING("ARES ADMIN DATA LINK FAILED"))
+ return FALSE
+ var/list/data = list()
+
+ data["is_pda"] = TRUE
+ data["admin_login"] = "[logged_in], AI Service Technician"
+ data["admin_access_log"] = access_list
+
+ data["current_menu"] = current_menu
+ data["last_page"] = last_menu
+
+ data["logged_in"] = logged_in
+ data["access_level"] = authentication
+ data["sudo"] = FALSE
+
+ var/admin_remote_access_text = "[link.interface.sudo_holder ? "(SUDO)," : ""] access level [link.interface.authentication], [link.interface.ares_auth_to_text(link.interface.authentication)]."
+ if(set_ui == "AresAdmin")
+ data["access_text"] = admin_remote_access_text
+ data["logged_in"] = link.interface.last_login
+ data["access_level"] = link.interface.authentication
+ data["sudo"] = link.interface.sudo_holder ? TRUE : FALSE
+ else if(set_ui == "WorkingJoe")
+ data["access_text"] = " access level [authentication], [apollo_auth_to_text(authentication)]."
+ else if(set_ui == "AresInterface")
+ data["access_text"] = " access level [authentication], [ares_auth_to_text(authentication)]."
+
+ data["alert_level"] = GLOB.security_level
+ data["evac_status"] = SShijack.evac_status
+ data["worldtime"] = world.time
+
+ data["access_log"] = datacore.interface_access_list
+ data["apollo_log"] = datacore.apollo_log
+
+ data["deleted_conversation"] = deleted_1to1
+
+ data["distresstime"] = datacore.ares_distress_cooldown
+ data["distresstimelock"] = DISTRESS_TIME_LOCK
+ data["quarterstime"] = datacore.ares_quarters_cooldown
+ data["mission_failed"] = SSticker.mode.is_in_endgame
+ data["nuketimelock"] = NUCLEAR_TIME_LOCK
+ data["nuke_available"] = datacore.nuke_available
+
+ data["printer_cooldown"] = !COOLDOWN_FINISHED(src, printer_cooldown)
+
+ var/list/logged_announcements = list()
+ for(var/datum/ares_record/announcement/broadcast as anything in datacore.records_announcement)
+ var/list/current_broadcast = list()
+ current_broadcast["time"] = broadcast.time
+ current_broadcast["title"] = broadcast.title
+ current_broadcast["details"] = broadcast.details
+ current_broadcast["ref"] = "\ref[broadcast]"
+ logged_announcements += list(current_broadcast)
+ data["records_announcement"] = logged_announcements
+
+ var/list/logged_alerts = list()
+ for(var/datum/ares_record/security/security_alert as anything in datacore.records_security)
+ var/list/current_alert = list()
+ current_alert["time"] = security_alert.time
+ current_alert["title"] = security_alert.title
+ current_alert["details"] = security_alert.details
+ current_alert["ref"] = "\ref[security_alert]"
+ logged_alerts += list(current_alert)
+ data["records_security"] = logged_alerts
+
+ var/list/logged_flights = list()
+ for(var/datum/ares_record/flight/flight_log as anything in datacore.records_flight)
+ var/list/current_flight = list()
+ current_flight["time"] = flight_log.time
+ current_flight["title"] = flight_log.title
+ current_flight["details"] = flight_log.details
+ current_flight["user"] = flight_log.user
+ current_flight["ref"] = "\ref[flight_log]"
+ logged_flights += list(current_flight)
+ data["records_flight"] = logged_flights
+
+ var/list/logged_bioscans = list()
+ for(var/datum/ares_record/bioscan/scan as anything in datacore.records_bioscan)
+ var/list/current_scan = list()
+ current_scan["time"] = scan.time
+ current_scan["title"] = scan.title
+ current_scan["details"] = scan.details
+ current_scan["ref"] = "\ref[scan]"
+ logged_bioscans += list(current_scan)
+ data["records_bioscan"] = logged_bioscans
+
+ var/list/logged_bombs = list()
+ for(var/datum/ares_record/bombardment/bomb as anything in datacore.records_bombardment)
+ var/list/current_bomb = list()
+ current_bomb["time"] = bomb.time
+ current_bomb["title"] = bomb.title
+ current_bomb["details"] = bomb.details
+ current_bomb["user"] = bomb.user
+ current_bomb["ref"] = "\ref[bomb]"
+ logged_bombs += list(current_bomb)
+ data["records_bombardment"] = logged_bombs
+
+ var/list/logged_deletes = list()
+ for(var/datum/ares_record/deletion/deleted as anything in datacore.records_deletion)
+ if(!istype(deleted))
+ continue
+ var/list/current_delete = list()
+ current_delete["time"] = deleted.time
+ current_delete["title"] = deleted.title
+ current_delete["details"] = deleted.details
+ current_delete["user"] = deleted.user
+ current_delete["ref"] = "\ref[deleted]"
+ logged_deletes += list(current_delete)
+ data["records_deletion"] = logged_deletes
+
+ var/list/logged_discussions = list()
+ for(var/datum/ares_record/deleted_talk/deleted_convo as anything in datacore.records_deletion)
+ if(!istype(deleted_convo))
+ continue
+ var/list/deleted_disc = list()
+ deleted_disc["time"] = deleted_convo.time
+ deleted_disc["title"] = deleted_convo.title
+ deleted_disc["ref"] = "\ref[deleted_convo]"
+ logged_discussions += list(deleted_disc)
+ data["deleted_discussions"] = logged_discussions
+
+ var/list/logged_orders = list()
+ for(var/datum/ares_record/requisition_log/req_order as anything in datacore.records_asrs)
+ if(!istype(req_order))
+ continue
+ var/list/current_order = list()
+ current_order["time"] = req_order.time
+ current_order["details"] = req_order.details
+ current_order["title"] = req_order.title
+ current_order["user"] = req_order.user
+ current_order["ref"] = "\ref[req_order]"
+ logged_orders += list(current_order)
+ data["records_requisition"] = logged_orders
+
+ var/list/logged_techs = list()
+ for(var/datum/ares_record/tech/tech_unlock as anything in datacore.records_tech)
+ var/list/current_tech = list()
+ current_tech["time"] = tech_unlock.time
+ current_tech["details"] = tech_unlock.details
+ current_tech["user"] = tech_unlock.user
+ current_tech["tier_changer"] = tech_unlock.is_tier
+ current_tech["ref"] = "\ref[tech_unlock]"
+ logged_techs += list(current_tech)
+ data["records_tech"] = logged_techs
+
+ var/list/logged_convos = list()
+ var/list/active_convo = list()
+ var/active_ref
+ for(var/datum/ares_record/talk_log/log as anything in datacore.records_talking)
+ if(!istype(log))
+ continue
+ if(log.user == link.interface.last_login)
+ active_convo = log.conversation
+ active_ref = "\ref[log]"
+
+ var/list/current_convo = list()
+ current_convo["user"] = log.user
+ current_convo["ref"] = "\ref[log]"
+ current_convo["conversation"] = log.conversation
+ logged_convos += list(current_convo)
+
+ data["active_convo"] = active_convo
+ data["active_ref"] = active_ref
+ data["conversations"] = logged_convos
+
+ var/list/logged_maintenance = list()
+ for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance)
+ if(!istype(maint_ticket))
+ continue
+ var/lock_status = TICKET_OPEN
+ switch(maint_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_maint = list()
+ current_maint["id"] = maint_ticket.ticket_id
+ current_maint["time"] = maint_ticket.ticket_time
+ current_maint["priority_status"] = maint_ticket.ticket_priority
+ current_maint["category"] = maint_ticket.ticket_name
+ current_maint["details"] = maint_ticket.ticket_details
+ current_maint["status"] = maint_ticket.ticket_status
+ current_maint["submitter"] = maint_ticket.ticket_submitter
+ current_maint["assignee"] = maint_ticket.ticket_assignee
+ current_maint["lock_status"] = lock_status
+ current_maint["ref"] = "\ref[maint_ticket]"
+ logged_maintenance += list(current_maint)
+ data["maintenance_tickets"] = logged_maintenance
+
+ var/list/logged_access = list()
+ var/list/requesting_access = list()
+ for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access)
+ var/lock_status = TICKET_OPEN
+ switch(access_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_ticket = list()
+ current_ticket["id"] = access_ticket.ticket_id
+ current_ticket["time"] = access_ticket.ticket_time
+ current_ticket["priority_status"] = access_ticket.ticket_priority
+ current_ticket["title"] = access_ticket.ticket_name
+ current_ticket["details"] = access_ticket.ticket_details
+ current_ticket["status"] = access_ticket.ticket_status
+ current_ticket["submitter"] = access_ticket.ticket_submitter
+ current_ticket["assignee"] = access_ticket.ticket_assignee
+ current_ticket["lock_status"] = lock_status
+ current_ticket["ref"] = "\ref[access_ticket]"
+ logged_access += list(current_ticket)
+
+ if(lock_status == TICKET_OPEN)
+ requesting_access += access_ticket.ticket_name
+ data["access_tickets"] = logged_access
+
+ data["notify_sounds"] = notify_sounds
+ data["security_vents"] = link.get_ares_vents()
+ data["sentry_setting"] = link.faction_label
+ data["faction_options"] = link.faction_options
+
+ return data
+
+
+
+/obj/item/device/ai_tech_pda/proc/get_apollo_access(obj/item/card/id/card)
+ if(ACCESS_ARES_DEBUG in card.access)
+ return APOLLO_ACCESS_DEBUG
+ switch(card.assignment)
+ if(JOB_WORKING_JOE)
+ return APOLLO_ACCESS_JOE
+ if(JOB_CHIEF_ENGINEER, JOB_SYNTH, JOB_CO)
+ return APOLLO_ACCESS_AUTHED
+ if(ACCESS_MARINE_AI in card.access)
+ return APOLLO_ACCESS_AUTHED
+ if(ACCESS_MARINE_AI_TEMP in card.access)
+ return APOLLO_ACCESS_TEMP
+ if((ACCESS_MARINE_SENIOR in card.access ) || (ACCESS_MARINE_ENGINEERING in card.access) || (ACCESS_WY_GENERAL in card.access))
+ return APOLLO_ACCESS_REPORTER
+ else
+ return APOLLO_ACCESS_REQUEST
+
+/obj/item/device/ai_tech_pda/proc/apollo_auth_to_text(access_level)
+ switch(access_level)
+ if(APOLLO_ACCESS_LOGOUT)//0
+ return "Logged Out"
+ if(APOLLO_ACCESS_REQUEST)//1
+ return "Unauthorized Personnel"
+ if(APOLLO_ACCESS_REPORTER)//2
+ return "Validated Incident Reporter"
+ if(APOLLO_ACCESS_TEMP)//3
+ return "Authorized Visitor"
+ if(APOLLO_ACCESS_AUTHED)//4
+ return "Certified Personnel"
+ if(APOLLO_ACCESS_JOE)//5
+ return "Working Joe"
+ if(APOLLO_ACCESS_DEBUG)//6
+ return "AI Service Technician"
+
+/obj/item/device/ai_tech_pda/proc/get_ares_access(obj/item/card/id/card)
+ if(ACCESS_ARES_DEBUG in card.access)
+ return ARES_ACCESS_DEBUG
+ switch(card.assignment)
+ if(JOB_WORKING_JOE)
+ return ARES_ACCESS_JOE
+ if(JOB_CHIEF_ENGINEER)
+ return ARES_ACCESS_CE
+ if(JOB_SYNTH)
+ return ARES_ACCESS_SYNTH
+ if(card.paygrade in GLOB.wy_highcom_paygrades)
+ return ARES_ACCESS_WY_COMMAND
+ if(card.paygrade in GLOB.uscm_highcom_paygrades)
+ return ARES_ACCESS_HIGH
+ if(card.paygrade in GLOB.co_paygrades)
+ return ARES_ACCESS_CO
+ if(ACCESS_MARINE_SENIOR in card.access)
+ return ARES_ACCESS_SENIOR
+ if(ACCESS_WY_GENERAL in card.access)
+ return ARES_ACCESS_CORPORATE
+ if(ACCESS_MARINE_COMMAND in card.access)
+ return ARES_ACCESS_COMMAND
+ else
+ return ARES_ACCESS_BASIC
+
+/obj/item/device/ai_tech_pda/proc/ares_auth_to_text(access_level)
+ switch(access_level)
+ if(ARES_ACCESS_LOGOUT)
+ return "Logged Out"
+ if(ARES_ACCESS_BASIC)
+ return "Authorized"
+ if(ARES_ACCESS_COMMAND)
+ return "[MAIN_SHIP_NAME] Command"
+ if(ARES_ACCESS_JOE)
+ return "Working Joe"
+ if(ARES_ACCESS_CORPORATE)
+ return "Weyland-Yutani"
+ if(ARES_ACCESS_SENIOR)
+ return "[MAIN_SHIP_NAME] Senior Command"
+ if(ARES_ACCESS_CE)
+ return "Chief Engineer"
+ if(ARES_ACCESS_SYNTH)
+ return "USCM Synthetic"
+ if(ARES_ACCESS_CO)
+ return "[MAIN_SHIP_NAME] Commanding Officer"
+ if(ARES_ACCESS_HIGH)
+ return "USCM High Command"
+ if(ARES_ACCESS_WY_COMMAND)
+ return "Weyland-Yutani Directorate"
+ if(ARES_ACCESS_DEBUG)
+ return "AI Service Technician"
diff --git a/code/game/machinery/ARES/debug_pda.dm b/code/game/machinery/ARES/debug_pda.dm
new file mode 100644
index 000000000000..7fc4319a1aaf
--- /dev/null
+++ b/code/game/machinery/ARES/debug_pda.dm
@@ -0,0 +1,988 @@
+/obj/item/device/ai_tech_pda
+ icon = 'icons/obj/items/synth/ait_pda.dmi'
+ name = "T411 AIDT"
+ desc = "Artifical Intelligence Diagnostic Tablet model T411. Built to withstand a nuclear bomb."
+ icon_state = "karnak_off"
+ unacidable = TRUE
+ indestructible = TRUE
+ req_access = list(ACCESS_ARES_DEBUG)
+
+ /// The ID used to link all devices.
+ var/datum/ares_link/link
+ /// The datacore storing all the information.
+ var/datum/ares_datacore/datacore
+
+ var/current_menu = "login"
+ var/last_menu = "off"
+
+ var/authentication = APOLLO_ACCESS_LOGOUT
+ /// The last person to login.
+ var/logged_in
+ /// A record of who logged in and when.
+ var/list/access_list = list()
+ var/list/deleted_1to1 = list()
+
+ /// Notification sound
+ var/notify_sounds = TRUE
+ COOLDOWN_DECLARE(printer_cooldown)
+ var/access_code = 0
+ var/set_ui = "AresAccessCode"
+
+/obj/item/device/ai_tech_pda/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
+ if(link && !override)
+ return FALSE
+ if(new_link)
+ new_link.ticket_computers += src
+ link = new_link
+ new_link.linked_systems += src
+ if(!datacore)
+ datacore = GLOB.ares_datacore
+ return TRUE
+
+/obj/item/device/ai_tech_pda/Initialize(mapload, ...)
+ link_systems(override = FALSE)
+ . = ..()
+
+/obj/item/device/ai_tech_pda/proc/delink()
+ if(link)
+ link.ticket_computers -= src
+ link.linked_systems -= src
+ link = null
+ datacore = null
+
+/obj/item/device/ai_tech_pda/verb/enter_code()
+ set name = "Enter Access Code"
+ set desc = "Enter an access code. Duh."
+ set category = "Object.AIDT"
+ set src in usr
+
+ if(access_code)
+ to_chat(usr, SPAN_WARNING("An access code has already been entered!"))
+ playsound(src, 'sound/machines/terminal_error.ogg', 15, TRUE)
+ return FALSE
+ var/mob/living/carbon/user = usr
+ playsound(src, 'sound/machines/terminal_prompt.ogg', 15, TRUE)
+ var/new_access_code = tgui_input_text(user, "Please enter a data access code.", "Access Code", "00000", 7, timeout = 20 SECONDS)
+ if(!new_access_code)
+ to_chat(usr, SPAN_WARNING("Error: No input detected!"))
+ playsound(src, 'sound/machines/terminal_error.ogg', 15, TRUE)
+ return FALSE
+ access_code = new_access_code
+ playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 15, TRUE)
+ to_chat(usr, SPAN_HELPFUL("New access code detected. Please reload your device."))
+
+/obj/item/device/ai_tech_pda/verb/clear_code()
+ set name = "Clear Access Code"
+ set desc = "Take a guess."
+ set category = "Object.AIDT"
+ set src in usr
+
+ var/mob/living/carbon/human/user
+ if(ishuman(usr))
+ user = usr
+ else
+ return FALSE
+
+ if(!access_code)
+ to_chat(user, SPAN_WARNING("You can't clear an already cleared code..."))
+ return FALSE
+
+ var/obj/item/card/id/card = user.wear_id
+ if(!card || !card.check_biometrics(user))
+ to_chat(user, SPAN_WARNING("You require an authenticated ID card to access this device!"))
+ playsound(src, 'sound/machines/terminal_error.ogg', 15, TRUE)
+ return FALSE
+ access_code = 0
+ last_menu = "off"
+ current_menu = "login"
+
+/obj/item/device/ai_tech_pda/Destroy()
+ delink()
+ return ..()
+
+/obj/item/device/ai_tech_pda/update_icon()
+ . = ..()
+ if(last_menu == "off")
+ icon_state = "karnak_off"
+ else if(current_menu == "login")
+ icon_state = "karnak_login_anim"
+ else
+ icon_state = "karnak_on_anim"
+
+/obj/item/device/ai_tech_pda/attack_self(mob/living/carbon/human/user)
+ if(..() || !allowed(user))
+ to_chat(user, SPAN_WARNING("Access Denied!"))
+ return FALSE
+
+ if((last_menu == "off") && (current_menu == "login"))
+ last_menu = "main"
+ update_icon()
+
+ tgui_interact(user)
+ return TRUE
+
+/obj/item/device/ai_tech_pda/tgui_interact(mob/user, datum/tgui/ui)
+ if(!link.interface || !datacore)
+ to_chat(user, SPAN_WARNING("ARES DATA LINK FAILED"))
+ return FALSE
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(access_code == GLOB.ares_link.code_apollo)
+ set_ui = "WorkingJoe"
+ else if(access_code == GLOB.ares_link.code_interface)
+ set_ui = "AresInterface"
+ else if(access_code == GLOB.ares_link.code_debug)
+ set_ui = "AresAdmin"
+ else
+ access_code = 0
+ set_ui = "AresAccessCode"
+ if(!ui)
+ ui = new(user, src, set_ui, name)
+ ui.open()
+
+/*
+/obj/item/device/ai_tech_pda/ui_data(mob/user)
+ if(!link.interface)
+ to_chat(user, SPAN_WARNING("ARES ADMIN DATA LINK FAILED"))
+ return FALSE
+ var/list/data = list()
+
+ data["is_pda"] = TRUE
+
+ data["admin_login"] = "[logged_in], AI Service Technician"
+ data["admin_access_log"] = access_list
+
+ data["current_menu"] = current_menu
+ data["last_page"] = last_menu
+
+ data["logged_in"] = link.interface.last_login
+ data["sudo"] = link.interface.sudo_holder ? TRUE : FALSE
+
+ data["access_text"] = "[link.interface.sudo_holder ? "(SUDO)," : ""] access level [link.interface.authentication], [link.interface.ares_auth_to_text(link.interface.authentication)]."
+ data["access_level"] = link.interface.authentication
+
+ data["alert_level"] = GLOB.security_level
+ data["evac_status"] = SShijack.evac_status
+ data["worldtime"] = world.time
+
+ data["access_log"] = datacore.interface_access_list
+ data["apollo_log"] = datacore.apollo_log
+
+ data["deleted_conversation"] = deleted_1to1
+
+ data["distresstime"] = datacore.ares_distress_cooldown
+ data["distresstimelock"] = DISTRESS_TIME_LOCK
+ data["mission_failed"] = SSticker.mode.is_in_endgame
+ data["nuketimelock"] = NUCLEAR_TIME_LOCK
+ data["nuke_available"] = datacore.nuke_available
+
+ var/list/logged_announcements = list()
+ for(var/datum/ares_record/announcement/broadcast as anything in datacore.records_announcement)
+ var/list/current_broadcast = list()
+ current_broadcast["time"] = broadcast.time
+ current_broadcast["title"] = broadcast.title
+ current_broadcast["details"] = broadcast.details
+ current_broadcast["ref"] = "\ref[broadcast]"
+ logged_announcements += list(current_broadcast)
+ data["records_announcement"] = logged_announcements
+
+ var/list/logged_alerts = list()
+ for(var/datum/ares_record/security/security_alert as anything in datacore.records_security)
+ var/list/current_alert = list()
+ current_alert["time"] = security_alert.time
+ current_alert["title"] = security_alert.title
+ current_alert["details"] = security_alert.details
+ current_alert["ref"] = "\ref[security_alert]"
+ logged_alerts += list(current_alert)
+ data["records_security"] = logged_alerts
+
+ var/list/logged_flights = list()
+ for(var/datum/ares_record/flight/flight_log as anything in datacore.records_flight)
+ var/list/current_flight = list()
+ current_flight["time"] = flight_log.time
+ current_flight["title"] = flight_log.title
+ current_flight["details"] = flight_log.details
+ current_flight["user"] = flight_log.user
+ current_flight["ref"] = "\ref[flight_log]"
+ logged_flights += list(current_flight)
+ data["records_flight"] = logged_flights
+
+ var/list/logged_bioscans = list()
+ for(var/datum/ares_record/bioscan/scan as anything in datacore.records_bioscan)
+ var/list/current_scan = list()
+ current_scan["time"] = scan.time
+ current_scan["title"] = scan.title
+ current_scan["details"] = scan.details
+ current_scan["ref"] = "\ref[scan]"
+ logged_bioscans += list(current_scan)
+ data["records_bioscan"] = logged_bioscans
+
+ var/list/logged_bombs = list()
+ for(var/datum/ares_record/bombardment/bomb as anything in datacore.records_bombardment)
+ var/list/current_bomb = list()
+ current_bomb["time"] = bomb.time
+ current_bomb["title"] = bomb.title
+ current_bomb["details"] = bomb.details
+ current_bomb["user"] = bomb.user
+ current_bomb["ref"] = "\ref[bomb]"
+ logged_bombs += list(current_bomb)
+ data["records_bombardment"] = logged_bombs
+
+ var/list/logged_deletes = list()
+ for(var/datum/ares_record/deletion/deleted as anything in datacore.records_deletion)
+ if(!istype(deleted))
+ continue
+ var/list/current_delete = list()
+ current_delete["time"] = deleted.time
+ current_delete["title"] = deleted.title
+ current_delete["details"] = deleted.details
+ current_delete["user"] = deleted.user
+ current_delete["ref"] = "\ref[deleted]"
+ logged_deletes += list(current_delete)
+ data["records_deletion"] = logged_deletes
+
+ var/list/logged_discussions = list()
+ for(var/datum/ares_record/deleted_talk/deleted_convo as anything in datacore.records_deletion)
+ if(!istype(deleted_convo))
+ continue
+ var/list/deleted_disc = list()
+ deleted_disc["time"] = deleted_convo.time
+ deleted_disc["title"] = deleted_convo.title
+ deleted_disc["ref"] = "\ref[deleted_convo]"
+ logged_discussions += list(deleted_disc)
+ data["deleted_discussions"] = logged_discussions
+
+ var/list/logged_orders = list()
+ for(var/datum/ares_record/requisition_log/req_order as anything in datacore.records_asrs)
+ if(!istype(req_order))
+ continue
+ var/list/current_order = list()
+ current_order["time"] = req_order.time
+ current_order["details"] = req_order.details
+ current_order["title"] = req_order.title
+ current_order["user"] = req_order.user
+ current_order["ref"] = "\ref[req_order]"
+ logged_orders += list(current_order)
+ data["records_requisition"] = logged_orders
+
+ var/list/logged_techs = list()
+ for(var/datum/ares_record/tech/tech_unlock as anything in datacore.records_tech)
+ var/list/current_tech = list()
+ current_tech["time"] = tech_unlock.time
+ current_tech["details"] = tech_unlock.details
+ current_tech["user"] = tech_unlock.user
+ current_tech["tier_changer"] = tech_unlock.is_tier
+ current_tech["ref"] = "\ref[tech_unlock]"
+ logged_techs += list(current_tech)
+ data["records_tech"] = logged_techs
+
+ var/list/logged_convos = list()
+ var/list/active_convo = list()
+ var/active_ref
+ for(var/datum/ares_record/talk_log/log as anything in datacore.records_talking)
+ if(!istype(log))
+ continue
+ if(log.user == link.interface.last_login)
+ active_convo = log.conversation
+ active_ref = "\ref[log]"
+
+ var/list/current_convo = list()
+ current_convo["user"] = log.user
+ current_convo["ref"] = "\ref[log]"
+ current_convo["conversation"] = log.conversation
+ logged_convos += list(current_convo)
+
+ data["active_convo"] = active_convo
+ data["active_ref"] = active_ref
+ data["conversations"] = logged_convos
+
+ var/list/logged_maintenance = list()
+ for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance)
+ if(!istype(maint_ticket))
+ continue
+ var/lock_status = TICKET_OPEN
+ switch(maint_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_maint = list()
+ current_maint["id"] = maint_ticket.ticket_id
+ current_maint["time"] = maint_ticket.ticket_time
+ current_maint["priority_status"] = maint_ticket.ticket_priority
+ current_maint["category"] = maint_ticket.ticket_name
+ current_maint["details"] = maint_ticket.ticket_details
+ current_maint["status"] = maint_ticket.ticket_status
+ current_maint["submitter"] = maint_ticket.ticket_submitter
+ current_maint["assignee"] = maint_ticket.ticket_assignee
+ current_maint["lock_status"] = lock_status
+ current_maint["ref"] = "\ref[maint_ticket]"
+ logged_maintenance += list(current_maint)
+ data["maintenance_tickets"] = logged_maintenance
+
+ var/list/logged_access = list()
+ for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access)
+ var/lock_status = TICKET_OPEN
+ switch(access_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_ticket = list()
+ current_ticket["id"] = access_ticket.ticket_id
+ current_ticket["time"] = access_ticket.ticket_time
+ current_ticket["priority_status"] = access_ticket.ticket_priority
+ current_ticket["title"] = access_ticket.ticket_name
+ current_ticket["details"] = access_ticket.ticket_details
+ current_ticket["status"] = access_ticket.ticket_status
+ current_ticket["submitter"] = access_ticket.ticket_submitter
+ current_ticket["assignee"] = access_ticket.ticket_assignee
+ current_ticket["lock_status"] = lock_status
+ current_ticket["ref"] = "\ref[access_ticket]"
+ logged_access += list(current_ticket)
+ data["access_tickets"] = logged_access
+
+ data["security_vents"] = link.get_ares_vents()
+ data["sentry_setting"] = link.faction_label
+ data["faction_options"] = link.faction_options
+
+ return data
+*/
+
+/obj/item/device/ai_tech_pda/ui_close(mob/user)
+ . = ..()
+ if(set_ui == "AresAdmin")
+ access_list += "[logged_in] logged out at [worldtime2text()]."
+ logged_in = null
+ authentication = 0
+ current_menu = "login"
+ last_menu = "off"
+ update_icon()
+
+/obj/item/device/ai_tech_pda/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/user = ui.user
+ var/playsound = TRUE
+
+ if(set_ui == "AresAdmin" && !check_security(user))
+ return FALSE
+
+ switch(action)
+ if("go_back")
+ if(!last_menu)
+ return to_chat(user, SPAN_WARNING("Error, no previous page detected."))
+ var/temp_holder = current_menu
+ current_menu = last_menu
+ last_menu = temp_holder
+
+ if("login")
+ var/failed = FALSE
+ var/obj/item/card/id/idcard = user.get_active_hand()
+ if(!istype(idcard))
+ if(user.wear_id)
+ idcard = user.wear_id
+ if(!istype(idcard))
+ failed = TRUE
+ if(!idcard.check_biometrics(user))
+ failed = TRUE
+ if(failed)
+ to_chat(user, SPAN_WARNING("You require an authenticated ID card to access this device!"))
+ playsound(src, 'sound/machines/terminal_error.ogg', 15, TRUE)
+ return FALSE
+
+ switch(set_ui)
+ if("AresInterface", "AresAdmin")
+ authentication = get_ares_access(idcard)
+ if("WorkingJoe")
+ authentication = get_apollo_access(idcard)
+
+ if(authentication)
+ logged_in = idcard.registered_name
+ access_list += "[logged_in] at [worldtime2text()]."
+ current_menu = "main"
+
+ if("sudo")
+ if(!check_security(user) || set_ui == "AresAdmin")
+ return FALSE
+ var/new_user = tgui_input_text(user, "Enter Sudo Username", "Sudo User", encode = FALSE)
+ if(new_user)
+ if(new_user == link.interface.sudo_holder)
+ link.interface.last_login = link.interface.sudo_holder
+ link.interface.sudo_holder = null
+ return FALSE
+ if(new_user == link.interface.last_login)
+ to_chat(user, SPAN_WARNING("Already remote logged in as this user."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ link.interface.sudo_holder = link.interface.last_login
+ link.interface.last_login = new_user
+ datacore.interface_access_list += "[link.interface.last_login] at [worldtime2text()], Sudo Access."
+ return TRUE
+ if("sudo_logout")
+ if(!check_security(user))
+ return FALSE
+ datacore.interface_access_list += "[link.interface.last_login] at [worldtime2text()], Sudo Logout."
+ link.interface.last_login = link.interface.sudo_holder
+ link.interface.sudo_holder = null
+ return
+
+ // -- Page Changers -- //
+ if("logout")
+ current_menu = "login"
+ last_menu = "login"
+ access_list += "[logged_in] logged out at [worldtime2text()]."
+ logged_in = null
+
+ if("home")
+ last_menu = current_menu
+ current_menu = "main"
+ if("page_1to1")
+ last_menu = current_menu
+ current_menu = "talking"
+ if("page_announcements")
+ last_menu = current_menu
+ current_menu = "announcements"
+ if("page_bioscans")
+ last_menu = current_menu
+ current_menu = "bioscans"
+ if("page_bombardments")
+ last_menu = current_menu
+ current_menu = "bombardments"
+ if("page_apollo")
+ last_menu = current_menu
+ current_menu = "apollo"
+ if("page_access")
+ last_menu = current_menu
+ current_menu = "access_log"
+ if("page_admin_list")
+ last_menu = current_menu
+ current_menu = "admin_access_log"
+ if("page_security")
+ last_menu = current_menu
+ current_menu = "security"
+ if("page_requisitions")
+ last_menu = current_menu
+ current_menu = "requisitions"
+ if("page_flight")
+ last_menu = current_menu
+ current_menu = "flight_log"
+ if("page_emergency")
+ last_menu = current_menu
+ current_menu = "emergency"
+ if("page_deleted")
+ last_menu = current_menu
+ current_menu = "delete_log"
+ if("page_deleted_1to1")
+ last_menu = current_menu
+ current_menu = "deleted_talks"
+ if("page_tech")
+ last_menu = current_menu
+ current_menu = "tech_log"
+ if("page_core_sec")
+ last_menu = current_menu
+ current_menu = "core_security"
+ if("page_access_management")
+ last_menu = current_menu
+ current_menu = "access_management"
+ if("page_maint_management")
+ last_menu = current_menu
+ current_menu = "maintenance_management"
+
+ // -- 1:1 Conversation -- //
+ if("new_conversation")
+ if(link.interface.last_login == "No User")
+ return FALSE
+ var/datum/ares_record/talk_log/convo = new(link.interface.last_login)
+ convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [link.interface.last_login].'"
+ datacore.records_talking += convo
+
+ if("clear_conversation")
+ var/datum/ares_record/talk_log/conversation = locate(params["active_convo"])
+ if(!istype(conversation))
+ return FALSE
+ var/datum/ares_record/deleted_talk/deleted = new
+ deleted.title = conversation.title
+ deleted.conversation = conversation.conversation
+ deleted.user = MAIN_AI_SYSTEM
+ datacore.records_deletion += deleted
+ datacore.records_talking -= conversation
+
+ if("fake_message_ares")
+ if(!check_security(user))
+ return FALSE
+ var/message = tgui_input_text(user, "What do you wish to say to ARES?", "ARES Message", encode = FALSE)
+ if(message)
+ link.interface.message_ares(message, user, params["active_convo"], TRUE)
+ if("ares_reply")
+ if(!check_security(user))
+ return FALSE
+ var/message = tgui_input_text(user, "What do you wish to reply with?", "ARES Response", encode = FALSE)
+ if(message)
+ link.interface.response_from_ares(message, params["active_convo"])
+ var/datum/ares_record/talk_log/conversation = locate(params["active_convo"])
+ var/admin_log = SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[key_name(user)] replied to [conversation.user]'s ARES message")] [SPAN_GREEN("via [src]")] with: [SPAN_BLUE(message)] ")
+ for(var/client/admin in GLOB.admins)
+ if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
+ to_chat(admin, admin_log)
+
+ if("read_record")
+ var/datum/ares_record/deleted_talk/conversation = locate(params["record"])
+ deleted_1to1 = conversation.conversation
+ last_menu = current_menu
+ current_menu = "read_deleted"
+
+ if("claim_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ var/claim = TRUE
+ var/assigned = ticket.ticket_assignee
+ if(assigned)
+ if(assigned == logged_in)
+ var/prompt = tgui_alert(user, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No"))
+ if(prompt != "Yes")
+ return FALSE
+ /// set ticket back to pending
+ ticket.ticket_assignee = null
+ ticket.ticket_status = TICKET_PENDING
+ return claim
+ var/choice = tgui_alert(user, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No"))
+ if(choice != "Yes")
+ claim = FALSE
+ if(claim)
+ ticket.ticket_assignee = logged_in
+ ticket.ticket_status = TICKET_ASSIGNED
+ return claim
+
+ if("auth_access")
+ if(!check_security(user))
+ return FALSE
+ playsound = FALSE
+ var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
+ if(!access_ticket)
+ return FALSE
+ for(var/obj/item/card/id/identification in link.waiting_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+ identification.handle_ares_access(logged_in, user)
+ access_ticket.ticket_status = TICKET_GRANTED
+ playsound(src, 'sound/machines/chime.ogg', 15, TRUE)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] granted core access.")
+ return TRUE
+ for(var/obj/item/card/id/identification in link.active_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+ identification.handle_ares_access(logged_in, user)
+ access_ticket.ticket_status = TICKET_REVOKED
+ playsound(src, 'sound/machines/chime.ogg', 15, TRUE)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: core access for [access_ticket.ticket_submitter] revoked.")
+ return TRUE
+ return FALSE
+
+ if("reject_access")
+ var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
+ if(!istype(access_ticket))
+ return FALSE
+ access_ticket.ticket_status = TICKET_REJECTED
+ to_chat(user, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected."))
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id] rejected.")
+ return TRUE
+
+ if("new_report")
+ var/priority_report = FALSE
+ var/maint_type = tgui_input_list(user, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS)
+ switch(maint_type)
+ if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure")
+ priority_report = TRUE
+
+ if(!maint_type)
+ return FALSE
+ var/details = tgui_input_text(user, "What are the details for this report?", "Ticket Details", encode = FALSE)
+ if(!details)
+ return FALSE
+
+ if(!priority_report)
+ var/is_priority = tgui_alert(user, "Is this a priority report?", "Priority designation", list("Yes", "No"))
+ if(is_priority == "Yes")
+ priority_report = TRUE
+
+ var/confirm = alert(user, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No")
+ if(confirm == "Yes")
+ var/datum/ares_ticket/maintenance/maint_ticket = new("[logged_in] (AIST)", maint_type, details, priority_report)
+ link.tickets_maintenance += maint_ticket
+ if(priority_report)
+ ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.")
+ log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(user)] as AI-ST with Category '[maint_type]' and Details of '[details]'.")
+ return TRUE
+ return FALSE
+
+ if("cancel_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ to_chat(user, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled."))
+ ticket.ticket_status = TICKET_CANCELLED
+ if(ticket.ticket_priority)
+ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.")
+ return TRUE
+
+ if("mark_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ var/options_list = list(TICKET_COMPLETED, TICKET_REJECTED)
+ if(ticket.ticket_priority)
+ options_list += TICKET_NON_PRIORITY
+ else
+ options_list += TICKET_PRIORITY
+ var/choice = tgui_alert(user, "What do you wish to mark the ticket as?", "Mark", options_list, 20 SECONDS)
+ switch(choice)
+ if(TICKET_PRIORITY)
+ ticket.ticket_priority = TRUE
+ ares_apollo_talk("[ticket.ticket_type] [ticket.ticket_id] upgraded to Priority.")
+ return TRUE
+ if(TICKET_NON_PRIORITY)
+ ticket.ticket_priority = FALSE
+ ares_apollo_talk("[ticket.ticket_type] [ticket.ticket_id] downgraded from Priority.")
+ return TRUE
+ if(TICKET_COMPLETED)
+ ticket.ticket_status = TICKET_COMPLETED
+ if(TICKET_REJECTED)
+ ticket.ticket_status = TICKET_REJECTED
+ else
+ return FALSE
+ if(ticket.ticket_priority)
+ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by AI-ST [logged_in].")
+ to_chat(user, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice]."))
+ return TRUE
+
+ if("delete_record")
+ if(!check_security(user))
+ return FALSE
+ playsound = FALSE
+ var/datum/ares_record/record = locate(params["record"])
+ if(record.record_name == ARES_RECORD_DELETED)
+ return FALSE
+ var/datum/ares_record/deletion/new_delete = new
+ var/new_details = "Error"
+ var/new_title = "Error"
+ switch(record.record_name)
+ if(ARES_RECORD_ANNOUNCE)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_announcement -= record
+ if(ARES_RECORD_SECURITY, ARES_RECORD_ANTIAIR)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_security -= record
+ if(ARES_RECORD_BIOSCAN)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_bioscan -= record
+ if(ARES_RECORD_BOMB)
+ new_title = "[record.title] at [record.time]"
+ new_details = "[record.details] Launched by [record.user]."
+ datacore.records_bombardment -= record
+ if(ARES_RECORD_TECH)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_tech -= record
+ if(ARES_RECORD_FLIGHT)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_flight -= record
+
+ new_delete.details = new_details
+ new_delete.user = "[logged_in] (AIST)"
+ new_delete.title = new_title
+
+ datacore.records_deletion += new_delete
+ playsound(src, 'sound/machines/terminal_error.ogg', 15, TRUE)
+
+ if("general_quarters")
+ if(!check_security(user))
+ return FALSE
+ if(!COOLDOWN_FINISHED(datacore, ares_quarters_cooldown))
+ to_chat(user, SPAN_WARNING("It has not been long enough since the last General Quarters call!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level < SEC_LEVEL_RED)
+ set_security_level(SEC_LEVEL_RED, no_sound = TRUE, announce = FALSE)
+ shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg')
+ log_game("[key_name(user)] has called for general quarters via ARES.")
+ message_admins("[key_name_admin(user)] has called for general quarters via ARES.")
+ log_ares_security("General Quarters", "[logged_in] has called for general quarters via ARES.")
+ COOLDOWN_START(datacore, ares_quarters_cooldown, 10 MINUTES)
+ . = TRUE
+
+ if("evacuation_start")
+ if(!check_security(user))
+ return FALSE
+ if(GLOB.security_level < SEC_LEVEL_RED)
+ to_chat(user, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ if(SShijack.evac_admin_denied)
+ to_chat(user, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ if(!SShijack.initiate_evacuation())
+ to_chat(user, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ log_game("[key_name(user)] has called for an emergency evacuation via ARES.")
+ message_admins("[key_name_admin(user)] has called for an emergency evacuation via ARES.")
+ log_ares_security("Initiate Evacuation", "[logged_in] has called for an emergency evacuation via ARES.")
+ . = TRUE
+
+ if("distress")
+ if(!check_security(user))
+ return FALSE
+ if(!SSticker.mode)
+ return FALSE //Not a game mode?
+ if(world.time < DISTRESS_TIME_LOCK)
+ to_chat(user, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(datacore, ares_distress_cooldown))
+ to_chat(user, SPAN_WARNING("The distress launcher is cooling down!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level == SEC_LEVEL_DELTA)
+ to_chat(user, SPAN_WARNING("The ship is already undergoing self destruct procedures!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level < SEC_LEVEL_RED)
+ to_chat(user, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ for(var/client/admin in GLOB.admins)
+ if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
+ playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
+ SSticker.mode.request_ert(user, TRUE)
+ to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command."))
+ COOLDOWN_START(datacore, ares_distress_cooldown, COOLDOWN_COMM_REQUEST)
+ return TRUE
+
+ if("nuclearbomb")
+ if(!check_security(user))
+ return FALSE
+ if(!SSticker.mode)
+ return FALSE //Not a game mode?
+ if(world.time < NUCLEAR_TIME_LOCK)
+ to_chat(user, SPAN_WARNING("It is too soon to request Nuclear Ordnance!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(datacore, ares_nuclear_cooldown))
+ to_chat(user, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame)
+ to_chat(user, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ var/reason = tgui_input_text(user, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance")
+ if(!reason)
+ return FALSE
+ for(var/client/admin in GLOB.admins)
+ if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
+ playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
+ message_admins("[key_name(user)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(user)] (APPROVE) (DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]")
+ to_chat(user, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]"))
+ log_ares_security("Nuclear Ordnance Request", "[logged_in] has sent a request for nuclear ordnance for the following reason: [reason]")
+ if(ares_can_interface())
+ ai_silent_announcement("[logged_in] has sent a request for nuclear ordnance to USCM High Command.", ".V")
+ ai_silent_announcement("Reason given: [reason].", ".V")
+ COOLDOWN_START(datacore, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT)
+ return TRUE
+
+ if("bioscan")
+ if(!check_security(user))
+ return FALSE
+ if(!SSticker.mode)
+ return FALSE //Not a game mode?
+ if(world.time < FORCE_SCAN_LOCK)
+ to_chat(user, SPAN_WARNING("Bio sensors are not yet ready to initiate a scan!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!(COOLDOWN_FINISHED(datacore, ares_bioscan_cooldown)) || (world.time < (GLOB.last_human_bioscan + COOLDOWN_FORCE_SCAN)))
+ to_chat(user, SPAN_WARNING("It is too soon since the last scan, wait for the sensor array to reset!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ GLOB.bioscan_data.ares_bioscan(FALSE, 2)
+ COOLDOWN_START(datacore, ares_bioscan_cooldown, COOLDOWN_FORCE_SCAN)
+ playsound(src, 'sound/machines/terminal_processing.ogg', 15, 1)
+ message_admins("BIOSCAN: [key_name(user)] triggered a Marine bioscan via ARES AIST.")
+ return TRUE
+
+ if("trigger_vent")
+ if(!check_security(user))
+ return FALSE
+ playsound = FALSE
+ var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"])
+ if(!istype(sec_vent) || sec_vent.welded)
+ to_chat(user, SPAN_WARNING("ERROR: Gas release failure."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown))
+ to_chat(user, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ to_chat(user, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag]."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT)
+ ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].")
+ log_ares_security("Nerve Gas Release", "[MAIN_AI_SYSTEM] released Nerve Gas from Vent '[sec_vent.vent_tag]'.")
+ sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS)
+ log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.")
+
+ if("security_lockdown")
+ if(!check_security(user))
+ return FALSE
+ if(!COOLDOWN_FINISHED(datacore, aicore_lockdown))
+ to_chat(user, SPAN_BOLDWARNING("AI Core Lockdown procedures are on cooldown! They will be ready in [COOLDOWN_SECONDSLEFT(datacore, aicore_lockdown)] seconds!"))
+ return FALSE
+ aicore_lockdown(user)
+ return TRUE
+
+ if("update_sentries")
+ if(!check_security(user))
+ return FALSE
+ playsound = FALSE
+ var/new_iff = params["chosen_iff"]
+ if(!new_iff)
+ to_chat(user, SPAN_WARNING("ERROR: Unknown setting."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(new_iff == link.faction_label)
+ return FALSE
+ link.change_iff(new_iff)
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ message_admins("ARES: [key_name(user)] updated ARES Sentry IFF to [new_iff].")
+ to_chat(user, SPAN_WARNING("Sentry IFF settings updated!"))
+ return TRUE
+
+ if("print_req")
+ playsound = FALSE
+ if(!COOLDOWN_FINISHED(src, printer_cooldown))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!length(datacore.records_asrs))
+ to_chat(user, SPAN_WARNING("There are no records to print!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ COOLDOWN_START(src, printer_cooldown, 20 SECONDS)
+ playsound(src, 'sound/machines/fax.ogg', 15, 1)
+ sleep(3.4 SECONDS)
+ var/contents = {"
+
A.S.R.S.
\ +Automatic Storage Retrieval System
\ +Audit Log
\ +Time | +User | +Source | +Order | +
---|---|---|---|
[req_order.time] | +[req_order.user] | +[req_order.title] | +[req_order.details] | +