diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index e65bdf134fe..9f82595eb33 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -187,31 +187,26 @@ SUBSYSTEM_DEF(shuttle) return S WARNING("couldn't find dock with id: [id]") +/// Check if we can call the evac shuttle. +/// Returns TRUE if we can. Otherwise, returns a string detailing the problem. /datum/controller/subsystem/shuttle/proc/canEvac(mob/user) var/srd = CONFIG_GET(number/shuttle_refuel_delay) if(world.time - SSticker.round_start_time < srd) - to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.") - return FALSE + return "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before attempting to call." switch(emergency.mode) if(SHUTTLE_RECALL) - to_chat(user, "The emergency shuttle may not be called while returning to CentCom.") - return FALSE + return "The emergency shuttle may not be called while returning to CentCom." if(SHUTTLE_CALL) - to_chat(user, "The emergency shuttle is already on its way.") - return FALSE + return "The emergency shuttle is already on its way." if(SHUTTLE_DOCKED) - to_chat(user, "The emergency shuttle is already here.") - return FALSE + return "The emergency shuttle is already here." if(SHUTTLE_IGNITING) - to_chat(user, "The emergency shuttle is firing its engines to leave.") - return FALSE + return "The emergency shuttle is firing its engines to leave." if(SHUTTLE_ESCAPE) - to_chat(user, "The emergency shuttle is moving away to a safe distance.") - return FALSE - if(SHUTTLE_STRANDED, SHUTTLE_DISABLED) - to_chat(user, "The emergency shuttle has been disabled by CentCom.") - return FALSE + return "The emergency shuttle is moving away to a safe distance." + if(SHUTTLE_STRANDED) + return "The emergency shuttle has been disabled by CentCom." return TRUE @@ -229,7 +224,9 @@ SUBSYSTEM_DEF(shuttle) Good luck.") emergency = backup_shuttle - if(!canEvac(user)) + var/can_evac_or_fail_reason = SSshuttle.canEvac(user) + if(can_evac_or_fail_reason != TRUE) + to_chat(user, "[can_evac_or_fail_reason]") return call_reason = trim(html_encode(call_reason)) diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index e4af943f2e7..7bde5574b71 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -99,7 +99,7 @@ minor_announce(input["message"], "Incoming message from [input["message_sender"]]") for(var/obj/machinery/computer/communications/CM in GLOB.machines) - CM.overrideCooldown() + CM.override_cooldown() /datum/world_topic/news_report keyword = "News_Report" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 911d6061664..953021652e6 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -1,14 +1,10 @@ -#define STATE_DEFAULT 1 -#define STATE_CALLSHUTTLE 2 -#define STATE_CANCELSHUTTLE 3 -#define STATE_MESSAGELIST 4 -#define STATE_VIEWMESSAGE 5 -#define STATE_DELMESSAGE 6 -#define STATE_STATUSDISPLAY 7 -#define STATE_ALERT_LEVEL 8 -#define STATE_CONFIRM_LEVEL 9 -#define STATE_TOGGLE_EMERGENCY 10 -#define STATE_PURCHASE 11 +#define IMPORTANT_ACTION_COOLDOWN (60 SECONDS) +#define MAX_STATUS_LINE_LENGTH 40 + +#define STATE_BUYING_SHUTTLE "buying_shuttle" +#define STATE_CHANGING_STATUS "changing_status" +#define STATE_MAIN "main" +#define STATE_MESSAGES "messages" // The communications computer /obj/machinery/computer/communications @@ -19,409 +15,53 @@ req_access = list(ACCESS_HEADS) circuit = /obj/item/circuitboard/computer/communications light_color = LIGHT_COLOR_BLUE - var/auth_id = "Unknown" //Who is currently logged in? - var/list/datum/comm_message/messages = list() - var/datum/comm_message/currmsg - var/datum/comm_message/aicurrmsg - var/state = STATE_DEFAULT - var/aistate = STATE_DEFAULT - var/message_cooldown = 0 - var/ai_message_cooldown = 0 - var/tmp_alertlevel = 0 - var/stat_msg1 - var/stat_msg2 + /// Cooldown for important actions, such as messaging CentCom or other sectors + COOLDOWN_DECLARE(static/important_action_cooldown) + /// The current state of the UI + var/state = STATE_MAIN -/obj/machinery/computer/communications/proc/checkCCcooldown() - var/obj/item/circuitboard/computer/communications/CM = circuit - if(CM.lastTimeUsed + 600 > world.time) - return FALSE - return TRUE + /// The current state of the UI for AIs + var/ai_state = STATE_MAIN + + /// The name of the user who logged in + var/authorize_name + + /// The access that the card had on login + var/list/authorize_access + + /// The messages this console has been sent + var/list/datum/comm_message/messages + + /// How many times the alert level has been changed + /// Used to clear the modal to change alert level + var/alert_level_tick = 0 + + /// The last lines used for changing the status display + var/static/last_status_display /obj/machinery/computer/communications/Initialize() . = ..() GLOB.shuttle_caller_list += src -/obj/machinery/computer/communications/Topic(href, href_list) - if(..()) - return - if(!usr.canUseTopic(src, !issilicon(usr))) - return - if(!is_station_level(z) && !is_reserved_level(z)) //Can only use in transit and on SS13 - to_chat(usr, "Unable to establish a connection: \black You're too far away from the station!") - return - usr.set_machine(src) +/// Are we NOT the AI, AND we're logged in as the captain? +/obj/machinery/computer/communications/proc/authenticated_as_non_ai_captain(mob/user) + if (isAI(user)) + return FALSE + return ACCESS_CAPTAIN in authorize_access +/// Are we the AI, OR we're logged in as the captain? +/obj/machinery/computer/communications/proc/authenticated_as_ai_or_captain(mob/user) + if (isAI(user)) + return TRUE + return ACCESS_CAPTAIN in authorize_access - if(!href_list["operation"]) - return - var/obj/item/circuitboard/computer/communications/CM = circuit - switch(href_list["operation"]) - // main interface - if("main") - state = STATE_DEFAULT - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) - if("login") - var/mob/M = usr - - var/obj/item/card/id/I = M.get_idcard(TRUE) - - if(I && istype(I)) - if(check_access(I)) - authenticated = 1 - auth_id = "[I.registered_name] ([I.assignment])" - if((20 in I.access)) - authenticated = 2 - playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) - if(obj_flags & EMAGGED) - authenticated = 2 - auth_id = "Unknown" - to_chat(M, "[src] lets out a quiet alarm as its login is overridden.") - playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) - playsound(src, 'sound/machines/terminal_alert.ogg', 25, FALSE) - if(prob(25)) - for(var/mob/living/silicon/ai/AI in active_ais()) - SEND_SOUND(AI, sound('sound/machines/terminal_alert.ogg', volume = 10)) //Very quiet for balance reasons - if("logout") - authenticated = 0 - playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) - - if("swipeidseclevel") - var/mob/M = usr - var/obj/item/card/id/I = M.get_active_held_item() - if (istype(I, /obj/item/pda)) - var/obj/item/pda/pda = I - I = pda.id - if (I && istype(I)) - if(ACCESS_CAPTAIN in I.access) - var/old_level = GLOB.security_level - if(!tmp_alertlevel) - tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel < SEC_LEVEL_GREEN) - tmp_alertlevel = SEC_LEVEL_GREEN - //if(tmp_alertlevel > SEC_LEVEL_BLUE) //ORIGINAL - // tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this //ORIGINAL - if(tmp_alertlevel > SEC_LEVEL_AMBER) //SKYRAT EDIT CHANGE - ALERTS - tmp_alertlevel = SEC_LEVEL_AMBER //Cannot engage delta with this //SKYRAT EDIT CHANGE - ALERTS - set_security_level(tmp_alertlevel) - if(GLOB.security_level != old_level) - to_chat(usr, "Authorization confirmed. Modifying security level.") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - //Only notify people if an actual change happened - var/security_level = get_security_level() - log_game("[key_name(usr)] has changed the security level to [security_level] with [src] at [AREACOORD(usr)].") - message_admins("[ADMIN_LOOKUPFLW(usr)] has changed the security level to [security_level] with [src] at [AREACOORD(usr)].") - deadchat_broadcast(" has changed the security level to [security_level] with [src] at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - tmp_alertlevel = 0 - else - to_chat(usr, "You are not authorized to do this!") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) - tmp_alertlevel = 0 - state = STATE_DEFAULT - else - to_chat(usr, "You need to swipe your ID!") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) - - if("announce") - if(authenticated==2) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) - make_announcement(usr) - - if("crossserver") - if(authenticated==2) - var/dest = href_list["cross_dest"] - if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) - return - var/warning = dest == "all" ? "Please choose a message to transmit to allied stations." : "Please choose a message to transmit to [dest] sector station." - var/input = stripped_multiline_input(usr, "[warning] Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "") - if(!input || !(usr in view(1,src)) || !checkCCcooldown()) - return - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - var/payload = list() - var/network_name = CONFIG_GET(string/cross_comms_network) - if (network_name) - payload["network"] = network_name - send2otherserver("[station_name()]", input,"Comms_Console", dest == "all" ? null : list(dest), additional_data = payload) - minor_announce(input, title = "Outgoing message to allied station") - usr.log_talk(input, LOG_SAY, tag="message to the other server") - message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server\[s].") - deadchat_broadcast(" has sent an outgoing message to the other station(s).", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - CM.lastTimeUsed = world.time - - if("purchase_menu") - state = STATE_PURCHASE - - if("buyshuttle") - if(authenticated==2) - var/list/shuttles = flatten_list(SSmapping.shuttle_templates) - var/datum/map_template/shuttle/S = locate(href_list["chosen_shuttle"]) in shuttles - if(S && istype(S)) - if(SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE) - to_chat(usr, "It's a bit late to buy a new shuttle, don't you think?") - return - if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_PURCHASED) - to_chat(usr, "A replacement shuttle has already been purchased.") - else if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) - to_chat(usr, "Due to unforseen circumstances, shuttle purchasing is no longer available.") - else if(!S.prerequisites_met()) - to_chat(usr, "You have not met the requirements for purchasing this shuttle.") - else - var/points_to_check - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) - if(D) - points_to_check = D.account_balance - if(points_to_check >= S.credit_cost) - SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_PURCHASED - SSshuttle.unload_preview() - SSshuttle.existing_shuttle = SSshuttle.emergency - SSshuttle.action_load(S) - D.adjust_money(-S.credit_cost) - minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits.[S.extra_desc ? " [S.extra_desc]" : ""]" , "Shuttle Purchase") - message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].") - log_shuttle("[key_name(usr)] has purchased [S.name].") - SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]") - else - to_chat(usr, "Insufficient credits.") - - if("callshuttle") - state = STATE_DEFAULT - if(authenticated && SSshuttle.canEvac(usr)) - state = STATE_CALLSHUTTLE - if("callshuttle2") - if(authenticated) - SSshuttle.requestEvac(usr, href_list["call"]) - if(SSshuttle.emergency.timer) - post_status("shuttle") - state = STATE_DEFAULT - if("cancelshuttle") - state = STATE_DEFAULT - if(authenticated) - state = STATE_CANCELSHUTTLE - if("cancelshuttle2") - if(authenticated) - SSshuttle.cancelEvac(usr) - state = STATE_DEFAULT - if("messagelist") - currmsg = 0 - state = STATE_MESSAGELIST - if("viewmessage") - state = STATE_VIEWMESSAGE - if (!currmsg) - if(href_list["message-num"]) - var/msgnum = text2num(href_list["message-num"]) - currmsg = messages[msgnum] - else - state = STATE_MESSAGELIST - if("delmessage") - state = currmsg ? STATE_DELMESSAGE : STATE_MESSAGELIST - if("delmessage2") - if(authenticated) - if(currmsg) - if(aicurrmsg == currmsg) - aicurrmsg = null - messages -= currmsg - currmsg = null - state = STATE_MESSAGELIST - else - state = STATE_VIEWMESSAGE - if("respond") - var/answer = text2num(href_list["answer"]) - if(!currmsg || !answer || currmsg.possible_answers.len < answer) - state = STATE_MESSAGELIST - else - if(!currmsg.answered) - currmsg.answered = answer - log_game("[key_name(usr)] answered [currmsg.title] comm message. Answer : [currmsg.answered]") - if(currmsg) - currmsg.answer_callback.InvokeAsync() - state = STATE_VIEWMESSAGE - updateDialog() - if("status") - state = STATE_STATUSDISPLAY - if("securitylevel") - tmp_alertlevel = text2num( href_list["newalertlevel"] ) - if(!tmp_alertlevel) - tmp_alertlevel = 0 - state = STATE_CONFIRM_LEVEL - if("changeseclevel") - state = STATE_ALERT_LEVEL - - if("emergencyaccess") - state = STATE_TOGGLE_EMERGENCY - if("enableemergency") - make_maint_all_access() - log_game("[key_name(usr)] enabled emergency maintenance access.") - message_admins("[ADMIN_LOOKUPFLW(usr)] enabled emergency maintenance access.") - deadchat_broadcast(" enabled emergency maintenance access at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - state = STATE_DEFAULT - if("disableemergency") - revoke_maint_all_access() - log_game("[key_name(usr)] disabled emergency maintenance access.") - message_admins("[ADMIN_LOOKUPFLW(usr)] disabled emergency maintenance access.") - deadchat_broadcast(" disabled emergency maintenance access at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - state = STATE_DEFAULT - - // Status display stuff - if("setstat") - playsound(src, "terminal_type", 50, FALSE) - switch(href_list["statdisp"]) - if("message") - post_status("message", stat_msg1, stat_msg2) - if("alert") - post_status("alert", href_list["alert"]) - else - post_status(href_list["statdisp"]) - - if("setmsg1") - stat_msg1 = reject_bad_text(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40) - updateDialog() - if("setmsg2") - stat_msg2 = reject_bad_text(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40) - updateDialog() - - // OMG CENTCOM LETTERHEAD - if("MessageCentCom") - if(authenticated) - if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") - return - var/input = stripped_input(usr, "Please choose a message to transmit to CentCom via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to CentCom.", "") - if(!input || !(usr in view(1,src)) || !checkCCcooldown()) - return - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - CentCom_announce(input, usr) - to_chat(usr, "Message transmitted to Central Command.") - usr.log_talk(input, LOG_SAY, tag="CentCom announcement") - deadchat_broadcast(" has messaged CentCom, \"[input]\" at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - CM.lastTimeUsed = world.time - - // OMG SYNDICATE ...LETTERHEAD - if("MessageSyndicate") - if((authenticated) && (obj_flags & EMAGGED)) - if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) - return - var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING COORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to /??????/.", "") - if(!input || !(usr in view(1,src)) || !checkCCcooldown()) - return - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - Syndicate_announce(input, usr) - to_chat(usr, "SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND.") - usr.log_talk(input, LOG_SAY, tag="Syndicate announcement") - deadchat_broadcast(" has messaged the Syndicate, \"[input]\" at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - CM.lastTimeUsed = world.time - - if("RestoreBackup") - to_chat(usr, "Backup routing data restored!") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - obj_flags &= ~EMAGGED - updateDialog() - - if("nukerequest") //When there's no other way - if(authenticated==2) - if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") - return - var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self-Destruct Code Request.","") - if(!input || !(usr in view(1,src)) || !checkCCcooldown()) - return - Nuke_request(input, usr) - to_chat(usr, "Request sent.") - usr.log_message("has requested the nuclear codes from CentCom with reason \"[input]\"", LOG_SAY) - priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested",'sound/ai/commandreport.ogg') - CM.lastTimeUsed = world.time - - - // AI interface - if("ai-main") - aicurrmsg = null - aistate = STATE_DEFAULT - if("ai-callshuttle") - aistate = STATE_DEFAULT - if(SSshuttle.canEvac(usr)) - aistate = STATE_CALLSHUTTLE - if("ai-callshuttle2") - SSshuttle.requestEvac(usr, href_list["call"]) - aistate = STATE_DEFAULT - if("ai-messagelist") - aicurrmsg = null - aistate = STATE_MESSAGELIST - if("ai-viewmessage") - aistate = STATE_VIEWMESSAGE - if (!aicurrmsg) - if(href_list["message-num"]) - var/msgnum = text2num(href_list["message-num"]) - aicurrmsg = messages[msgnum] - else - aistate = STATE_MESSAGELIST - if("ai-delmessage") - aistate = aicurrmsg ? STATE_DELMESSAGE : STATE_MESSAGELIST - if("ai-delmessage2") - if(aicurrmsg) - if(currmsg == aicurrmsg) - currmsg = null - messages -= aicurrmsg - aicurrmsg = null - aistate = STATE_MESSAGELIST - if("ai-respond") - var/answer = text2num(href_list["answer"]) - if(!aicurrmsg || !answer || aicurrmsg.possible_answers.len < answer) - aistate = STATE_MESSAGELIST - else - if(!aicurrmsg.answered) - aicurrmsg.answered = answer - log_game("[key_name(usr)] answered [aicurrmsg.title] comm message. Answer : [aicurrmsg.answered]") - if(aicurrmsg.answer_callback) - aicurrmsg.answer_callback.InvokeAsync() - aistate = STATE_VIEWMESSAGE - if("ai-status") - aistate = STATE_STATUSDISPLAY - if("ai-announce") - make_announcement(usr, 1) - if("ai-securitylevel") - tmp_alertlevel = text2num( href_list["newalertlevel"] ) - if(!tmp_alertlevel) - tmp_alertlevel = 0 - var/old_level = GLOB.security_level - if(!tmp_alertlevel) - tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel < SEC_LEVEL_GREEN) - tmp_alertlevel = SEC_LEVEL_GREEN - //if(tmp_alertlevel > SEC_LEVEL_BLUE) //ORIGINAL - // tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this //ORIGINAL - if(tmp_alertlevel > SEC_LEVEL_AMBER) //SKYRAT EDIT CHANGE - ALERTS - tmp_alertlevel = SEC_LEVEL_AMBER //Cannot engage delta with this //SKYRAT EDIT CHANGE - ALERTS - set_security_level(tmp_alertlevel) - if(GLOB.security_level != old_level) - //Only notify people if an actual change happened - var/security_level = get_security_level() - log_game("[key_name(usr)] has changed the security level to [security_level] from [src] at [AREACOORD(usr)].") - message_admins("[ADMIN_LOOKUPFLW(usr)] has changed the security level to [security_level] from [src] at [AREACOORD(usr)].") - deadchat_broadcast(" has changed the security level to [security_level] from [src] at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - tmp_alertlevel = 0 - aistate = STATE_DEFAULT - if("ai-changeseclevel") - aistate = STATE_ALERT_LEVEL - if("ai-emergencyaccess") - aistate = STATE_TOGGLE_EMERGENCY - if("ai-enableemergency") - make_maint_all_access() - log_game("[key_name(usr)] enabled emergency maintenance access.") - message_admins("[ADMIN_LOOKUPFLW(usr)] enabled emergency maintenance access.") - deadchat_broadcast(" enabled emergency maintenance access.", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - aistate = STATE_DEFAULT - if("ai-disableemergency") - revoke_maint_all_access() - log_game("[key_name(usr)] disabled emergency maintenance access.") - message_admins("[ADMIN_LOOKUPFLW(usr)] disabled emergency maintenance access.") - deadchat_broadcast(" disabled emergency maintenance access.", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) - aistate = STATE_DEFAULT - - updateUsrDialog() +/// Are we the AI, OR logged in? +/obj/machinery/computer/communications/proc/authenticated(mob/user) + if (isAI(user)) + return TRUE + return authenticated /obj/machinery/computer/communications/attackby(obj/I, mob/user, params) if(istype(I, /obj/item/card/id)) @@ -430,298 +70,400 @@ return ..() /obj/machinery/computer/communications/emag_act(mob/user) - if(obj_flags & EMAGGED) + if (obj_flags & EMAGGED) return obj_flags |= EMAGGED - if(authenticated == 1) - authenticated = 2 + if (authenticated) + authorize_access = get_all_accesses() to_chat(user, "You scramble the communication routing circuits!") playsound(src, 'sound/machines/terminal_alert.ogg', 50, FALSE) -/obj/machinery/computer/communications/ui_interact(mob/user) +/obj/machinery/computer/communications/ui_act(action, list/params) + var/static/list/approved_states = list(STATE_BUYING_SHUTTLE, STATE_CHANGING_STATUS, STATE_MAIN, STATE_MESSAGES) + var/static/list/approved_status_pictures = list("biohazard", "blank", "default", "lockdown", "redalert", "shuttle") + . = ..() - if (z > 6) - to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") + if (.) return - var/dat = "" - if(SSshuttle.emergency.mode == SHUTTLE_CALL) - var/timeleft = SSshuttle.emergency.timeLeft() - dat += "Emergency shuttle\n
\nETA: [timeleft / 60 % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]" + . = TRUE + switch (action) + if ("answerMessage") + if (!authenticated(usr)) + return + var/answer_index = text2num(params["answer"]) + var/message_index = text2num(params["message"]) + if (!answer_index || !message_index || answer_index < 1 || message_index < 1) + return + var/datum/comm_message/message = messages[message_index] + if (message.answered) + return + message.answered = answer_index + message.answer_callback.InvokeAsync() + if ("callShuttle") + if (!authenticated(usr)) + return + var/reason = trim(params["reason"], MAX_MESSAGE_LEN) + if (length(reason) < CALL_SHUTTLE_REASON_LENGTH) + return + SSshuttle.requestEvac(usr, reason) + post_status("shuttle") + if ("changeSecurityLevel") + if (!authenticated_as_ai_or_captain(usr)) + return - var/datum/browser/popup = new(user, "communications", "Communications Console", 400, 500) + // Check if they have + if (!isAI(usr)) + var/obj/item/held_item = usr.get_active_held_item() + var/obj/item/card/id/id_card = held_item?.GetID() + if (!istype(id_card)) + to_chat(usr, "You need to swipe your ID!") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) + return + if (!(ACCESS_CAPTAIN in id_card.access)) + to_chat(usr, "You are not authorized to do this!") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) + return - if(issilicon(user)) - var/dat2 = interact_ai(user) // give the AI a different interact proc to limit its access - if(dat2) - dat += dat2 - popup.set_content(dat) - popup.open() - return + var/new_sec_level = seclevel2num(params["newSecurityLevel"]) + if (new_sec_level != SEC_LEVEL_GREEN && new_sec_level != SEC_LEVEL_BLUE) + return + if (GLOB.security_level == new_sec_level) + return - switch(state) - if(STATE_DEFAULT) - if (authenticated) - if(SSshuttle.emergencyCallAmount) - if(SSshuttle.emergencyLastCallLoc) - dat += "Most recent shuttle call/recall traced to: [format_text(SSshuttle.emergencyLastCallLoc.name)]
" - else - dat += "Unable to trace most recent shuttle call/recall signal.
" - dat += "Logged in as: [auth_id]" - dat += "
" - dat += "
\[ Log Out \]
" - dat += "
General Functions" - dat += "
\[ Message List \]" - switch(SSshuttle.emergency.mode) - if(SHUTTLE_IDLE, SHUTTLE_RECALL) - dat += "
\[ Call Emergency Shuttle \]" - else - dat += "
\[ Cancel Shuttle Call \]" + set_security_level(new_sec_level) - dat += "
\[ Set Status Display \]" - if (authenticated==2) - dat += "

Captain Functions" - dat += "
\[ Make a Captain's Announcement \]" - var/list/cross_servers = CONFIG_GET(keyed_list/cross_server) + to_chat(usr, "Authorization confirmed. Modifying security level.") + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + + // Only notify people if an actual change happened + log_game("[key_name(usr)] has changed the security level to [params["newSecurityLevel"]] with [src] at [AREACOORD(usr)].") + message_admins("[ADMIN_LOOKUPFLW(usr)] has changed the security level to [params["newSecurityLevel"]] with [src] at [AREACOORD(usr)].") + deadchat_broadcast(" has changed the security level to [params["newSecurityLevel"]] with [src] at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type=DEADCHAT_ANNOUNCEMENT) + + alert_level_tick += 1 + if ("deleteMessage") + if (!authenticated(usr)) + return + var/message_index = text2num(params["message"]) + if (!message_index) + return + LAZYREMOVE(messages, LAZYACCESS(messages, message_index)) + if ("makePriorityAnnouncement") + if (!authenticated_as_ai_or_captain(usr)) + return + make_announcement(usr) + if ("messageAssociates") + if (!authenticated_as_non_ai_captain(usr)) + return + if (!COOLDOWN_FINISHED(src, important_action_cooldown)) + return + + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + var/message = trim(html_encode(params["message"]), MAX_MESSAGE_LEN) + + var/emagged = obj_flags & EMAGGED + if (emagged) + message_syndicate(message, usr) + to_chat(usr, "SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND.") + else + message_centcom(message, usr) + to_chat(usr, "Message transmitted to Central Command.") + + var/associates = emagged ? "the Syndicate": "CentCom" + usr.log_talk(message, LOG_SAY, tag = "message to [associates]") + deadchat_broadcast(" has messaged [associates], \"[message]\" at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type = DEADCHAT_ANNOUNCEMENT) + COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN) + if ("purchaseShuttle") + var/can_buy_shuttles_or_fail_reason = can_buy_shuttles(usr) + if (can_buy_shuttles_or_fail_reason != TRUE) + if (can_buy_shuttles_or_fail_reason != FALSE) + to_chat(usr, "[can_buy_shuttles_or_fail_reason]") + return + var/list/shuttles = flatten_list(SSmapping.shuttle_templates) + var/datum/map_template/shuttle/shuttle = locate(params["shuttle"]) in shuttles + if (!istype(shuttle)) + return + if (!shuttle.prerequisites_met()) + to_chat(usr, "You have not met the requirements for purchasing this shuttle.") + return + var/datum/bank_account/bank_account = SSeconomy.get_dep_account(ACCOUNT_CAR) + if (bank_account.account_balance < shuttle.credit_cost) + return + SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_PURCHASED + SSshuttle.unload_preview() + SSshuttle.existing_shuttle = SSshuttle.emergency + SSshuttle.action_load(shuttle) + bank_account.adjust_money(-shuttle.credit_cost) + minor_announce("[usr.real_name] has purchased [shuttle.name] for [shuttle.credit_cost] credits.[shuttle.extra_desc ? " [shuttle.extra_desc]" : ""]" , "Shuttle Purchase") + message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [shuttle.name].") + log_shuttle("[key_name(usr)] has purchased [shuttle.name].") + SSblackbox.record_feedback("text", "shuttle_purchase", 1, shuttle.name) + state = STATE_MAIN + if ("recallShuttle") + // AIs cannot recall the shuttle + if (!authenticated(usr) || isAI(usr)) + return + SSshuttle.cancelEvac(usr) + if ("requestNukeCodes") + if (!authenticated_as_non_ai_captain(usr)) + return + if (!COOLDOWN_FINISHED(src, important_action_cooldown)) + return + var/reason = trim(html_encode(params["reason"]), MAX_MESSAGE_LEN) + nuke_request(reason, usr) + to_chat(usr, "Request sent.") + usr.log_message("has requested the nuclear codes from CentCom with reason \"[reason]\"", LOG_SAY) + priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested", 'sound/ai/commandreport.ogg') + playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) + COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN) + if ("restoreBackupRoutingData") + if (!authenticated_as_non_ai_captain(usr)) + return + if (!(obj_flags & EMAGGED)) + return + to_chat(usr, "Backup routing data restored.") + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + obj_flags &= ~EMAGGED + if ("sendToOtherSector") + if (!authenticated_as_non_ai_captain(usr)) + return + if (!can_send_messages_to_other_sectors(usr)) + return + if (!COOLDOWN_FINISHED(src, important_action_cooldown)) + return + + var/message = trim(html_encode(params["message"]), MAX_MESSAGE_LEN) + if (!message) + return + + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + + var/destination = params["destination"] + var/list/payload = list() + + var/network_name = CONFIG_GET(string/cross_comms_network) + if (network_name) + payload["network"] = network_name + + send2otherserver(station_name(), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload) + minor_announce(message, title = "Outgoing message to allied station") + usr.log_talk(message, LOG_SAY, tag = "message to the other server") + message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server\[s].") + deadchat_broadcast(" has sent an outgoing message to the other station(s).
", "[usr.real_name]", usr, message_type = DEADCHAT_ANNOUNCEMENT) + + COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN) + if ("setState") + if (!authenticated(usr)) + return + if (!(params["state"] in approved_states)) + return + if (state == STATE_BUYING_SHUTTLE && can_buy_shuttles(usr) != TRUE) + return + set_state(usr, params["state"]) + playsound(src, "terminal_type", 50, FALSE) + if ("setStatusMessage") + if (!authenticated(usr)) + return + var/line_one = reject_bad_text(params["lineOne"] || "", MAX_STATUS_LINE_LENGTH) + var/line_two = reject_bad_text(params["lineTwo"] || "", MAX_STATUS_LINE_LENGTH) + post_status("alert", "blank") + post_status("message", line_one, line_two) + last_status_display = list(line_one, line_two) + playsound(src, "terminal_type", 50, FALSE) + if ("setStatusPicture") + if (!authenticated(usr)) + return + var/picture = params["picture"] + if (!(picture in approved_status_pictures)) + return + post_status("alert", picture) + playsound(src, "terminal_type", 50, FALSE) + if ("toggleAuthentication") + // Log out if we're logged in + if (authorize_name) + authenticated = FALSE + authorize_access = null + authorize_name = null + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) + return + + if (obj_flags & EMAGGED) + authenticated = TRUE + authorize_access = get_all_accesses() + authorize_name = "Unknown" + to_chat(usr, "[src] lets out a quiet alarm as its login is overridden.") + playsound(src, 'sound/machines/terminal_alert.ogg', 25, FALSE) + else + var/obj/item/card/id/id_card = usr.get_idcard(hand_first = TRUE) + if (check_access(id_card)) + authenticated = TRUE + authorize_access = id_card.access + authorize_name = "[id_card.registered_name] - [id_card.assignment]" + + state = STATE_MAIN + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + if ("toggleEmergencyAccess") + if (!authenticated_as_ai_or_captain(usr)) + return + if (GLOB.emergency_access) + revoke_maint_all_access() + log_game("[key_name(usr)] disabled emergency maintenance access.") + message_admins("[ADMIN_LOOKUPFLW(usr)] disabled emergency maintenance access.") + deadchat_broadcast(" disabled emergency maintenance access at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type = DEADCHAT_ANNOUNCEMENT) + else + make_maint_all_access() + log_game("[key_name(usr)] enabled emergency maintenance access.") + message_admins("[ADMIN_LOOKUPFLW(usr)] enabled emergency maintenance access.") + deadchat_broadcast(" enabled emergency maintenance access at [get_area_name(usr, TRUE)].", "[usr.real_name]", usr, message_type = DEADCHAT_ANNOUNCEMENT) + +/obj/machinery/computer/communications/ui_data(mob/user) + var/list/data = list( + "authenticated" = FALSE, + "emagged" = FALSE, + ) + + var/ui_state = isAI(user) ? ai_state : state + + if (authenticated || isAI(user)) + data["authenticated"] = TRUE + data["canLogOut"] = !isAI(user) + data["page"] = ui_state + + if (obj_flags & EMAGGED) + data["emagged"] = TRUE + + switch (ui_state) + if (STATE_MAIN) + data["canBuyShuttles"] = can_buy_shuttles(user) + data["canMakeAnnouncement"] = FALSE + data["canMessageAssociates"] = FALSE + data["canRequestNuke"] = FALSE + data["canSendToSectors"] = FALSE + data["canSetAlertLevel"] = FALSE + data["canToggleEmergencyAccess"] = FALSE + data["importantActionReady"] = COOLDOWN_FINISHED(src, important_action_cooldown) + data["shuttleCalled"] = FALSE + data["shuttleLastCalled"] = FALSE + + data["alertLevel"] = get_security_level() + data["authorizeName"] = authorize_name + data["canLogOut"] = !isAI(user) + data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user) + + if (authenticated_as_non_ai_captain(user)) + data["canMessageAssociates"] = TRUE + data["canRequestNuke"] = TRUE + + if (can_send_messages_to_other_sectors(user)) + data["canSendToSectors"] = TRUE + + var/list/sectors = list() var/our_id = CONFIG_GET(string/cross_comms_name) - if(cross_servers.len) - for(var/server in cross_servers) - if(server == our_id) - continue - dat += "
\[ Send a message to station in [server] sector. \]" - if(cross_servers.len > 2) - dat += "
\[ Send a message to all allied stations \]" - if(SSmapping.config.allow_custom_shuttles) - dat += "
\[ Purchase Shuttle \]" - dat += "
\[ Change Alert Level \]" - dat += "
\[ Emergency Maintenance Access \]" - dat += "
\[ Request Nuclear Authentication Codes \]" - if(!(obj_flags & EMAGGED)) - dat += "
\[ Send Message to CentCom \]" - else - dat += "
\[ Send Message to \[UNKNOWN\] \]" - dat += "
\[ Restore Backup Routing Data \]" - else - dat += "
\[ Log In \]" - if(STATE_CALLSHUTTLE) - dat += get_call_shuttle_form() - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) - if(STATE_CANCELSHUTTLE) - dat += get_cancel_shuttle_form() - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) - if(STATE_MESSAGELIST) - dat += "Messages:" - for(var/i in 1 to messages.len) - var/datum/comm_message/M = messages[i] - dat += "
[M.title]" - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - if(STATE_VIEWMESSAGE) - if (currmsg) - dat += "[currmsg.title]

[currmsg.content]" - if(!currmsg.answered && currmsg.possible_answers.len) - for(var/i in 1 to currmsg.possible_answers.len) - var/answer = currmsg.possible_answers[i] - dat += "
\[ Answer : [answer] \]" - else if(currmsg.answered) - var/answered = currmsg.possible_answers[currmsg.answered] - dat += "
Archived Answer : [answered]" - dat += "

\[ Delete \]" - else - aistate = STATE_MESSAGELIST - attack_hand(user) - return - if(STATE_DELMESSAGE) - if (currmsg) - dat += "Are you sure you want to delete this message? \[ OK | Cancel \]" - else - state = STATE_MESSAGELIST - attack_hand(user) - return - if(STATE_STATUSDISPLAY) - dat += "Set Status Displays
" - dat += "\[ Clear \]
" - dat += "\[ Shuttle ETA \]
" - dat += "\[ Message \]" - dat += "
" - dat += "\[ Alert: None |" - dat += " Red Alert |" - dat += " Lockdown |" - dat += " Biohazard \]

" - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - if(STATE_ALERT_LEVEL) - dat += "Current alert level: [get_security_level()]
" - if(GLOB.security_level == SEC_LEVEL_DELTA) - dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate." - else - //SKYRAT CHANGE ADDITION BEGIN - ALERTS - dat += "Amber
" - dat += "Orange
" - dat += "Violet
" - //SKYRAT CHANGE END - dat += "Blue
" - dat += "Green" - if(STATE_CONFIRM_LEVEL) - dat += "Current alert level: [get_security_level()]
" - dat += "Confirm the change to: [num2seclevel(tmp_alertlevel)]
" - dat += "Swipe ID to confirm change.
" - if(STATE_TOGGLE_EMERGENCY) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) - if(GLOB.emergency_access == 1) - dat += "Emergency Maintenance Access is currently ENABLED" - dat += "
Restore maintenance access restrictions?
\[ OK | Cancel \]" - else - dat += "Emergency Maintenance Access is currently DISABLED" - dat += "
Lift access restrictions on maintenance and external airlocks?
\[ OK | Cancel \]" - if(STATE_PURCHASE) - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) - dat += "Budget: [D.account_balance] Credits.
" - dat += "
" - dat += "Caution: Purchasing dangerous shuttles may lead to mutiny and/or death.
" - dat += "
" - for(var/shuttle_id in SSmapping.shuttle_templates) - var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id] - if(S.can_be_bought && S.credit_cost < INFINITY) - dat += "[S.name] | [S.credit_cost] Credits
" - dat += "[S.description]
" - if(S.prerequisites) - dat += "Prerequisites: [S.prerequisites]
" - dat += "(Purchase)

" + for (var/server in CONFIG_GET(keyed_list/cross_server)) + if (server == our_id) + continue + sectors += server - dat += "

\[ [(state != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" + data["sectors"] = sectors - popup.set_content(dat) - popup.open() + if (authenticated_as_ai_or_captain(user)) + data["canToggleEmergencyAccess"] = TRUE + data["emergencyAccess"] = GLOB.emergency_access -/obj/machinery/computer/communications/proc/get_javascript_header(form_id) - var/dat = {""} - return dat + data["alertLevelTick"] = alert_level_tick + data["canMakeAnnouncement"] = TRUE + data["canSetAlertLevel"] = isAI(user) ? "NO_SWIPE_NEEDED" : "SWIPE_NEEDED" -/obj/machinery/computer/communications/proc/get_call_shuttle_form(ai_interface = 0) - var/form_id = "callshuttle" - var/dat = get_javascript_header(form_id) - dat += "
" - dat += "" - dat += "" - dat += "Nature of emergency:
" - dat += "
Are you sure you want to call the shuttle? \[ Call \]" - return dat + if (SSshuttle.emergency.mode != SHUTTLE_IDLE && SSshuttle.emergency.mode != SHUTTLE_RECALL) + data["shuttleCalled"] = TRUE + data["shuttleRecallable"] = SSshuttle.canRecall() -/obj/machinery/computer/communications/proc/get_cancel_shuttle_form() - var/form_id = "cancelshuttle" - var/dat = get_javascript_header(form_id) - dat += "" - dat += "" - dat += "" + if (SSshuttle.emergencyCallAmount) + data["shuttleCalledPreviously"] = TRUE + if (SSshuttle.emergencyLastCallLoc) + data["shuttleLastCalled"] = format_text(SSshuttle.emergencyLastCallLoc.name) + if (STATE_MESSAGES) + data["messages"] = list() - dat += "
Are you sure you want to cancel the shuttle? \[ Cancel \]" - return dat + if (messages) + for (var/_message in messages) + var/datum/comm_message/message = _message + data["messages"] += list(list( + "answered" = message.answered, + "content" = message.content, + "title" = message.title, + "possibleAnswers" = message.possible_answers, + )) + if (STATE_BUYING_SHUTTLE) + var/datum/bank_account/bank_account = SSeconomy.get_dep_account(ACCOUNT_CAR) + var/list/shuttles = list() -/obj/machinery/computer/communications/proc/interact_ai(mob/living/silicon/ai/user) - var/dat = "" - switch(aistate) - if(STATE_DEFAULT) - if(SSshuttle.emergencyCallAmount) - if(SSshuttle.emergencyLastCallLoc) - dat += "Latest emergency signal trace attempt successful.
Last signal origin: [format_text(SSshuttle.emergencyLastCallLoc.name)].
" - else - dat += "Latest emergency signal trace attempt failed.
" - if(authenticated) - dat += "Current login: [auth_id]" - else - dat += "Current login: None" - dat += "

General Functions" - dat += "
\[ Message List \]" - if(SSshuttle.emergency.mode == SHUTTLE_IDLE) - dat += "
\[ Call Emergency Shuttle \]" - dat += "
\[ Set Status Display \]" - dat += "

Special Functions" - dat += "
\[ Make an Announcement \]" - dat += "
\[ Change Alert Level \]" - dat += "
\[ Emergency Maintenance Access \]" - if(STATE_CALLSHUTTLE) - dat += get_call_shuttle_form(1) - if(STATE_MESSAGELIST) - dat += "Messages:" - for(var/i in 1 to messages.len) - var/datum/comm_message/M = messages[i] - dat += "
[M.title]" - if(STATE_VIEWMESSAGE) - if (aicurrmsg) - dat += "[aicurrmsg.title]

[aicurrmsg.content]" - if(!aicurrmsg.answered && aicurrmsg.possible_answers.len) - for(var/i in 1 to aicurrmsg.possible_answers.len) - var/answer = aicurrmsg.possible_answers[i] - dat += "
\[ Answer : [answer] \]" - else if(aicurrmsg.answered) - var/answered = aicurrmsg.possible_answers[aicurrmsg.answered] - dat += "
Archived Answer : [answered]" - dat += "

\[ Delete \]" - else - aistate = STATE_MESSAGELIST - attack_hand(user) - return null - if(STATE_DELMESSAGE) - if(aicurrmsg) - dat += "Are you sure you want to delete this message? \[ OK | Cancel \]" - else - aistate = STATE_MESSAGELIST - attack_hand(user) - return + for (var/shuttle_id in SSmapping.shuttle_templates) + var/datum/map_template/shuttle/shuttle_template = SSmapping.shuttle_templates[shuttle_id] + if (!shuttle_template.can_be_bought || shuttle_template.credit_cost == INFINITY) + continue + shuttles += list(list( + "name" = shuttle_template.name, + "description" = shuttle_template.description, + "creditCost" = shuttle_template.credit_cost, + "prerequisites" = shuttle_template.prerequisites, + "ref" = REF(shuttle_template), + )) - if(STATE_STATUSDISPLAY) - dat += "Set Status Displays
" - dat += "\[ Clear \]
" - dat += "\[ Shuttle ETA \]
" - dat += "\[ Message \]" - dat += "
" - dat += "\[ Alert: None |" - dat += " Red Alert |" - dat += " Lockdown |" - dat += " Biohazard \]

" + data["budget"] = bank_account.account_balance + data["shuttles"] = shuttles + if (STATE_CHANGING_STATUS) + data["lineOne"] = last_status_display ? last_status_display[1] : "" + data["lineTwo"] = last_status_display ? last_status_display[2] : "" - if(STATE_ALERT_LEVEL) - dat += "Current alert level: [get_security_level()]
" - if(GLOB.security_level == SEC_LEVEL_DELTA) - dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate." - else - //SKYRAT EDIT ADDITION - ALERTS - dat += "Amber
" - dat += "Orange
" - dat += "Violet
" - //SKYRAT EDIT END - dat += "Blue
" - dat += "Green" + return data - if(STATE_TOGGLE_EMERGENCY) - if(GLOB.emergency_access == 1) - dat += "Emergency Maintenance Access is currently ENABLED" - dat += "
Restore maintenance access restrictions?
\[ OK | Cancel \]" - else - dat += "Emergency Maintenance Access is currently DISABLED" - dat += "
Lift access restrictions on maintenance and external airlocks?
\[ OK | Cancel \]" +/obj/machinery/computer/communications/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "CommunicationsConsole") + ui.open() - dat += "

\[ [(aistate != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" - return dat +/obj/machinery/computer/communications/ui_static_data(mob/user) + return list( + "callShuttleReasonMinLength" = CALL_SHUTTLE_REASON_LENGTH, + "maxStatusLineLength" = MAX_STATUS_LINE_LENGTH, + "maxMessageLength" = MAX_MESSAGE_LEN, + ) -/obj/machinery/computer/communications/proc/make_announcement(mob/living/user, is_silicon) - if(!SScommunications.can_announce(user, is_silicon)) +/obj/machinery/computer/communications/proc/set_state(mob/user, new_state) + if (isAI(user)) + ai_state = new_state + else + state = new_state + +/// Returns TRUE if the user can buy shuttles. +/// If they cannot, returns FALSE or a string detailing why. +/obj/machinery/computer/communications/proc/can_buy_shuttles(mob/user) + if (!SSmapping.config.allow_custom_shuttles) + return FALSE + if (!authenticated_as_non_ai_captain(user)) + return FALSE + if (SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE) + return "The shuttle is already in transit." + if (SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_PURCHASED) + return "A replacement shuttle has already been purchased." + if (SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) + return "Due to unforseen circumstances, shuttle purchasing is no longer available." + return TRUE + +/obj/machinery/computer/communications/proc/can_send_messages_to_other_sectors(mob/user) + if (!authenticated_as_non_ai_captain(user)) + return + + return length(CONFIG_GET(keyed_list/cross_server)) > 0 + +/obj/machinery/computer/communications/proc/make_announcement(mob/living/user) + var/is_ai = isAI(user) + if(!SScommunications.can_announce(user, is_ai)) to_chat(user, "Intercomms recharging. Please stand by.") return var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?") @@ -732,7 +474,7 @@ to_chat(user, "You find yourself unable to speak.") else input = user.treat_message(input) //Adds slurs and so on. Someone should make this use languages too. - SScommunications.make_announcement(user, is_silicon, input) + SScommunications.make_announcement(user, is_ai, input) deadchat_broadcast(" made a priority announcement from [get_area_name(usr, TRUE)].", "[user.real_name]", user, message_type=DEADCHAT_ANNOUNCEMENT) /obj/machinery/computer/communications/proc/post_status(command, data1, data2) @@ -758,12 +500,13 @@ SSshuttle.autoEvac() return ..() -/obj/machinery/computer/communications/proc/overrideCooldown() - var/obj/item/circuitboard/computer/communications/CM = circuit - CM.lastTimeUsed = 0 +/// Override the cooldown for special actions +/// Used in places such as CentCom messaging back so that the crew can answer right away +/obj/machinery/computer/communications/proc/override_cooldown() + COOLDOWN_RESET(src, important_action_cooldown) /obj/machinery/computer/communications/proc/add_message(datum/comm_message/new_message) - messages += new_message + LAZYADD(messages, new_message) /datum/comm_message var/title @@ -781,14 +524,9 @@ if(new_possible_answers) possible_answers = new_possible_answers -#undef STATE_DEFAULT -#undef STATE_CALLSHUTTLE -#undef STATE_CANCELSHUTTLE -#undef STATE_MESSAGELIST -#undef STATE_VIEWMESSAGE -#undef STATE_DELMESSAGE -#undef STATE_STATUSDISPLAY -#undef STATE_ALERT_LEVEL -#undef STATE_CONFIRM_LEVEL -#undef STATE_TOGGLE_EMERGENCY -#undef STATE_PURCHASE +#undef IMPORTANT_ACTION_COOLDOWN +#undef MAX_STATUS_LINE_LENGTH +#undef STATE_BUYING_SHUTTLE +#undef STATE_CHANGING_STATUS +#undef STATE_MAIN +#undef STATE_MESSAGES diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index e3dcba60f33..091afbbd50a 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -187,7 +187,6 @@ name = "Communications (Computer Board)" icon_state = "engineering" build_path = /obj/machinery/computer/communications - var/lastTimeUsed = 0 /obj/item/circuitboard/computer/message_monitor name = "Message Monitor (Computer Board)" diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index a11c9a24596..873007a2a55 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -38,10 +38,10 @@ cross.icon_state = "holylight" font_color = "blue" prayer_type = "SPIRITUAL PRAYER" - + var/msg_tmp = msg msg = "[icon2html(cross, GLOB.admins)][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]: [msg]" - + for(var/client/C in GLOB.admins) if(C.prefs.chat_toggles & CHAT_PRAYER) to_chat(C, msg, confidential = TRUE) @@ -53,23 +53,26 @@ SSblackbox.record_feedback("tally", "admin_verb", 1, "Prayer") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! //log_admin("HELP: [key_name(src)]: [msg]") -/proc/CentCom_announce(text , mob/Sender) +/// Used by communications consoles to message CentCom +/proc/message_centcom(text, mob/sender) var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN) - msg = "CENTCOM:[ADMIN_FULLMONTY(Sender)] [ADMIN_CENTCOM_REPLY(Sender)]: [msg]" + msg = "CENTCOM:[ADMIN_FULLMONTY(sender)] [ADMIN_CENTCOM_REPLY(sender)]: [msg]" to_chat(GLOB.admins, msg, confidential = TRUE) - for(var/obj/machinery/computer/communications/C in GLOB.machines) - C.overrideCooldown() + for(var/obj/machinery/computer/communications/console in GLOB.machines) + console.override_cooldown() -/proc/Syndicate_announce(text , mob/Sender) +/// Used by communications consoles to message the Syndicate +/proc/message_syndicate(text, mob/sender) var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN) - msg = "SYNDICATE:[ADMIN_FULLMONTY(Sender)] [ADMIN_SYNDICATE_REPLY(Sender)]: [msg]" + msg = "SYNDICATE:[ADMIN_FULLMONTY(sender)] [ADMIN_SYNDICATE_REPLY(sender)]: [msg]" to_chat(GLOB.admins, msg, confidential = TRUE) - for(var/obj/machinery/computer/communications/C in GLOB.machines) - C.overrideCooldown() + for(var/obj/machinery/computer/communications/console in GLOB.machines) + console.override_cooldown() -/proc/Nuke_request(text , mob/Sender) +/// Used by communications consoles to request the nuclear launch codes +/proc/nuke_request(text, mob/sender) var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN) - msg = "NUKE CODE REQUEST:[ADMIN_FULLMONTY(Sender)] [ADMIN_CENTCOM_REPLY(Sender)] [ADMIN_SET_SD_CODE]: [msg]" + msg = "NUKE CODE REQUEST:[ADMIN_FULLMONTY(sender)] [ADMIN_CENTCOM_REPLY(sender)] [ADMIN_SET_SD_CODE]: [msg]" to_chat(GLOB.admins, msg, confidential = TRUE) - for(var/obj/machinery/computer/communications/C in GLOB.machines) - C.overrideCooldown() + for(var/obj/machinery/computer/communications/console in GLOB.machines) + console.override_cooldown() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index bd85233d166..09a8056d063 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -313,7 +313,9 @@ to_chat(usr, "Wireless control is disabled!") return - if(!SSshuttle.canEvac(src)) + var/can_evac_or_fail_reason = SSshuttle.canEvac(src) + if(can_evac_or_fail_reason != TRUE) + to_chat(usr, "[can_evac_or_fail_reason]") return var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as null|text diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js new file mode 100644 index 00000000000..4cd0b7e6b5f --- /dev/null +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -0,0 +1,667 @@ +import { sortBy } from "common/collections"; +import { capitalize } from "common/string"; +import { useBackend, useLocalState } from "../backend"; +import { Box, Button, Flex, Input, Modal, Section, Table, TextArea } from "../components"; +import { Window } from "../layouts"; + +const STATE_BUYING_SHUTTLE = "buying_shuttle"; +const STATE_CHANGING_STATUS = "changing_status"; +const STATE_MAIN = "main"; +const STATE_MESSAGES = "messages"; + +// Used for whether or not you need to swipe to confirm an alert level change +const SWIPE_NEEDED = "SWIPE_NEEDED"; + +const sortByCreditCost = sortBy(shuttle => shuttle.creditCost); + +const AlertButton = (props, context) => { + const { act, data } = useBackend(context); + const { alertLevelTick, canSetAlertLevel } = data; + const { alertLevel, setShowAlertLevelConfirm } = props; + + const thisIsCurrent = data.alertLevel === alertLevel; + + return ( +