diff --git a/code/__DEFINES/ARES.dm b/code/__DEFINES/ARES.dm index a1b82af25821..5487c908976c 100644 --- a/code/__DEFINES/ARES.dm +++ b/code/__DEFINES/ARES.dm @@ -1,21 +1,22 @@ +#define ARES_ACCESS_LOGOUT 0 /// Generic access for 1:1 conversations with ARES and unrestricted commands. -#define ARES_ACCESS_BASIC 0 +#define ARES_ACCESS_BASIC 1 /// Secure Access, can read ARES Announcements and Bioscans. -#define ARES_ACCESS_COMMAND 1 -#define ARES_ACCESS_JOE 2 +#define ARES_ACCESS_COMMAND 2 +#define ARES_ACCESS_JOE 3 /// CL, can read Apollo Log and also Delete Announcements. -#define ARES_ACCESS_CORPORATE 3 +#define ARES_ACCESS_CORPORATE 4 /// Senior Command, can Delete Bioscans. -#define ARES_ACCESS_SENIOR 4 +#define ARES_ACCESS_SENIOR 5 /// Synth, CE & Commanding Officer, can read the access log. -#define ARES_ACCESS_CE 5 -#define ARES_ACCESS_SYNTH 6 -#define ARES_ACCESS_CO 7 +#define ARES_ACCESS_CE 6 +#define ARES_ACCESS_SYNTH 7 +#define ARES_ACCESS_CO 8 /// High Command, can read the deletion log. -#define ARES_ACCESS_HIGH 8 -#define ARES_ACCESS_WY_COMMAND 9 +#define ARES_ACCESS_HIGH 9 +#define ARES_ACCESS_WY_COMMAND 10 /// Debugging. Allows me to view everything without using a high command rank. Unlikely to stay in a full merge. -#define ARES_ACCESS_DEBUG 10 +#define ARES_ACCESS_DEBUG 11 #define ARES_RECORD_ANNOUNCE "Announcement Record" #define ARES_RECORD_ANTIAIR "AntiAir Control Log" @@ -27,6 +28,7 @@ #define ARES_RECORD_MAINTENANCE "Maintenance Ticket" #define ARES_RECORD_ACCESS "Access Ticket" #define ARES_RECORD_FLIGHT "Flight Record" +#define ARES_RECORD_TECH "Tech Control Record" /// Not by ARES logged through marine_announcement() #define ARES_LOG_NONE 0 @@ -67,6 +69,13 @@ #define TICKET_OPEN "OPEN" #define TICKET_CLOSED "CLOSED" +// Priority status changes. +/// Upgraded to Priority +#define TICKET_PRIORITY "priority" +/// Downgraded from Priority +#define TICKET_NON_PRIORITY "non-priority" + /// Cooldowns #define COOLDOWN_ARES_SENSOR 60 SECONDS #define COOLDOWN_ARES_ACCESS_CONTROL 20 SECONDS +#define COOLDOWN_ARES_VENT 60 SECONDS diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm index ad3b9fe3af32..7fdded9017a2 100644 --- a/code/__DEFINES/job.dm +++ b/code/__DEFINES/job.dm @@ -121,6 +121,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/mode.dm b/code/__DEFINES/mode.dm index ef3dfb03b337..7dc47c90738b 100644 --- a/code/__DEFINES/mode.dm +++ b/code/__DEFINES/mode.dm @@ -106,6 +106,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. @@ -117,7 +118,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_PILOT, JOB_DROPSHIP_CREW_CHIEF, 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)) diff --git a/code/controllers/subsystem/objectives_controller.dm b/code/controllers/subsystem/objectives_controller.dm index a858dff07475..38accda46004 100644 --- a/code/controllers/subsystem/objectives_controller.dm +++ b/code/controllers/subsystem/objectives_controller.dm @@ -96,6 +96,7 @@ SUBSYSTEM_DEF(objectives) ai_silent_announcement(message, ":v", TRUE) ai_silent_announcement(message, ":t", TRUE) + log_ares_tech(MAIN_AI_SYSTEM, FALSE, "TECH REPORT", "[round(tree.points, 0.1)] points available.", 0) tree.total_points_last_sitrep = tree.total_points next_sitrep = world.time + SITREP_INTERVAL diff --git a/code/datums/factions/uscm.dm b/code/datums/factions/uscm.dm index 0a9b0cff40b9..38b65725dfbe 100644 --- a/code/datums/factions/uscm.dm +++ b/code/datums/factions/uscm.dm @@ -153,7 +153,7 @@ // Whiskey Outpost if(JOB_WO_CO) marine_rk = "wo_co" - if(JOB_WO_XO) + if(JOB_WO_XO, JOB_AI_TECH) marine_rk = "wo_xo" if(JOB_WO_CHIEF_POLICE) marine_rk = "hgsl" diff --git a/code/game/jobs/job/special/uscm.dm b/code/game/jobs/job/special/uscm.dm index 2308c5af2961..dec47056aefa 100644 --- a/code/game/jobs/job/special/uscm.dm +++ b/code/game/jobs/job/special/uscm.dm @@ -12,3 +12,21 @@ title = JOB_RIOT /datum/job/special/uscm/riot/chief title = JOB_RIOT_CHIEF + +/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|ROLE_HIDDEN + 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 visiting AI Service Technician aboard 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 a high-ranking 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." + return ..() diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm index aa1cd92547ec..66f522c7f3b0 100644 --- a/code/game/machinery/ARES/ARES_interface.dm +++ b/code/game/machinery/ARES/ARES_interface.dm @@ -9,10 +9,10 @@ var/current_menu = "login" var/last_menu = "" - var/authentication = ARES_ACCESS_BASIC + var/authentication = ARES_ACCESS_LOGOUT /// The last person to login. - var/last_login + var/last_login = "No User" /// The person pretending to be last_login var/sudo_holder @@ -183,6 +183,17 @@ 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 @@ -203,6 +214,25 @@ data["active_ref"] = active_ref data["conversations"] = logged_convos + var/list/security_vents = list() + for(var/obj/structure/pipes/vents/pump/no_boom/gas/vent in link.linked_vents) + if(!istype(vent)) + continue + if(!vent.vent_tag) + vent.vent_tag = "Security Vent #[link.tag_num]" + link.tag_num++ + + var/list/current_vent = list() + var/is_available = TRUE + if(!COOLDOWN_FINISHED(vent, vent_trigger_cooldown)) + is_available = FALSE + current_vent["vent_tag"] = vent.vent_tag + current_vent["ref"] = "\ref[vent]" + current_vent["available"] = is_available + security_vents += list(current_vent) + + data["security_vents"] = security_vents + return data /obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state) @@ -216,19 +246,19 @@ . = ..() if(.) return - - playsound(src, "keyboard_alt", 15, 1) + var/mob/user = usr + var/playsound = TRUE switch (action) if("go_back") if(!last_menu) - return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + 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/mob/living/carbon/human/operator = usr + var/mob/living/carbon/human/operator = user var/obj/item/card/id/idcard = operator.get_active_hand() if(istype(idcard)) authentication = get_ares_access(idcard) @@ -239,7 +269,7 @@ authentication = get_ares_access(idcard) last_login = idcard.registered_name else - to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!")) + to_chat(user, SPAN_WARNING("You require an ID card to access this terminal!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(authentication) @@ -247,14 +277,14 @@ current_menu = "main" if("sudo") - var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE) + var/new_user = tgui_input_text(user, "Enter Sudo Username", "Sudo User", encode = FALSE) if(new_user) if(new_user == sudo_holder) last_login = sudo_holder sudo_holder = null return FALSE if(new_user == last_login) - to_chat(usr, SPAN_WARNING("Already remote logged in as this user.")) + to_chat(user, SPAN_WARNING("Already remote logged in as this user.")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE sudo_holder = last_login @@ -275,6 +305,8 @@ last_login = sudo_holder sudo_holder = null datacore.interface_access_list += "[last_login] logged out at [worldtime2text()]." + last_login = "No User" + authentication = ARES_ACCESS_LOGOUT if("home") last_menu = current_menu @@ -315,10 +347,18 @@ 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" // -- Delete Button -- // if("delete_record") var/datum/ares_record/record = locate(params["record"]) + if(!istype(record)) + return FALSE if(record.record_name == ARES_RECORD_DELETED) return FALSE var/datum/ares_record/deletion/new_delete = new @@ -366,12 +406,14 @@ datacore.records_talking -= conversation if("message_ares") - var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) + var/message = tgui_input_text(user, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) if(message) - message_ares(message, usr, params["active_convo"]) + message_ares(message, user, params["active_convo"]) if("read_record") var/datum/ares_record/deleted_talk/conversation = locate(params["record"]) + if(!istype(conversation)) + return FALSE deleted_1to1 = conversation.conversation last_menu = current_menu current_menu = "read_deleted" @@ -379,36 +421,36 @@ // -- Emergency Buttons -- // if("general_quarters") if(!COOLDOWN_FINISHED(datacore, ares_quarters_cooldown)) - to_chat(usr, SPAN_WARNING("It has not been long enough since the last General Quarters call!")) + 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(usr)] has called for general quarters via ARES.") - message_admins("[key_name_admin(usr)] has called for general quarters via ARES.") + 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", "[last_login] has called for general quarters via ARES.") COOLDOWN_START(datacore, ares_quarters_cooldown, 10 MINUTES) . = TRUE if("evacuation_start") if(GLOB.security_level < SEC_LEVEL_RED) - to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) + 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(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) + 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(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) + 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(usr)] has called for an emergency evacuation via ARES.") - message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.") + 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", "[last_login] has called for an emergency evacuation via ARES.") . = TRUE @@ -416,27 +458,27 @@ if(!SSticker.mode) return FALSE //Not a game mode? if(world.time < DISTRESS_TIME_LOCK) - to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!")) + 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(usr, SPAN_WARNING("The distress launcher is cooling down!")) + 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(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!")) + 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(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!")) + 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(usr, TRUE) - to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command.")) + 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 @@ -444,28 +486,50 @@ if(!SSticker.mode) return FALSE //Not a game mode? if(world.time < NUCLEAR_TIME_LOCK) - to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!")) + 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(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!")) + 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(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!")) + 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(usr, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance") + 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(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") - to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]")) + 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", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]") if(ares_can_interface()) ai_silent_announcement("[last_login] 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("trigger_vent") + 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", "[last_login] 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(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 new file mode 100644 index 000000000000..37b48ca4fda5 --- /dev/null +++ b/code/game/machinery/ARES/ARES_interface_admin.dm @@ -0,0 +1,481 @@ +/client/proc/cmd_admin_open_ares() + set name = "Open ARES Interface" + set category = "Admin.Factions" + + var/mob/user = usr + if(!check_rights(R_MOD)) + to_chat(user, SPAN_WARNING("You do not have access to this command.")) + return FALSE + + if(!SSticker.mode) + to_chat(user, SPAN_WARNING("The round has not started yet.")) + return FALSE + + if(!GLOB.ares_link || !GLOB.ares_link.admin_interface || !GLOB.ares_link.interface) + to_chat(usr, SPAN_BOLDWARNING("ERROR: ARES Link or Interface not found!")) + return FALSE + GLOB.ares_link.tgui_interact(user) + var/log = "[key_name(user)] opened the remote ARES Interface." + if(user.job) + log = "[key_name(user)] ([user.job]) opened the remote ARES Interface." + log_admin(log) + +/datum/ares_console_admin + var/current_menu = "login" + var/last_menu = "" + + var/authentication = ARES_ACCESS_BASIC + + /// The last admin to login. + var/last_login + /// The currently logged in admin. + var/logged_in + /// A record of who logged in and when. + var/list/access_list = list() + var/list/deleted_1to1 = list() + + +/datum/ares_link/tgui_interact(mob/user, datum/tgui/ui) + if(!interface || !admin_interface) + to_chat(user, SPAN_WARNING("ARES ADMIN DATA LINK FAILED")) + return FALSE + ui = SStgui.try_update_ui(user, GLOB.ares_link, ui) + if(!ui) + ui = new(user, GLOB.ares_link, "AresAdmin", "ARES Admin Interface") + ui.open() + +/datum/ares_link/ui_data(mob/user) + if(!interface) + to_chat(user, SPAN_WARNING("ARES ADMIN DATA LINK FAILED")) + 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["current_menu"] = admin_interface.current_menu + data["last_page"] = admin_interface.last_menu + + data["logged_in"] = interface.last_login + data["sudo"] = interface.sudo_holder ? TRUE : FALSE + + data["access_text"] = "[interface.sudo_holder ? "(SUDO)," : ""] access level [interface.authentication], [interface.ares_auth_to_text(interface.authentication)]." + data["access_level"] = 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"] = admin_interface.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 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 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 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 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 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 in datacore.records_deletion) + 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 in datacore.records_deletion) + 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 in datacore.records_asrs) + 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_convos = list() + var/list/active_convo = list() + var/active_ref + for(var/datum/ares_record/talk_log/log in datacore.records_talking) + if(log.user == 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 in tickets_maintenance) + 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 in 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 + + return data + + +/datum/ares_link/ui_state(mob/user) + return GLOB.admin_state + +/datum/ares_link/ui_close(mob/user) + . = ..() + if(admin_interface.logged_in && (user.ckey == admin_interface.logged_in)) + admin_interface.current_menu = "login" + admin_interface.last_menu = "login" + admin_interface.access_list += "[admin_interface.logged_in] logged out at [worldtime2text()]." + admin_interface.last_login = admin_interface.logged_in + admin_interface.logged_in = null + +/datum/ares_link/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + var/mob/user = ui.user + if(!check_rights_for(user.client, R_MOD)) + to_chat(user, SPAN_WARNING("You require staff identification to access this terminal!")) + return FALSE + switch (action) + if("go_back") + if(!admin_interface.last_menu) + to_chat(user, SPAN_WARNING("Error, no previous page detected.")) + return FALSE + var/temp_holder = admin_interface.current_menu + admin_interface.current_menu = admin_interface.last_menu + admin_interface.last_menu = temp_holder + + if("login") + admin_interface.logged_in = user.client.ckey + admin_interface.access_list += "[user.client.ckey] at [worldtime2text()], Access Level '[user.client.admin_holder?.rank]'." + admin_interface.current_menu = "main" + + // -- Page Changers -- // + if("logout") + admin_interface.current_menu = "login" + admin_interface.last_menu = "login" + admin_interface.access_list += "[admin_interface.logged_in] logged out at [worldtime2text()]. (UI Termination)" + admin_interface.last_login = admin_interface.logged_in + admin_interface.logged_in = null + + if("home") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "main" + if("page_1to1") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "talking" + if("page_announcements") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "announcements" + if("page_bioscans") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "bioscans" + if("page_bombardments") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "bombardments" + if("page_apollo") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "apollo" + if("page_access") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "access_log" + if("page_admin_list") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "admin_access_log" + if("page_security") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "security" + if("page_requisitions") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "requisitions" + if("page_flight") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "flight_log" + if("page_emergency") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "emergency" + if("page_deleted") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "delete_log" + if("page_deleted_1to1") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "deleted_talks" + if("page_access_management") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "access_management" + if("page_maint_management") + admin_interface.last_menu = admin_interface.current_menu + admin_interface.current_menu = "maintenance_management" + + // -- 1:1 Conversation -- // + if("new_conversation") + var/datum/ares_record/talk_log/convo = new(interface.last_login) + convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [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") + var/message = tgui_input_text(user, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) + if(message) + interface.message_ares(message, user, params["active_convo"], TRUE) + if("ares_reply") + var/message = tgui_input_text(user, "What do you wish to reply with?", "ARES Response", encode = FALSE) + if(message) + interface.response_from_ares(message, params["active_convo"]) + var/datum/ares_record/talk_log/conversation = locate(params["active_convo"]) + if(!istype(conversation)) + return FALSE + var/admin_log = SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[key_name(user)] replied to [conversation.user]'s ARES message")] [SPAN_GREEN("via Remote Interface")] 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"]) + if(!istype(conversation)) + return FALSE + admin_interface.deleted_1to1 = conversation.conversation + admin_interface.last_menu = admin_interface.current_menu + admin_interface.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 == MAIN_AI_SYSTEM) + var/prompt = tgui_alert(user, "ARES already claimed this ticket! Do you wish to drop the 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 = MAIN_AI_SYSTEM + ticket.ticket_status = TICKET_ASSIGNED + return claim + + if("auth_access") + var/datum/ares_ticket/access/access_ticket = locate(params["ticket"]) + if(!istype(access_ticket)) + return FALSE + for(var/obj/item/card/id/identification in waiting_ids) + if(identification.registered_gid != access_ticket.user_id_num) + continue + identification.handle_ares_access(MAIN_AI_SYSTEM, user) + access_ticket.ticket_status = TICKET_GRANTED + 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 active_ids) + if(identification.registered_gid != access_ticket.user_id_num) + continue + identification.handle_ares_access(MAIN_AI_SYSTEM, user) + access_ticket.ticket_status = TICKET_REVOKED + 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(MAIN_AI_SYSTEM, maint_type, details, priority_report) + 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 [MAIN_AI_SYSTEM] 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 + if(ticket.ticket_submitter != MAIN_AI_SYSTEM) + to_chat(user, SPAN_WARNING("You cannot cancel a ticket that does not belong to [MAIN_AI_SYSTEM]!")) + 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 [MAIN_AI_SYSTEM].") + to_chat(user, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) + return TRUE diff --git a/code/game/machinery/ARES/ARES_interface_apollo.dm b/code/game/machinery/ARES/ARES_interface_apollo.dm index 56283417ae05..4796c25514fd 100644 --- a/code/game/machinery/ARES/ARES_interface_apollo.dm +++ b/code/game/machinery/ARES/ARES_interface_apollo.dm @@ -127,6 +127,25 @@ requesting_access += access_ticket.ticket_name data["access_tickets"] = logged_access + var/list/security_vents = list() + for(var/obj/structure/pipes/vents/pump/no_boom/gas/vent in link.linked_vents) + if(!istype(vent)) + continue + if(!vent.vent_tag) + vent.vent_tag = "Security Vent #[link.tag_num]" + link.tag_num++ + + var/list/current_vent = list() + var/is_available = TRUE + if(!COOLDOWN_FINISHED(vent, vent_trigger_cooldown)) + is_available = FALSE + current_vent["vent_tag"] = vent.vent_tag + current_vent["ref"] = "\ref[vent]" + current_vent["available"] = is_available + security_vents += list(current_vent) + + data["security_vents"] = security_vents + return data /obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state) @@ -197,6 +216,9 @@ if("page_maintenance") last_menu = current_menu current_menu = "maint_claim" + if("page_core_gas") + last_menu = current_menu + current_menu = "core_security_gas" if("new_report") var/priority_report = FALSE @@ -382,13 +404,32 @@ if(!istype(access_ticket)) return FALSE if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + to_chat(operator, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) return FALSE access_ticket.ticket_status = TICKET_REJECTED - to_chat(usr, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) + to_chat(operator, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].") return TRUE + if("trigger_vent") + 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(operator, 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(operator, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + to_chat(operator, 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", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.") + sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS) + log_admin("[key_name(operator)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + 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 8113614d9b92..ed713947ab25 100644 --- a/code/game/machinery/ARES/ARES_procs.dm +++ b/code/game/machinery/ARES/ARES_procs.dm @@ -1,5 +1,5 @@ -GLOBAL_DATUM_INIT(ares_link, /datum/ares_link, new) GLOBAL_DATUM_INIT(ares_datacore, /datum/ares_datacore, new) +GLOBAL_DATUM_INIT(ares_link, /datum/ares_link, new) GLOBAL_LIST_INIT(maintenance_categories, list( "Broken Light", "Shattered Glass", @@ -25,7 +25,14 @@ GLOBAL_LIST_INIT(maintenance_categories, list( var/obj/structure/machinery/ares/processor/apollo/processor_apollo var/obj/structure/machinery/ares/processor/bioscan/processor_bioscan var/obj/structure/machinery/computer/ares_console/interface + var/datum/ares_console_admin/admin_interface + var/datum/ares_datacore/datacore + var/list/obj/structure/machinery/computer/working_joe/ticket_computers = list() + /// Linked security gas vents. + var/list/linked_vents = list() + /// The tag number for generated vent labels, if none is manually set. + var/tag_num = 1 /// Working Joe stuff var/list/tickets_maintenance = list() @@ -33,6 +40,25 @@ GLOBAL_LIST_INIT(maintenance_categories, list( var/list/waiting_ids = list() var/list/active_ids = list() +/datum/ares_link/New() + admin_interface = new + datacore = GLOB.ares_datacore + +/datum/ares_link/Destroy() + qdel(admin_interface) + for(var/obj/structure/machinery/ares/link in linked_systems) + link.delink() + for(var/obj/structure/machinery/computer/ares_console/interface in linked_systems) + interface.delink() + for(var/obj/effect/step_trigger/ares_alert/alert in linked_alerts) + alert.delink() + ..() + +/* BELOW ARE IN AdminAres.dm +/datum/ares_link/tgui_interact(mob/user, datum/tgui/ui) +/datum/ares_link/ui_data(mob/user) +*/ + /datum/ares_datacore /// A record of who logged in and when. var/list/interface_access_list = list() @@ -58,24 +84,15 @@ GLOBAL_LIST_INIT(maintenance_categories, list( var/list/records_security = list() /// Holds all (/datum/ares_record/flight)s var/list/records_flight = list() + /// Holds all (/datum/ares_record/tech)s + var/list/records_tech = list() /// Is nuke request usable or not? var/nuke_available = TRUE - COOLDOWN_DECLARE(ares_distress_cooldown) COOLDOWN_DECLARE(ares_nuclear_cooldown) COOLDOWN_DECLARE(ares_quarters_cooldown) -/datum/ares_link/Destroy() - for(var/obj/structure/machinery/ares/link in linked_systems) - link.delink() - for(var/obj/structure/machinery/computer/ares_console/interface in linked_systems) - interface.delink() - for(var/obj/effect/step_trigger/ares_alert/alert in linked_alerts) - alert.delink() - ..() - - // ------ ARES Logging Procs ------ // /proc/ares_is_active() for(var/mob/living/silicon/decoy/ship_ai/ai in GLOB.ai_mob_list) @@ -166,6 +183,16 @@ GLOBAL_LIST_INIT(maintenance_categories, list( return FALSE var/datum/ares_datacore/datacore = GLOB.ares_datacore datacore.records_flight.Add(new /datum/ares_record/flight(details, user_name)) + +/proc/log_ares_tech(user_name, tier_tech = FALSE, title, details, point_cost, current_points) + if(!ares_can_log()) + return FALSE + var/new_details = "[title] - [details]" + if(point_cost) + new_details += " - Used [point_cost] INT of [current_points]." + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_tech.Add(new /datum/ares_record/tech(title, new_details, user_name, tier_tech)) + // ------ End ARES Logging Procs ------ // // ------ ARES Interface Procs ------ // @@ -196,43 +223,58 @@ GLOBAL_LIST_INIT(maintenance_categories, list( /obj/structure/machinery/computer/proc/ares_auth_to_text(access_level) switch(access_level) - if(ARES_ACCESS_BASIC)//0 + if(ARES_ACCESS_LOGOUT) + return "Logged Out" + if(ARES_ACCESS_BASIC) return "Authorized" - if(ARES_ACCESS_COMMAND)//1 + if(ARES_ACCESS_COMMAND) return "[MAIN_SHIP_NAME] Command" - if(ARES_ACCESS_JOE)//2 + if(ARES_ACCESS_JOE) return "Working Joe" - if(ARES_ACCESS_CORPORATE)//3 + if(ARES_ACCESS_CORPORATE) return "Weyland-Yutani" - if(ARES_ACCESS_SENIOR)//4 + if(ARES_ACCESS_SENIOR) return "[MAIN_SHIP_NAME] Senior Command" - if(ARES_ACCESS_CE)//5 + if(ARES_ACCESS_CE) return "Chief Engineer" - if(ARES_ACCESS_SYNTH)//6 + if(ARES_ACCESS_SYNTH) return "USCM Synthetic" - if(ARES_ACCESS_CO)//7 + if(ARES_ACCESS_CO) return "[MAIN_SHIP_NAME] Commanding Officer" - if(ARES_ACCESS_HIGH)//8 + if(ARES_ACCESS_HIGH) return "USCM High Command" - if(ARES_ACCESS_WY_COMMAND)//9 + if(ARES_ACCESS_WY_COMMAND) return "Weyland-Yutani Directorate" - if(ARES_ACCESS_DEBUG)//10 + if(ARES_ACCESS_DEBUG) return "AI Service Technician" -/obj/structure/machinery/computer/ares_console/proc/message_ares(text, mob/Sender, ref) - var/msg = SPAN_STAFF_IC("ARES: [key_name(Sender, 1)] [ARES_MARK(Sender)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] [ADMIN_JMP_USER(Sender)] [ARES_REPLY(Sender, ref)]: [text]") +/obj/structure/machinery/computer/ares_console/proc/message_ares(text, mob/Sender, ref, fake = FALSE) var/datum/ares_record/talk_log/conversation = locate(ref) + if(!istype(conversation)) + return + var/msg = SPAN_STAFF_IC("ARES: [key_name(Sender, 1)] [ARES_MARK(Sender)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] [ADMIN_JMP_USER(Sender)] [ARES_REPLY(Sender, ref)]: [text]") conversation.conversation += "[last_login] at [worldtime2text()], '[text]'" + if(fake) + log_say("[key_name(Sender)] faked the message '[text]' from [last_login] in ARES 1:1.") + msg = SPAN_STAFF_IC("ARES: [key_name(Sender, 1)] faked a message from '[last_login]': [text]") + else + log_say("[key_name(Sender)] sent '[text]' to ARES 1:1.") + for(var/client/admin in GLOB.admins) + if(admin.prefs.toggles_sound & SOUND_ARES_MESSAGE) + playsound_client(admin, 'sound/machines/chime.ogg', vol = 25) + for(var/client/admin in GLOB.admins) if((R_ADMIN|R_MOD) & admin.admin_holder.rights) to_chat(admin, msg) - if(admin.prefs.toggles_sound & SOUND_ARES_MESSAGE) - playsound_client(admin, 'sound/machines/chime.ogg', vol = 25) - log_say("[key_name(Sender)] sent '[text]' to ARES 1:1.") + var/admin_user = GLOB.ares_link.admin_interface.logged_in + if(admin_user && !fake) + to_chat(admin, SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[admin_user] is logged in to ARES Remote Interface! They may be replying to this message!")]")) /obj/structure/machinery/computer/ares_console/proc/response_from_ares(text, ref) var/datum/ares_record/talk_log/conversation = locate(ref) + if(!istype(conversation)) + return conversation.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], '[text]'" // ------ End ARES Interface Procs ------ // diff --git a/code/game/machinery/ARES/ARES_records.dm b/code/game/machinery/ARES/ARES_records.dm index f89b2c120e05..5bfe50dce068 100644 --- a/code/game/machinery/ARES/ARES_records.dm +++ b/code/game/machinery/ARES/ARES_records.dm @@ -45,7 +45,7 @@ /datum/ares_record/flight/New(details, user) time = worldtime2text() - src.title = "Flight Log" + title = "Flight Log" src.details = details src.user = user @@ -58,6 +58,18 @@ src.details = details src.user = user +/datum/ares_record/tech + record_name = ARES_RECORD_TECH + /// If this tech unlock changed the tier. + var/is_tier = FALSE + +/datum/ares_record/tech/New(title, details, user, tier_tech) + time = worldtime2text() + src.title = title + src.details = details + src.user = user + is_tier = tier_tech + /datum/ares_record/deletion record_name = ARES_RECORD_DELETED diff --git a/code/game/machinery/ARES/apollo_pda.dm b/code/game/machinery/ARES/apollo_pda.dm index 8df3faf79260..2d395d79932f 100644 --- a/code/game/machinery/ARES/apollo_pda.dm +++ b/code/game/machinery/ARES/apollo_pda.dm @@ -151,6 +151,25 @@ requesting_access += access_ticket.ticket_name data["access_tickets"] = logged_access + var/list/security_vents = list() + for(var/obj/structure/pipes/vents/pump/no_boom/gas/vent in link.linked_vents) + if(!istype(vent)) + continue + if(!vent.vent_tag) + vent.vent_tag = "Security Vent #[link.tag_num]" + link.tag_num++ + + var/list/current_vent = list() + var/is_available = TRUE + if(!COOLDOWN_FINISHED(vent, vent_trigger_cooldown)) + is_available = FALSE + current_vent["vent_tag"] = vent.vent_tag + current_vent["ref"] = "\ref[vent]" + current_vent["available"] = is_available + security_vents += list(current_vent) + + data["security_vents"] = security_vents + return data /obj/item/device/working_joe_pda/ui_status(mob/user, datum/ui_state/state) @@ -222,6 +241,9 @@ if("page_maintenance") last_menu = current_menu current_menu = "maint_claim" + if("page_core_gas") + last_menu = current_menu + current_menu = "core_security_gas" if("new_report") var/priority_report = FALSE @@ -407,13 +429,32 @@ if(!istype(access_ticket)) return FALSE if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + to_chat(operator, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) return FALSE access_ticket.ticket_status = TICKET_REJECTED - to_chat(usr, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) + to_chat(operator, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].") return TRUE + if("trigger_vent") + 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(operator, 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(operator, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + to_chat(operator, 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", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.") + sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS) + log_admin("[key_name(operator)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + 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_pda.dm b/code/game/machinery/ARES/debug_pda.dm new file mode 100644 index 000000000000..2b01502d307b --- /dev/null +++ b/code/game/machinery/ARES/debug_pda.dm @@ -0,0 +1,662 @@ +/obj/item/device/ai_tech_pda + icon = 'icons/obj/items/synth/wj_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() + +/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/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(!ui) + ui = new(user, src, "AresAdmin", 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"] = list() + 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"] = list() + data["access_log"] += datacore.interface_access_list + data["apollo_log"] = list() + data["apollo_log"] += datacore.apollo_log + + data["deleted_conversation"] = list() + 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_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 + + return data + +/obj/item/device/ai_tech_pda/ui_close(mob/user) + . = ..() + current_menu = "login" + last_menu = "off" + if(logged_in) + access_list += "[logged_in] logged out at [worldtime2text()]." + logged_in = null + 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 = usr + var/playsound = TRUE + + 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/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 + logged_in = user.real_name + access_list += "[logged_in] at [worldtime2text()]." + current_menu = "main" + + // -- 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_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") + 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") + 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 Remote link.interface")] 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") + 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") + 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 + + 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(!COOLDOWN_FINISHED(datacore, ares_quarters_cooldown)) + to_chat(usr, 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(usr)] has called for general quarters via ARES.") + message_admins("[key_name_admin(usr)] 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(GLOB.security_level < SEC_LEVEL_RED) + to_chat(usr, 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(usr, 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(usr, 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(usr)] has called for an emergency evacuation via ARES.") + message_admins("[key_name_admin(usr)] 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(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < DISTRESS_TIME_LOCK) + to_chat(usr, 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(usr, 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(usr, 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(usr, 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(usr, TRUE) + to_chat(usr, 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(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < NUCLEAR_TIME_LOCK) + to_chat(usr, 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(usr, 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(usr, 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(usr, "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(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, 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(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/camera/presets.dm b/code/game/machinery/camera/presets.dm index 103e3f709afe..a1d7f00cf94a 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -97,7 +97,7 @@ /obj/structure/machinery/camera/autoname/almayer/containment/ares name = "ares core camera" - network = list(CAMERA_NET_ALMAYER, CAMERA_NET_ARES) + network = list(CAMERA_NET_ARES) //used by the landing camera dropship equipment. Do not place them right under where the dropship lands. //Should place them near each corner of your LZs. diff --git a/code/game/objects/structures/pipes/vents/pump_scrubber.dm b/code/game/objects/structures/pipes/vents/pump_scrubber.dm index a4565c610ad5..acc8b4784af9 100644 --- a/code/game/objects/structures/pipes/vents/pump_scrubber.dm +++ b/code/game/objects/structures/pipes/vents/pump_scrubber.dm @@ -21,6 +21,35 @@ name = "Reinforced Air Vent" explodey = FALSE +/// Vents that are linked to ARES Security Protocols, allowing the ARES Interface to trigger security measures. +/obj/structure/pipes/vents/pump/no_boom/gas + name = "Security Air Vent" + var/datum/ares_link/link + var/vent_tag + COOLDOWN_DECLARE(vent_trigger_cooldown) + +/obj/structure/pipes/vents/pump/no_boom/gas/Initialize() + link_systems(override = FALSE) + . = ..() + +/obj/structure/pipes/vents/pump/no_boom/gas/Destroy() + delink() + return ..() + +/obj/structure/pipes/vents/pump/no_boom/gas/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + delink() + if(new_link) + link = new_link + new_link.linked_vents += src + return TRUE + +/obj/structure/pipes/vents/pump/no_boom/gas/proc/delink() + if(link) + link.linked_vents -= src + link = null + /obj/structure/pipes/vents/pump/on icon_state = "on" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index d6e20cbf23b8..ac0f997e20d3 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -68,6 +68,7 @@ GLOBAL_LIST_INIT(admin_verbs_default, list( /datum/admins/proc/alertall, /datum/admins/proc/imaginary_friend, /client/proc/toggle_admin_pings, + /client/proc/cmd_admin_open_ares, /client/proc/cmd_admin_say, /*staff-only ooc chat*/ /client/proc/cmd_mod_say, /* alternate way of typing asay, no different than cmd_admin_say */ /client/proc/cmd_admin_tacmaps_panel, diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 113d585e44ef..5f5b6a64a883 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -674,6 +674,8 @@ GLOBAL_LIST_INIT(bgstate_options, list( if(!job) debug_log("Missing job for prefs: [role_name]") continue + if(job.flags_startup_parameters & ROLE_HIDDEN) + continue index++ if((index >= limit) || (job.title in splitJobs)) HTML += "" @@ -787,6 +789,8 @@ GLOBAL_LIST_INIT(bgstate_options, list( if(!job) debug_log("Missing job for prefs: [role_name]") continue + if(job.flags_startup_parameters & ROLE_HIDDEN) + continue index++ if((index >= limit) || (job.title in splitJobs)) HTML += "
" diff --git a/code/modules/cm_marines/marines_consoles.dm b/code/modules/cm_marines/marines_consoles.dm index 1d72ab5a4d99..f0794a74349a 100644 --- a/code/modules/cm_marines/marines_consoles.dm +++ b/code/modules/cm_marines/marines_consoles.dm @@ -923,6 +923,7 @@ GLOBAL_LIST_EMPTY_TYPED(crewmonitor, /datum/crewmonitor) JOB_SURGEON = 42, JOB_NURSE = 43, // 50-59: Engineering + JOB_AI_TECH = 50, JOB_CHIEF_ENGINEER = 50, JOB_ORDNANCE_TECH = 51, JOB_MAINT_TECH = 52, diff --git a/code/modules/cm_tech/tech.dm b/code/modules/cm_tech/tech.dm index dea505f3237a..3472ac5b3df5 100644 --- a/code/modules/cm_tech/tech.dm +++ b/code/modules/cm_tech/tech.dm @@ -21,7 +21,7 @@ var/background_icon = "background" var/background_icon_locked = "marine" - var/announce_name + var/announce_name = "ALMAYER SPECIAL ASSETS AUTHORIZED" var/announce_message /datum/tech/proc/can_unlock(mob/M) @@ -58,6 +58,9 @@ return TRUE +/datum/tech/proc/is_tier_tech() + return FALSE + /** Called when a tech is unlocked. Usually, benefits can be applied here * however, the purchase can still be cancelled by returning FALSE * @@ -69,11 +72,17 @@ unlocked = TRUE to_chat(user, SPAN_HELPFUL("You have purchased the '[name]' tech node.")) log_admin("[key_name_admin(user)] has bought '[name]' via tech points.") + if(!is_tier_tech()) + var/log_details = announce_message + if(!log_details) + log_details = name + var/current_points = holder.points + log_ares_tech(user.real_name, is_tier_tech(), announce_name, log_details, required_points, current_points) holder.spend_points(required_points) update_icon(node) if(!(tech_flags & TECH_FLAG_NO_ANNOUNCE) && announce_message && announce_name) - marine_announcement(announce_message, announce_name, 'sound/misc/notice2.ogg') + marine_announcement(announce_message, announce_name, 'sound/misc/notice2.ogg', logging = ARES_LOG_NONE) return TRUE diff --git a/code/modules/cm_tech/techs/abstract/transitory.dm b/code/modules/cm_tech/techs/abstract/transitory.dm index 7798b6053d0e..b7c5775fd6b2 100644 --- a/code/modules/cm_tech/techs/abstract/transitory.dm +++ b/code/modules/cm_tech/techs/abstract/transitory.dm @@ -22,7 +22,10 @@ return TRUE -/datum/tech/transitory/on_unlock() +/datum/tech/transitory/is_tier_tech() + return TRUE + +/datum/tech/transitory/on_unlock(mob/user) . = ..() if(!next) return @@ -31,6 +34,10 @@ if(next_tier) holder.tier = next_tier holder.on_tier_change(previous_tier) + if(flags & TREE_FLAG_MARINE) + /// Due to calling parent, points will have already been spent by now. + var/current_points = holder.points + required_points + log_ares_tech(user.real_name, is_tier_tech(), "ALMAYER DEFCON LEVEL INCREASED", "THREAT ASSESSMENT LEVEL INCREASED TO LEVEL [next_tier.tier].\n\nLEVEL [next_tier.tier] assets have been authorised to handle the situation.", required_points, current_points) /datum/tech/transitory/get_tier_overlay() if(!next) diff --git a/code/modules/cm_tech/techs/marine/tier1/points.dm b/code/modules/cm_tech/techs/marine/tier1/points.dm index d6bb5bace6fc..7768d8da2ab7 100644 --- a/code/modules/cm_tech/techs/marine/tier1/points.dm +++ b/code/modules/cm_tech/techs/marine/tier1/points.dm @@ -31,7 +31,6 @@ icon_state = "budget_ds" desc = "Distributes resources to the dropship fabricator." - announce_name = "ALMAYER SPECIAL ASSETS AUTHORIZED" announce_message = "Additional dropship part fabricator points have been authorised for this operation." required_points = 12 diff --git a/code/modules/cm_tech/techs/marine/tier2/orbital_ammo.dm b/code/modules/cm_tech/techs/marine/tier2/orbital_ammo.dm index 303ea6121734..51675ccd27f2 100644 --- a/code/modules/cm_tech/techs/marine/tier2/orbital_ammo.dm +++ b/code/modules/cm_tech/techs/marine/tier2/orbital_ammo.dm @@ -7,8 +7,6 @@ tier = /datum/tier/two - announce_name = "ALMAYER SPECIAL ASSETS AUTHORIZED" - var/type_to_give /datum/tech/repeatable/ob/on_unlock() diff --git a/code/modules/cm_tech/techs/marine/tier3/cryo_spec.dm b/code/modules/cm_tech/techs/marine/tier3/cryo_spec.dm index acee904af305..06770b1d6afe 100644 --- a/code/modules/cm_tech/techs/marine/tier3/cryo_spec.dm +++ b/code/modules/cm_tech/techs/marine/tier3/cryo_spec.dm @@ -3,7 +3,6 @@ desc = "Wakes up an additional specialist to fight against any threats." icon_state = "overshield" - announce_name = "ALMAYER SPECIAL ASSETS AUTHORIZED" announce_message = "An additional specialist is being taken out of cryo." required_points = 8 diff --git a/code/modules/cm_tech/techs/marine/tier3/cryorine.dm b/code/modules/cm_tech/techs/marine/tier3/cryorine.dm index 404fbd07c2ae..19200698db02 100644 --- a/code/modules/cm_tech/techs/marine/tier3/cryorine.dm +++ b/code/modules/cm_tech/techs/marine/tier3/cryorine.dm @@ -4,7 +4,6 @@ desc = "Wakes up additional troops to fight against any threats." icon_state = "cryotroops" - announce_name = "ALMAYER SPECIAL ASSETS AUTHORIZED" announce_message = "Additional troops are being taken out of cryo." required_points = 6 diff --git a/code/modules/cm_tech/trees/marine.dm b/code/modules/cm_tech/trees/marine.dm index aae057b90198..046712f9656b 100644 --- a/code/modules/cm_tech/trees/marine.dm +++ b/code/modules/cm_tech/trees/marine.dm @@ -174,4 +174,4 @@ GLOBAL_LIST_EMPTY(tech_controls_marine) return //No need to announce tier updates for tier 1 var/name = "ALMAYER DEFCON LEVEL INCREASED" var/input = "THREAT ASSESSMENT LEVEL INCREASED TO LEVEL [tier.tier].\n\nLEVEL [tier.tier] assets have been authorised to handle the situation." - marine_announcement(input, name, 'sound/AI/commandreport.ogg') + marine_announcement(input, name, 'sound/AI/commandreport.ogg', logging = ARES_LOG_NONE) diff --git a/code/modules/gear_presets/uscm_event.dm b/code/modules/gear_presets/uscm_event.dm index ce36f1fd807f..bdcd811b5922 100644 --- a/code/modules/gear_presets/uscm_event.dm +++ b/code/modules/gear_presets/uscm_event.dm @@ -442,3 +442,55 @@ /*****************************************************************************************************/ +/datum/equipment_preset/uscm_event/ai_tech + name = "USCM AI Technician" + flags = EQUIPMENT_PRESET_EXTRA + faction = FACTION_MARINE + faction_group = list(FACTION_MARINE) + assignment = JOB_AI_TECH + rank = JOB_AI_TECH + paygrade = PAY_SHORT_MO3 + role_comm_title = "AIST" + skills = /datum/skills/CE + languages = list(LANGUAGE_ENGLISH, LANGUAGE_RUSSIAN, LANGUAGE_JAPANESE, LANGUAGE_GERMAN, LANGUAGE_SPANISH, LANGUAGE_CHINESE) + idtype = /obj/item/card/id/silver + access = list( + ACCESS_MARINE_CE, + ACCESS_MARINE_ENGINEERING, + ACCESS_MARINE_COMMAND, + ACCESS_CIVILIAN_ENGINEERING, + ACCESS_MARINE_DATABASE, + ACCESS_MARINE_MAINT, + ACCESS_MARINE_OT, + ACCESS_MARINE_SYNTH, + ACCESS_MARINE_AI, + ACCESS_ARES_DEBUG, + ) + +/datum/equipment_preset/uscm_event/ai_tech/load_vanity(mob/living/carbon/human/new_human) + return + +/datum/equipment_preset/uscm_event/ai_tech/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/dress(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/welding(new_human), WEAR_EYES) + new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/yellow(new_human), WEAR_HANDS) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/storage/holster(new_human), WEAR_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/revolver/m44/custom/pkd_special(new_human.back), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/revolver/pkd(new_human.back), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/revolver/pkd(new_human.back), WEAR_IN_ACCESSORY) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/lockable(new_human), WEAR_BACK) + new_human.equip_to_slot_or_del(new /obj/item/storage/belt/utility/full(new_human), WEAR_WAIST) + + new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/hazardvest/black(new_human), WEAR_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/device/flash(new_human), WEAR_IN_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/device/flashlight(new_human), WEAR_J_STORE) + + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcom/cdrcom(new_human), WEAR_L_EAR) + + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/sling(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/device/ai_tech_pda(new_human.back), WEAR_IN_L_STORE) + + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert(new_human), WEAR_R_STORE) diff --git a/colonialmarines.dme b/colonialmarines.dme index d10abbaefaa0..6d2989624927 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -875,10 +875,12 @@ #include "code\game\machinery\ARES\apollo_pda.dm" #include "code\game\machinery\ARES\ARES.dm" #include "code\game\machinery\ARES\ARES_interface.dm" +#include "code\game\machinery\ARES\ARES_interface_admin.dm" #include "code\game\machinery\ARES\ARES_interface_apollo.dm" #include "code\game\machinery\ARES\ARES_procs.dm" #include "code\game\machinery\ARES\ARES_records.dm" #include "code\game\machinery\ARES\ARES_step_triggers.dm" +#include "code\game\machinery\ARES\debug_pda.dm" #include "code\game\machinery\atmoalter\canister.dm" #include "code\game\machinery\atmoalter\meter.dm" #include "code\game\machinery\atmoalter\portable_atmospherics.dm" diff --git a/icons/mob/hud/sec_hud.dmi b/icons/mob/hud/sec_hud.dmi index 9cc3e66c3e0b..09ea17cc43f0 100644 Binary files a/icons/mob/hud/sec_hud.dmi and b/icons/mob/hud/sec_hud.dmi differ diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm index 0d15799978a9..7ca1ae8afcff 100644 --- a/maps/map_files/USS_Almayer/USS_Almayer.dmm +++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm @@ -3994,10 +3994,10 @@ /turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "avM" = ( -/obj/structure/machinery/computer/cameras/almayer/ares{ +/obj/structure/machinery/computer/cameras/almayer{ dir = 8; pixel_x = 17; - pixel_y = 6 + pixel_y = 8 }, /obj/structure/surface/table/reinforced/almayer_B{ climbable = 0; @@ -4009,7 +4009,14 @@ pixel_y = 6 }, /obj/item/tool/pen, -/turf/open/floor/almayer/aicore/no_build, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 8; + pixel_x = 17; + pixel_y = -6 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, /area/almayer/command/airoom) "avN" = ( /obj/structure/machinery/telecomms/processor/preset_two, @@ -4690,7 +4697,13 @@ /obj/item/storage/belt/medical/full, /obj/structure/machinery/computer/working_joe{ dir = 8; - pixel_x = 17 + pixel_x = 17; + pixel_y = 8 + }, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 8; + pixel_x = 17; + pixel_y = -6 }, /turf/open/floor/almayer{ icon_state = "plate" @@ -6037,13 +6050,13 @@ /area/almayer/living/grunt_rnr) "aDX" = ( /obj/structure/surface/table/almayer, -/obj/structure/machinery/computer/cameras/containment{ - dir = 4 - }, /obj/structure/sign/safety/terminal{ pixel_x = 8; pixel_y = 32 }, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 4 + }, /turf/open/floor/almayer{ icon_state = "plate" }, @@ -9278,7 +9291,8 @@ "aWb" = ( /obj/structure/machinery/computer/working_joe{ dir = 4; - pixel_x = -17 + pixel_x = -17; + pixel_y = 8 }, /obj/structure/machinery/door_control/brbutton{ id = "engie_store"; @@ -9287,6 +9301,11 @@ pixel_y = 26; req_one_access_txt = "6" }, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 4; + pixel_x = -17; + pixel_y = -6 + }, /turf/open/floor/almayer{ dir = 1; icon_state = "orangecorner" @@ -16663,6 +16682,15 @@ icon_state = "cargo" }, /area/almayer/living/tankerbunks) +"bTo" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E" + }, +/obj/structure/pipes/vents/pump/no_boom/gas{ + vent_tag = "Server chamber" + }, +/turf/open/floor/almayer/aicore/glowing/no_build, +/area/almayer/command/airoom) "bTq" = ( /obj/structure/machinery/door/airlock/almayer/secure/reinforced{ name = "\improper Evacuation Airlock PL-3"; @@ -26196,6 +26224,16 @@ icon_state = "plate" }, /area/almayer/squads/req) +"eHe" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + layer = 3.3 + }, +/obj/structure/pipes/vents/pump/no_boom/gas{ + vent_tag = "CPU Chamber" + }, +/turf/open/floor/almayer/aicore/glowing/no_build, +/area/almayer/command/airoom) "eHx" = ( /obj/structure/surface/table/reinforced/almayer_B, /obj/structure/machinery/faxmachine/uscm/command, @@ -33362,6 +33400,11 @@ pixel_x = -1; pixel_y = 3 }, +/obj/item/reagent_container/spray/cleaner{ + layer = 3.04; + pixel_x = 5; + pixel_y = 22 + }, /turf/open/floor/wood/ship, /area/almayer/living/commandbunks) "hlH" = ( @@ -37805,13 +37848,14 @@ layer = 3.2; pixel_y = 4 }, -/obj/structure/machinery/computer/secure_data{ - dir = 4; - pixel_y = 23 - }, /obj/structure/machinery/light{ dir = 8 }, +/obj/structure/machinery/computer/secure_data{ + dir = 4; + pixel_y = 23; + layer = 2.99 + }, /turf/open/floor/almayer{ dir = 8; icon_state = "red" @@ -38518,15 +38562,6 @@ /obj/structure/machinery/light{ dir = 8 }, -/obj/item/clothing/mask/cigarette/pipe{ - layer = 2.8; - pixel_y = -7 - }, -/obj/item/reagent_container/spray/cleaner{ - layer = 3.04; - pixel_x = -4; - pixel_y = 7 - }, /obj/structure/machinery/door_control/brbutton{ id = "Brig Lockdown Shutters"; name = "Brig Lockdown"; @@ -38545,6 +38580,9 @@ pixel_x = 8; pixel_y = 26 }, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 4 + }, /turf/open/floor/wood/ship, /area/almayer/living/commandbunks) "jbO" = ( @@ -45994,6 +46032,15 @@ "lFp" = ( /turf/closed/wall/almayer, /area/almayer/engineering/lower/workshop/hangar) +"lFq" = ( +/obj/structure/pipes/vents/pump/no_boom/gas{ + vent_tag = "Operations - Observation"; + dir = 1 + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_plates" + }, +/area/almayer/command/airoom) "lFr" = ( /obj/structure/machinery/firealarm{ dir = 8; @@ -50473,15 +50520,14 @@ /area/almayer/hallways/upper/starboard) "nkX" = ( /obj/structure/surface/table/almayer, -/obj/structure/machinery/computer/cameras/almayer_network{ - dir = 4; - layer = 2.8; - pixel_y = 5 - }, /obj/structure/sign/safety/terminal{ pixel_x = 8; pixel_y = 32 }, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 4; + pixel_y = 5 + }, /turf/open/floor/almayer{ dir = 9; icon_state = "red" @@ -51408,6 +51454,10 @@ pixel_x = -1; pixel_y = 2 }, +/obj/item/clothing/mask/cigarette/pipe{ + layer = 2.8; + pixel_x = 14 + }, /turf/open/floor/wood/ship, /area/almayer/living/commandbunks) "nCD" = ( @@ -56394,14 +56444,14 @@ }, /area/almayer/living/briefing) "pmV" = ( -/obj/structure/prop/server_equipment/yutani_server/broken{ - density = 0; - desc = "A powerful server tower housing various AI functions."; - name = "server tower"; - pixel_y = 16 - }, /obj/structure/pipes/standard/simple/hidden/supply/no_boom, -/turf/open/floor/almayer/aicore/no_build, +/obj/structure/machinery/computer/tech_control{ + pixel_y = 16; + density = 0 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, /area/almayer/command/airoom) "pnh" = ( /obj/structure/ladder{ @@ -58323,7 +58373,8 @@ }, /area/almayer/hallways/lower/starboard_midship_hallway) "pYi" = ( -/obj/structure/pipes/vents/pump/no_boom{ +/obj/structure/pipes/vents/pump/no_boom/gas{ + vent_tag = "Access Corridor"; dir = 8 }, /turf/open/floor/almayer/aicore/no_build{ @@ -77255,9 +77306,8 @@ /obj/structure/bed/chair/comfy/ares{ dir = 1 }, -/obj/structure/pipes/vents/pump/no_boom{ - desc = "Has a valve and pump attached to it, connected to multiple gas tanks."; - name = "Security Vent" +/obj/structure/pipes/vents/pump/no_boom/gas{ + vent_tag = "Core Chamber" }, /turf/open/floor/almayer/no_build{ icon_state = "plating" @@ -82828,7 +82878,8 @@ }, /area/almayer/maint/hull/lower/l_m_s) "yit" = ( -/obj/structure/pipes/vents/pump/no_boom{ +/obj/structure/pipes/vents/pump/no_boom/gas{ + vent_tag = "Operations - Records"; dir = 1 }, /turf/open/floor/almayer/aicore/no_build, @@ -139794,7 +139845,7 @@ cqm gTH qit ebN -cxc +qQS gwn pfT jYR @@ -139999,7 +140050,7 @@ qQS bIp fKe dDp -dDp +eHe frM lcg daz @@ -140605,8 +140656,8 @@ ebN ebN roH ebN -ebN -ebN +daz +daz daz wnh wnh @@ -141417,8 +141468,8 @@ ebN ebN gXs ebN -ebN -ebN +daz +daz daz wnh wnh @@ -141619,9 +141670,9 @@ ebN ebN gbg uVv -yit +lFq ebN -cxc +qQS kBy kBy gfu @@ -142029,7 +142080,7 @@ qQS mFN igr sEK -sEK +bTo mlb lcg daz diff --git a/tgui/packages/tgui/interfaces/AresAdmin.js b/tgui/packages/tgui/interfaces/AresAdmin.js new file mode 100644 index 000000000000..f6421cf800aa --- /dev/null +++ b/tgui/packages/tgui/interfaces/AresAdmin.js @@ -0,0 +1,2040 @@ +import { useBackend } from '../backend'; +import { Flex, Box, Section, Button, Stack } from '../components'; +import { Window } from '../layouts'; + +const PAGES = { + 'login': () => Login, + 'main': () => MainMenu, + 'announcements': () => AnnouncementLogs, + 'bioscans': () => BioscanLogs, + 'bombardments': () => BombardmentLogs, + 'apollo': () => ApolloLog, + 'access_log': () => AccessLogs, + 'delete_log': () => DeletionLogs, + 'flight_log': () => FlightLogs, + 'talking': () => ARESTalk, + 'deleted_talks': () => DeletedTalks, + 'read_deleted': () => ReadingTalks, + 'security': () => Security, + 'requisitions': () => Requisitions, + 'emergency': () => Emergency, + 'admin_access_log': () => AdminAccessLogs, + 'access_management': () => AccessManagement, + 'maintenance_management': () => MaintManagement, +}; + +const { data } = useBackend(); +const { is_pda } = data; +let remotelock = !is_pda; +let remotetip = 'You cannot do this via remote console.'; +let deletetip = remotetip; +if (!remotelock) { + remotetip = ''; + deletetip = 'Delete Record'; +} + +export const AresAdmin = (props, context) => { + const { data } = useBackend(context); + const { current_menu, sudo } = data; + const PageComponent = PAGES[current_menu](); + + let themecolor = 'crtyellow'; + if (sudo >= 1) { + themecolor = 'crtred'; + } + + return ( + + + + + + ); +}; + +const Login = (props, context) => { + const { act } = useBackend(context); + + return ( + + ARES v3.2 Remote Interface + + WY-DOS Executive + + Version 4.5.2 + Copyright © 2182, Weyland Yutani Corp. + +